diff options
-rw-r--r-- | Documentation/devicetree/bindings/arm/atmel-at91.txt | 1 | ||||
-rw-r--r-- | arch/arm/mach-at91/Kconfig | 4 | ||||
-rw-r--r-- | arch/arm/mach-at91/setup.c | 1 | ||||
-rw-r--r-- | drivers/clk/at91/clk-system.c | 8 | ||||
-rw-r--r-- | drivers/memory/Kconfig | 10 | ||||
-rw-r--r-- | drivers/memory/Makefile | 1 | ||||
-rw-r--r-- | drivers/memory/atmel-sdramc.c | 98 | ||||
-rw-r--r-- | drivers/power/reset/Kconfig | 33 | ||||
-rw-r--r-- | drivers/power/reset/Makefile | 2 | ||||
-rw-r--r-- | drivers/power/reset/at91-poweroff.c | 156 | ||||
-rw-r--r-- | drivers/power/reset/at91-reset.c | 252 |
11 files changed, 551 insertions, 15 deletions
diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 16f60b41c147..33bcf8b57798 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt | |||
@@ -61,6 +61,7 @@ RAMC SDRAM/DDR Controller required properties: | |||
61 | - compatible: Should be "atmel,at91rm9200-sdramc", | 61 | - compatible: Should be "atmel,at91rm9200-sdramc", |
62 | "atmel,at91sam9260-sdramc", | 62 | "atmel,at91sam9260-sdramc", |
63 | "atmel,at91sam9g45-ddramc", | 63 | "atmel,at91sam9g45-ddramc", |
64 | "atmel,sama5d3-ddramc", | ||
64 | - reg: Should contain registers location and length | 65 | - reg: Should contain registers location and length |
65 | For at91sam9263 and at91sam9g45 you must specify 2 entries. | 66 | For at91sam9263 and at91sam9g45 you must specify 2 entries. |
66 | 67 | ||
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index dd28e1fedbdc..6aa7ab47205e 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig | |||
@@ -53,6 +53,8 @@ config SOC_AT91SAM9 | |||
53 | select ATMEL_AIC_IRQ if !OLD_IRQ_AT91 | 53 | select ATMEL_AIC_IRQ if !OLD_IRQ_AT91 |
54 | select CPU_ARM926T | 54 | select CPU_ARM926T |
55 | select GENERIC_CLOCKEVENTS | 55 | select GENERIC_CLOCKEVENTS |
56 | select MEMORY if USE_OF | ||
57 | select ATMEL_SDRAMC if USE_OF | ||
56 | 58 | ||
57 | config SOC_SAMA5 | 59 | config SOC_SAMA5 |
58 | bool | 60 | bool |
@@ -61,6 +63,8 @@ config SOC_SAMA5 | |||
61 | select CPU_V7 | 63 | select CPU_V7 |
62 | select GENERIC_CLOCKEVENTS | 64 | select GENERIC_CLOCKEVENTS |
63 | select USE_OF | 65 | select USE_OF |
66 | select MEMORY | ||
67 | select ATMEL_SDRAMC | ||
64 | 68 | ||
65 | menu "Atmel AT91 System-on-Chip" | 69 | menu "Atmel AT91 System-on-Chip" |
66 | 70 | ||
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c index 0bf893a574f9..1174b5fe74d8 100644 --- a/arch/arm/mach-at91/setup.c +++ b/arch/arm/mach-at91/setup.c | |||
@@ -385,6 +385,7 @@ static struct of_device_id ramc_ids[] = { | |||
385 | { .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby }, | 385 | { .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby }, |
386 | { .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby }, | 386 | { .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby }, |
387 | { .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby }, | 387 | { .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby }, |
388 | { .compatible = "atmel,sama5d3-ddramc", .data = at91_ddr_standby }, | ||
388 | { /*sentinel*/ } | 389 | { /*sentinel*/ } |
389 | }; | 390 | }; |
390 | 391 | ||
diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c index 8c96307d7363..a76d03fd577b 100644 --- a/drivers/clk/at91/clk-system.c +++ b/drivers/clk/at91/clk-system.c | |||
@@ -119,13 +119,7 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name, | |||
119 | init.ops = &system_ops; | 119 | init.ops = &system_ops; |
120 | init.parent_names = &parent_name; | 120 | init.parent_names = &parent_name; |
121 | init.num_parents = 1; | 121 | init.num_parents = 1; |
122 | /* | 122 | init.flags = CLK_SET_RATE_PARENT; |
123 | * CLK_IGNORE_UNUSED is used to avoid ddrck switch off. | ||
124 | * TODO : we should implement a driver supporting at91 ddr controller | ||
125 | * (see drivers/memory) which would request and enable the ddrck clock. | ||
126 | * When this is done we will be able to remove CLK_IGNORE_UNUSED flag. | ||
127 | */ | ||
128 | init.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED; | ||
129 | 123 | ||
130 | sys->id = id; | 124 | sys->id = id; |
131 | sys->hw.init = &init; | 125 | sys->hw.init = &init; |
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index fab81a143bd7..6d91c27fd4c8 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig | |||
@@ -7,6 +7,16 @@ menuconfig MEMORY | |||
7 | 7 | ||
8 | if MEMORY | 8 | if MEMORY |
9 | 9 | ||
10 | config ATMEL_SDRAMC | ||
11 | bool "Atmel (Multi-port DDR-)SDRAM Controller" | ||
12 | default y | ||
13 | depends on ARCH_AT91 && OF | ||
14 | help | ||
15 | This driver is for Atmel SDRAM Controller or Atmel Multi-port | ||
16 | DDR-SDRAM Controller available on Atmel AT91SAM9 and SAMA5 SoCs. | ||
17 | Starting with the at91sam9g45, this controller supports SDR, DDR and | ||
18 | LP-DDR memories. | ||
19 | |||
10 | config TI_AEMIF | 20 | config TI_AEMIF |
11 | tristate "Texas Instruments AEMIF driver" | 21 | tristate "Texas Instruments AEMIF driver" |
12 | depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF | 22 | depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF |
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index 4055c47f45ab..c32d31981be3 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile | |||
@@ -5,6 +5,7 @@ | |||
5 | ifeq ($(CONFIG_DDR),y) | 5 | ifeq ($(CONFIG_DDR),y) |
6 | obj-$(CONFIG_OF) += of_memory.o | 6 | obj-$(CONFIG_OF) += of_memory.o |
7 | endif | 7 | endif |
8 | obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o | ||
8 | obj-$(CONFIG_TI_AEMIF) += ti-aemif.o | 9 | obj-$(CONFIG_TI_AEMIF) += ti-aemif.o |
9 | obj-$(CONFIG_TI_EMIF) += emif.o | 10 | obj-$(CONFIG_TI_EMIF) += emif.o |
10 | obj-$(CONFIG_FSL_CORENET_CF) += fsl-corenet-cf.o | 11 | obj-$(CONFIG_FSL_CORENET_CF) += fsl-corenet-cf.o |
diff --git a/drivers/memory/atmel-sdramc.c b/drivers/memory/atmel-sdramc.c new file mode 100644 index 000000000000..fed04e8efe75 --- /dev/null +++ b/drivers/memory/atmel-sdramc.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * Atmel (Multi-port DDR-)SDRAM Controller driver | ||
3 | * | ||
4 | * Copyright (C) 2014 Atmel | ||
5 | * | ||
6 | * This program is free software: you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation version 2 of the License. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/clk.h> | ||
21 | #include <linux/err.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/of_platform.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | |||
27 | struct at91_ramc_caps { | ||
28 | bool has_ddrck; | ||
29 | bool has_mpddr_clk; | ||
30 | }; | ||
31 | |||
32 | static const struct at91_ramc_caps at91rm9200_caps = { }; | ||
33 | |||
34 | static const struct at91_ramc_caps at91sam9g45_caps = { | ||
35 | .has_ddrck = 1, | ||
36 | .has_mpddr_clk = 0, | ||
37 | }; | ||
38 | |||
39 | static const struct at91_ramc_caps sama5d3_caps = { | ||
40 | .has_ddrck = 1, | ||
41 | .has_mpddr_clk = 1, | ||
42 | }; | ||
43 | |||
44 | static const struct of_device_id atmel_ramc_of_match[] = { | ||
45 | { .compatible = "atmel,at91rm9200-sdramc", .data = &at91rm9200_caps, }, | ||
46 | { .compatible = "atmel,at91sam9260-sdramc", .data = &at91rm9200_caps, }, | ||
47 | { .compatible = "atmel,at91sam9g45-ddramc", .data = &at91sam9g45_caps, }, | ||
48 | { .compatible = "atmel,sama5d3-ddramc", .data = &sama5d3_caps, }, | ||
49 | {}, | ||
50 | }; | ||
51 | MODULE_DEVICE_TABLE(of, atmel_ramc_of_match); | ||
52 | |||
53 | static int atmel_ramc_probe(struct platform_device *pdev) | ||
54 | { | ||
55 | const struct of_device_id *match; | ||
56 | const struct at91_ramc_caps *caps; | ||
57 | struct clk *clk; | ||
58 | |||
59 | match = of_match_device(atmel_ramc_of_match, &pdev->dev); | ||
60 | caps = match->data; | ||
61 | |||
62 | if (caps->has_ddrck) { | ||
63 | clk = devm_clk_get(&pdev->dev, "ddrck"); | ||
64 | if (IS_ERR(clk)) | ||
65 | return PTR_ERR(clk); | ||
66 | clk_prepare_enable(clk); | ||
67 | } | ||
68 | |||
69 | if (caps->has_mpddr_clk) { | ||
70 | clk = devm_clk_get(&pdev->dev, "mpddr"); | ||
71 | if (IS_ERR(clk)) { | ||
72 | pr_err("AT91 RAMC: couldn't get mpddr clock\n"); | ||
73 | return PTR_ERR(clk); | ||
74 | } | ||
75 | clk_prepare_enable(clk); | ||
76 | } | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static struct platform_driver atmel_ramc_driver = { | ||
82 | .probe = atmel_ramc_probe, | ||
83 | .driver = { | ||
84 | .name = "atmel-ramc", | ||
85 | .owner = THIS_MODULE, | ||
86 | .of_match_table = atmel_ramc_of_match, | ||
87 | }, | ||
88 | }; | ||
89 | |||
90 | static int __init atmel_ramc_init(void) | ||
91 | { | ||
92 | return platform_driver_register(&atmel_ramc_driver); | ||
93 | } | ||
94 | module_init(atmel_ramc_init); | ||
95 | |||
96 | MODULE_LICENSE("GPL v2"); | ||
97 | MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>"); | ||
98 | MODULE_DESCRIPTION("Atmel (Multi-port DDR-)SDRAM Controller"); | ||
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index ca41523bbebf..c1c046d0464e 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig | |||
@@ -6,15 +6,33 @@ menuconfig POWER_RESET | |||
6 | 6 | ||
7 | Say Y here to enable board reset and power off | 7 | Say Y here to enable board reset and power off |
8 | 8 | ||
9 | if POWER_RESET | ||
10 | |||
9 | config POWER_RESET_AS3722 | 11 | config POWER_RESET_AS3722 |
10 | bool "ams AS3722 power-off driver" | 12 | bool "ams AS3722 power-off driver" |
11 | depends on MFD_AS3722 && POWER_RESET | 13 | depends on MFD_AS3722 |
12 | help | 14 | help |
13 | This driver supports turning off board via a ams AS3722 power-off. | 15 | This driver supports turning off board via a ams AS3722 power-off. |
14 | 16 | ||
17 | config POWER_RESET_AT91_POWEROFF | ||
18 | bool "Atmel AT91 poweroff driver" | ||
19 | depends on MACH_AT91 | ||
20 | default SOC_AT91SAM9 || SOC_SAMA5 | ||
21 | help | ||
22 | This driver supports poweroff for Atmel AT91SAM9 and SAMA5 | ||
23 | SoCs | ||
24 | |||
25 | config POWER_RESET_AT91_RESET | ||
26 | bool "Atmel AT91 reset driver" | ||
27 | depends on MACH_AT91 | ||
28 | default SOC_AT91SAM9 || SOC_SAMA5 | ||
29 | help | ||
30 | This driver supports restart for Atmel AT91SAM9 and SAMA5 | ||
31 | SoCs | ||
32 | |||
15 | config POWER_RESET_AXXIA | 33 | config POWER_RESET_AXXIA |
16 | bool "LSI Axxia reset driver" | 34 | bool "LSI Axxia reset driver" |
17 | depends on POWER_RESET && ARCH_AXXIA | 35 | depends on ARCH_AXXIA |
18 | help | 36 | help |
19 | This driver supports restart for Axxia SoC. | 37 | This driver supports restart for Axxia SoC. |
20 | 38 | ||
@@ -33,7 +51,7 @@ config POWER_RESET_BRCMSTB | |||
33 | 51 | ||
34 | config POWER_RESET_GPIO | 52 | config POWER_RESET_GPIO |
35 | bool "GPIO power-off driver" | 53 | bool "GPIO power-off driver" |
36 | depends on OF_GPIO && POWER_RESET | 54 | depends on OF_GPIO |
37 | help | 55 | help |
38 | This driver supports turning off your board via a GPIO line. | 56 | This driver supports turning off your board via a GPIO line. |
39 | If your board needs a GPIO high/low to power down, say Y and | 57 | If your board needs a GPIO high/low to power down, say Y and |
@@ -47,13 +65,13 @@ config POWER_RESET_HISI | |||
47 | 65 | ||
48 | config POWER_RESET_MSM | 66 | config POWER_RESET_MSM |
49 | bool "Qualcomm MSM power-off driver" | 67 | bool "Qualcomm MSM power-off driver" |
50 | depends on POWER_RESET && ARCH_QCOM | 68 | depends on ARCH_QCOM |
51 | help | 69 | help |
52 | Power off and restart support for Qualcomm boards. | 70 | Power off and restart support for Qualcomm boards. |
53 | 71 | ||
54 | config POWER_RESET_QNAP | 72 | config POWER_RESET_QNAP |
55 | bool "QNAP power-off driver" | 73 | bool "QNAP power-off driver" |
56 | depends on OF_GPIO && POWER_RESET && PLAT_ORION | 74 | depends on OF_GPIO && PLAT_ORION |
57 | help | 75 | help |
58 | This driver supports turning off QNAP NAS devices by sending | 76 | This driver supports turning off QNAP NAS devices by sending |
59 | commands to the microcontroller which controls the main power. | 77 | commands to the microcontroller which controls the main power. |
@@ -71,14 +89,13 @@ config POWER_RESET_RESTART | |||
71 | config POWER_RESET_SUN6I | 89 | config POWER_RESET_SUN6I |
72 | bool "Allwinner A31 SoC reset driver" | 90 | bool "Allwinner A31 SoC reset driver" |
73 | depends on ARCH_SUNXI | 91 | depends on ARCH_SUNXI |
74 | depends on POWER_RESET | ||
75 | help | 92 | help |
76 | Reboot support for the Allwinner A31 SoCs. | 93 | Reboot support for the Allwinner A31 SoCs. |
77 | 94 | ||
78 | config POWER_RESET_VEXPRESS | 95 | config POWER_RESET_VEXPRESS |
79 | bool "ARM Versatile Express power-off and reset driver" | 96 | bool "ARM Versatile Express power-off and reset driver" |
80 | depends on ARM || ARM64 | 97 | depends on ARM || ARM64 |
81 | depends on POWER_RESET && VEXPRESS_CONFIG | 98 | depends on VEXPRESS_CONFIG |
82 | help | 99 | help |
83 | Power off and reset support for the ARM Ltd. Versatile | 100 | Power off and reset support for the ARM Ltd. Versatile |
84 | Express boards. | 101 | Express boards. |
@@ -86,7 +103,6 @@ config POWER_RESET_VEXPRESS | |||
86 | config POWER_RESET_XGENE | 103 | config POWER_RESET_XGENE |
87 | bool "APM SoC X-Gene reset driver" | 104 | bool "APM SoC X-Gene reset driver" |
88 | depends on ARM64 | 105 | depends on ARM64 |
89 | depends on POWER_RESET | ||
90 | help | 106 | help |
91 | Reboot support for the APM SoC X-Gene Eval boards. | 107 | Reboot support for the APM SoC X-Gene Eval boards. |
92 | 108 | ||
@@ -97,3 +113,4 @@ config POWER_RESET_KEYSTONE | |||
97 | help | 113 | help |
98 | Reboot support for the KEYSTONE SoCs. | 114 | Reboot support for the KEYSTONE SoCs. |
99 | 115 | ||
116 | endif | ||
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index a42e70edd037..4433a753fd93 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile | |||
@@ -1,4 +1,6 @@ | |||
1 | obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o | 1 | obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o |
2 | obj-$(CONFIG_POWER_RESET_AT91_POWEROFF) += at91-poweroff.o | ||
3 | obj-$(CONFIG_POWER_RESET_AT91_RESET) += at91-reset.o | ||
2 | obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o | 4 | obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o |
3 | obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o | 5 | obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o |
4 | obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o | 6 | obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o |
diff --git a/drivers/power/reset/at91-poweroff.c b/drivers/power/reset/at91-poweroff.c new file mode 100644 index 000000000000..40bf42d146f1 --- /dev/null +++ b/drivers/power/reset/at91-poweroff.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * Atmel AT91 SAM9 SoCs reset code | ||
3 | * | ||
4 | * Copyright (C) 2007 Atmel Corporation. | ||
5 | * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> | ||
6 | * Copyright (C) 2014 Free Electrons | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2. This program is licensed "as is" without any | ||
10 | * warranty of any kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/io.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/printk.h> | ||
18 | |||
19 | #define AT91_SHDW_CR 0x00 /* Shut Down Control Register */ | ||
20 | #define AT91_SHDW_SHDW BIT(0) /* Shut Down command */ | ||
21 | #define AT91_SHDW_KEY (0xa5 << 24) /* KEY Password */ | ||
22 | |||
23 | #define AT91_SHDW_MR 0x04 /* Shut Down Mode Register */ | ||
24 | #define AT91_SHDW_WKMODE0 GENMASK(2, 0) /* Wake-up 0 Mode Selection */ | ||
25 | #define AT91_SHDW_CPTWK0_MAX 0xf /* Maximum Counter On Wake Up 0 */ | ||
26 | #define AT91_SHDW_CPTWK0 (AT91_SHDW_CPTWK0_MAX << 4) /* Counter On Wake Up 0 */ | ||
27 | #define AT91_SHDW_CPTWK0_(x) ((x) << 4) | ||
28 | #define AT91_SHDW_RTTWKEN BIT(16) /* Real Time Timer Wake-up Enable */ | ||
29 | #define AT91_SHDW_RTCWKEN BIT(17) /* Real Time Clock Wake-up Enable */ | ||
30 | |||
31 | #define AT91_SHDW_SR 0x08 /* Shut Down Status Register */ | ||
32 | #define AT91_SHDW_WAKEUP0 BIT(0) /* Wake-up 0 Status */ | ||
33 | #define AT91_SHDW_RTTWK BIT(16) /* Real-time Timer Wake-up */ | ||
34 | #define AT91_SHDW_RTCWK BIT(17) /* Real-time Clock Wake-up [SAM9RL] */ | ||
35 | |||
36 | enum wakeup_type { | ||
37 | AT91_SHDW_WKMODE0_NONE = 0, | ||
38 | AT91_SHDW_WKMODE0_HIGH = 1, | ||
39 | AT91_SHDW_WKMODE0_LOW = 2, | ||
40 | AT91_SHDW_WKMODE0_ANYLEVEL = 3, | ||
41 | }; | ||
42 | |||
43 | static const char *shdwc_wakeup_modes[] = { | ||
44 | [AT91_SHDW_WKMODE0_NONE] = "none", | ||
45 | [AT91_SHDW_WKMODE0_HIGH] = "high", | ||
46 | [AT91_SHDW_WKMODE0_LOW] = "low", | ||
47 | [AT91_SHDW_WKMODE0_ANYLEVEL] = "any", | ||
48 | }; | ||
49 | |||
50 | static void __iomem *at91_shdwc_base; | ||
51 | |||
52 | static void __init at91_wakeup_status(void) | ||
53 | { | ||
54 | u32 reg = readl(at91_shdwc_base); | ||
55 | char *reason = "unknown"; | ||
56 | |||
57 | /* Simple power-on, just bail out */ | ||
58 | if (!reg) | ||
59 | return; | ||
60 | |||
61 | if (reg & AT91_SHDW_RTTWK) | ||
62 | reason = "RTT"; | ||
63 | else if (reg & AT91_SHDW_RTCWK) | ||
64 | reason = "RTC"; | ||
65 | |||
66 | pr_info("AT91: Wake-Up source: %s\n", reason); | ||
67 | } | ||
68 | |||
69 | static void at91_poweroff(void) | ||
70 | { | ||
71 | writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, at91_shdwc_base + AT91_SHDW_CR); | ||
72 | } | ||
73 | |||
74 | const enum wakeup_type at91_poweroff_get_wakeup_mode(struct device_node *np) | ||
75 | { | ||
76 | const char *pm; | ||
77 | int err, i; | ||
78 | |||
79 | err = of_property_read_string(np, "atmel,wakeup-mode", &pm); | ||
80 | if (err < 0) | ||
81 | return AT91_SHDW_WKMODE0_ANYLEVEL; | ||
82 | |||
83 | for (i = 0; i < ARRAY_SIZE(shdwc_wakeup_modes); i++) | ||
84 | if (!strcasecmp(pm, shdwc_wakeup_modes[i])) | ||
85 | return i; | ||
86 | |||
87 | return -ENODEV; | ||
88 | } | ||
89 | |||
90 | static void at91_poweroff_dt_set_wakeup_mode(struct platform_device *pdev) | ||
91 | { | ||
92 | struct device_node *np = pdev->dev.of_node; | ||
93 | enum wakeup_type wakeup_mode; | ||
94 | u32 mode = 0, tmp; | ||
95 | |||
96 | wakeup_mode = at91_poweroff_get_wakeup_mode(np); | ||
97 | if (wakeup_mode < 0) { | ||
98 | dev_warn(&pdev->dev, "shdwc unknown wakeup mode\n"); | ||
99 | return; | ||
100 | } | ||
101 | |||
102 | if (!of_property_read_u32(np, "atmel,wakeup-counter", &tmp)) { | ||
103 | if (tmp > AT91_SHDW_CPTWK0_MAX) { | ||
104 | dev_warn(&pdev->dev, | ||
105 | "shdwc wakeup counter 0x%x > 0x%x reduce it to 0x%x\n", | ||
106 | tmp, AT91_SHDW_CPTWK0_MAX, AT91_SHDW_CPTWK0_MAX); | ||
107 | tmp = AT91_SHDW_CPTWK0_MAX; | ||
108 | } | ||
109 | mode |= AT91_SHDW_CPTWK0_(tmp); | ||
110 | } | ||
111 | |||
112 | if (of_property_read_bool(np, "atmel,wakeup-rtc-timer")) | ||
113 | mode |= AT91_SHDW_RTCWKEN; | ||
114 | |||
115 | if (of_property_read_bool(np, "atmel,wakeup-rtt-timer")) | ||
116 | mode |= AT91_SHDW_RTTWKEN; | ||
117 | |||
118 | writel(wakeup_mode | mode, at91_shdwc_base + AT91_SHDW_MR); | ||
119 | } | ||
120 | |||
121 | static int at91_poweroff_probe(struct platform_device *pdev) | ||
122 | { | ||
123 | struct resource *res; | ||
124 | |||
125 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
126 | at91_shdwc_base = devm_ioremap_resource(&pdev->dev, res); | ||
127 | if (IS_ERR(at91_shdwc_base)) { | ||
128 | dev_err(&pdev->dev, "Could not map reset controller address\n"); | ||
129 | return PTR_ERR(at91_shdwc_base); | ||
130 | } | ||
131 | |||
132 | at91_wakeup_status(); | ||
133 | |||
134 | if (pdev->dev.of_node) | ||
135 | at91_poweroff_dt_set_wakeup_mode(pdev); | ||
136 | |||
137 | pm_power_off = at91_poweroff; | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static struct of_device_id at91_poweroff_of_match[] = { | ||
143 | { .compatible = "atmel,at91sam9260-shdwc", }, | ||
144 | { .compatible = "atmel,at91sam9rl-shdwc", }, | ||
145 | { .compatible = "atmel,at91sam9x5-shdwc", }, | ||
146 | { /*sentinel*/ } | ||
147 | }; | ||
148 | |||
149 | static struct platform_driver at91_poweroff_driver = { | ||
150 | .probe = at91_poweroff_probe, | ||
151 | .driver = { | ||
152 | .name = "at91-poweroff", | ||
153 | .of_match_table = at91_poweroff_of_match, | ||
154 | }, | ||
155 | }; | ||
156 | module_platform_driver(at91_poweroff_driver); | ||
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c new file mode 100644 index 000000000000..3611806c9cfd --- /dev/null +++ b/drivers/power/reset/at91-reset.c | |||
@@ -0,0 +1,252 @@ | |||
1 | /* | ||
2 | * Atmel AT91 SAM9 SoCs reset code | ||
3 | * | ||
4 | * Copyright (C) 2007 Atmel Corporation. | ||
5 | * Copyright (C) BitBox Ltd 2010 | ||
6 | * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcosoft.com> | ||
7 | * Copyright (C) 2014 Free Electrons | ||
8 | * | ||
9 | * This file is licensed under the terms of the GNU General Public | ||
10 | * License version 2. This program is licensed "as is" without any | ||
11 | * warranty of any kind, whether express or implied. | ||
12 | */ | ||
13 | |||
14 | #include <linux/io.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/of_address.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/reboot.h> | ||
19 | |||
20 | #include <asm/system_misc.h> | ||
21 | |||
22 | #include <mach/at91sam9_ddrsdr.h> | ||
23 | #include <mach/at91sam9_sdramc.h> | ||
24 | |||
25 | #define AT91_RSTC_CR 0x00 /* Reset Controller Control Register */ | ||
26 | #define AT91_RSTC_PROCRST BIT(0) /* Processor Reset */ | ||
27 | #define AT91_RSTC_PERRST BIT(2) /* Peripheral Reset */ | ||
28 | #define AT91_RSTC_EXTRST BIT(3) /* External Reset */ | ||
29 | #define AT91_RSTC_KEY (0xa5 << 24) /* KEY Password */ | ||
30 | |||
31 | #define AT91_RSTC_SR 0x04 /* Reset Controller Status Register */ | ||
32 | #define AT91_RSTC_URSTS BIT(0) /* User Reset Status */ | ||
33 | #define AT91_RSTC_RSTTYP GENMASK(10, 8) /* Reset Type */ | ||
34 | #define AT91_RSTC_NRSTL BIT(16) /* NRST Pin Level */ | ||
35 | #define AT91_RSTC_SRCMP BIT(17) /* Software Reset Command in Progress */ | ||
36 | |||
37 | #define AT91_RSTC_MR 0x08 /* Reset Controller Mode Register */ | ||
38 | #define AT91_RSTC_URSTEN BIT(0) /* User Reset Enable */ | ||
39 | #define AT91_RSTC_URSTIEN BIT(4) /* User Reset Interrupt Enable */ | ||
40 | #define AT91_RSTC_ERSTL GENMASK(11, 8) /* External Reset Length */ | ||
41 | |||
42 | enum reset_type { | ||
43 | RESET_TYPE_GENERAL = 0, | ||
44 | RESET_TYPE_WAKEUP = 1, | ||
45 | RESET_TYPE_WATCHDOG = 2, | ||
46 | RESET_TYPE_SOFTWARE = 3, | ||
47 | RESET_TYPE_USER = 4, | ||
48 | }; | ||
49 | |||
50 | static void __iomem *at91_ramc_base[2], *at91_rstc_base; | ||
51 | |||
52 | /* | ||
53 | * unless the SDRAM is cleanly shutdown before we hit the | ||
54 | * reset register it can be left driving the data bus and | ||
55 | * killing the chance of a subsequent boot from NAND | ||
56 | */ | ||
57 | static void at91sam9260_restart(enum reboot_mode mode, const char *cmd) | ||
58 | { | ||
59 | asm volatile( | ||
60 | /* Align to cache lines */ | ||
61 | ".balign 32\n\t" | ||
62 | |||
63 | /* Disable SDRAM accesses */ | ||
64 | "str %2, [%0, #" __stringify(AT91_SDRAMC_TR) "]\n\t" | ||
65 | |||
66 | /* Power down SDRAM */ | ||
67 | "str %3, [%0, #" __stringify(AT91_SDRAMC_LPR) "]\n\t" | ||
68 | |||
69 | /* Reset CPU */ | ||
70 | "str %4, [%1, #" __stringify(AT91_RSTC_CR) "]\n\t" | ||
71 | |||
72 | "b .\n\t" | ||
73 | : | ||
74 | : "r" (at91_ramc_base[0]), | ||
75 | "r" (at91_rstc_base), | ||
76 | "r" (1), | ||
77 | "r" (AT91_SDRAMC_LPCB_POWER_DOWN), | ||
78 | "r" (AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)); | ||
79 | } | ||
80 | |||
81 | static void at91sam9g45_restart(enum reboot_mode mode, const char *cmd) | ||
82 | { | ||
83 | asm volatile( | ||
84 | /* | ||
85 | * Test wether we have a second RAM controller to care | ||
86 | * about. | ||
87 | * | ||
88 | * First, test that we can dereference the virtual address. | ||
89 | */ | ||
90 | "cmp %1, #0\n\t" | ||
91 | "beq 1f\n\t" | ||
92 | |||
93 | /* Then, test that the RAM controller is enabled */ | ||
94 | "ldr r0, [%1]\n\t" | ||
95 | "cmp r0, #0\n\t" | ||
96 | |||
97 | /* Align to cache lines */ | ||
98 | ".balign 32\n\t" | ||
99 | |||
100 | /* Disable SDRAM0 accesses */ | ||
101 | "1: str %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" | ||
102 | /* Power down SDRAM0 */ | ||
103 | " str %4, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" | ||
104 | /* Disable SDRAM1 accesses */ | ||
105 | " strne %3, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" | ||
106 | /* Power down SDRAM1 */ | ||
107 | " strne %4, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" | ||
108 | /* Reset CPU */ | ||
109 | " str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t" | ||
110 | |||
111 | " b .\n\t" | ||
112 | : | ||
113 | : "r" (at91_ramc_base[0]), | ||
114 | "r" (at91_ramc_base[1]), | ||
115 | "r" (at91_rstc_base), | ||
116 | "r" (1), | ||
117 | "r" (AT91_DDRSDRC_LPCB_POWER_DOWN), | ||
118 | "r" (AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST) | ||
119 | : "r0"); | ||
120 | } | ||
121 | |||
122 | static void __init at91_reset_status(struct platform_device *pdev) | ||
123 | { | ||
124 | u32 reg = readl(at91_rstc_base + AT91_RSTC_SR); | ||
125 | char *reason; | ||
126 | |||
127 | switch ((reg & AT91_RSTC_RSTTYP) >> 8) { | ||
128 | case RESET_TYPE_GENERAL: | ||
129 | reason = "general reset"; | ||
130 | break; | ||
131 | case RESET_TYPE_WAKEUP: | ||
132 | reason = "wakeup"; | ||
133 | break; | ||
134 | case RESET_TYPE_WATCHDOG: | ||
135 | reason = "watchdog reset"; | ||
136 | break; | ||
137 | case RESET_TYPE_SOFTWARE: | ||
138 | reason = "software reset"; | ||
139 | break; | ||
140 | case RESET_TYPE_USER: | ||
141 | reason = "user reset"; | ||
142 | break; | ||
143 | default: | ||
144 | reason = "unknown reset"; | ||
145 | break; | ||
146 | } | ||
147 | |||
148 | pr_info("AT91: Starting after %s\n", reason); | ||
149 | } | ||
150 | |||
151 | static struct of_device_id at91_ramc_of_match[] = { | ||
152 | { .compatible = "atmel,at91sam9260-sdramc", }, | ||
153 | { .compatible = "atmel,at91sam9g45-ddramc", }, | ||
154 | { .compatible = "atmel,sama5d3-ddramc", }, | ||
155 | { /* sentinel */ } | ||
156 | }; | ||
157 | |||
158 | static struct of_device_id at91_reset_of_match[] = { | ||
159 | { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9260_restart }, | ||
160 | { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart }, | ||
161 | { /* sentinel */ } | ||
162 | }; | ||
163 | |||
164 | static int at91_reset_of_probe(struct platform_device *pdev) | ||
165 | { | ||
166 | const struct of_device_id *match; | ||
167 | struct device_node *np; | ||
168 | int idx = 0; | ||
169 | |||
170 | at91_rstc_base = of_iomap(pdev->dev.of_node, 0); | ||
171 | if (!at91_rstc_base) { | ||
172 | dev_err(&pdev->dev, "Could not map reset controller address\n"); | ||
173 | return -ENODEV; | ||
174 | } | ||
175 | |||
176 | for_each_matching_node(np, at91_ramc_of_match) { | ||
177 | at91_ramc_base[idx] = of_iomap(np, 0); | ||
178 | if (!at91_ramc_base[idx]) { | ||
179 | dev_err(&pdev->dev, "Could not map ram controller address\n"); | ||
180 | return -ENODEV; | ||
181 | } | ||
182 | idx++; | ||
183 | } | ||
184 | |||
185 | match = of_match_node(at91_reset_of_match, pdev->dev.of_node); | ||
186 | arm_pm_restart = match->data; | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static int at91_reset_platform_probe(struct platform_device *pdev) | ||
192 | { | ||
193 | const struct platform_device_id *match; | ||
194 | struct resource *res; | ||
195 | int idx = 0; | ||
196 | |||
197 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
198 | at91_rstc_base = devm_ioremap_resource(&pdev->dev, res); | ||
199 | if (IS_ERR(at91_rstc_base)) { | ||
200 | dev_err(&pdev->dev, "Could not map reset controller address\n"); | ||
201 | return PTR_ERR(at91_rstc_base); | ||
202 | } | ||
203 | |||
204 | for (idx = 0; idx < 2; idx++) { | ||
205 | res = platform_get_resource(pdev, IORESOURCE_MEM, idx + 1 ); | ||
206 | at91_ramc_base[idx] = devm_ioremap(&pdev->dev, res->start, | ||
207 | resource_size(res)); | ||
208 | if (IS_ERR(at91_ramc_base[idx])) { | ||
209 | dev_err(&pdev->dev, "Could not map ram controller address\n"); | ||
210 | return PTR_ERR(at91_ramc_base[idx]); | ||
211 | } | ||
212 | } | ||
213 | |||
214 | match = platform_get_device_id(pdev); | ||
215 | arm_pm_restart = (void (*)(enum reboot_mode, const char*)) | ||
216 | match->driver_data; | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int at91_reset_probe(struct platform_device *pdev) | ||
222 | { | ||
223 | int ret; | ||
224 | |||
225 | if (pdev->dev.of_node) | ||
226 | ret = at91_reset_of_probe(pdev); | ||
227 | else | ||
228 | ret = at91_reset_platform_probe(pdev); | ||
229 | |||
230 | if (ret) | ||
231 | return ret; | ||
232 | |||
233 | at91_reset_status(pdev); | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static struct platform_device_id at91_reset_plat_match[] = { | ||
239 | { "at91-sam9260-reset", (unsigned long)at91sam9260_restart }, | ||
240 | { "at91-sam9g45-reset", (unsigned long)at91sam9g45_restart }, | ||
241 | { /* sentinel */ } | ||
242 | }; | ||
243 | |||
244 | static struct platform_driver at91_reset_driver = { | ||
245 | .probe = at91_reset_probe, | ||
246 | .driver = { | ||
247 | .name = "at91-reset", | ||
248 | .of_match_table = at91_reset_of_match, | ||
249 | }, | ||
250 | .id_table = at91_reset_plat_match, | ||
251 | }; | ||
252 | module_platform_driver(at91_reset_driver); | ||