Browse Source

Merge tag 'at91-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91 into next/soc

First SoC batch for 4.7:
- chipid registers reading for SoC detection

* tag 'at91-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91:
  ARM: at91/soc: reference the whole sama5d2 family
  ARM: at91: use chipid device for soc detection

Signed-off-by: Olof Johansson <olof@lixom.net>
Olof Johansson 9 years ago
parent
commit
49ad80df26

+ 4 - 0
Documentation/devicetree/bindings/arm/atmel-at91.txt

@@ -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

+ 19 - 1
arch/arm/mach-at91/sama5.c

@@ -18,8 +18,26 @@
 #include "soc.h"
 
 static const struct at91_soc sama5_socs[] = {
-	AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27_EXID_MATCH,
+	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,

+ 63 - 18
arch/arm/mach-at91/soc.c

@@ -22,48 +22,93 @@
 #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;
 }

+ 11 - 1
arch/arm/mach-at91/soc.h

@@ -63,7 +63,17 @@ at91_soc_init(const struct at91_soc *socs);
 #define AT91SAM9XE512_CIDR_MATCH	0x329aa3a0
 
 #define SAMA5D2_CIDR_MATCH		0x0a5c08c0
-#define SAMA5D27_EXID_MATCH		0x00000021
+#define SAMA5D21CU_EXID_MATCH		0x0000005a
+#define SAMA5D22CU_EXID_MATCH		0x00000059
+#define SAMA5D22CN_EXID_MATCH		0x00000069
+#define SAMA5D23CU_EXID_MATCH		0x00000058
+#define SAMA5D24CX_EXID_MATCH		0x00000004
+#define SAMA5D24CU_EXID_MATCH		0x00000014
+#define SAMA5D26CU_EXID_MATCH		0x00000012
+#define SAMA5D27CU_EXID_MATCH		0x00000011
+#define SAMA5D27CN_EXID_MATCH		0x00000021
+#define SAMA5D28CU_EXID_MATCH		0x00000010
+#define SAMA5D28CN_EXID_MATCH		0x00000020
 
 #define SAMA5D3_CIDR_MATCH		0x0a5c07c0
 #define SAMA5D31_EXID_MATCH		0x00444300