aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/reset/Kconfig42
-rw-r--r--drivers/power/reset/Makefile3
-rw-r--r--drivers/power/reset/arm-versatile-reboot.c111
-rw-r--r--drivers/power/reset/at91-poweroff.c156
-rw-r--r--drivers/power/reset/at91-reset.c252
5 files changed, 556 insertions, 8 deletions
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index ca41523bbebf..527a0f47ef44 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
9if POWER_RESET
10
9config POWER_RESET_AS3722 11config 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
17config POWER_RESET_AT91_POWEROFF
18 bool "Atmel AT91 poweroff driver"
19 depends on ARCH_AT91
20 default SOC_AT91SAM9 || SOC_SAMA5
21 help
22 This driver supports poweroff for Atmel AT91SAM9 and SAMA5
23 SoCs
24
25config POWER_RESET_AT91_RESET
26 bool "Atmel AT91 reset driver"
27 depends on ARCH_AT91
28 default SOC_AT91SAM9 || SOC_SAMA5
29 help
30 This driver supports restart for Atmel AT91SAM9 and SAMA5
31 SoCs
32
15config POWER_RESET_AXXIA 33config 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
34config POWER_RESET_GPIO 52config 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
48config POWER_RESET_MSM 66config 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
54config POWER_RESET_QNAP 72config 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,22 @@ config POWER_RESET_RESTART
71config POWER_RESET_SUN6I 89config 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
95config POWER_RESET_VERSATILE
96 bool "ARM Versatile family reboot driver"
97 depends on ARM
98 depends on MFD_SYSCON
99 depends on OF
100 help
101 Power off and restart support for ARM Versatile family of
102 reference boards.
103
78config POWER_RESET_VEXPRESS 104config POWER_RESET_VEXPRESS
79 bool "ARM Versatile Express power-off and reset driver" 105 bool "ARM Versatile Express power-off and reset driver"
80 depends on ARM || ARM64 106 depends on ARM || ARM64
81 depends on POWER_RESET && VEXPRESS_CONFIG 107 depends on VEXPRESS_CONFIG
82 help 108 help
83 Power off and reset support for the ARM Ltd. Versatile 109 Power off and reset support for the ARM Ltd. Versatile
84 Express boards. 110 Express boards.
@@ -86,7 +112,6 @@ config POWER_RESET_VEXPRESS
86config POWER_RESET_XGENE 112config POWER_RESET_XGENE
87 bool "APM SoC X-Gene reset driver" 113 bool "APM SoC X-Gene reset driver"
88 depends on ARM64 114 depends on ARM64
89 depends on POWER_RESET
90 help 115 help
91 Reboot support for the APM SoC X-Gene Eval boards. 116 Reboot support for the APM SoC X-Gene Eval boards.
92 117
@@ -97,3 +122,4 @@ config POWER_RESET_KEYSTONE
97 help 122 help
98 Reboot support for the KEYSTONE SoCs. 123 Reboot support for the KEYSTONE SoCs.
99 124
125endif
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index a42e70edd037..73221009f2bf 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -1,4 +1,6 @@
1obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o 1obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o
2obj-$(CONFIG_POWER_RESET_AT91_POWEROFF) += at91-poweroff.o
3obj-$(CONFIG_POWER_RESET_AT91_RESET) += at91-reset.o
2obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o 4obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o
3obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o 5obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o
4obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o 6obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
@@ -7,6 +9,7 @@ obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
7obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o 9obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
8obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o 10obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
9obj-$(CONFIG_POWER_RESET_SUN6I) += sun6i-reboot.o 11obj-$(CONFIG_POWER_RESET_SUN6I) += sun6i-reboot.o
12obj-$(CONFIG_POWER_RESET_VERSATILE) += arm-versatile-reboot.o
10obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o 13obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o
11obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o 14obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o
12obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o 15obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o
diff --git a/drivers/power/reset/arm-versatile-reboot.c b/drivers/power/reset/arm-versatile-reboot.c
new file mode 100644
index 000000000000..5b08bffcf1a8
--- /dev/null
+++ b/drivers/power/reset/arm-versatile-reboot.c
@@ -0,0 +1,111 @@
1/*
2 * Copyright (C) 2014 Linaro Ltd.
3 *
4 * Author: Linus Walleij <linus.walleij@linaro.org>
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 version 2, as
8 * published by the Free Software Foundation.
9 *
10 */
11#include <linux/init.h>
12#include <linux/mfd/syscon.h>
13#include <linux/reboot.h>
14#include <linux/regmap.h>
15#include <linux/of.h>
16#include <asm/system_misc.h>
17
18#define REALVIEW_SYS_LOCK_OFFSET 0x20
19#define REALVIEW_SYS_LOCK_VAL 0xA05F
20#define REALVIEW_SYS_RESETCTL_OFFSET 0x40
21
22/*
23 * We detect the different syscon types from the compatible strings.
24 */
25enum versatile_reboot {
26 REALVIEW_REBOOT_EB,
27 REALVIEW_REBOOT_PB1176,
28 REALVIEW_REBOOT_PB11MP,
29 REALVIEW_REBOOT_PBA8,
30 REALVIEW_REBOOT_PBX,
31};
32
33/* Pointer to the system controller */
34static struct regmap *syscon_regmap;
35static enum versatile_reboot versatile_reboot_type;
36
37static const struct of_device_id versatile_reboot_of_match[] = {
38 {
39 .compatible = "arm,realview-eb-syscon",
40 .data = (void *)REALVIEW_REBOOT_EB,
41 },
42 {
43 .compatible = "arm,realview-pb1176-syscon",
44 .data = (void *)REALVIEW_REBOOT_PB1176,
45 },
46 {
47 .compatible = "arm,realview-pb11mp-syscon",
48 .data = (void *)REALVIEW_REBOOT_PB11MP,
49 },
50 {
51 .compatible = "arm,realview-pba8-syscon",
52 .data = (void *)REALVIEW_REBOOT_PBA8,
53 },
54 {
55 .compatible = "arm,realview-pbx-syscon",
56 .data = (void *)REALVIEW_REBOOT_PBX,
57 },
58};
59
60static void versatile_reboot(enum reboot_mode mode, const char *cmd)
61{
62 /* Unlock the reset register */
63 regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
64 REALVIEW_SYS_LOCK_VAL);
65 /* Then hit reset on the different machines */
66 switch (versatile_reboot_type) {
67 case REALVIEW_REBOOT_EB:
68 regmap_write(syscon_regmap,
69 REALVIEW_SYS_RESETCTL_OFFSET, 0x0008);
70 break;
71 case REALVIEW_REBOOT_PB1176:
72 regmap_write(syscon_regmap,
73 REALVIEW_SYS_RESETCTL_OFFSET, 0x0100);
74 break;
75 case REALVIEW_REBOOT_PB11MP:
76 case REALVIEW_REBOOT_PBA8:
77 regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
78 0x0000);
79 regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
80 0x0004);
81 break;
82 case REALVIEW_REBOOT_PBX:
83 regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
84 0x00f0);
85 regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
86 0x00f4);
87 break;
88 }
89 dsb();
90}
91
92static int __init versatile_reboot_probe(void)
93{
94 const struct of_device_id *reboot_id;
95 struct device_node *np;
96
97 np = of_find_matching_node_and_match(NULL, versatile_reboot_of_match,
98 &reboot_id);
99 if (!np)
100 return -ENODEV;
101 versatile_reboot_type = (enum versatile_reboot)reboot_id->data;
102
103 syscon_regmap = syscon_node_to_regmap(np);
104 if (IS_ERR(syscon_regmap))
105 return PTR_ERR(syscon_regmap);
106
107 arm_pm_restart = versatile_reboot;
108 pr_info("versatile reboot driver registered\n");
109 return 0;
110}
111device_initcall(versatile_reboot_probe);
diff --git a/drivers/power/reset/at91-poweroff.c b/drivers/power/reset/at91-poweroff.c
new file mode 100644
index 000000000000..c61000333bb9
--- /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
36enum 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
43static 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
50static void __iomem *at91_shdwc_base;
51
52static void __init at91_wakeup_status(void)
53{
54 u32 reg = readl(at91_shdwc_base + AT91_SHDW_SR);
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
69static void at91_poweroff(void)
70{
71 writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, at91_shdwc_base + AT91_SHDW_CR);
72}
73
74const 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
90static 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
121static 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
142static 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
149static 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};
156module_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
42enum 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
50static 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*/
57static 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
81static 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
122static 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
151static 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
158static 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
164static 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
191static 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
221static 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
238static 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
244static 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};
252module_platform_driver(at91_reset_driver);