diff options
author | Alexandre Belloni <alexandre.belloni@free-electrons.com> | 2017-02-16 05:31:06 -0500 |
---|---|---|
committer | Alexandre Belloni <alexandre.belloni@free-electrons.com> | 2017-03-31 14:36:10 -0400 |
commit | b32de9dd38fcf9063e993dcdd64cc64ad344d3ac (patch) | |
tree | 366da11875feb5f0ecaf486984493f6f07bcd76d | |
parent | 8c9290aee18ef33fd7d6817ef36bb430278e542b (diff) |
ARM: at91: move SoC detection to its own driver
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>
-rw-r--r-- | arch/arm/mach-at91/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-at91/at91rm9200.c | 15 | ||||
-rw-r--r-- | arch/arm/mach-at91/at91sam9.c | 46 | ||||
-rw-r--r-- | arch/arm/mach-at91/sama5.c | 52 | ||||
-rw-r--r-- | arch/arm/mach-at91/soc.c | 142 | ||||
-rw-r--r-- | drivers/soc/Kconfig | 1 | ||||
-rw-r--r-- | drivers/soc/Makefile | 1 | ||||
-rw-r--r-- | drivers/soc/atmel/Kconfig | 6 | ||||
-rw-r--r-- | drivers/soc/atmel/Makefile | 1 | ||||
-rw-r--r-- | drivers/soc/atmel/soc.c | 231 | ||||
-rw-r--r-- | drivers/soc/atmel/soc.h (renamed from arch/arm/mach-at91/soc.h) | 0 |
11 files changed, 243 insertions, 253 deletions
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index 858ef14f961c..cfd8f60a9268 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile | |||
@@ -1,7 +1,6 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the linux kernel. | 2 | # Makefile for the linux kernel. |
3 | # | 3 | # |
4 | obj-y := soc.o | ||
5 | 4 | ||
6 | # CPU-specific support | 5 | # CPU-specific support |
7 | obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o | 6 | obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o |
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c index d068ec3cd1f6..656ad409a253 100644 --- a/arch/arm/mach-at91/at91rm9200.c +++ b/arch/arm/mach-at91/at91rm9200.c | |||
@@ -14,23 +14,10 @@ | |||
14 | #include <asm/mach/arch.h> | 14 | #include <asm/mach/arch.h> |
15 | 15 | ||
16 | #include "generic.h" | 16 | #include "generic.h" |
17 | #include "soc.h" | ||
18 | |||
19 | static const struct at91_soc rm9200_socs[] = { | ||
20 | AT91_SOC(AT91RM9200_CIDR_MATCH, 0, "at91rm9200 BGA", "at91rm9200"), | ||
21 | { /* sentinel */ }, | ||
22 | }; | ||
23 | 17 | ||
24 | static void __init at91rm9200_dt_device_init(void) | 18 | static void __init at91rm9200_dt_device_init(void) |
25 | { | 19 | { |
26 | struct soc_device *soc; | 20 | of_platform_default_populate(NULL, NULL, NULL); |
27 | struct device *soc_dev = NULL; | ||
28 | |||
29 | soc = at91_soc_init(rm9200_socs); | ||
30 | if (soc != NULL) | ||
31 | soc_dev = soc_device_to_device(soc); | ||
32 | |||
33 | of_platform_default_populate(NULL, NULL, soc_dev); | ||
34 | 21 | ||
35 | at91rm9200_pm_init(); | 22 | at91rm9200_pm_init(); |
36 | } | 23 | } |
diff --git a/arch/arm/mach-at91/at91sam9.c b/arch/arm/mach-at91/at91sam9.c index c089bfd0dc2f..3dbdef4d3cbf 100644 --- a/arch/arm/mach-at91/at91sam9.c +++ b/arch/arm/mach-at91/at91sam9.c | |||
@@ -14,54 +14,10 @@ | |||
14 | #include <asm/system_misc.h> | 14 | #include <asm/system_misc.h> |
15 | 15 | ||
16 | #include "generic.h" | 16 | #include "generic.h" |
17 | #include "soc.h" | ||
18 | |||
19 | static const struct at91_soc at91sam9_socs[] = { | ||
20 | AT91_SOC(AT91SAM9260_CIDR_MATCH, 0, "at91sam9260", NULL), | ||
21 | AT91_SOC(AT91SAM9261_CIDR_MATCH, 0, "at91sam9261", NULL), | ||
22 | AT91_SOC(AT91SAM9263_CIDR_MATCH, 0, "at91sam9263", NULL), | ||
23 | AT91_SOC(AT91SAM9G20_CIDR_MATCH, 0, "at91sam9g20", NULL), | ||
24 | AT91_SOC(AT91SAM9RL64_CIDR_MATCH, 0, "at91sam9rl64", NULL), | ||
25 | AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9M11_EXID_MATCH, | ||
26 | "at91sam9m11", "at91sam9g45"), | ||
27 | AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9M10_EXID_MATCH, | ||
28 | "at91sam9m10", "at91sam9g45"), | ||
29 | AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9G46_EXID_MATCH, | ||
30 | "at91sam9g46", "at91sam9g45"), | ||
31 | AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9G45_EXID_MATCH, | ||
32 | "at91sam9g45", "at91sam9g45"), | ||
33 | AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G15_EXID_MATCH, | ||
34 | "at91sam9g15", "at91sam9x5"), | ||
35 | AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G35_EXID_MATCH, | ||
36 | "at91sam9g35", "at91sam9x5"), | ||
37 | AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9X35_EXID_MATCH, | ||
38 | "at91sam9x35", "at91sam9x5"), | ||
39 | AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G25_EXID_MATCH, | ||
40 | "at91sam9g25", "at91sam9x5"), | ||
41 | AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9X25_EXID_MATCH, | ||
42 | "at91sam9x25", "at91sam9x5"), | ||
43 | AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9CN12_EXID_MATCH, | ||
44 | "at91sam9cn12", "at91sam9n12"), | ||
45 | AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9N12_EXID_MATCH, | ||
46 | "at91sam9n12", "at91sam9n12"), | ||
47 | AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9CN11_EXID_MATCH, | ||
48 | "at91sam9cn11", "at91sam9n12"), | ||
49 | AT91_SOC(AT91SAM9XE128_CIDR_MATCH, 0, "at91sam9xe128", "at91sam9xe128"), | ||
50 | AT91_SOC(AT91SAM9XE256_CIDR_MATCH, 0, "at91sam9xe256", "at91sam9xe256"), | ||
51 | AT91_SOC(AT91SAM9XE512_CIDR_MATCH, 0, "at91sam9xe512", "at91sam9xe512"), | ||
52 | { /* sentinel */ }, | ||
53 | }; | ||
54 | 17 | ||
55 | static void __init at91sam9_init(void) | 18 | static void __init at91sam9_init(void) |
56 | { | 19 | { |
57 | struct soc_device *soc; | 20 | of_platform_default_populate(NULL, NULL, NULL); |
58 | struct device *soc_dev = NULL; | ||
59 | |||
60 | soc = at91_soc_init(at91sam9_socs); | ||
61 | if (soc != NULL) | ||
62 | soc_dev = soc_device_to_device(soc); | ||
63 | |||
64 | of_platform_default_populate(NULL, NULL, soc_dev); | ||
65 | 21 | ||
66 | at91sam9_pm_init(); | 22 | at91sam9_pm_init(); |
67 | } | 23 | } |
diff --git a/arch/arm/mach-at91/sama5.c b/arch/arm/mach-at91/sama5.c index b272c45b400f..6d157d0ead8e 100644 --- a/arch/arm/mach-at91/sama5.c +++ b/arch/arm/mach-at91/sama5.c | |||
@@ -15,60 +15,10 @@ | |||
15 | #include <asm/system_misc.h> | 15 | #include <asm/system_misc.h> |
16 | 16 | ||
17 | #include "generic.h" | 17 | #include "generic.h" |
18 | #include "soc.h" | ||
19 | |||
20 | static const struct at91_soc sama5_socs[] = { | ||
21 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D21CU_EXID_MATCH, | ||
22 | "sama5d21", "sama5d2"), | ||
23 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D22CU_EXID_MATCH, | ||
24 | "sama5d22", "sama5d2"), | ||
25 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D23CU_EXID_MATCH, | ||
26 | "sama5d23", "sama5d2"), | ||
27 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CX_EXID_MATCH, | ||
28 | "sama5d24", "sama5d2"), | ||
29 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CU_EXID_MATCH, | ||
30 | "sama5d24", "sama5d2"), | ||
31 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D26CU_EXID_MATCH, | ||
32 | "sama5d26", "sama5d2"), | ||
33 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CU_EXID_MATCH, | ||
34 | "sama5d27", "sama5d2"), | ||
35 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CN_EXID_MATCH, | ||
36 | "sama5d27", "sama5d2"), | ||
37 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CU_EXID_MATCH, | ||
38 | "sama5d28", "sama5d2"), | ||
39 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CN_EXID_MATCH, | ||
40 | "sama5d28", "sama5d2"), | ||
41 | AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D31_EXID_MATCH, | ||
42 | "sama5d31", "sama5d3"), | ||
43 | AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D33_EXID_MATCH, | ||
44 | "sama5d33", "sama5d3"), | ||
45 | AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D34_EXID_MATCH, | ||
46 | "sama5d34", "sama5d3"), | ||
47 | AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D35_EXID_MATCH, | ||
48 | "sama5d35", "sama5d3"), | ||
49 | AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D36_EXID_MATCH, | ||
50 | "sama5d36", "sama5d3"), | ||
51 | AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D41_EXID_MATCH, | ||
52 | "sama5d41", "sama5d4"), | ||
53 | AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D42_EXID_MATCH, | ||
54 | "sama5d42", "sama5d4"), | ||
55 | AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D43_EXID_MATCH, | ||
56 | "sama5d43", "sama5d4"), | ||
57 | AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D44_EXID_MATCH, | ||
58 | "sama5d44", "sama5d4"), | ||
59 | { /* sentinel */ }, | ||
60 | }; | ||
61 | 18 | ||
62 | static void __init sama5_dt_device_init(void) | 19 | static void __init sama5_dt_device_init(void) |
63 | { | 20 | { |
64 | struct soc_device *soc; | 21 | of_platform_default_populate(NULL, NULL, NULL); |
65 | struct device *soc_dev = NULL; | ||
66 | |||
67 | soc = at91_soc_init(sama5_socs); | ||
68 | if (soc != NULL) | ||
69 | soc_dev = soc_device_to_device(soc); | ||
70 | |||
71 | of_platform_default_populate(NULL, NULL, soc_dev); | ||
72 | sama5_pm_init(); | 22 | sama5_pm_init(); |
73 | } | 23 | } |
74 | 24 | ||
diff --git a/arch/arm/mach-at91/soc.c b/arch/arm/mach-at91/soc.c deleted file mode 100644 index c6fda75ddb89..000000000000 --- a/arch/arm/mach-at91/soc.c +++ /dev/null | |||
@@ -1,142 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Atmel | ||
3 | * | ||
4 | * Alexandre Belloni <alexandre.belloni@free-electrons.com | ||
5 | * Boris Brezillon <boris.brezillon@free-electrons.com | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #define pr_fmt(fmt) "AT91: " fmt | ||
14 | |||
15 | #include <linux/io.h> | ||
16 | #include <linux/of.h> | ||
17 | #include <linux/of_address.h> | ||
18 | #include <linux/of_platform.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/sys_soc.h> | ||
21 | |||
22 | #include "soc.h" | ||
23 | |||
24 | #define AT91_DBGU_CIDR 0x40 | ||
25 | #define AT91_DBGU_EXID 0x44 | ||
26 | #define AT91_CHIPID_CIDR 0x00 | ||
27 | #define AT91_CHIPID_EXID 0x04 | ||
28 | #define AT91_CIDR_VERSION(x) ((x) & 0x1f) | ||
29 | #define AT91_CIDR_EXT BIT(31) | ||
30 | #define AT91_CIDR_MATCH_MASK 0x7fffffe0 | ||
31 | |||
32 | static int __init at91_get_cidr_exid_from_dbgu(u32 *cidr, u32 *exid) | ||
33 | { | ||
34 | struct device_node *np; | ||
35 | void __iomem *regs; | ||
36 | |||
37 | np = of_find_compatible_node(NULL, NULL, "atmel,at91rm9200-dbgu"); | ||
38 | if (!np) | ||
39 | np = of_find_compatible_node(NULL, NULL, | ||
40 | "atmel,at91sam9260-dbgu"); | ||
41 | if (!np) | ||
42 | return -ENODEV; | ||
43 | |||
44 | regs = of_iomap(np, 0); | ||
45 | of_node_put(np); | ||
46 | |||
47 | if (!regs) { | ||
48 | pr_warn("Could not map DBGU iomem range"); | ||
49 | return -ENXIO; | ||
50 | } | ||
51 | |||
52 | *cidr = readl(regs + AT91_DBGU_CIDR); | ||
53 | *exid = readl(regs + AT91_DBGU_EXID); | ||
54 | |||
55 | iounmap(regs); | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static int __init at91_get_cidr_exid_from_chipid(u32 *cidr, u32 *exid) | ||
61 | { | ||
62 | struct device_node *np; | ||
63 | void __iomem *regs; | ||
64 | |||
65 | np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-chipid"); | ||
66 | if (!np) | ||
67 | return -ENODEV; | ||
68 | |||
69 | regs = of_iomap(np, 0); | ||
70 | of_node_put(np); | ||
71 | |||
72 | if (!regs) { | ||
73 | pr_warn("Could not map DBGU iomem range"); | ||
74 | return -ENXIO; | ||
75 | } | ||
76 | |||
77 | *cidr = readl(regs + AT91_CHIPID_CIDR); | ||
78 | *exid = readl(regs + AT91_CHIPID_EXID); | ||
79 | |||
80 | iounmap(regs); | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | struct soc_device * __init at91_soc_init(const struct at91_soc *socs) | ||
86 | { | ||
87 | struct soc_device_attribute *soc_dev_attr; | ||
88 | const struct at91_soc *soc; | ||
89 | struct soc_device *soc_dev; | ||
90 | u32 cidr, exid; | ||
91 | int ret; | ||
92 | |||
93 | /* | ||
94 | * With SAMA5D2 and later SoCs, CIDR and EXID registers are no more | ||
95 | * in the dbgu device but in the chipid device whose purpose is only | ||
96 | * to expose these two registers. | ||
97 | */ | ||
98 | ret = at91_get_cidr_exid_from_dbgu(&cidr, &exid); | ||
99 | if (ret) | ||
100 | ret = at91_get_cidr_exid_from_chipid(&cidr, &exid); | ||
101 | if (ret) { | ||
102 | if (ret == -ENODEV) | ||
103 | pr_warn("Could not find identification node"); | ||
104 | return NULL; | ||
105 | } | ||
106 | |||
107 | for (soc = socs; soc->name; soc++) { | ||
108 | if (soc->cidr_match != (cidr & AT91_CIDR_MATCH_MASK)) | ||
109 | continue; | ||
110 | |||
111 | if (!(cidr & AT91_CIDR_EXT) || soc->exid_match == exid) | ||
112 | break; | ||
113 | } | ||
114 | |||
115 | if (!soc->name) { | ||
116 | pr_warn("Could not find matching SoC description\n"); | ||
117 | return NULL; | ||
118 | } | ||
119 | |||
120 | soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); | ||
121 | if (!soc_dev_attr) | ||
122 | return NULL; | ||
123 | |||
124 | soc_dev_attr->family = soc->family; | ||
125 | soc_dev_attr->soc_id = soc->name; | ||
126 | soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%X", | ||
127 | AT91_CIDR_VERSION(cidr)); | ||
128 | soc_dev = soc_device_register(soc_dev_attr); | ||
129 | if (IS_ERR(soc_dev)) { | ||
130 | kfree(soc_dev_attr->revision); | ||
131 | kfree(soc_dev_attr); | ||
132 | pr_warn("Could not register SoC device\n"); | ||
133 | return NULL; | ||
134 | } | ||
135 | |||
136 | if (soc->family) | ||
137 | pr_info("Detected SoC family: %s\n", soc->family); | ||
138 | pr_info("Detected SoC: %s, revision %X\n", soc->name, | ||
139 | AT91_CIDR_VERSION(cidr)); | ||
140 | |||
141 | return soc_dev; | ||
142 | } | ||
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index f09023f7ab11..45e5b13a3c02 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig | |||
@@ -1,5 +1,6 @@ | |||
1 | menu "SOC (System On Chip) specific Drivers" | 1 | menu "SOC (System On Chip) specific Drivers" |
2 | 2 | ||
3 | source "drivers/soc/atmel/Kconfig" | ||
3 | source "drivers/soc/bcm/Kconfig" | 4 | source "drivers/soc/bcm/Kconfig" |
4 | source "drivers/soc/fsl/Kconfig" | 5 | source "drivers/soc/fsl/Kconfig" |
5 | source "drivers/soc/mediatek/Kconfig" | 6 | source "drivers/soc/mediatek/Kconfig" |
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 05eae52a30b4..3467de7d3890 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile | |||
@@ -2,6 +2,7 @@ | |||
2 | # Makefile for the Linux Kernel SOC specific device drivers. | 2 | # Makefile for the Linux Kernel SOC specific device drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_ARCH_AT91) += atmel/ | ||
5 | obj-y += bcm/ | 6 | obj-y += bcm/ |
6 | obj-$(CONFIG_ARCH_DOVE) += dove/ | 7 | obj-$(CONFIG_ARCH_DOVE) += dove/ |
7 | obj-$(CONFIG_MACH_DOVE) += dove/ | 8 | obj-$(CONFIG_MACH_DOVE) += dove/ |
diff --git a/drivers/soc/atmel/Kconfig b/drivers/soc/atmel/Kconfig new file mode 100644 index 000000000000..6242ebb41abb --- /dev/null +++ b/drivers/soc/atmel/Kconfig | |||
@@ -0,0 +1,6 @@ | |||
1 | config AT91_SOC_ID | ||
2 | bool "SoC bus for Atmel ARM SoCs" | ||
3 | depends on ARCH_AT91 || COMPILE_TEST | ||
4 | default ARCH_AT91 | ||
5 | help | ||
6 | 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 index 000000000000..2d92f32e4ea5 --- /dev/null +++ b/drivers/soc/atmel/Makefile | |||
@@ -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 index 000000000000..4790094b498e --- /dev/null +++ b/drivers/soc/atmel/soc.c | |||
@@ -0,0 +1,231 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Atmel | ||
3 | * | ||
4 | * Alexandre Belloni <alexandre.belloni@free-electrons.com | ||
5 | * Boris Brezillon <boris.brezillon@free-electrons.com | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #define pr_fmt(fmt) "AT91: " fmt | ||
14 | |||
15 | #include <linux/io.h> | ||
16 | #include <linux/of.h> | ||
17 | #include <linux/of_address.h> | ||
18 | #include <linux/of_platform.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/sys_soc.h> | ||
21 | |||
22 | #include "soc.h" | ||
23 | |||
24 | #define AT91_DBGU_CIDR 0x40 | ||
25 | #define AT91_DBGU_EXID 0x44 | ||
26 | #define AT91_CHIPID_CIDR 0x00 | ||
27 | #define AT91_CHIPID_EXID 0x04 | ||
28 | #define AT91_CIDR_VERSION(x) ((x) & 0x1f) | ||
29 | #define AT91_CIDR_EXT BIT(31) | ||
30 | #define AT91_CIDR_MATCH_MASK 0x7fffffe0 | ||
31 | |||
32 | static const struct at91_soc __initconst socs[] = { | ||
33 | #ifdef CONFIG_SOC_AT91RM9200 | ||
34 | AT91_SOC(AT91RM9200_CIDR_MATCH, 0, "at91rm9200 BGA", "at91rm9200"), | ||
35 | #endif | ||
36 | #ifdef CONFIG_SOC_AT91SAM9 | ||
37 | AT91_SOC(AT91SAM9260_CIDR_MATCH, 0, "at91sam9260", NULL), | ||
38 | AT91_SOC(AT91SAM9261_CIDR_MATCH, 0, "at91sam9261", NULL), | ||
39 | AT91_SOC(AT91SAM9263_CIDR_MATCH, 0, "at91sam9263", NULL), | ||
40 | AT91_SOC(AT91SAM9G20_CIDR_MATCH, 0, "at91sam9g20", NULL), | ||
41 | AT91_SOC(AT91SAM9RL64_CIDR_MATCH, 0, "at91sam9rl64", NULL), | ||
42 | AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9M11_EXID_MATCH, | ||
43 | "at91sam9m11", "at91sam9g45"), | ||
44 | AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9M10_EXID_MATCH, | ||
45 | "at91sam9m10", "at91sam9g45"), | ||
46 | AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9G46_EXID_MATCH, | ||
47 | "at91sam9g46", "at91sam9g45"), | ||
48 | AT91_SOC(AT91SAM9G45_CIDR_MATCH, AT91SAM9G45_EXID_MATCH, | ||
49 | "at91sam9g45", "at91sam9g45"), | ||
50 | AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G15_EXID_MATCH, | ||
51 | "at91sam9g15", "at91sam9x5"), | ||
52 | AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G35_EXID_MATCH, | ||
53 | "at91sam9g35", "at91sam9x5"), | ||
54 | AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9X35_EXID_MATCH, | ||
55 | "at91sam9x35", "at91sam9x5"), | ||
56 | AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9G25_EXID_MATCH, | ||
57 | "at91sam9g25", "at91sam9x5"), | ||
58 | AT91_SOC(AT91SAM9X5_CIDR_MATCH, AT91SAM9X25_EXID_MATCH, | ||
59 | "at91sam9x25", "at91sam9x5"), | ||
60 | AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9CN12_EXID_MATCH, | ||
61 | "at91sam9cn12", "at91sam9n12"), | ||
62 | AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9N12_EXID_MATCH, | ||
63 | "at91sam9n12", "at91sam9n12"), | ||
64 | AT91_SOC(AT91SAM9N12_CIDR_MATCH, AT91SAM9CN11_EXID_MATCH, | ||
65 | "at91sam9cn11", "at91sam9n12"), | ||
66 | AT91_SOC(AT91SAM9XE128_CIDR_MATCH, 0, "at91sam9xe128", "at91sam9xe128"), | ||
67 | AT91_SOC(AT91SAM9XE256_CIDR_MATCH, 0, "at91sam9xe256", "at91sam9xe256"), | ||
68 | AT91_SOC(AT91SAM9XE512_CIDR_MATCH, 0, "at91sam9xe512", "at91sam9xe512"), | ||
69 | #endif | ||
70 | #ifdef CONFIG_SOC_SAMA5 | ||
71 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D21CU_EXID_MATCH, | ||
72 | "sama5d21", "sama5d2"), | ||
73 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D22CU_EXID_MATCH, | ||
74 | "sama5d22", "sama5d2"), | ||
75 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D23CU_EXID_MATCH, | ||
76 | "sama5d23", "sama5d2"), | ||
77 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CX_EXID_MATCH, | ||
78 | "sama5d24", "sama5d2"), | ||
79 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CU_EXID_MATCH, | ||
80 | "sama5d24", "sama5d2"), | ||
81 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D26CU_EXID_MATCH, | ||
82 | "sama5d26", "sama5d2"), | ||
83 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CU_EXID_MATCH, | ||
84 | "sama5d27", "sama5d2"), | ||
85 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CN_EXID_MATCH, | ||
86 | "sama5d27", "sama5d2"), | ||
87 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CU_EXID_MATCH, | ||
88 | "sama5d28", "sama5d2"), | ||
89 | AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CN_EXID_MATCH, | ||
90 | "sama5d28", "sama5d2"), | ||
91 | AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D31_EXID_MATCH, | ||
92 | "sama5d31", "sama5d3"), | ||
93 | AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D33_EXID_MATCH, | ||
94 | "sama5d33", "sama5d3"), | ||
95 | AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D34_EXID_MATCH, | ||
96 | "sama5d34", "sama5d3"), | ||
97 | AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D35_EXID_MATCH, | ||
98 | "sama5d35", "sama5d3"), | ||
99 | AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D36_EXID_MATCH, | ||
100 | "sama5d36", "sama5d3"), | ||
101 | AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D41_EXID_MATCH, | ||
102 | "sama5d41", "sama5d4"), | ||
103 | AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D42_EXID_MATCH, | ||
104 | "sama5d42", "sama5d4"), | ||
105 | AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D43_EXID_MATCH, | ||
106 | "sama5d43", "sama5d4"), | ||
107 | AT91_SOC(SAMA5D4_CIDR_MATCH, SAMA5D44_EXID_MATCH, | ||
108 | "sama5d44", "sama5d4"), | ||
109 | #endif | ||
110 | { /* sentinel */ }, | ||
111 | }; | ||
112 | |||
113 | static int __init at91_get_cidr_exid_from_dbgu(u32 *cidr, u32 *exid) | ||
114 | { | ||
115 | struct device_node *np; | ||
116 | void __iomem *regs; | ||
117 | |||
118 | np = of_find_compatible_node(NULL, NULL, "atmel,at91rm9200-dbgu"); | ||
119 | if (!np) | ||
120 | np = of_find_compatible_node(NULL, NULL, | ||
121 | "atmel,at91sam9260-dbgu"); | ||
122 | if (!np) | ||
123 | return -ENODEV; | ||
124 | |||
125 | regs = of_iomap(np, 0); | ||
126 | of_node_put(np); | ||
127 | |||
128 | if (!regs) { | ||
129 | pr_warn("Could not map DBGU iomem range"); | ||
130 | return -ENXIO; | ||
131 | } | ||
132 | |||
133 | *cidr = readl(regs + AT91_DBGU_CIDR); | ||
134 | *exid = readl(regs + AT91_DBGU_EXID); | ||
135 | |||
136 | iounmap(regs); | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static int __init at91_get_cidr_exid_from_chipid(u32 *cidr, u32 *exid) | ||
142 | { | ||
143 | struct device_node *np; | ||
144 | void __iomem *regs; | ||
145 | |||
146 | np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-chipid"); | ||
147 | if (!np) | ||
148 | return -ENODEV; | ||
149 | |||
150 | regs = of_iomap(np, 0); | ||
151 | of_node_put(np); | ||
152 | |||
153 | if (!regs) { | ||
154 | pr_warn("Could not map DBGU iomem range"); | ||
155 | return -ENXIO; | ||
156 | } | ||
157 | |||
158 | *cidr = readl(regs + AT91_CHIPID_CIDR); | ||
159 | *exid = readl(regs + AT91_CHIPID_EXID); | ||
160 | |||
161 | iounmap(regs); | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | struct soc_device * __init at91_soc_init(const struct at91_soc *socs) | ||
167 | { | ||
168 | struct soc_device_attribute *soc_dev_attr; | ||
169 | const struct at91_soc *soc; | ||
170 | struct soc_device *soc_dev; | ||
171 | u32 cidr, exid; | ||
172 | int ret; | ||
173 | |||
174 | /* | ||
175 | * With SAMA5D2 and later SoCs, CIDR and EXID registers are no more | ||
176 | * in the dbgu device but in the chipid device whose purpose is only | ||
177 | * to expose these two registers. | ||
178 | */ | ||
179 | ret = at91_get_cidr_exid_from_dbgu(&cidr, &exid); | ||
180 | if (ret) | ||
181 | ret = at91_get_cidr_exid_from_chipid(&cidr, &exid); | ||
182 | if (ret) { | ||
183 | if (ret == -ENODEV) | ||
184 | pr_warn("Could not find identification node"); | ||
185 | return NULL; | ||
186 | } | ||
187 | |||
188 | for (soc = socs; soc->name; soc++) { | ||
189 | if (soc->cidr_match != (cidr & AT91_CIDR_MATCH_MASK)) | ||
190 | continue; | ||
191 | |||
192 | if (!(cidr & AT91_CIDR_EXT) || soc->exid_match == exid) | ||
193 | break; | ||
194 | } | ||
195 | |||
196 | if (!soc->name) { | ||
197 | pr_warn("Could not find matching SoC description\n"); | ||
198 | return NULL; | ||
199 | } | ||
200 | |||
201 | soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); | ||
202 | if (!soc_dev_attr) | ||
203 | return NULL; | ||
204 | |||
205 | soc_dev_attr->family = soc->family; | ||
206 | soc_dev_attr->soc_id = soc->name; | ||
207 | soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%X", | ||
208 | AT91_CIDR_VERSION(cidr)); | ||
209 | soc_dev = soc_device_register(soc_dev_attr); | ||
210 | if (IS_ERR(soc_dev)) { | ||
211 | kfree(soc_dev_attr->revision); | ||
212 | kfree(soc_dev_attr); | ||
213 | pr_warn("Could not register SoC device\n"); | ||
214 | return NULL; | ||
215 | } | ||
216 | |||
217 | if (soc->family) | ||
218 | pr_info("Detected SoC family: %s\n", soc->family); | ||
219 | pr_info("Detected SoC: %s, revision %X\n", soc->name, | ||
220 | AT91_CIDR_VERSION(cidr)); | ||
221 | |||
222 | return soc_dev; | ||
223 | } | ||
224 | |||
225 | static int __init atmel_soc_device_init(void) | ||
226 | { | ||
227 | at91_soc_init(socs); | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | subsys_initcall(atmel_soc_device_init); | ||
diff --git a/arch/arm/mach-at91/soc.h b/drivers/soc/atmel/soc.h index 228efded5085..228efded5085 100644 --- a/arch/arm/mach-at91/soc.h +++ b/drivers/soc/atmel/soc.h | |||