xref: /qemu/hw/misc/imx7_src.c (revision b49f4755)
1 /*
2  * IMX7 System Reset Controller
3  *
4  * Copyright (c) 2023 Jean-Christophe Dubois <jcd@tribudubois.net>
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7  * See the COPYING file in the top-level directory.
8  *
9  */
10 
11 #include "qemu/osdep.h"
12 #include "hw/misc/imx7_src.h"
13 #include "migration/vmstate.h"
14 #include "qemu/bitops.h"
15 #include "qemu/log.h"
16 #include "qemu/main-loop.h"
17 #include "qemu/module.h"
18 #include "target/arm/arm-powerctl.h"
19 #include "hw/core/cpu.h"
20 #include "hw/registerfields.h"
21 
22 #include "trace.h"
23 
24 static const char *imx7_src_reg_name(uint32_t reg)
25 {
26     static char unknown[20];
27 
28     switch (reg) {
29     case SRC_SCR:
30         return "SRC_SCR";
31     case SRC_A7RCR0:
32         return "SRC_A7RCR0";
33     case SRC_A7RCR1:
34         return "SRC_A7RCR1";
35     case SRC_M4RCR:
36         return "SRC_M4RCR";
37     case SRC_ERCR:
38         return "SRC_ERCR";
39     case SRC_HSICPHY_RCR:
40         return "SRC_HSICPHY_RCR";
41     case SRC_USBOPHY1_RCR:
42         return "SRC_USBOPHY1_RCR";
43     case SRC_USBOPHY2_RCR:
44         return "SRC_USBOPHY2_RCR";
45     case SRC_PCIEPHY_RCR:
46         return "SRC_PCIEPHY_RCR";
47     case SRC_SBMR1:
48         return "SRC_SBMR1";
49     case SRC_SRSR:
50         return "SRC_SRSR";
51     case SRC_SISR:
52         return "SRC_SISR";
53     case SRC_SIMR:
54         return "SRC_SIMR";
55     case SRC_SBMR2:
56         return "SRC_SBMR2";
57     case SRC_GPR1:
58         return "SRC_GPR1";
59     case SRC_GPR2:
60         return "SRC_GPR2";
61     case SRC_GPR3:
62         return "SRC_GPR3";
63     case SRC_GPR4:
64         return "SRC_GPR4";
65     case SRC_GPR5:
66         return "SRC_GPR5";
67     case SRC_GPR6:
68         return "SRC_GPR6";
69     case SRC_GPR7:
70         return "SRC_GPR7";
71     case SRC_GPR8:
72         return "SRC_GPR8";
73     case SRC_GPR9:
74         return "SRC_GPR9";
75     case SRC_GPR10:
76         return "SRC_GPR10";
77     default:
78         sprintf(unknown, "%u ?", reg);
79         return unknown;
80     }
81 }
82 
83 static const VMStateDescription vmstate_imx7_src = {
84     .name = TYPE_IMX7_SRC,
85     .version_id = 1,
86     .minimum_version_id = 1,
87     .fields = (VMStateField[]) {
88         VMSTATE_UINT32_ARRAY(regs, IMX7SRCState, SRC_MAX),
89         VMSTATE_END_OF_LIST()
90     },
91 };
92 
93 static void imx7_src_reset(DeviceState *dev)
94 {
95     IMX7SRCState *s = IMX7_SRC(dev);
96 
97     memset(s->regs, 0, sizeof(s->regs));
98 
99     /* Set reset values */
100     s->regs[SRC_SCR] = 0xA0;
101     s->regs[SRC_SRSR] = 0x1;
102     s->regs[SRC_SIMR] = 0x1F;
103 }
104 
105 static uint64_t imx7_src_read(void *opaque, hwaddr offset, unsigned size)
106 {
107     uint32_t value = 0;
108     IMX7SRCState *s = (IMX7SRCState *)opaque;
109     uint32_t index = offset >> 2;
110 
111     if (index < SRC_MAX) {
112         value = s->regs[index];
113     } else {
114         qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
115                       HWADDR_PRIx "\n", TYPE_IMX7_SRC, __func__, offset);
116     }
117 
118     trace_imx7_src_read(imx7_src_reg_name(index), value);
119 
120     return value;
121 }
122 
123 
124 /*
125  * The reset is asynchronous so we need to defer clearing the reset
126  * bit until the work is completed.
127  */
128 
129 struct SRCSCRResetInfo {
130     IMX7SRCState *s;
131     uint32_t reset_bit;
132 };
133 
134 static void imx7_clear_reset_bit(CPUState *cpu, run_on_cpu_data data)
135 {
136     struct SRCSCRResetInfo *ri = data.host_ptr;
137     IMX7SRCState *s = ri->s;
138 
139     assert(qemu_mutex_iothread_locked());
140 
141     s->regs[SRC_A7RCR0] = deposit32(s->regs[SRC_A7RCR0], ri->reset_bit, 1, 0);
142 
143     trace_imx7_src_write(imx7_src_reg_name(SRC_A7RCR0), s->regs[SRC_A7RCR0]);
144 
145     g_free(ri);
146 }
147 
148 static void imx7_defer_clear_reset_bit(uint32_t cpuid,
149                                        IMX7SRCState *s,
150                                        uint32_t reset_shift)
151 {
152     struct SRCSCRResetInfo *ri;
153     CPUState *cpu = arm_get_cpu_by_id(cpuid);
154 
155     if (!cpu) {
156         return;
157     }
158 
159     ri = g_new(struct SRCSCRResetInfo, 1);
160     ri->s = s;
161     ri->reset_bit = reset_shift;
162 
163     async_run_on_cpu(cpu, imx7_clear_reset_bit, RUN_ON_CPU_HOST_PTR(ri));
164 }
165 
166 
167 static void imx7_src_write(void *opaque, hwaddr offset, uint64_t value,
168                            unsigned size)
169 {
170     IMX7SRCState *s = (IMX7SRCState *)opaque;
171     uint32_t index = offset >> 2;
172     long unsigned int change_mask;
173     uint32_t current_value = value;
174 
175     if (index >= SRC_MAX) {
176         qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
177                       HWADDR_PRIx "\n", TYPE_IMX7_SRC, __func__, offset);
178         return;
179     }
180 
181     trace_imx7_src_write(imx7_src_reg_name(SRC_A7RCR0), s->regs[SRC_A7RCR0]);
182 
183     change_mask = s->regs[index] ^ (uint32_t)current_value;
184 
185     switch (index) {
186     case SRC_A7RCR0:
187         if (FIELD_EX32(change_mask, CORE0, RST)) {
188             arm_reset_cpu(0);
189             imx7_defer_clear_reset_bit(0, s, R_CORE0_RST_SHIFT);
190         }
191         if (FIELD_EX32(change_mask, CORE1, RST)) {
192             arm_reset_cpu(1);
193             imx7_defer_clear_reset_bit(1, s, R_CORE1_RST_SHIFT);
194         }
195         s->regs[index] = current_value;
196         break;
197     case SRC_A7RCR1:
198         /*
199          * On real hardware when the system reset controller starts a
200          * secondary CPU it runs through some boot ROM code which reads
201          * the SRC_GPRX registers controlling the start address and branches
202          * to it.
203          * Here we are taking a short cut and branching directly to the
204          * requested address (we don't want to run the boot ROM code inside
205          * QEMU)
206          */
207         if (FIELD_EX32(change_mask, CORE1, ENABLE)) {
208             if (FIELD_EX32(current_value, CORE1, ENABLE)) {
209                 /* CORE 1 is brought up */
210                 arm_set_cpu_on(1, s->regs[SRC_GPR3], s->regs[SRC_GPR4],
211                                3, false);
212             } else {
213                 /* CORE 1 is shut down */
214                 arm_set_cpu_off(1);
215             }
216             /* We clear the reset bits as the processor changed state */
217             imx7_defer_clear_reset_bit(1, s, R_CORE1_RST_SHIFT);
218             clear_bit(R_CORE1_RST_SHIFT, &change_mask);
219         }
220         s->regs[index] = current_value;
221         break;
222     default:
223         s->regs[index] = current_value;
224         break;
225     }
226 }
227 
228 static const struct MemoryRegionOps imx7_src_ops = {
229     .read = imx7_src_read,
230     .write = imx7_src_write,
231     .endianness = DEVICE_NATIVE_ENDIAN,
232     .valid = {
233         /*
234          * Our device would not work correctly if the guest was doing
235          * unaligned access. This might not be a limitation on the real
236          * device but in practice there is no reason for a guest to access
237          * this device unaligned.
238          */
239         .min_access_size = 4,
240         .max_access_size = 4,
241         .unaligned = false,
242     },
243 };
244 
245 static void imx7_src_realize(DeviceState *dev, Error **errp)
246 {
247     IMX7SRCState *s = IMX7_SRC(dev);
248 
249     memory_region_init_io(&s->iomem, OBJECT(dev), &imx7_src_ops, s,
250                           TYPE_IMX7_SRC, 0x1000);
251     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
252 }
253 
254 static void imx7_src_class_init(ObjectClass *klass, void *data)
255 {
256     DeviceClass *dc = DEVICE_CLASS(klass);
257 
258     dc->realize = imx7_src_realize;
259     dc->reset = imx7_src_reset;
260     dc->vmsd = &vmstate_imx7_src;
261     dc->desc = "i.MX6 System Reset Controller";
262 }
263 
264 static const TypeInfo imx7_src_info = {
265     .name          = TYPE_IMX7_SRC,
266     .parent        = TYPE_SYS_BUS_DEVICE,
267     .instance_size = sizeof(IMX7SRCState),
268     .class_init    = imx7_src_class_init,
269 };
270 
271 static void imx7_src_register_types(void)
272 {
273     type_register_static(&imx7_src_info);
274 }
275 
276 type_init(imx7_src_register_types)
277