ARM: at91: use chipid device for soc detection
authorLudovic Desroches <ludovic.desroches@atmel.com>
Fri, 18 Mar 2016 07:21:19 +0000 (08:21 +0100)
committerNicolas Ferre <nicolas.ferre@atmel.com>
Tue, 29 Mar 2016 14:34:21 +0000 (16:34 +0200)
So far, the CIDR and EXID registers were in the DBGU interface. This device
has disappeared with the SAMA5D2 family. These registers are exposed
through a new device called chipid.

Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
[nicolas.ferre@atmel.com: remove useless warnings]
Acked-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Acked-by: Rob Herring <robh@kernel.org>
[arnd@arndb.de: suggest to use static functions to reduce scope]
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Documentation/devicetree/bindings/arm/atmel-at91.txt
arch/arm/mach-at91/soc.c

index 7fd64ec9ee1d5dcf78f1c1ff241a7b39f31da4f6..0b1fcbfe2299c3c350b0c8e1a9a76ce113969d0d 100644 (file)
@@ -41,6 +41,10 @@ compatible: must be one of:
        - "atmel,sama5d43"
        - "atmel,sama5d44"
 
+Chipid required properties:
+- compatible: Should be "atmel,sama5d2-chipid"
+- reg : Should contain registers location and length
+
 PIT Timer required properties:
 - compatible: Should be "atmel,at91sam9260-pit"
 - reg: Should contain registers location and length
index 54343ffa3e53352ba142c7ed1894f00f37193bc3..c6fda75ddb8970a320a9055d56b1eee45178c49f 100644 (file)
 #include "soc.h"
 
 #define AT91_DBGU_CIDR                 0x40
-#define AT91_DBGU_CIDR_VERSION(x)      ((x) & 0x1f)
-#define AT91_DBGU_CIDR_EXT             BIT(31)
-#define AT91_DBGU_CIDR_MATCH_MASK      0x7fffffe0
 #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
 
-struct soc_device * __init at91_soc_init(const struct at91_soc *socs)
+static int __init at91_get_cidr_exid_from_dbgu(u32 *cidr, u32 *exid)
 {
-       struct soc_device_attribute *soc_dev_attr;
-       const struct at91_soc *soc;
-       struct soc_device *soc_dev;
        struct device_node *np;
        void __iomem *regs;
-       u32 cidr, exid;
 
        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;
 
-       if (!np) {
-               pr_warn("Could not find DBGU node");
-               return NULL;
+       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 NULL;
+               return -ENXIO;
        }
 
-       cidr = readl(regs + AT91_DBGU_CIDR);
-       exid = readl(regs + AT91_DBGU_EXID);
+       *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_DBGU_CIDR_MATCH_MASK))
+               if (soc->cidr_match != (cidr & AT91_CIDR_MATCH_MASK))
                        continue;
 
-               if (!(cidr & AT91_DBGU_CIDR_EXT) || soc->exid_match == exid)
+               if (!(cidr & AT91_CIDR_EXT) || soc->exid_match == exid)
                        break;
        }
 
@@ -79,7 +124,7 @@ struct soc_device * __init at91_soc_init(const struct at91_soc *socs)
        soc_dev_attr->family = soc->family;
        soc_dev_attr->soc_id = soc->name;
        soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%X",
-                                          AT91_DBGU_CIDR_VERSION(cidr));
+                                          AT91_CIDR_VERSION(cidr));
        soc_dev = soc_device_register(soc_dev_attr);
        if (IS_ERR(soc_dev)) {
                kfree(soc_dev_attr->revision);
@@ -91,7 +136,7 @@ struct soc_device * __init at91_soc_init(const struct at91_soc *socs)
        if (soc->family)
                pr_info("Detected SoC family: %s\n", soc->family);
        pr_info("Detected SoC: %s, revision %X\n", soc->name,
-               AT91_DBGU_CIDR_VERSION(cidr));
+               AT91_CIDR_VERSION(cidr));
 
        return soc_dev;
 }