Merge tag 'trace-v5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[linux-2.6-microblaze.git] / drivers / power / reset / arm-versatile-reboot.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2014 Linaro Ltd.
4  *
5  * Author: Linus Walleij <linus.walleij@linaro.org>
6  */
7 #include <linux/init.h>
8 #include <linux/mfd/syscon.h>
9 #include <linux/reboot.h>
10 #include <linux/regmap.h>
11 #include <linux/of.h>
12
13 #define INTEGRATOR_HDR_CTRL_OFFSET      0x0C
14 #define INTEGRATOR_HDR_LOCK_OFFSET      0x14
15 #define INTEGRATOR_CM_CTRL_RESET        (1 << 3)
16
17 #define VERSATILE_SYS_LOCK_OFFSET       0x20
18 #define VERSATILE_SYS_RESETCTL_OFFSET   0x40
19
20 /* Magic unlocking token used on all Versatile boards */
21 #define VERSATILE_LOCK_VAL              0xA05F
22
23 /*
24  * We detect the different syscon types from the compatible strings.
25  */
26 enum versatile_reboot {
27         INTEGRATOR_REBOOT_CM,
28         VERSATILE_REBOOT_CM,
29         REALVIEW_REBOOT_EB,
30         REALVIEW_REBOOT_PB1176,
31         REALVIEW_REBOOT_PB11MP,
32         REALVIEW_REBOOT_PBA8,
33         REALVIEW_REBOOT_PBX,
34 };
35
36 /* Pointer to the system controller */
37 static struct regmap *syscon_regmap;
38 static enum versatile_reboot versatile_reboot_type;
39
40 static const struct of_device_id versatile_reboot_of_match[] = {
41         {
42                 .compatible = "arm,core-module-integrator",
43                 .data = (void *)INTEGRATOR_REBOOT_CM
44         },
45         {
46                 .compatible = "arm,core-module-versatile",
47                 .data = (void *)VERSATILE_REBOOT_CM,
48         },
49         {
50                 .compatible = "arm,realview-eb-syscon",
51                 .data = (void *)REALVIEW_REBOOT_EB,
52         },
53         {
54                 .compatible = "arm,realview-pb1176-syscon",
55                 .data = (void *)REALVIEW_REBOOT_PB1176,
56         },
57         {
58                 .compatible = "arm,realview-pb11mp-syscon",
59                 .data = (void *)REALVIEW_REBOOT_PB11MP,
60         },
61         {
62                 .compatible = "arm,realview-pba8-syscon",
63                 .data = (void *)REALVIEW_REBOOT_PBA8,
64         },
65         {
66                 .compatible = "arm,realview-pbx-syscon",
67                 .data = (void *)REALVIEW_REBOOT_PBX,
68         },
69         {},
70 };
71
72 static int versatile_reboot(struct notifier_block *this, unsigned long mode,
73                             void *cmd)
74 {
75         /* Unlock the reset register */
76         /* Then hit reset on the different machines */
77         switch (versatile_reboot_type) {
78         case INTEGRATOR_REBOOT_CM:
79                 regmap_write(syscon_regmap, INTEGRATOR_HDR_LOCK_OFFSET,
80                              VERSATILE_LOCK_VAL);
81                 regmap_update_bits(syscon_regmap,
82                                    INTEGRATOR_HDR_CTRL_OFFSET,
83                                    INTEGRATOR_CM_CTRL_RESET,
84                                    INTEGRATOR_CM_CTRL_RESET);
85                 break;
86         case VERSATILE_REBOOT_CM:
87                 regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
88                              VERSATILE_LOCK_VAL);
89                 regmap_update_bits(syscon_regmap,
90                                    VERSATILE_SYS_RESETCTL_OFFSET,
91                                    0x0107,
92                                    0x0105);
93                 regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
94                              0);
95                 break;
96         case REALVIEW_REBOOT_EB:
97                 regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
98                              VERSATILE_LOCK_VAL);
99                 regmap_write(syscon_regmap,
100                              VERSATILE_SYS_RESETCTL_OFFSET, 0x0008);
101                 break;
102         case REALVIEW_REBOOT_PB1176:
103                 regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
104                              VERSATILE_LOCK_VAL);
105                 regmap_write(syscon_regmap,
106                              VERSATILE_SYS_RESETCTL_OFFSET, 0x0100);
107                 break;
108         case REALVIEW_REBOOT_PB11MP:
109         case REALVIEW_REBOOT_PBA8:
110                 regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
111                              VERSATILE_LOCK_VAL);
112                 regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,
113                              0x0000);
114                 regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,
115                              0x0004);
116                 break;
117         case REALVIEW_REBOOT_PBX:
118                 regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
119                              VERSATILE_LOCK_VAL);
120                 regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,
121                              0x00f0);
122                 regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,
123                              0x00f4);
124                 break;
125         }
126         dsb();
127
128         return NOTIFY_DONE;
129 }
130
131 static struct notifier_block versatile_reboot_nb = {
132         .notifier_call = versatile_reboot,
133         .priority = 192,
134 };
135
136 static int __init versatile_reboot_probe(void)
137 {
138         const struct of_device_id *reboot_id;
139         struct device_node *np;
140         int err;
141
142         np = of_find_matching_node_and_match(NULL, versatile_reboot_of_match,
143                                                  &reboot_id);
144         if (!np)
145                 return -ENODEV;
146         versatile_reboot_type = (enum versatile_reboot)reboot_id->data;
147
148         syscon_regmap = syscon_node_to_regmap(np);
149         if (IS_ERR(syscon_regmap))
150                 return PTR_ERR(syscon_regmap);
151
152         err = register_restart_handler(&versatile_reboot_nb);
153         if (err)
154                 return err;
155
156         pr_info("versatile reboot driver registered\n");
157         return 0;
158 }
159 device_initcall(versatile_reboot_probe);