1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | #include <linux/kernel.h> |
3 | #include <linux/module.h> |
4 | #include <linux/delay.h> |
5 | #include <linux/gpio.h> |
6 | #include <linux/io.h> |
7 | #include <asm/proc-fns.h> |
8 | #include <asm/system_misc.h> |
9 | |
10 | #include "regs-ost.h" |
11 | #include "reset.h" |
12 | #include "smemc.h" |
13 | #include "generic.h" |
14 | |
15 | static void do_hw_reset(void); |
16 | |
17 | static int reset_gpio = -1; |
18 | |
19 | int init_gpio_reset(int gpio, int output, int level) |
20 | { |
21 | int rc; |
22 | |
23 | rc = gpio_request(gpio, label: "reset generator" ); |
24 | if (rc) { |
25 | printk(KERN_ERR "Can't request reset_gpio\n" ); |
26 | goto out; |
27 | } |
28 | |
29 | if (output) |
30 | rc = gpio_direction_output(gpio, value: level); |
31 | else |
32 | rc = gpio_direction_input(gpio); |
33 | if (rc) { |
34 | printk(KERN_ERR "Can't configure reset_gpio\n" ); |
35 | gpio_free(gpio); |
36 | goto out; |
37 | } |
38 | |
39 | out: |
40 | if (!rc) |
41 | reset_gpio = gpio; |
42 | |
43 | return rc; |
44 | } |
45 | |
46 | /* |
47 | * Trigger GPIO reset. |
48 | * This covers various types of logic connecting gpio pin |
49 | * to RESET pins (nRESET or GPIO_RESET): |
50 | */ |
51 | static void do_gpio_reset(void) |
52 | { |
53 | BUG_ON(reset_gpio == -1); |
54 | |
55 | /* drive it low */ |
56 | gpio_direction_output(gpio: reset_gpio, value: 0); |
57 | mdelay(2); |
58 | /* rising edge or drive high */ |
59 | gpio_set_value(gpio: reset_gpio, value: 1); |
60 | mdelay(2); |
61 | /* falling edge */ |
62 | gpio_set_value(gpio: reset_gpio, value: 0); |
63 | |
64 | /* give it some time */ |
65 | mdelay(10); |
66 | |
67 | WARN_ON(1); |
68 | /* fallback */ |
69 | do_hw_reset(); |
70 | } |
71 | |
72 | static void do_hw_reset(void) |
73 | { |
74 | /* Initialize the watchdog and let it fire */ |
75 | writel_relaxed(OWER_WME, OWER); |
76 | writel_relaxed(OSSR_M3, OSSR); |
77 | /* ... in 100 ms */ |
78 | writel_relaxed(readl_relaxed(OSCR) + 368640, OSMR3); |
79 | /* |
80 | * SDRAM hangs on watchdog reset on Marvell PXA270 (erratum 71) |
81 | * we put SDRAM into self-refresh to prevent that |
82 | */ |
83 | while (1) |
84 | writel_relaxed(MDREFR_SLFRSH, MDREFR); |
85 | } |
86 | |
87 | void pxa_restart(enum reboot_mode mode, const char *cmd) |
88 | { |
89 | local_irq_disable(); |
90 | local_fiq_disable(); |
91 | |
92 | clear_reset_status(RESET_STATUS_ALL); |
93 | |
94 | switch (mode) { |
95 | case REBOOT_SOFT: |
96 | /* Jump into ROM at address 0 */ |
97 | soft_restart(0); |
98 | break; |
99 | case REBOOT_GPIO: |
100 | do_gpio_reset(); |
101 | break; |
102 | case REBOOT_HARD: |
103 | default: |
104 | do_hw_reset(); |
105 | break; |
106 | } |
107 | } |
108 | |