]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
ARM: at91: move SoC detection to its own driver
authorAlexandre Belloni <alexandre.belloni@free-electrons.com>
Thu, 16 Feb 2017 10:31:06 +0000 (11:31 +0100)
committerAlexandre Belloni <alexandre.belloni@free-electrons.com>
Fri, 31 Mar 2017 18:36:10 +0000 (20:36 +0200)
To simplify machine init and as the soc_device struct is not used as the
parent for on-chip devices anymore, move SoC detection to its own driver.

Change in dmesg:
 - before:
DMA: preallocated 256 KiB pool for atomic coherent allocations
AT91: Detected SoC family: sama5d2
AT91: Detected SoC: sama5d27, revision 0
No ATAGs?
clocksource: tcb_clksrc: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 184217874325 ns
at_xdmac f0010000.dma-controller: 16 channels, mapped at 0xe085b000
SCSI subsystem initialized

 - after:
DMA: preallocated 256 KiB pool for atomic coherent allocations
No ATAGs?
clocksource: tcb_clksrc: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 184217874325 ns
at_xdmac f0010000.dma-controller: 16 channels, mapped at 0xe0859000
AT91: Detected SoC family: sama5d2
AT91: Detected SoC: sama5d27, revision 0
SCSI subsystem initialized

Suggested-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/at91rm9200.c
arch/arm/mach-at91/at91sam9.c
arch/arm/mach-at91/sama5.c
arch/arm/mach-at91/soc.c [deleted file]
drivers/soc/Kconfig
drivers/soc/Makefile
drivers/soc/atmel/Kconfig [new file with mode: 0644]
drivers/soc/atmel/Makefile [new file with mode: 0644]
drivers/soc/atmel/soc.c [new file with mode: 0644]
drivers/soc/atmel/soc.h [moved from arch/arm/mach-at91/soc.h with 100% similarity]

index 858ef14f961c5b15f5d94fbba0680e94eab52203..cfd8f60a9268f85f30048e92949c0d13051e71d8 100644 (file)
@@ -1,7 +1,6 @@
 #
 # Makefile for the linux kernel.
 #
-obj-y          := soc.o
 
 # CPU-specific support
 obj-$(CONFIG_SOC_AT91RM9200)   += at91rm9200.o
index d068ec3cd1f6dbaf7c2e9ff99ac5e22f82fb6e81..656ad409a2533ad832611ade5e0149d0fd80aafb 100644 (file)
 #include <asm/mach/arch.h>
 
 #include "generic.h"
-#include "soc.h"
-
-static const struct at91_soc rm9200_socs[] = {
-       AT91_SOC(AT91RM9200_CIDR_MATCH, 0, "at91rm9200 BGA", "at91rm9200"),
-       { /* sentinel */ },
-};
 
 static void __init at91rm9200_dt_device_init(void)
 {
-       struct soc_device *soc;
-       struct device *soc_dev = NULL;
-
-       soc = at91_soc_init(rm9200_socs);
-       if (soc != NULL)
-               soc_dev = soc_device_to_device(soc);
-
-       of_platform_default_populate(NULL, NULL, soc_dev);
+       of_platform_default_populate(NULL, NULL, NULL);
 
        at91rm9200_pm_init();
 }
index c089bfd0dc2f90efaa75bfeaa66ee26435e423b5..3dbdef4d3cbf5a5f979046abcf6de8241365ae71 100644 (file)
 #include <asm/system_misc.h>
 
 #include "generic.h"
-#include "soc.h"
-
-static const struct at91_soc at91sam9_socs[] = {
-       AT91_SOC(AT91SAM9260_CIDR_MATCH, 0, "at91sam9260", NULL),
-       AT91_SOC(AT91SAM9261_CIDR_MATCH, 0, "at91sam9261", NULL),
-       AT91_SOC(AT91SAM9263_CIDR_MATCH, 0, "at91sam9263", NULL),
-       AT91_SOC(AT91SAM9G20_CIDR_MATCH, 0, "at91sam9g20", NULL),
-       AT91_SOC(AT91SAM9RL64_CIDR_MATCH, 0, "at91sam9rl64", NULL),
-       AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9M11_EXID_MATCH,
-                "at91sam9m11", "at91sam9g45"),
-       AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9M10_EXID_MATCH,
-                "at91sam9m10", "at91sam9g45"),
-       AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9G46_EXID_MATCH,
-                "at91sam9g46", "at91sam9g45"),
-       AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9G45_EXID_MATCH,
-                "at91sam9g45", "at91sam9g45"),
-       AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G15_EXID_MATCH,
-                "at91sam9g15", "at91sam9x5"),
-       AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G35_EXID_MATCH,
-                "at91sam9g35", "at91sam9x5"),
-       AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9X35_EXID_MATCH,
-                "at91sam9x35", "at91sam9x5"),
-       AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G25_EXID_MATCH,
-                "at91sam9g25", "at91sam9x5"),
-       AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9X25_EXID_MATCH,
-                "at91sam9x25", "at91sam9x5"),
-       AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9CN12_EXID_MATCH,
-                "at91sam9cn12", "at91sam9n12"),
-       AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9N12_EXID_MATCH,
-                "at91sam9n12", "at91sam9n12"),
-       AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9CN11_EXID_MATCH,
-                "at91sam9cn11", "at91sam9n12"),
-       AT91_SOC(AT91SAM9XE128_CIDR_MATCH, 0, "at91sam9xe128", "at91sam9xe128"),
-       AT91_SOC(AT91SAM9XE256_CIDR_MATCH, 0, "at91sam9xe256", "at91sam9xe256"),
-       AT91_SOC(AT91SAM9XE512_CIDR_MATCH, 0, "at91sam9xe512", "at91sam9xe512"),
-       { /* sentinel */ },
-};
 
 static void __init at91sam9_init(void)
 {
-       struct soc_device *soc;
-       struct device *soc_dev = NULL;
-
-       soc = at91_soc_init(at91sam9_socs);
-       if (soc != NULL)
-               soc_dev = soc_device_to_device(soc);
-
-       of_platform_default_populate(NULL, NULL, soc_dev);
+       of_platform_default_populate(NULL, NULL, NULL);
 
        at91sam9_pm_init();
 }
index b272c45b400fe70df69ab46e799fd7dca60efc8b..6d157d0ead8e3d61b474212d538c7a2de86a3b70 100644 (file)
 #include <asm/system_misc.h>
 
 #include "generic.h"
-#include "soc.h"
-
-static const struct at91_soc sama5_socs[] = {
-       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D21CU_EXID_MATCH,
-                "sama5d21", "sama5d2"),
-       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D22CU_EXID_MATCH,
-                "sama5d22", "sama5d2"),
-       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D23CU_EXID_MATCH,
-                "sama5d23", "sama5d2"),
-       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CX_EXID_MATCH,
-                "sama5d24", "sama5d2"),
-       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CU_EXID_MATCH,
-                "sama5d24", "sama5d2"),
-       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D26CU_EXID_MATCH,
-                "sama5d26", "sama5d2"),
-       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CU_EXID_MATCH,
-                "sama5d27", "sama5d2"),
-       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CN_EXID_MATCH,
-                "sama5d27", "sama5d2"),
-       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CU_EXID_MATCH,
-                "sama5d28", "sama5d2"),
-       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CN_EXID_MATCH,
-                "sama5d28", "sama5d2"),
-       AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D31_EXID_MATCH,
-                "sama5d31", "sama5d3"),
-       AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D33_EXID_MATCH,
-                "sama5d33", "sama5d3"),
-       AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D34_EXID_MATCH,
-                "sama5d34", "sama5d3"),
-       AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D35_EXID_MATCH,
-                "sama5d35", "sama5d3"),
-       AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D36_EXID_MATCH,
-                "sama5d36", "sama5d3"),
-       AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D41_EXID_MATCH,
-                "sama5d41", "sama5d4"),
-       AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D42_EXID_MATCH,
-                "sama5d42", "sama5d4"),
-       AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D43_EXID_MATCH,
-                "sama5d43", "sama5d4"),
-       AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D44_EXID_MATCH,
-                "sama5d44", "sama5d4"),
-       { /* sentinel */ },
-};
 
 static void __init sama5_dt_device_init(void)
 {
-       struct soc_device *soc;
-       struct device *soc_dev = NULL;
-
-       soc = at91_soc_init(sama5_socs);
-       if (soc != NULL)
-               soc_dev = soc_device_to_device(soc);
-
-       of_platform_default_populate(NULL, NULL, soc_dev);
+       of_platform_default_populate(NULL, NULL, NULL);
        sama5_pm_init();
 }
 
diff --git a/arch/arm/mach-at91/soc.c b/arch/arm/mach-at91/soc.c
deleted file mode 100644 (file)
index c6fda75..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2015 Atmel
- *
- * Alexandre Belloni <alexandre.belloni@free-electrons.com
- * Boris Brezillon <boris.brezillon@free-electrons.com
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- *
- */
-
-#define pr_fmt(fmt)    "AT91: " fmt
-
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/slab.h>
-#include <linux/sys_soc.h>
-
-#include "soc.h"
-
-#define AT91_DBGU_CIDR                 0x40
-#define AT91_DBGU_EXID                 0x44
-#define AT91_CHIPID_CIDR               0x00
-#define AT91_CHIPID_EXID               0x04
-#define AT91_CIDR_VERSION(x)           ((x) & 0x1f)
-#define AT91_CIDR_EXT                  BIT(31)
-#define AT91_CIDR_MATCH_MASK           0x7fffffe0
-
-static int __init at91_get_cidr_exid_from_dbgu(u32 *cidr, u32 *exid)
-{
-       struct device_node *np;
-       void __iomem *regs;
-
-       np = of_find_compatible_node(NULL, NULL, "atmel,at91rm9200-dbgu");
-       if (!np)
-               np = of_find_compatible_node(NULL, NULL,
-                                            "atmel,at91sam9260-dbgu");
-       if (!np)
-               return -ENODEV;
-
-       regs = of_iomap(np, 0);
-       of_node_put(np);
-
-       if (!regs) {
-               pr_warn("Could not map DBGU iomem range");
-               return -ENXIO;
-       }
-
-       *cidr = readl(regs + AT91_DBGU_CIDR);
-       *exid = readl(regs + AT91_DBGU_EXID);
-
-       iounmap(regs);
-
-       return 0;
-}
-
-static int __init at91_get_cidr_exid_from_chipid(u32 *cidr, u32 *exid)
-{
-       struct device_node *np;
-       void __iomem *regs;
-
-       np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-chipid");
-       if (!np)
-               return -ENODEV;
-
-       regs = of_iomap(np, 0);
-       of_node_put(np);
-
-       if (!regs) {
-               pr_warn("Could not map DBGU iomem range");
-               return -ENXIO;
-       }
-
-       *cidr = readl(regs + AT91_CHIPID_CIDR);
-       *exid = readl(regs + AT91_CHIPID_EXID);
-
-       iounmap(regs);
-
-       return 0;
-}
-
-struct soc_device * __init at91_soc_init(const struct at91_soc *socs)
-{
-       struct soc_device_attribute *soc_dev_attr;
-       const struct at91_soc *soc;
-       struct soc_device *soc_dev;
-       u32 cidr, exid;
-       int ret;
-
-       /*
-        * With SAMA5D2 and later SoCs, CIDR and EXID registers are no more
-        * in the dbgu device but in the chipid device whose purpose is only
-        * to expose these two registers.
-        */
-       ret = at91_get_cidr_exid_from_dbgu(&cidr, &exid);
-       if (ret)
-               ret = at91_get_cidr_exid_from_chipid(&cidr, &exid);
-       if (ret) {
-               if (ret == -ENODEV)
-                       pr_warn("Could not find identification node");
-               return NULL;
-       }
-
-       for (soc = socs; soc->name; soc++) {
-               if (soc->cidr_match != (cidr & AT91_CIDR_MATCH_MASK))
-                       continue;
-
-               if (!(cidr & AT91_CIDR_EXT) || soc->exid_match == exid)
-                       break;
-       }
-
-       if (!soc->name) {
-               pr_warn("Could not find matching SoC description\n");
-               return NULL;
-       }
-
-       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
-       if (!soc_dev_attr)
-               return NULL;
-
-       soc_dev_attr->family = soc->family;
-       soc_dev_attr->soc_id = soc->name;
-       soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%X",
-                                          AT91_CIDR_VERSION(cidr));
-       soc_dev = soc_device_register(soc_dev_attr);
-       if (IS_ERR(soc_dev)) {
-               kfree(soc_dev_attr->revision);
-               kfree(soc_dev_attr);
-               pr_warn("Could not register SoC device\n");
-               return NULL;
-       }
-
-       if (soc->family)
-               pr_info("Detected SoC family: %s\n", soc->family);
-       pr_info("Detected SoC: %s, revision %X\n", soc->name,
-               AT91_CIDR_VERSION(cidr));
-
-       return soc_dev;
-}
index f09023f7ab11902523563541615e91077b2d1f4a..45e5b13a3c02ba3e4373ff685985191bccc2873a 100644 (file)
@@ -1,5 +1,6 @@
 menu "SOC (System On Chip) specific Drivers"
 
+source "drivers/soc/atmel/Kconfig"
 source "drivers/soc/bcm/Kconfig"
 source "drivers/soc/fsl/Kconfig"
 source "drivers/soc/mediatek/Kconfig"
index 05eae52a30b45133ed78da635118976327d9de78..3467de7d3890d7d7c27eb7182334c6d18f68ba66 100644 (file)
@@ -2,6 +2,7 @@
 # Makefile for the Linux Kernel SOC specific device drivers.
 #
 
+obj-$(CONFIG_ARCH_AT91)                += atmel/
 obj-y                          += bcm/
 obj-$(CONFIG_ARCH_DOVE)                += dove/
 obj-$(CONFIG_MACH_DOVE)                += dove/
diff --git a/drivers/soc/atmel/Kconfig b/drivers/soc/atmel/Kconfig
new file mode 100644 (file)
index 0000000..6242ebb
--- /dev/null
@@ -0,0 +1,6 @@
+config AT91_SOC_ID
+       bool "SoC bus for Atmel ARM SoCs"
+       depends on ARCH_AT91 || COMPILE_TEST
+       default ARCH_AT91
+       help
+         Include support for the SoC bus on the Atmel ARM SoCs.
diff --git a/drivers/soc/atmel/Makefile b/drivers/soc/atmel/Makefile
new file mode 100644 (file)
index 0000000..2d92f32
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_AT91_SOC_ID) += soc.o
diff --git a/drivers/soc/atmel/soc.c b/drivers/soc/atmel/soc.c
new file mode 100644 (file)
index 0000000..4790094
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2015 Atmel
+ *
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com
+ * Boris Brezillon <boris.brezillon@free-electrons.com
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ */
+
+#define pr_fmt(fmt)    "AT91: " fmt
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+
+#include "soc.h"
+
+#define AT91_DBGU_CIDR                 0x40
+#define AT91_DBGU_EXID                 0x44
+#define AT91_CHIPID_CIDR               0x00
+#define AT91_CHIPID_EXID               0x04
+#define AT91_CIDR_VERSION(x)           ((x) & 0x1f)
+#define AT91_CIDR_EXT                  BIT(31)
+#define AT91_CIDR_MATCH_MASK           0x7fffffe0
+
+static const struct at91_soc __initconst socs[] = {
+#ifdef CONFIG_SOC_AT91RM9200
+       AT91_SOC(AT91RM9200_CIDR_MATCH, 0, "at91rm9200 BGA", "at91rm9200"),
+#endif
+#ifdef CONFIG_SOC_AT91SAM9
+       AT91_SOC(AT91SAM9260_CIDR_MATCH, 0, "at91sam9260", NULL),
+       AT91_SOC(AT91SAM9261_CIDR_MATCH, 0, "at91sam9261", NULL),
+       AT91_SOC(AT91SAM9263_CIDR_MATCH, 0, "at91sam9263", NULL),
+       AT91_SOC(AT91SAM9G20_CIDR_MATCH, 0, "at91sam9g20", NULL),
+       AT91_SOC(AT91SAM9RL64_CIDR_MATCH, 0, "at91sam9rl64", NULL),
+       AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9M11_EXID_MATCH,
+                "at91sam9m11", "at91sam9g45"),
+       AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9M10_EXID_MATCH,
+                "at91sam9m10", "at91sam9g45"),
+       AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9G46_EXID_MATCH,
+                "at91sam9g46", "at91sam9g45"),
+       AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9G45_EXID_MATCH,
+                "at91sam9g45", "at91sam9g45"),
+       AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G15_EXID_MATCH,
+                "at91sam9g15", "at91sam9x5"),
+       AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G35_EXID_MATCH,
+                "at91sam9g35", "at91sam9x5"),
+       AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9X35_EXID_MATCH,
+                "at91sam9x35", "at91sam9x5"),
+       AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G25_EXID_MATCH,
+                "at91sam9g25", "at91sam9x5"),
+       AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9X25_EXID_MATCH,
+                "at91sam9x25", "at91sam9x5"),
+       AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9CN12_EXID_MATCH,
+                "at91sam9cn12", "at91sam9n12"),
+       AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9N12_EXID_MATCH,
+                "at91sam9n12", "at91sam9n12"),
+       AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9CN11_EXID_MATCH,
+                "at91sam9cn11", "at91sam9n12"),
+       AT91_SOC(AT91SAM9XE128_CIDR_MATCH, 0, "at91sam9xe128", "at91sam9xe128"),
+       AT91_SOC(AT91SAM9XE256_CIDR_MATCH, 0, "at91sam9xe256", "at91sam9xe256"),
+       AT91_SOC(AT91SAM9XE512_CIDR_MATCH, 0, "at91sam9xe512", "at91sam9xe512"),
+#endif
+#ifdef CONFIG_SOC_SAMA5
+       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D21CU_EXID_MATCH,
+                "sama5d21", "sama5d2"),
+       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D22CU_EXID_MATCH,
+                "sama5d22", "sama5d2"),
+       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D23CU_EXID_MATCH,
+                "sama5d23", "sama5d2"),
+       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CX_EXID_MATCH,
+                "sama5d24", "sama5d2"),
+       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CU_EXID_MATCH,
+                "sama5d24", "sama5d2"),
+       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D26CU_EXID_MATCH,
+                "sama5d26", "sama5d2"),
+       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CU_EXID_MATCH,
+                "sama5d27", "sama5d2"),
+       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CN_EXID_MATCH,
+                "sama5d27", "sama5d2"),
+       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CU_EXID_MATCH,
+                "sama5d28", "sama5d2"),
+       AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CN_EXID_MATCH,
+                "sama5d28", "sama5d2"),
+       AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D31_EXID_MATCH,
+                "sama5d31", "sama5d3"),
+       AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D33_EXID_MATCH,
+                "sama5d33", "sama5d3"),
+       AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D34_EXID_MATCH,
+                "sama5d34", "sama5d3"),
+       AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D35_EXID_MATCH,
+                "sama5d35", "sama5d3"),
+       AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D36_EXID_MATCH,
+                "sama5d36", "sama5d3"),
+       AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D41_EXID_MATCH,
+                "sama5d41", "sama5d4"),
+       AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D42_EXID_MATCH,
+                "sama5d42", "sama5d4"),
+       AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D43_EXID_MATCH,
+                "sama5d43", "sama5d4"),
+       AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D44_EXID_MATCH,
+                "sama5d44", "sama5d4"),
+#endif
+       { /* sentinel */ },
+};
+
+static int __init at91_get_cidr_exid_from_dbgu(u32 *cidr, u32 *exid)
+{
+       struct device_node *np;
+       void __iomem *regs;
+
+       np = of_find_compatible_node(NULL, NULL, "atmel,at91rm9200-dbgu");
+       if (!np)
+               np = of_find_compatible_node(NULL, NULL,
+                                            "atmel,at91sam9260-dbgu");
+       if (!np)
+               return -ENODEV;
+
+       regs = of_iomap(np, 0);
+       of_node_put(np);
+
+       if (!regs) {
+               pr_warn("Could not map DBGU iomem range");
+               return -ENXIO;
+       }
+
+       *cidr = readl(regs + AT91_DBGU_CIDR);
+       *exid = readl(regs + AT91_DBGU_EXID);
+
+       iounmap(regs);
+
+       return 0;
+}
+
+static int __init at91_get_cidr_exid_from_chipid(u32 *cidr, u32 *exid)
+{
+       struct device_node *np;
+       void __iomem *regs;
+
+       np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-chipid");
+       if (!np)
+               return -ENODEV;
+
+       regs = of_iomap(np, 0);
+       of_node_put(np);
+
+       if (!regs) {
+               pr_warn("Could not map DBGU iomem range");
+               return -ENXIO;
+       }
+
+       *cidr = readl(regs + AT91_CHIPID_CIDR);
+       *exid = readl(regs + AT91_CHIPID_EXID);
+
+       iounmap(regs);
+
+       return 0;
+}
+
+struct soc_device * __init at91_soc_init(const struct at91_soc *socs)
+{
+       struct soc_device_attribute *soc_dev_attr;
+       const struct at91_soc *soc;
+       struct soc_device *soc_dev;
+       u32 cidr, exid;
+       int ret;
+
+       /*
+        * With SAMA5D2 and later SoCs, CIDR and EXID registers are no more
+        * in the dbgu device but in the chipid device whose purpose is only
+        * to expose these two registers.
+        */
+       ret = at91_get_cidr_exid_from_dbgu(&cidr, &exid);
+       if (ret)
+               ret = at91_get_cidr_exid_from_chipid(&cidr, &exid);
+       if (ret) {
+               if (ret == -ENODEV)
+                       pr_warn("Could not find identification node");
+               return NULL;
+       }
+
+       for (soc = socs; soc->name; soc++) {
+               if (soc->cidr_match != (cidr & AT91_CIDR_MATCH_MASK))
+                       continue;
+
+               if (!(cidr & AT91_CIDR_EXT) || soc->exid_match == exid)
+                       break;
+       }
+
+       if (!soc->name) {
+               pr_warn("Could not find matching SoC description\n");
+               return NULL;
+       }
+
+       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return NULL;
+
+       soc_dev_attr->family = soc->family;
+       soc_dev_attr->soc_id = soc->name;
+       soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%X",
+                                          AT91_CIDR_VERSION(cidr));
+       soc_dev = soc_device_register(soc_dev_attr);
+       if (IS_ERR(soc_dev)) {
+               kfree(soc_dev_attr->revision);
+               kfree(soc_dev_attr);
+               pr_warn("Could not register SoC device\n");
+               return NULL;
+       }
+
+       if (soc->family)
+               pr_info("Detected SoC family: %s\n", soc->family);
+       pr_info("Detected SoC: %s, revision %X\n", soc->name,
+               AT91_CIDR_VERSION(cidr));
+
+       return soc_dev;
+}
+
+static int __init atmel_soc_device_init(void)
+{
+       at91_soc_init(socs);
+
+       return 0;
+}
+subsys_initcall(atmel_soc_device_init);