aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2017-04-19 10:03:33 -0400
committerOlof Johansson <olof@lixom.net>2017-04-19 10:03:33 -0400
commit1bbecc8cd0a4192ec2a30f6cb3e6f4bd166f576a (patch)
treeb02abf10a7aad5eccbaa9d2d586ddeaeca2a75f6
parentd7718c147a89783ec3bf1735f724ca32174393dd (diff)
parentb32de9dd38fcf9063e993dcdd64cc64ad344d3ac (diff)
Merge tag 'at91-ab-4.12-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux into next/soc
SoC for 4.12: - huge PM cleanup - Move SoC detection to its own driver * tag 'at91-ab-4.12-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: ARM: at91: move SoC detection to its own driver ARM: at91: pm: correct typo ARM: at91: pm: Remove at91_pm_set_standby ARM: at91: pm: Merge all at91sam9*_pm_init ARM: at91: pm: Tie the USB clock mask to the pmc ARM: at91: pm: Tie the memory controller type to the ramc id ARM: at91: pm: Workaround DDRSDRC self-refresh bug with LPDDR1 memories. ARM: at91: pm: Simplify at91rm9200_standby ARM: at91: pm: Use struct at91_pm_data in pm_suspend.S ARM: at91: pm: Move global variables into at91_pm_data ARM: at91: pm: Move at91_ramc_read/write to pm.c ARM: at91: pm: Cleanup headers MAINTAINERS: Add memory drivers to AT91 entry MAINTAINERS: Update AT91 entry ARM: at91: pm: cpu_idle: switch DDR to power-down mode Revert "ARM: at91/dt: sama5d2: Use new compatible for ohci node" Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r--MAINTAINERS2
-rw-r--r--arch/arm/boot/dts/sama5d2.dtsi2
-rw-r--r--arch/arm/mach-at91/Makefile34
-rw-r--r--arch/arm/mach-at91/at91rm9200.c15
-rw-r--r--arch/arm/mach-at91/at91sam9.c91
-rw-r--r--arch/arm/mach-at91/generic.h8
-rw-r--r--arch/arm/mach-at91/pm.c215
-rw-r--r--arch/arm/mach-at91/pm.h24
-rw-r--r--arch/arm/mach-at91/pm_data-offsets.c13
-rw-r--r--arch/arm/mach-at91/pm_suspend.S31
-rw-r--r--arch/arm/mach-at91/sama5.c52
-rw-r--r--arch/arm/mach-at91/soc.c142
-rw-r--r--drivers/soc/Kconfig1
-rw-r--r--drivers/soc/Makefile1
-rw-r--r--drivers/soc/atmel/Kconfig6
-rw-r--r--drivers/soc/atmel/Makefile1
-rw-r--r--drivers/soc/atmel/soc.c231
-rw-r--r--drivers/soc/atmel/soc.h (renamed from arch/arm/mach-at91/soc.h)0
18 files changed, 433 insertions, 436 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 8cd40d7063b2..f79067d79dfc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1104,7 +1104,6 @@ F: drivers/*/*aspeed*
1104ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT 1104ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT
1105M: Nicolas Ferre <nicolas.ferre@microchip.com> 1105M: Nicolas Ferre <nicolas.ferre@microchip.com>
1106M: Alexandre Belloni <alexandre.belloni@free-electrons.com> 1106M: Alexandre Belloni <alexandre.belloni@free-electrons.com>
1107M: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
1108L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) 1107L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
1109W: http://www.linux4sam.org 1108W: http://www.linux4sam.org
1110T: git git://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91.git 1109T: git git://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91.git
@@ -1116,6 +1115,7 @@ F: arch/arm/boot/dts/at91*.dtsi
1116F: arch/arm/boot/dts/sama*.dts 1115F: arch/arm/boot/dts/sama*.dts
1117F: arch/arm/boot/dts/sama*.dtsi 1116F: arch/arm/boot/dts/sama*.dtsi
1118F: arch/arm/include/debug/at91.S 1117F: arch/arm/include/debug/at91.S
1118F: drivers/memory/atmel*
1119 1119
1120ARM/ATMEL AT91 Clock Support 1120ARM/ATMEL AT91 Clock Support
1121M: Boris Brezillon <boris.brezillon@free-electrons.com> 1121M: Boris Brezillon <boris.brezillon@free-electrons.com>
diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi
index 22332be72140..528b4e9c6d3d 100644
--- a/arch/arm/boot/dts/sama5d2.dtsi
+++ b/arch/arm/boot/dts/sama5d2.dtsi
@@ -266,7 +266,7 @@
266 }; 266 };
267 267
268 usb1: ohci@00400000 { 268 usb1: ohci@00400000 {
269 compatible = "atmel,sama5d2-ohci", "usb-ohci"; 269 compatible = "atmel,at91rm9200-ohci", "usb-ohci";
270 reg = <0x00400000 0x100000>; 270 reg = <0x00400000 0x100000>;
271 interrupts = <41 IRQ_TYPE_LEVEL_HIGH 2>; 271 interrupts = <41 IRQ_TYPE_LEVEL_HIGH 2>;
272 clocks = <&uhphs_clk>, <&uhphs_clk>, <&uhpck>; 272 clocks = <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index c5bbf8bb8c0f..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#
4obj-y := soc.o
5 4
6# CPU-specific support 5# CPU-specific support
7obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o 6obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o
@@ -18,3 +17,36 @@ endif
18ifeq ($(CONFIG_PM_DEBUG),y) 17ifeq ($(CONFIG_PM_DEBUG),y)
19CFLAGS_pm.o += -DDEBUG 18CFLAGS_pm.o += -DDEBUG
20endif 19endif
20
21# Default sed regexp - multiline due to syntax constraints
22define sed-y
23 "/^->/{s:->#\(.*\):/* \1 */:; \
24 s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \
25 s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
26 s:->::; p;}"
27endef
28
29# Use filechk to avoid rebuilds when a header changes, but the resulting file
30# does not
31define filechk_offsets
32 (set -e; \
33 echo "#ifndef $2"; \
34 echo "#define $2"; \
35 echo "/*"; \
36 echo " * DO NOT MODIFY."; \
37 echo " *"; \
38 echo " * This file was generated by Kbuild"; \
39 echo " */"; \
40 echo ""; \
41 sed -ne $(sed-y); \
42 echo ""; \
43 echo "#endif" )
44endef
45
46arch/arm/mach-at91/pm_data-offsets.s: arch/arm/mach-at91/pm_data-offsets.c
47 $(call if_changed_dep,cc_s_c)
48
49include/generated/at91_pm_data-offsets.h: arch/arm/mach-at91/pm_data-offsets.s FORCE
50 $(call filechk,offsets,__PM_DATA_OFFSETS_H__)
51
52arch/arm/mach-at91/pm_suspend.o: include/generated/at91_pm_data-offsets.h
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
19static const struct at91_soc rm9200_socs[] = {
20 AT91_SOC(AT91RM9200_CIDR_MATCH, 0, "at91rm9200 BGA", "at91rm9200"),
21 { /* sentinel */ },
22};
23 17
24static void __init at91rm9200_dt_device_init(void) 18static 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 ba28e9cc584d..3dbdef4d3cbf 100644
--- a/arch/arm/mach-at91/at91sam9.c
+++ b/arch/arm/mach-at91/at91sam9.c
@@ -14,60 +14,12 @@
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 17
19static const struct at91_soc at91sam9_socs[] = { 18static void __init at91sam9_init(void)
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
55static void __init at91sam9_common_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 21
64 of_platform_default_populate(NULL, NULL, soc_dev); 22 at91sam9_pm_init();
65}
66
67static void __init at91sam9_dt_device_init(void)
68{
69 at91sam9_common_init();
70 at91sam9260_pm_init();
71} 23}
72 24
73static const char *const at91_dt_board_compat[] __initconst = { 25static const char *const at91_dt_board_compat[] __initconst = {
@@ -77,41 +29,6 @@ static const char *const at91_dt_board_compat[] __initconst = {
77 29
78DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM9") 30DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM9")
79 /* Maintainer: Atmel */ 31 /* Maintainer: Atmel */
80 .init_machine = at91sam9_dt_device_init, 32 .init_machine = at91sam9_init,
81 .dt_compat = at91_dt_board_compat, 33 .dt_compat = at91_dt_board_compat,
82MACHINE_END 34MACHINE_END
83
84static void __init at91sam9g45_dt_device_init(void)
85{
86 at91sam9_common_init();
87 at91sam9g45_pm_init();
88}
89
90static const char *const at91sam9g45_board_compat[] __initconst = {
91 "atmel,at91sam9g45",
92 NULL
93};
94
95DT_MACHINE_START(at91sam9g45_dt, "Atmel AT91SAM9G45")
96 /* Maintainer: Atmel */
97 .init_machine = at91sam9g45_dt_device_init,
98 .dt_compat = at91sam9g45_board_compat,
99MACHINE_END
100
101static void __init at91sam9x5_dt_device_init(void)
102{
103 at91sam9_common_init();
104 at91sam9x5_pm_init();
105}
106
107static const char *const at91sam9x5_board_compat[] __initconst = {
108 "atmel,at91sam9x5",
109 "atmel,at91sam9n12",
110 NULL
111};
112
113DT_MACHINE_START(at91sam9x5_dt, "Atmel AT91SAM9")
114 /* Maintainer: Atmel */
115 .init_machine = at91sam9x5_dt_device_init,
116 .dt_compat = at91sam9x5_board_compat,
117MACHINE_END
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index 28ca57a2060f..f1ead0f13c19 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -13,15 +13,11 @@
13 13
14#ifdef CONFIG_PM 14#ifdef CONFIG_PM
15extern void __init at91rm9200_pm_init(void); 15extern void __init at91rm9200_pm_init(void);
16extern void __init at91sam9260_pm_init(void); 16extern void __init at91sam9_pm_init(void);
17extern void __init at91sam9g45_pm_init(void);
18extern void __init at91sam9x5_pm_init(void);
19extern void __init sama5_pm_init(void); 17extern void __init sama5_pm_init(void);
20#else 18#else
21static inline void __init at91rm9200_pm_init(void) { } 19static inline void __init at91rm9200_pm_init(void) { }
22static inline void __init at91sam9260_pm_init(void) { } 20static inline void __init at91sam9_pm_init(void) { }
23static inline void __init at91sam9g45_pm_init(void) { }
24static inline void __init at91sam9x5_pm_init(void) { }
25static inline void __init sama5_pm_init(void) { } 21static inline void __init sama5_pm_init(void) { }
26#endif 22#endif
27 23
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 3d89b7905bd9..2cd27c830ab6 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -10,35 +10,22 @@
10 * (at your option) any later version. 10 * (at your option) any later version.
11 */ 11 */
12 12
13#include <linux/gpio.h>
14#include <linux/suspend.h>
15#include <linux/sched.h>
16#include <linux/proc_fs.h>
17#include <linux/genalloc.h> 13#include <linux/genalloc.h>
18#include <linux/interrupt.h> 14#include <linux/io.h>
19#include <linux/sysfs.h> 15#include <linux/of_address.h>
20#include <linux/module.h>
21#include <linux/of.h> 16#include <linux/of.h>
22#include <linux/of_platform.h> 17#include <linux/of_platform.h>
23#include <linux/of_address.h> 18#include <linux/suspend.h>
24#include <linux/platform_device.h> 19
25#include <linux/platform_data/atmel.h>
26#include <linux/io.h>
27#include <linux/clk/at91_pmc.h> 20#include <linux/clk/at91_pmc.h>
28 21
29#include <asm/irq.h>
30#include <linux/atomic.h>
31#include <asm/mach/time.h>
32#include <asm/mach/irq.h>
33#include <asm/fncpy.h>
34#include <asm/cacheflush.h> 22#include <asm/cacheflush.h>
23#include <asm/fncpy.h>
35#include <asm/system_misc.h> 24#include <asm/system_misc.h>
36 25
37#include "generic.h" 26#include "generic.h"
38#include "pm.h" 27#include "pm.h"
39 28
40static void __iomem *pmc;
41
42/* 29/*
43 * FIXME: this is needed to communicate between the pinctrl driver and 30 * FIXME: this is needed to communicate between the pinctrl driver and
44 * the PM implementation in the machine. Possibly part of the PM 31 * the PM implementation in the machine. Possibly part of the PM
@@ -50,12 +37,13 @@ extern void at91_pinctrl_gpio_suspend(void);
50extern void at91_pinctrl_gpio_resume(void); 37extern void at91_pinctrl_gpio_resume(void);
51#endif 38#endif
52 39
53static struct { 40static struct at91_pm_data pm_data;
54 unsigned long uhp_udp_mask;
55 int memctrl;
56} at91_pm_data;
57 41
58static void __iomem *at91_ramc_base[2]; 42#define at91_ramc_read(id, field) \
43 __raw_readl(pm_data.ramc[id] + field)
44
45#define at91_ramc_write(id, field, value) \
46 __raw_writel(value, pm_data.ramc[id] + field)
59 47
60static int at91_pm_valid_state(suspend_state_t state) 48static int at91_pm_valid_state(suspend_state_t state)
61{ 49{
@@ -91,10 +79,10 @@ static int at91_pm_verify_clocks(void)
91 unsigned long scsr; 79 unsigned long scsr;
92 int i; 80 int i;
93 81
94 scsr = readl(pmc + AT91_PMC_SCSR); 82 scsr = readl(pm_data.pmc + AT91_PMC_SCSR);
95 83
96 /* USB must not be using PLLB */ 84 /* USB must not be using PLLB */
97 if ((scsr & at91_pm_data.uhp_udp_mask) != 0) { 85 if ((scsr & pm_data.uhp_udp_mask) != 0) {
98 pr_err("AT91: PM - Suspend-to-RAM with USB still active\n"); 86 pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
99 return 0; 87 return 0;
100 } 88 }
@@ -105,7 +93,7 @@ static int at91_pm_verify_clocks(void)
105 93
106 if ((scsr & (AT91_PMC_PCK0 << i)) == 0) 94 if ((scsr & (AT91_PMC_PCK0 << i)) == 0)
107 continue; 95 continue;
108 css = readl(pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS; 96 css = readl(pm_data.pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
109 if (css != AT91_PMC_CSS_SLOW) { 97 if (css != AT91_PMC_CSS_SLOW) {
110 pr_err("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css); 98 pr_err("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css);
111 return 0; 99 return 0;
@@ -131,25 +119,18 @@ int at91_suspend_entering_slow_clock(void)
131} 119}
132EXPORT_SYMBOL(at91_suspend_entering_slow_clock); 120EXPORT_SYMBOL(at91_suspend_entering_slow_clock);
133 121
134static void (*at91_suspend_sram_fn)(void __iomem *pmc, void __iomem *ramc0, 122static void (*at91_suspend_sram_fn)(struct at91_pm_data *);
135 void __iomem *ramc1, int memctrl); 123extern void at91_pm_suspend_in_sram(struct at91_pm_data *pm_data);
136
137extern void at91_pm_suspend_in_sram(void __iomem *pmc, void __iomem *ramc0,
138 void __iomem *ramc1, int memctrl);
139extern u32 at91_pm_suspend_in_sram_sz; 124extern u32 at91_pm_suspend_in_sram_sz;
140 125
141static void at91_pm_suspend(suspend_state_t state) 126static void at91_pm_suspend(suspend_state_t state)
142{ 127{
143 unsigned int pm_data = at91_pm_data.memctrl; 128 pm_data.mode = (state == PM_SUSPEND_MEM) ? AT91_PM_SLOW_CLOCK : 0;
144
145 pm_data |= (state == PM_SUSPEND_MEM) ?
146 AT91_PM_MODE(AT91_PM_SLOW_CLOCK) : 0;
147 129
148 flush_cache_all(); 130 flush_cache_all();
149 outer_disable(); 131 outer_disable();
150 132
151 at91_suspend_sram_fn(pmc, at91_ramc_base[0], 133 at91_suspend_sram_fn(&pm_data);
152 at91_ramc_base[1], pm_data);
153 134
154 outer_resume(); 135 outer_resume();
155} 136}
@@ -224,12 +205,6 @@ static struct platform_device at91_cpuidle_device = {
224 .name = "cpuidle-at91", 205 .name = "cpuidle-at91",
225}; 206};
226 207
227static void at91_pm_set_standby(void (*at91_standby)(void))
228{
229 if (at91_standby)
230 at91_cpuidle_device.dev.platform_data = at91_standby;
231}
232
233/* 208/*
234 * The AT91RM9200 goes into self-refresh mode with this command, and will 209 * The AT91RM9200 goes into self-refresh mode with this command, and will
235 * terminate self-refresh automatically on the next SDRAM access. 210 * terminate self-refresh automatically on the next SDRAM access.
@@ -241,20 +216,15 @@ static void at91_pm_set_standby(void (*at91_standby)(void))
241 */ 216 */
242static void at91rm9200_standby(void) 217static void at91rm9200_standby(void)
243{ 218{
244 u32 lpr = at91_ramc_read(0, AT91_MC_SDRAMC_LPR);
245
246 asm volatile( 219 asm volatile(
247 "b 1f\n\t" 220 "b 1f\n\t"
248 ".align 5\n\t" 221 ".align 5\n\t"
249 "1: mcr p15, 0, %0, c7, c10, 4\n\t" 222 "1: mcr p15, 0, %0, c7, c10, 4\n\t"
250 " str %0, [%1, %2]\n\t" 223 " str %2, [%1, %3]\n\t"
251 " str %3, [%1, %4]\n\t"
252 " mcr p15, 0, %0, c7, c0, 4\n\t" 224 " mcr p15, 0, %0, c7, c0, 4\n\t"
253 " str %5, [%1, %2]"
254 : 225 :
255 : "r" (0), "r" (at91_ramc_base[0]), "r" (AT91_MC_SDRAMC_LPR), 226 : "r" (0), "r" (pm_data.ramc[0]),
256 "r" (1), "r" (AT91_MC_SDRAMC_SRR), 227 "r" (1), "r" (AT91_MC_SDRAMC_SRR));
257 "r" (lpr));
258} 228}
259 229
260/* We manage both DDRAM/SDRAM controllers, we need more than one value to 230/* We manage both DDRAM/SDRAM controllers, we need more than one value to
@@ -265,12 +235,27 @@ static void at91_ddr_standby(void)
265 /* Those two values allow us to delay self-refresh activation 235 /* Those two values allow us to delay self-refresh activation
266 * to the maximum. */ 236 * to the maximum. */
267 u32 lpr0, lpr1 = 0; 237 u32 lpr0, lpr1 = 0;
238 u32 mdr, saved_mdr0, saved_mdr1 = 0;
268 u32 saved_lpr0, saved_lpr1 = 0; 239 u32 saved_lpr0, saved_lpr1 = 0;
269 240
270 if (at91_ramc_base[1]) { 241 /* LPDDR1 --> force DDR2 mode during self-refresh */
242 saved_mdr0 = at91_ramc_read(0, AT91_DDRSDRC_MDR);
243 if ((saved_mdr0 & AT91_DDRSDRC_MD) == AT91_DDRSDRC_MD_LOW_POWER_DDR) {
244 mdr = saved_mdr0 & ~AT91_DDRSDRC_MD;
245 mdr |= AT91_DDRSDRC_MD_DDR2;
246 at91_ramc_write(0, AT91_DDRSDRC_MDR, mdr);
247 }
248
249 if (pm_data.ramc[1]) {
271 saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR); 250 saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR);
272 lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB; 251 lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB;
273 lpr1 |= AT91_DDRSDRC_LPCB_SELF_REFRESH; 252 lpr1 |= AT91_DDRSDRC_LPCB_SELF_REFRESH;
253 saved_mdr1 = at91_ramc_read(1, AT91_DDRSDRC_MDR);
254 if ((saved_mdr1 & AT91_DDRSDRC_MD) == AT91_DDRSDRC_MD_LOW_POWER_DDR) {
255 mdr = saved_mdr1 & ~AT91_DDRSDRC_MD;
256 mdr |= AT91_DDRSDRC_MD_DDR2;
257 at91_ramc_write(1, AT91_DDRSDRC_MDR, mdr);
258 }
274 } 259 }
275 260
276 saved_lpr0 = at91_ramc_read(0, AT91_DDRSDRC_LPR); 261 saved_lpr0 = at91_ramc_read(0, AT91_DDRSDRC_LPR);
@@ -279,14 +264,33 @@ static void at91_ddr_standby(void)
279 264
280 /* self-refresh mode now */ 265 /* self-refresh mode now */
281 at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0); 266 at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0);
282 if (at91_ramc_base[1]) 267 if (pm_data.ramc[1])
283 at91_ramc_write(1, AT91_DDRSDRC_LPR, lpr1); 268 at91_ramc_write(1, AT91_DDRSDRC_LPR, lpr1);
284 269
285 cpu_do_idle(); 270 cpu_do_idle();
286 271
272 at91_ramc_write(0, AT91_DDRSDRC_MDR, saved_mdr0);
287 at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0); 273 at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0);
288 if (at91_ramc_base[1]) 274 if (pm_data.ramc[1]) {
275 at91_ramc_write(0, AT91_DDRSDRC_MDR, saved_mdr1);
289 at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); 276 at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1);
277 }
278}
279
280static void sama5d3_ddr_standby(void)
281{
282 u32 lpr0;
283 u32 saved_lpr0;
284
285 saved_lpr0 = at91_ramc_read(0, AT91_DDRSDRC_LPR);
286 lpr0 = saved_lpr0 & ~AT91_DDRSDRC_LPCB;
287 lpr0 |= AT91_DDRSDRC_LPCB_POWER_DOWN;
288
289 at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0);
290
291 cpu_do_idle();
292
293 at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0);
290} 294}
291 295
292/* We manage both DDRAM/SDRAM controllers, we need more than one value to 296/* We manage both DDRAM/SDRAM controllers, we need more than one value to
@@ -297,7 +301,7 @@ static void at91sam9_sdram_standby(void)
297 u32 lpr0, lpr1 = 0; 301 u32 lpr0, lpr1 = 0;
298 u32 saved_lpr0, saved_lpr1 = 0; 302 u32 saved_lpr0, saved_lpr1 = 0;
299 303
300 if (at91_ramc_base[1]) { 304 if (pm_data.ramc[1]) {
301 saved_lpr1 = at91_ramc_read(1, AT91_SDRAMC_LPR); 305 saved_lpr1 = at91_ramc_read(1, AT91_SDRAMC_LPR);
302 lpr1 = saved_lpr1 & ~AT91_SDRAMC_LPCB; 306 lpr1 = saved_lpr1 & ~AT91_SDRAMC_LPCB;
303 lpr1 |= AT91_SDRAMC_LPCB_SELF_REFRESH; 307 lpr1 |= AT91_SDRAMC_LPCB_SELF_REFRESH;
@@ -309,21 +313,33 @@ static void at91sam9_sdram_standby(void)
309 313
310 /* self-refresh mode now */ 314 /* self-refresh mode now */
311 at91_ramc_write(0, AT91_SDRAMC_LPR, lpr0); 315 at91_ramc_write(0, AT91_SDRAMC_LPR, lpr0);
312 if (at91_ramc_base[1]) 316 if (pm_data.ramc[1])
313 at91_ramc_write(1, AT91_SDRAMC_LPR, lpr1); 317 at91_ramc_write(1, AT91_SDRAMC_LPR, lpr1);
314 318
315 cpu_do_idle(); 319 cpu_do_idle();
316 320
317 at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr0); 321 at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr0);
318 if (at91_ramc_base[1]) 322 if (pm_data.ramc[1])
319 at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1); 323 at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1);
320} 324}
321 325
326struct ramc_info {
327 void (*idle)(void);
328 unsigned int memctrl;
329};
330
331static const struct ramc_info ramc_infos[] __initconst = {
332 { .idle = at91rm9200_standby, .memctrl = AT91_MEMCTRL_MC},
333 { .idle = at91sam9_sdram_standby, .memctrl = AT91_MEMCTRL_SDRAMC},
334 { .idle = at91_ddr_standby, .memctrl = AT91_MEMCTRL_DDRSDR},
335 { .idle = sama5d3_ddr_standby, .memctrl = AT91_MEMCTRL_DDRSDR},
336};
337
322static const struct of_device_id const ramc_ids[] __initconst = { 338static const struct of_device_id const ramc_ids[] __initconst = {
323 { .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby }, 339 { .compatible = "atmel,at91rm9200-sdramc", .data = &ramc_infos[0] },
324 { .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby }, 340 { .compatible = "atmel,at91sam9260-sdramc", .data = &ramc_infos[1] },
325 { .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby }, 341 { .compatible = "atmel,at91sam9g45-ddramc", .data = &ramc_infos[2] },
326 { .compatible = "atmel,sama5d3-ddramc", .data = at91_ddr_standby }, 342 { .compatible = "atmel,sama5d3-ddramc", .data = &ramc_infos[3] },
327 { /*sentinel*/ } 343 { /*sentinel*/ }
328}; 344};
329 345
@@ -332,15 +348,18 @@ static __init void at91_dt_ramc(void)
332 struct device_node *np; 348 struct device_node *np;
333 const struct of_device_id *of_id; 349 const struct of_device_id *of_id;
334 int idx = 0; 350 int idx = 0;
335 const void *standby = NULL; 351 void *standby = NULL;
352 const struct ramc_info *ramc;
336 353
337 for_each_matching_node_and_match(np, ramc_ids, &of_id) { 354 for_each_matching_node_and_match(np, ramc_ids, &of_id) {
338 at91_ramc_base[idx] = of_iomap(np, 0); 355 pm_data.ramc[idx] = of_iomap(np, 0);
339 if (!at91_ramc_base[idx]) 356 if (!pm_data.ramc[idx])
340 panic(pr_fmt("unable to map ramc[%d] cpu registers\n"), idx); 357 panic(pr_fmt("unable to map ramc[%d] cpu registers\n"), idx);
341 358
359 ramc = of_id->data;
342 if (!standby) 360 if (!standby)
343 standby = of_id->data; 361 standby = ramc->idle;
362 pm_data.memctrl = ramc->memctrl;
344 363
345 idx++; 364 idx++;
346 } 365 }
@@ -353,7 +372,7 @@ static __init void at91_dt_ramc(void)
353 return; 372 return;
354 } 373 }
355 374
356 at91_pm_set_standby(standby); 375 at91_cpuidle_device.dev.platform_data = standby;
357} 376}
358 377
359static void at91rm9200_idle(void) 378static void at91rm9200_idle(void)
@@ -362,12 +381,12 @@ static void at91rm9200_idle(void)
362 * Disable the processor clock. The processor will be automatically 381 * Disable the processor clock. The processor will be automatically
363 * re-enabled by an interrupt or by a reset. 382 * re-enabled by an interrupt or by a reset.
364 */ 383 */
365 writel(AT91_PMC_PCK, pmc + AT91_PMC_SCDR); 384 writel(AT91_PMC_PCK, pm_data.pmc + AT91_PMC_SCDR);
366} 385}
367 386
368static void at91sam9_idle(void) 387static void at91sam9_idle(void)
369{ 388{
370 writel(AT91_PMC_PCK, pmc + AT91_PMC_SCDR); 389 writel(AT91_PMC_PCK, pm_data.pmc + AT91_PMC_SCDR);
371 cpu_do_idle(); 390 cpu_do_idle();
372} 391}
373 392
@@ -417,31 +436,46 @@ static void __init at91_pm_sram_init(void)
417 &at91_pm_suspend_in_sram, at91_pm_suspend_in_sram_sz); 436 &at91_pm_suspend_in_sram, at91_pm_suspend_in_sram_sz);
418} 437}
419 438
439struct pmc_info {
440 unsigned long uhp_udp_mask;
441};
442
443static const struct pmc_info pmc_infos[] __initconst = {
444 { .uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP },
445 { .uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP },
446 { .uhp_udp_mask = AT91SAM926x_PMC_UHP },
447};
448
420static const struct of_device_id atmel_pmc_ids[] __initconst = { 449static const struct of_device_id atmel_pmc_ids[] __initconst = {
421 { .compatible = "atmel,at91rm9200-pmc" }, 450 { .compatible = "atmel,at91rm9200-pmc", .data = &pmc_infos[0] },
422 { .compatible = "atmel,at91sam9260-pmc" }, 451 { .compatible = "atmel,at91sam9260-pmc", .data = &pmc_infos[1] },
423 { .compatible = "atmel,at91sam9g45-pmc" }, 452 { .compatible = "atmel,at91sam9g45-pmc", .data = &pmc_infos[2] },
424 { .compatible = "atmel,at91sam9n12-pmc" }, 453 { .compatible = "atmel,at91sam9n12-pmc", .data = &pmc_infos[1] },
425 { .compatible = "atmel,at91sam9x5-pmc" }, 454 { .compatible = "atmel,at91sam9x5-pmc", .data = &pmc_infos[1] },
426 { .compatible = "atmel,sama5d3-pmc" }, 455 { .compatible = "atmel,sama5d3-pmc", .data = &pmc_infos[1] },
427 { .compatible = "atmel,sama5d2-pmc" }, 456 { .compatible = "atmel,sama5d2-pmc", .data = &pmc_infos[1] },
428 { /* sentinel */ }, 457 { /* sentinel */ },
429}; 458};
430 459
431static void __init at91_pm_init(void (*pm_idle)(void)) 460static void __init at91_pm_init(void (*pm_idle)(void))
432{ 461{
433 struct device_node *pmc_np; 462 struct device_node *pmc_np;
463 const struct of_device_id *of_id;
464 const struct pmc_info *pmc;
434 465
435 if (at91_cpuidle_device.dev.platform_data) 466 if (at91_cpuidle_device.dev.platform_data)
436 platform_device_register(&at91_cpuidle_device); 467 platform_device_register(&at91_cpuidle_device);
437 468
438 pmc_np = of_find_matching_node(NULL, atmel_pmc_ids); 469 pmc_np = of_find_matching_node_and_match(NULL, atmel_pmc_ids, &of_id);
439 pmc = of_iomap(pmc_np, 0); 470 pm_data.pmc = of_iomap(pmc_np, 0);
440 if (!pmc) { 471 if (!pm_data.pmc) {
441 pr_err("AT91: PM not supported, PMC not found\n"); 472 pr_err("AT91: PM not supported, PMC not found\n");
442 return; 473 return;
443 } 474 }
444 475
476 pmc = of_id->data;
477 pm_data.uhp_udp_mask = pmc->uhp_udp_mask;
478
445 if (pm_idle) 479 if (pm_idle)
446 arm_pm_idle = pm_idle; 480 arm_pm_idle = pm_idle;
447 481
@@ -462,40 +496,17 @@ void __init at91rm9200_pm_init(void)
462 */ 496 */
463 at91_ramc_write(0, AT91_MC_SDRAMC_LPR, 0); 497 at91_ramc_write(0, AT91_MC_SDRAMC_LPR, 0);
464 498
465 at91_pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP;
466 at91_pm_data.memctrl = AT91_MEMCTRL_MC;
467
468 at91_pm_init(at91rm9200_idle); 499 at91_pm_init(at91rm9200_idle);
469} 500}
470 501
471void __init at91sam9260_pm_init(void) 502void __init at91sam9_pm_init(void)
472{
473 at91_dt_ramc();
474 at91_pm_data.memctrl = AT91_MEMCTRL_SDRAMC;
475 at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
476 at91_pm_init(at91sam9_idle);
477}
478
479void __init at91sam9g45_pm_init(void)
480{
481 at91_dt_ramc();
482 at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP;
483 at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
484 at91_pm_init(at91sam9_idle);
485}
486
487void __init at91sam9x5_pm_init(void)
488{ 503{
489 at91_dt_ramc(); 504 at91_dt_ramc();
490 at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
491 at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
492 at91_pm_init(at91sam9_idle); 505 at91_pm_init(at91sam9_idle);
493} 506}
494 507
495void __init sama5_pm_init(void) 508void __init sama5_pm_init(void)
496{ 509{
497 at91_dt_ramc(); 510 at91_dt_ramc();
498 at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
499 at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
500 at91_pm_init(NULL); 511 at91_pm_init(NULL);
501} 512}
diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h
index bf980c6ef294..fc0f7d048187 100644
--- a/arch/arm/mach-at91/pm.h
+++ b/arch/arm/mach-at91/pm.h
@@ -17,24 +17,20 @@
17#include <soc/at91/at91sam9_ddrsdr.h> 17#include <soc/at91/at91sam9_ddrsdr.h>
18#include <soc/at91/at91sam9_sdramc.h> 18#include <soc/at91/at91sam9_sdramc.h>
19 19
20#ifndef __ASSEMBLY__
21#define at91_ramc_read(id, field) \
22 __raw_readl(at91_ramc_base[id] + field)
23
24#define at91_ramc_write(id, field, value) \
25 __raw_writel(value, at91_ramc_base[id] + field)
26#endif
27
28#define AT91_MEMCTRL_MC 0 20#define AT91_MEMCTRL_MC 0
29#define AT91_MEMCTRL_SDRAMC 1 21#define AT91_MEMCTRL_SDRAMC 1
30#define AT91_MEMCTRL_DDRSDR 2 22#define AT91_MEMCTRL_DDRSDR 2
31 23
32#define AT91_PM_MEMTYPE_MASK 0x0f
33
34#define AT91_PM_MODE_OFFSET 4
35#define AT91_PM_MODE_MASK 0x01
36#define AT91_PM_MODE(x) (((x) & AT91_PM_MODE_MASK) << AT91_PM_MODE_OFFSET)
37
38#define AT91_PM_SLOW_CLOCK 0x01 24#define AT91_PM_SLOW_CLOCK 0x01
39 25
26#ifndef __ASSEMBLY__
27struct at91_pm_data {
28 void __iomem *pmc;
29 void __iomem *ramc[2];
30 unsigned long uhp_udp_mask;
31 unsigned int memctrl;
32 unsigned int mode;
33};
34#endif
35
40#endif 36#endif
diff --git a/arch/arm/mach-at91/pm_data-offsets.c b/arch/arm/mach-at91/pm_data-offsets.c
new file mode 100644
index 000000000000..30302cb16df0
--- /dev/null
+++ b/arch/arm/mach-at91/pm_data-offsets.c
@@ -0,0 +1,13 @@
1#include <linux/stddef.h>
2#include <linux/kbuild.h>
3#include "pm.h"
4
5int main(void)
6{
7 DEFINE(PM_DATA_PMC, offsetof(struct at91_pm_data, pmc));
8 DEFINE(PM_DATA_RAMC0, offsetof(struct at91_pm_data, ramc[0]));
9 DEFINE(PM_DATA_RAMC1, offsetof(struct at91_pm_data, ramc[1]));
10 DEFINE(PM_DATA_MEMCTRL, offsetof(struct at91_pm_data, memctrl));
11 DEFINE(PM_DATA_MODE, offsetof(struct at91_pm_data, mode));
12 return 0;
13}
diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S
index a25defda3d22..96781daa671a 100644
--- a/arch/arm/mach-at91/pm_suspend.S
+++ b/arch/arm/mach-at91/pm_suspend.S
@@ -4,7 +4,7 @@
4 * Copyright (C) 2006 Savin Zlobec 4 * Copyright (C) 2006 Savin Zlobec
5 * 5 *
6 * AT91SAM9 support: 6 * AT91SAM9 support:
7 * Copyright (C) 2007 Anti Sullin <anti.sullin@artecdesign.ee 7 * Copyright (C) 2007 Anti Sullin <anti.sullin@artecdesign.ee>
8 * 8 *
9 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as 10 * it under the terms of the GNU General Public License version 2 as
@@ -14,6 +14,7 @@
14#include <linux/linkage.h> 14#include <linux/linkage.h>
15#include <linux/clk/at91_pmc.h> 15#include <linux/clk/at91_pmc.h>
16#include "pm.h" 16#include "pm.h"
17#include "generated/at91_pm_data-offsets.h"
17 18
18#define SRAMC_SELF_FRESH_ACTIVE 0x01 19#define SRAMC_SELF_FRESH_ACTIVE 0x01
19#define SRAMC_SELF_FRESH_EXIT 0x00 20#define SRAMC_SELF_FRESH_EXIT 0x00
@@ -72,13 +73,9 @@ tmp2 .req r5
72 .arm 73 .arm
73 74
74/* 75/*
75 * void at91_pm_suspend_in_sram(void __iomem *pmc, void __iomem *sdramc, 76 * void at91_suspend_sram_fn(struct at91_pm_data*)
76 * void __iomem *ramc1, int memctrl)
77 * @input param: 77 * @input param:
78 * @r0: base address of AT91_PMC 78 * @r0: base address of struct at91_pm_data
79 * @r1: base address of SDRAM Controller (SDRAM, DDRSDR, or AT91_SYS)
80 * @r2: base address of second SDRAM Controller or 0 if not present
81 * @r3: pm information
82 */ 79 */
83/* at91_pm_suspend_in_sram must be 8-byte aligned per the requirements of fncpy() */ 80/* at91_pm_suspend_in_sram must be 8-byte aligned per the requirements of fncpy() */
84 .align 3 81 .align 3
@@ -90,16 +87,16 @@ ENTRY(at91_pm_suspend_in_sram)
90 mov tmp1, #0 87 mov tmp1, #0
91 mcr p15, 0, tmp1, c7, c10, 4 88 mcr p15, 0, tmp1, c7, c10, 4
92 89
93 str r0, .pmc_base 90 ldr tmp1, [r0, #PM_DATA_PMC]
94 str r1, .sramc_base 91 str tmp1, .pmc_base
95 str r2, .sramc1_base 92 ldr tmp1, [r0, #PM_DATA_RAMC0]
96 93 str tmp1, .sramc_base
97 and r0, r3, #AT91_PM_MEMTYPE_MASK 94 ldr tmp1, [r0, #PM_DATA_RAMC1]
98 str r0, .memtype 95 str tmp1, .sramc1_base
99 96 ldr tmp1, [r0, #PM_DATA_MEMCTRL]
100 lsr r0, r3, #AT91_PM_MODE_OFFSET 97 str tmp1, .memtype
101 and r0, r0, #AT91_PM_MODE_MASK 98 ldr tmp1, [r0, #PM_DATA_MODE]
102 str r0, .pm_mode 99 str tmp1, .pm_mode
103 100
104 /* Active the self-refresh mode */ 101 /* Active the self-refresh mode */
105 mov r0, #SRAMC_SELF_FRESH_ACTIVE 102 mov r0, #SRAMC_SELF_FRESH_ACTIVE
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
20static 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
62static void __init sama5_dt_device_init(void) 19static 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
32static 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
60static 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
85struct 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 @@
1menu "SOC (System On Chip) specific Drivers" 1menu "SOC (System On Chip) specific Drivers"
2 2
3source "drivers/soc/atmel/Kconfig"
3source "drivers/soc/bcm/Kconfig" 4source "drivers/soc/bcm/Kconfig"
4source "drivers/soc/fsl/Kconfig" 5source "drivers/soc/fsl/Kconfig"
5source "drivers/soc/mediatek/Kconfig" 6source "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
5obj-$(CONFIG_ARCH_AT91) += atmel/
5obj-y += bcm/ 6obj-y += bcm/
6obj-$(CONFIG_ARCH_DOVE) += dove/ 7obj-$(CONFIG_ARCH_DOVE) += dove/
7obj-$(CONFIG_MACH_DOVE) += dove/ 8obj-$(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 @@
1config 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
32static 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
113static 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
141static 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
166struct 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
225static int __init atmel_soc_device_init(void)
226{
227 at91_soc_init(socs);
228
229 return 0;
230}
231subsys_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