1 /*
2 * Copyright (C) 2020 Marek Behun, CZ.NIC
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 * https://spdx.org/licenses
6 */
7
8 #include <stdbool.h>
9
10 #include <common/debug.h>
11 #include <drivers/arm/gic_common.h>
12 #include <drivers/arm/gicv3.h>
13 #include <drivers/delay_timer.h>
14 #include <lib/mmio.h>
15 #include <lib/utils_def.h>
16
17 #include <a3700_pm.h>
18 #include <platform_def.h>
19 #include <mvebu_def.h>
20
21 /* IO Decoder Error Interrupt Status Registers */
22 #define MVEBU_DEC_WIN_REGS_BASE(p) (MVEBU_REGS_BASE + 0xC000 + \
23 (p) * 0x100)
24 #define MVEBU_DEC_WIN_ERR_INT_STS_REG(p) (MVEBU_DEC_WIN_REGS_BASE(p) + \
25 0xF8)
26
27 /* Cortex-M3 Secure Processor Mailbox Registers */
28 #define MVEBU_RWTM_PARAM0_REG (MVEBU_RWTM_REG_BASE)
29 #define MVEBU_RWTM_CMD_REG (MVEBU_RWTM_REG_BASE + 0x40)
30 #define MVEBU_RWTM_HOST_INT_RESET_REG (MVEBU_RWTM_REG_BASE + 0xC8)
31 #define MVEBU_RWTM_HOST_INT_MASK_REG (MVEBU_RWTM_REG_BASE + 0xCC)
32 #define MVEBU_RWTM_HOST_INT_SP_COMPLETE BIT(0)
33
34 #define MVEBU_RWTM_REBOOT_CMD 0x0009
35 #define MVEBU_RWTM_REBOOT_MAGIC 0xDEADBEEF
36
a3700_gicd_read(uint32_t reg)37 static inline uint32_t a3700_gicd_read(uint32_t reg)
38 {
39 return mmio_read_32(PLAT_MARVELL_GICD_BASE + reg);
40 }
41
a3700_gicd_write(uint32_t reg,uint32_t value)42 static inline void a3700_gicd_write(uint32_t reg, uint32_t value)
43 {
44 mmio_write_32(PLAT_MARVELL_GICD_BASE + reg, value);
45 }
46
a3700_gicd_ctlr_clear_bits(uint32_t bits)47 static void a3700_gicd_ctlr_clear_bits(uint32_t bits)
48 {
49 uint32_t val;
50
51 val = a3700_gicd_read(GICD_CTLR);
52 if ((val & bits) != 0U) {
53 a3700_gicd_write(GICD_CTLR, val & ~bits);
54 mdelay(1);
55
56 if ((a3700_gicd_read(GICD_CTLR) & GICD_CTLR_RWP_BIT) != 0U) {
57 ERROR("could not clear bits 0x%x in GIC distributor control\n",
58 bits);
59 }
60 }
61 }
62
a3700_gic_dist_disable_irqs(void)63 static void a3700_gic_dist_disable_irqs(void)
64 {
65 int i;
66
67 for (i = 32; i < 224; i += 32) {
68 a3700_gicd_write(GICD_ICENABLER + (i >> 3), GENMASK_32(31, 0));
69 }
70 }
71
a3700_rdist_base(unsigned int proc)72 static inline uintptr_t a3700_rdist_base(unsigned int proc)
73 {
74 return PLAT_MARVELL_GICR_BASE + (proc << GICR_V3_PCPUBASE_SHIFT);
75 }
76
a3700_gicr_read(unsigned int proc,uint32_t reg)77 static inline uint32_t a3700_gicr_read(unsigned int proc, uint32_t reg)
78 {
79 return mmio_read_32(a3700_rdist_base(proc) + reg);
80 }
81
a3700_gicr_write(unsigned int proc,uint32_t reg,uint32_t value)82 static inline void a3700_gicr_write(unsigned int proc, uint32_t reg,
83 uint32_t value)
84 {
85 mmio_write_32(a3700_rdist_base(proc) + reg, value);
86 }
87
a3700_gic_redist_disable_irqs(unsigned int proc)88 static void a3700_gic_redist_disable_irqs(unsigned int proc)
89 {
90 a3700_gicr_write(proc, GICR_ICENABLER0, GENMASK_32(31, 0));
91 mdelay(1);
92
93 if ((a3700_gicr_read(proc, GICR_CTLR) & GICR_CTLR_RWP_BIT) != 0U) {
94 ERROR("could not disable core %u PPIs & SGIs\n", proc);
95 }
96 }
97
a3700_gic_redist_mark_asleep(unsigned int proc)98 static void a3700_gic_redist_mark_asleep(unsigned int proc)
99 {
100 a3700_gicr_write(proc, GICR_WAKER,
101 a3700_gicr_read(proc, GICR_WAKER) | WAKER_PS_BIT);
102 mdelay(1);
103
104 if ((a3700_gicr_read(proc, GICR_WAKER) & WAKER_CA_BIT) == 0U) {
105 ERROR("could not mark core %u redistributor asleep\n", proc);
106 }
107 }
108
a3700_io_addr_dec_ack_err_irq(void)109 static void a3700_io_addr_dec_ack_err_irq(void)
110 {
111 unsigned int periph;
112
113 for (periph = 0; periph < 16; ++periph) {
114 /* periph 6 does not exist */
115 if (periph == 6)
116 continue;
117
118 mmio_write_32(MVEBU_DEC_WIN_ERR_INT_STS_REG(periph),
119 GENMASK_32(1, 0));
120 }
121 }
122
a3700_gic_reset(void)123 static void a3700_gic_reset(void)
124 {
125 a3700_gic_redist_disable_irqs(0);
126 a3700_gic_redist_disable_irqs(1);
127
128 a3700_gic_redist_mark_asleep(0);
129 a3700_gic_redist_mark_asleep(1);
130
131 a3700_io_addr_dec_ack_err_irq();
132
133 a3700_pm_ack_irq();
134
135 a3700_gic_dist_disable_irqs();
136
137 a3700_gicd_ctlr_clear_bits(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1NS_BIT |
138 CTLR_ENABLE_G1S_BIT);
139
140 /* Clearing ARE_S and ARE_NS bits is undefined in the specification, but
141 * works if the previous operations are successful. We need to do it in
142 * order to put GIC into the same state it was in just after reset. If
143 * this is successful, the rWTM firmware in the secure coprocessor will
144 * reset all other peripherals one by one, load new firmware and boot
145 * it, all without triggering the true warm reset via the WARM_RESET
146 * register (which may hang the board).
147 */
148
149 a3700_gicd_ctlr_clear_bits(CTLR_ARE_S_BIT);
150 a3700_gicd_ctlr_clear_bits(CTLR_ARE_NS_BIT);
151 }
152
rwtm_completed(void)153 static inline bool rwtm_completed(void)
154 {
155 return (mmio_read_32(MVEBU_RWTM_HOST_INT_RESET_REG) &
156 MVEBU_RWTM_HOST_INT_SP_COMPLETE) != 0;
157 }
158
rwtm_wait(int ms)159 static bool rwtm_wait(int ms)
160 {
161 while (ms && !rwtm_completed()) {
162 mdelay(1);
163 --ms;
164 }
165
166 return rwtm_completed();
167 }
168
cm3_system_reset(void)169 void cm3_system_reset(void)
170 {
171 int tries = 5;
172
173 /* Put GIC into the same state it was just after reset. This is needed
174 * for the reset issue workaround to work.
175 */
176 a3700_gic_reset();
177
178 for (; tries > 0; --tries) {
179 mmio_clrbits_32(MVEBU_RWTM_HOST_INT_RESET_REG,
180 MVEBU_RWTM_HOST_INT_SP_COMPLETE);
181
182 mmio_write_32(MVEBU_RWTM_PARAM0_REG, MVEBU_RWTM_REBOOT_MAGIC);
183 mmio_write_32(MVEBU_RWTM_CMD_REG, MVEBU_RWTM_REBOOT_CMD);
184
185 if (rwtm_wait(10)) {
186 break;
187 }
188
189 mdelay(100);
190 }
191
192 /* If we reach here, the command is not implemented. */
193 WARN("System reset command not implemented in WTMI firmware!\n");
194 }
195