xref: /qemu/hw/misc/aspeed_scu.c (revision b103cc6e74ac92f070a0e004bd84334e845c20b5)
1 /*
2  * ASPEED System Control Unit
3  *
4  * Andrew Jeffery <andrew@aj.id.au>
5  *
6  * Copyright 2016 IBM Corp.
7  *
8  * This code is licensed under the GPL version 2 or later.  See
9  * the COPYING file in the top-level directory.
10  */
11 
12 #include "qemu/osdep.h"
13 #include "hw/misc/aspeed_scu.h"
14 #include "hw/qdev-properties.h"
15 #include "migration/vmstate.h"
16 #include "qapi/error.h"
17 #include "qapi/visitor.h"
18 #include "qemu/bitops.h"
19 #include "qemu/log.h"
20 #include "qemu/guest-random.h"
21 #include "qemu/module.h"
22 #include "trace.h"
23 
24 #define TO_REG(offset) ((offset) >> 2)
25 
26 #define PROT_KEY             TO_REG(0x00)
27 #define SYS_RST_CTRL         TO_REG(0x04)
28 #define CLK_SEL              TO_REG(0x08)
29 #define CLK_STOP_CTRL        TO_REG(0x0C)
30 #define FREQ_CNTR_CTRL       TO_REG(0x10)
31 #define FREQ_CNTR_EVAL       TO_REG(0x14)
32 #define IRQ_CTRL             TO_REG(0x18)
33 #define D2PLL_PARAM          TO_REG(0x1C)
34 #define MPLL_PARAM           TO_REG(0x20)
35 #define HPLL_PARAM           TO_REG(0x24)
36 #define FREQ_CNTR_RANGE      TO_REG(0x28)
37 #define MISC_CTRL1           TO_REG(0x2C)
38 #define PCI_CTRL1            TO_REG(0x30)
39 #define PCI_CTRL2            TO_REG(0x34)
40 #define PCI_CTRL3            TO_REG(0x38)
41 #define SYS_RST_STATUS       TO_REG(0x3C)
42 #define SOC_SCRATCH1         TO_REG(0x40)
43 #define SOC_SCRATCH2         TO_REG(0x44)
44 #define MAC_CLK_DELAY        TO_REG(0x48)
45 #define MISC_CTRL2           TO_REG(0x4C)
46 #define VGA_SCRATCH1         TO_REG(0x50)
47 #define VGA_SCRATCH2         TO_REG(0x54)
48 #define VGA_SCRATCH3         TO_REG(0x58)
49 #define VGA_SCRATCH4         TO_REG(0x5C)
50 #define VGA_SCRATCH5         TO_REG(0x60)
51 #define VGA_SCRATCH6         TO_REG(0x64)
52 #define VGA_SCRATCH7         TO_REG(0x68)
53 #define VGA_SCRATCH8         TO_REG(0x6C)
54 #define HW_STRAP1            TO_REG(0x70)
55 #define RNG_CTRL             TO_REG(0x74)
56 #define RNG_DATA             TO_REG(0x78)
57 #define SILICON_REV          TO_REG(0x7C)
58 #define PINMUX_CTRL1         TO_REG(0x80)
59 #define PINMUX_CTRL2         TO_REG(0x84)
60 #define PINMUX_CTRL3         TO_REG(0x88)
61 #define PINMUX_CTRL4         TO_REG(0x8C)
62 #define PINMUX_CTRL5         TO_REG(0x90)
63 #define PINMUX_CTRL6         TO_REG(0x94)
64 #define WDT_RST_CTRL         TO_REG(0x9C)
65 #define PINMUX_CTRL7         TO_REG(0xA0)
66 #define PINMUX_CTRL8         TO_REG(0xA4)
67 #define PINMUX_CTRL9         TO_REG(0xA8)
68 #define WAKEUP_EN            TO_REG(0xC0)
69 #define WAKEUP_CTRL          TO_REG(0xC4)
70 #define HW_STRAP2            TO_REG(0xD0)
71 #define FREE_CNTR4           TO_REG(0xE0)
72 #define FREE_CNTR4_EXT       TO_REG(0xE4)
73 #define CPU2_CTRL            TO_REG(0x100)
74 #define CPU2_BASE_SEG1       TO_REG(0x104)
75 #define CPU2_BASE_SEG2       TO_REG(0x108)
76 #define CPU2_BASE_SEG3       TO_REG(0x10C)
77 #define CPU2_BASE_SEG4       TO_REG(0x110)
78 #define CPU2_BASE_SEG5       TO_REG(0x114)
79 #define CPU2_CACHE_CTRL      TO_REG(0x118)
80 #define CHIP_ID0             TO_REG(0x150)
81 #define CHIP_ID1             TO_REG(0x154)
82 #define UART_HPLL_CLK        TO_REG(0x160)
83 #define PCIE_CTRL            TO_REG(0x180)
84 #define BMC_MMIO_CTRL        TO_REG(0x184)
85 #define RELOC_DECODE_BASE1   TO_REG(0x188)
86 #define RELOC_DECODE_BASE2   TO_REG(0x18C)
87 #define MAILBOX_DECODE_BASE  TO_REG(0x190)
88 #define SRAM_DECODE_BASE1    TO_REG(0x194)
89 #define SRAM_DECODE_BASE2    TO_REG(0x198)
90 #define BMC_REV              TO_REG(0x19C)
91 #define BMC_DEV_ID           TO_REG(0x1A4)
92 
93 #define AST2600_PROT_KEY          TO_REG(0x00)
94 #define AST2600_SILICON_REV       TO_REG(0x04)
95 #define AST2600_SILICON_REV2      TO_REG(0x14)
96 #define AST2600_SYS_RST_CTRL      TO_REG(0x40)
97 #define AST2600_SYS_RST_CTRL_CLR  TO_REG(0x44)
98 #define AST2600_SYS_RST_CTRL2     TO_REG(0x50)
99 #define AST2600_SYS_RST_CTRL2_CLR TO_REG(0x54)
100 #define AST2600_CLK_STOP_CTRL     TO_REG(0x80)
101 #define AST2600_CLK_STOP_CTRL_CLR TO_REG(0x84)
102 #define AST2600_CLK_STOP_CTRL2     TO_REG(0x90)
103 #define AST2600_CLK_STOP_CTRL2_CLR TO_REG(0x94)
104 #define AST2600_DEBUG_CTRL        TO_REG(0xC8)
105 #define AST2600_DEBUG_CTRL2       TO_REG(0xD8)
106 #define AST2600_SDRAM_HANDSHAKE   TO_REG(0x100)
107 #define AST2600_HPLL_PARAM        TO_REG(0x200)
108 #define AST2600_HPLL_EXT          TO_REG(0x204)
109 #define AST2600_APLL_PARAM        TO_REG(0x210)
110 #define AST2600_APLL_EXT          TO_REG(0x214)
111 #define AST2600_MPLL_PARAM        TO_REG(0x220)
112 #define AST2600_MPLL_EXT          TO_REG(0x224)
113 #define AST2600_EPLL_PARAM        TO_REG(0x240)
114 #define AST2600_EPLL_EXT          TO_REG(0x244)
115 #define AST2600_DPLL_PARAM        TO_REG(0x260)
116 #define AST2600_DPLL_EXT          TO_REG(0x264)
117 #define AST2600_CLK_SEL           TO_REG(0x300)
118 #define AST2600_CLK_SEL2          TO_REG(0x304)
119 #define AST2600_CLK_SEL3          TO_REG(0x308)
120 #define AST2600_CLK_SEL4          TO_REG(0x310)
121 #define AST2600_CLK_SEL5          TO_REG(0x314)
122 #define AST2600_UARTCLK           TO_REG(0x338)
123 #define AST2600_HUARTCLK          TO_REG(0x33C)
124 #define AST2600_HW_STRAP1         TO_REG(0x500)
125 #define AST2600_HW_STRAP1_CLR     TO_REG(0x504)
126 #define AST2600_HW_STRAP1_PROT    TO_REG(0x508)
127 #define AST2600_HW_STRAP2         TO_REG(0x510)
128 #define AST2600_HW_STRAP2_CLR     TO_REG(0x514)
129 #define AST2600_HW_STRAP2_PROT    TO_REG(0x518)
130 #define AST2600_RNG_CTRL          TO_REG(0x524)
131 #define AST2600_RNG_DATA          TO_REG(0x540)
132 #define AST2600_CHIP_ID0          TO_REG(0x5B0)
133 #define AST2600_CHIP_ID1          TO_REG(0x5B4)
134 
135 #define AST2600_CLK TO_REG(0x40)
136 
137 #define AST2700_SILICON_REV       TO_REG(0x00)
138 #define AST2700_HW_STRAP1         TO_REG(0x10)
139 #define AST2700_HW_STRAP1_CLR     TO_REG(0x14)
140 #define AST2700_HW_STRAP1_LOCK    TO_REG(0x20)
141 #define AST2700_HW_STRAP1_SEC1    TO_REG(0x24)
142 #define AST2700_HW_STRAP1_SEC2    TO_REG(0x28)
143 #define AST2700_HW_STRAP1_SEC3    TO_REG(0x2C)
144 
145 #define AST2700_SCU_CLK_SEL_1       TO_REG(0x280)
146 #define AST2700_SCU_HPLL_PARAM      TO_REG(0x300)
147 #define AST2700_SCU_HPLL_EXT_PARAM  TO_REG(0x304)
148 #define AST2700_SCU_DPLL_PARAM      TO_REG(0x308)
149 #define AST2700_SCU_DPLL_EXT_PARAM  TO_REG(0x30c)
150 #define AST2700_SCU_MPLL_PARAM      TO_REG(0x310)
151 #define AST2700_SCU_MPLL_EXT_PARAM  TO_REG(0x314)
152 #define AST2700_SCU_D1CLK_PARAM     TO_REG(0x320)
153 #define AST2700_SCU_D2CLK_PARAM     TO_REG(0x330)
154 #define AST2700_SCU_CRT1CLK_PARAM   TO_REG(0x340)
155 #define AST2700_SCU_CRT2CLK_PARAM   TO_REG(0x350)
156 #define AST2700_SCU_MPHYCLK_PARAM   TO_REG(0x360)
157 #define AST2700_SCU_FREQ_CNTR       TO_REG(0x3b0)
158 #define AST2700_SCU_CPU_SCRATCH_0   TO_REG(0x780)
159 #define AST2700_SCU_CPU_SCRATCH_1   TO_REG(0x784)
160 #define AST2700_SCU_VGA_SCRATCH_0   TO_REG(0x900)
161 
162 #define AST2700_SCUIO_CLK_STOP_CTL_1    TO_REG(0x240)
163 #define AST2700_SCUIO_CLK_STOP_CLR_1    TO_REG(0x244)
164 #define AST2700_SCUIO_CLK_STOP_CTL_2    TO_REG(0x260)
165 #define AST2700_SCUIO_CLK_STOP_CLR_2    TO_REG(0x264)
166 #define AST2700_SCUIO_CLK_SEL_1         TO_REG(0x280)
167 #define AST2700_SCUIO_CLK_SEL_2         TO_REG(0x284)
168 #define AST2700_SCUIO_HPLL_PARAM        TO_REG(0x300)
169 #define AST2700_SCUIO_HPLL_EXT_PARAM    TO_REG(0x304)
170 #define AST2700_SCUIO_APLL_PARAM        TO_REG(0x310)
171 #define AST2700_SCUIO_APLL_EXT_PARAM    TO_REG(0x314)
172 #define AST2700_SCUIO_DPLL_PARAM        TO_REG(0x320)
173 #define AST2700_SCUIO_DPLL_EXT_PARAM    TO_REG(0x324)
174 #define AST2700_SCUIO_DPLL_PARAM_READ   TO_REG(0x328)
175 #define AST2700_SCUIO_DPLL_EXT_PARAM_READ TO_REG(0x32c)
176 #define AST2700_SCUIO_UARTCLK_GEN       TO_REG(0x330)
177 #define AST2700_SCUIO_HUARTCLK_GEN      TO_REG(0x334)
178 #define AST2700_SCUIO_CLK_DUTY_MEAS_RST TO_REG(0x388)
179 
180 #define SCU_IO_REGION_SIZE 0x1000
181 
182 static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = {
183      [SYS_RST_CTRL]    = 0xFFCFFEDCU,
184      [CLK_SEL]         = 0xF3F40000U,
185      [CLK_STOP_CTRL]   = 0x19FC3E8BU,
186      [D2PLL_PARAM]     = 0x00026108U,
187      [MPLL_PARAM]      = 0x00030291U,
188      [HPLL_PARAM]      = 0x00000291U,
189      [MISC_CTRL1]      = 0x00000010U,
190      [PCI_CTRL1]       = 0x20001A03U,
191      [PCI_CTRL2]       = 0x20001A03U,
192      [PCI_CTRL3]       = 0x04000030U,
193      [SYS_RST_STATUS]  = 0x00000001U,
194      [SOC_SCRATCH1]    = 0x000000C0U, /* SoC completed DRAM init */
195      [MISC_CTRL2]      = 0x00000023U,
196      [RNG_CTRL]        = 0x0000000EU,
197      [PINMUX_CTRL2]    = 0x0000F000U,
198      [PINMUX_CTRL3]    = 0x01000000U,
199      [PINMUX_CTRL4]    = 0x000000FFU,
200      [PINMUX_CTRL5]    = 0x0000A000U,
201      [WDT_RST_CTRL]    = 0x003FFFF3U,
202      [PINMUX_CTRL8]    = 0xFFFF0000U,
203      [PINMUX_CTRL9]    = 0x000FFFFFU,
204      [FREE_CNTR4]      = 0x000000FFU,
205      [FREE_CNTR4_EXT]  = 0x000000FFU,
206      [CPU2_BASE_SEG1]  = 0x80000000U,
207      [CPU2_BASE_SEG4]  = 0x1E600000U,
208      [CPU2_BASE_SEG5]  = 0xC0000000U,
209      [UART_HPLL_CLK]   = 0x00001903U,
210      [PCIE_CTRL]       = 0x0000007BU,
211      [BMC_DEV_ID]      = 0x00002402U
212 };
213 
214 /* SCU70 bit 23: 0 24Mhz. bit 11:9: 0b001 AXI:ABH ratio 2:1 */
215 /* AST2500 revision A1 */
216 
217 static const uint32_t ast2500_a1_resets[ASPEED_SCU_NR_REGS] = {
218      [SYS_RST_CTRL]    = 0xFFCFFEDCU,
219      [CLK_SEL]         = 0xF3F40000U,
220      [CLK_STOP_CTRL]   = 0x19FC3E8BU,
221      [D2PLL_PARAM]     = 0x00026108U,
222      [MPLL_PARAM]      = 0x00030291U,
223      [HPLL_PARAM]      = 0x93000400U,
224      [MISC_CTRL1]      = 0x00000010U,
225      [PCI_CTRL1]       = 0x20001A03U,
226      [PCI_CTRL2]       = 0x20001A03U,
227      [PCI_CTRL3]       = 0x04000030U,
228      [SYS_RST_STATUS]  = 0x00000001U,
229      [SOC_SCRATCH1]    = 0x000000C0U, /* SoC completed DRAM init */
230      [MISC_CTRL2]      = 0x00000023U,
231      [RNG_CTRL]        = 0x0000000EU,
232      [PINMUX_CTRL2]    = 0x0000F000U,
233      [PINMUX_CTRL3]    = 0x03000000U,
234      [PINMUX_CTRL4]    = 0x00000000U,
235      [PINMUX_CTRL5]    = 0x0000A000U,
236      [WDT_RST_CTRL]    = 0x023FFFF3U,
237      [PINMUX_CTRL8]    = 0xFFFF0000U,
238      [PINMUX_CTRL9]    = 0x000FFFFFU,
239      [FREE_CNTR4]      = 0x000000FFU,
240      [FREE_CNTR4_EXT]  = 0x000000FFU,
241      [CPU2_BASE_SEG1]  = 0x80000000U,
242      [CPU2_BASE_SEG4]  = 0x1E600000U,
243      [CPU2_BASE_SEG5]  = 0xC0000000U,
244      [CHIP_ID0]        = 0x1234ABCDU,
245      [CHIP_ID1]        = 0x88884444U,
246      [UART_HPLL_CLK]   = 0x00001903U,
247      [PCIE_CTRL]       = 0x0000007BU,
248      [BMC_DEV_ID]      = 0x00002402U
249 };
250 
251 static uint32_t aspeed_scu_get_random(void)
252 {
253     uint32_t num;
254     qemu_guest_getrandom_nofail(&num, sizeof(num));
255     return num;
256 }
257 
258 uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s)
259 {
260     return ASPEED_SCU_GET_CLASS(s)->get_apb(s);
261 }
262 
263 static uint32_t aspeed_2400_scu_get_apb_freq(AspeedSCUState *s)
264 {
265     AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s);
266     uint32_t hpll = asc->calc_hpll(s, s->regs[HPLL_PARAM]);
267 
268     return hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[CLK_SEL]) + 1)
269         / asc->apb_divider;
270 }
271 
272 static uint32_t aspeed_2600_scu_get_apb_freq(AspeedSCUState *s)
273 {
274     AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s);
275     uint32_t hpll = asc->calc_hpll(s, s->regs[AST2600_HPLL_PARAM]);
276 
277     return hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[AST2600_CLK_SEL]) + 1)
278         / asc->apb_divider;
279 }
280 
281 static uint32_t aspeed_1030_scu_get_apb_freq(AspeedSCUState *s)
282 {
283     AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s);
284     uint32_t hpll = asc->calc_hpll(s, s->regs[AST2600_HPLL_PARAM]);
285 
286     return hpll / (SCU_AST1030_CLK_GET_PCLK_DIV(s->regs[AST2600_CLK_SEL4]) + 1)
287         / asc->apb_divider;
288 }
289 
290 static uint32_t aspeed_2700_scu_get_apb_freq(AspeedSCUState *s)
291 {
292     AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s);
293     uint32_t hpll = asc->calc_hpll(s, s->regs[AST2700_SCU_HPLL_PARAM]);
294 
295     return hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[AST2700_SCU_CLK_SEL_1]) + 1)
296            / asc->apb_divider;
297 }
298 
299 static uint32_t aspeed_2700_scuio_get_apb_freq(AspeedSCUState *s)
300 {
301     AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s);
302     uint32_t hpll = asc->calc_hpll(s, s->regs[AST2700_SCUIO_HPLL_PARAM]);
303 
304     return hpll /
305         (SCUIO_AST2700_CLK_GET_PCLK_DIV(s->regs[AST2700_SCUIO_CLK_SEL_1]) + 1)
306         / asc->apb_divider;
307 }
308 
309 static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size)
310 {
311     AspeedSCUState *s = ASPEED_SCU(opaque);
312     int reg = TO_REG(offset);
313 
314     if (reg >= ASPEED_SCU_NR_REGS) {
315         qemu_log_mask(LOG_GUEST_ERROR,
316                       "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
317                       __func__, offset);
318         return 0;
319     }
320 
321     switch (reg) {
322     case RNG_DATA:
323         /*
324          * On hardware, RNG_DATA works regardless of
325          * the state of the enable bit in RNG_CTRL
326          */
327         s->regs[RNG_DATA] = aspeed_scu_get_random();
328         break;
329     case WAKEUP_EN:
330         qemu_log_mask(LOG_GUEST_ERROR,
331                       "%s: Read of write-only offset 0x%" HWADDR_PRIx "\n",
332                       __func__, offset);
333         break;
334     }
335 
336     trace_aspeed_scu_read(offset, size, s->regs[reg]);
337     return s->regs[reg];
338 }
339 
340 static void aspeed_ast2400_scu_write(void *opaque, hwaddr offset,
341                                      uint64_t data, unsigned size)
342 {
343     AspeedSCUState *s = ASPEED_SCU(opaque);
344     int reg = TO_REG(offset);
345 
346     if (reg >= ASPEED_SCU_NR_REGS) {
347         qemu_log_mask(LOG_GUEST_ERROR,
348                       "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
349                       __func__, offset);
350         return;
351     }
352 
353     if (reg > PROT_KEY && reg < CPU2_BASE_SEG1 &&
354             !s->regs[PROT_KEY]) {
355         qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__);
356     }
357 
358     trace_aspeed_scu_write(offset, size, data);
359 
360     switch (reg) {
361     case PROT_KEY:
362         s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0;
363         return;
364     case SILICON_REV:
365     case FREQ_CNTR_EVAL:
366     case VGA_SCRATCH1 ... VGA_SCRATCH8:
367     case RNG_DATA:
368     case FREE_CNTR4:
369     case FREE_CNTR4_EXT:
370         qemu_log_mask(LOG_GUEST_ERROR,
371                       "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n",
372                       __func__, offset);
373         return;
374     }
375 
376     s->regs[reg] = data;
377 }
378 
379 static void aspeed_ast2500_scu_write(void *opaque, hwaddr offset,
380                                      uint64_t data, unsigned size)
381 {
382     AspeedSCUState *s = ASPEED_SCU(opaque);
383     int reg = TO_REG(offset);
384 
385     if (reg >= ASPEED_SCU_NR_REGS) {
386         qemu_log_mask(LOG_GUEST_ERROR,
387                       "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
388                       __func__, offset);
389         return;
390     }
391 
392     if (reg > PROT_KEY && reg < CPU2_BASE_SEG1 &&
393             !s->regs[PROT_KEY]) {
394         qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__);
395         return;
396     }
397 
398     trace_aspeed_scu_write(offset, size, data);
399 
400     switch (reg) {
401     case PROT_KEY:
402         s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0;
403         return;
404     case HW_STRAP1:
405         s->regs[HW_STRAP1] |= data;
406         return;
407     case SILICON_REV:
408         s->regs[HW_STRAP1] &= ~data;
409         return;
410     case FREQ_CNTR_EVAL:
411     case VGA_SCRATCH1 ... VGA_SCRATCH8:
412     case RNG_DATA:
413     case FREE_CNTR4:
414     case FREE_CNTR4_EXT:
415     case CHIP_ID0:
416     case CHIP_ID1:
417         qemu_log_mask(LOG_GUEST_ERROR,
418                       "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n",
419                       __func__, offset);
420         return;
421     }
422 
423     s->regs[reg] = data;
424 }
425 
426 static const MemoryRegionOps aspeed_ast2400_scu_ops = {
427     .read = aspeed_scu_read,
428     .write = aspeed_ast2400_scu_write,
429     .endianness = DEVICE_LITTLE_ENDIAN,
430     .impl = {
431         .min_access_size = 4,
432         .max_access_size = 4,
433     },
434     .valid = {
435         .min_access_size = 1,
436         .max_access_size = 4,
437     },
438 };
439 
440 static const MemoryRegionOps aspeed_ast2500_scu_ops = {
441     .read = aspeed_scu_read,
442     .write = aspeed_ast2500_scu_write,
443     .endianness = DEVICE_LITTLE_ENDIAN,
444     .impl.min_access_size = 4,
445     .impl.max_access_size = 4,
446     .valid.min_access_size = 1,
447     .valid.max_access_size = 4,
448     .valid.unaligned = false,
449 };
450 
451 static uint32_t aspeed_scu_get_clkin(AspeedSCUState *s)
452 {
453     if (s->hw_strap1 & SCU_HW_STRAP_CLK_25M_IN ||
454         ASPEED_SCU_GET_CLASS(s)->clkin_25Mhz) {
455         return 25000000;
456     } else if (s->hw_strap1 & SCU_HW_STRAP_CLK_48M_IN) {
457         return 48000000;
458     } else {
459         return 24000000;
460     }
461 }
462 
463 /*
464  * Strapped frequencies for the AST2400 in MHz. They depend on the
465  * clkin frequency.
466  */
467 static const uint32_t hpll_ast2400_freqs[][4] = {
468     { 384, 360, 336, 408 }, /* 24MHz or 48MHz */
469     { 400, 375, 350, 425 }, /* 25MHz */
470 };
471 
472 static uint32_t aspeed_2400_scu_calc_hpll(AspeedSCUState *s, uint32_t hpll_reg)
473 {
474     uint8_t freq_select;
475     bool clk_25m_in;
476     uint32_t clkin = aspeed_scu_get_clkin(s);
477 
478     if (hpll_reg & SCU_AST2400_H_PLL_OFF) {
479         return 0;
480     }
481 
482     if (hpll_reg & SCU_AST2400_H_PLL_PROGRAMMED) {
483         uint32_t multiplier = 1;
484 
485         if (!(hpll_reg & SCU_AST2400_H_PLL_BYPASS_EN)) {
486             uint32_t n  = (hpll_reg >> 5) & 0x3f;
487             uint32_t od = (hpll_reg >> 4) & 0x1;
488             uint32_t d  = hpll_reg & 0xf;
489 
490             multiplier = (2 - od) * ((n + 2) / (d + 1));
491         }
492 
493         return clkin * multiplier;
494     }
495 
496     /* HW strapping */
497     clk_25m_in = !!(s->hw_strap1 & SCU_HW_STRAP_CLK_25M_IN);
498     freq_select = SCU_AST2400_HW_STRAP_GET_H_PLL_CLK(s->hw_strap1);
499 
500     return hpll_ast2400_freqs[clk_25m_in][freq_select] * 1000000;
501 }
502 
503 static uint32_t aspeed_2500_scu_calc_hpll(AspeedSCUState *s, uint32_t hpll_reg)
504 {
505     uint32_t multiplier = 1;
506     uint32_t clkin = aspeed_scu_get_clkin(s);
507 
508     if (hpll_reg & SCU_H_PLL_OFF) {
509         return 0;
510     }
511 
512     if (!(hpll_reg & SCU_H_PLL_BYPASS_EN)) {
513         uint32_t p = (hpll_reg >> 13) & 0x3f;
514         uint32_t m = (hpll_reg >> 5) & 0xff;
515         uint32_t n = hpll_reg & 0x1f;
516 
517         multiplier = ((m + 1) / (n + 1)) / (p + 1);
518     }
519 
520     return clkin * multiplier;
521 }
522 
523 static uint32_t aspeed_2600_scu_calc_hpll(AspeedSCUState *s, uint32_t hpll_reg)
524 {
525     uint32_t multiplier = 1;
526     uint32_t clkin = aspeed_scu_get_clkin(s);
527 
528     if (hpll_reg & SCU_AST2600_H_PLL_OFF) {
529         return 0;
530     }
531 
532     if (!(hpll_reg & SCU_AST2600_H_PLL_BYPASS_EN)) {
533         uint32_t p = (hpll_reg >> 19) & 0xf;
534         uint32_t n = (hpll_reg >> 13) & 0x3f;
535         uint32_t m = hpll_reg & 0x1fff;
536 
537         multiplier = ((m + 1) / (n + 1)) / (p + 1);
538     }
539 
540     return clkin * multiplier;
541 }
542 
543 static void aspeed_scu_reset(DeviceState *dev)
544 {
545     AspeedSCUState *s = ASPEED_SCU(dev);
546     AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
547 
548     memcpy(s->regs, asc->resets, asc->nr_regs * 4);
549     s->regs[SILICON_REV] = s->silicon_rev;
550     s->regs[HW_STRAP1] = s->hw_strap1;
551     s->regs[HW_STRAP2] = s->hw_strap2;
552     s->regs[PROT_KEY] = s->hw_prot_key;
553 }
554 
555 static uint32_t aspeed_silicon_revs[] = {
556     AST2400_A0_SILICON_REV,
557     AST2400_A1_SILICON_REV,
558     AST2500_A0_SILICON_REV,
559     AST2500_A1_SILICON_REV,
560     AST2600_A0_SILICON_REV,
561     AST2600_A1_SILICON_REV,
562     AST2600_A2_SILICON_REV,
563     AST2600_A3_SILICON_REV,
564     AST1030_A0_SILICON_REV,
565     AST1030_A1_SILICON_REV,
566     AST2700_A0_SILICON_REV,
567     AST2720_A0_SILICON_REV,
568     AST2750_A0_SILICON_REV,
569     AST2700_A1_SILICON_REV,
570     AST2750_A1_SILICON_REV,
571 };
572 
573 bool is_supported_silicon_rev(uint32_t silicon_rev)
574 {
575     int i;
576 
577     for (i = 0; i < ARRAY_SIZE(aspeed_silicon_revs); i++) {
578         if (silicon_rev == aspeed_silicon_revs[i]) {
579             return true;
580         }
581     }
582 
583     return false;
584 }
585 
586 static void aspeed_scu_realize(DeviceState *dev, Error **errp)
587 {
588     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
589     AspeedSCUState *s = ASPEED_SCU(dev);
590     AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
591 
592     if (!is_supported_silicon_rev(s->silicon_rev)) {
593         error_setg(errp, "Unknown silicon revision: 0x%" PRIx32,
594                 s->silicon_rev);
595         return;
596     }
597 
598     memory_region_init_io(&s->iomem, OBJECT(s), asc->ops, s,
599                           TYPE_ASPEED_SCU, SCU_IO_REGION_SIZE);
600 
601     sysbus_init_mmio(sbd, &s->iomem);
602 }
603 
604 static const VMStateDescription vmstate_aspeed_scu = {
605     .name = "aspeed.scu",
606     .version_id = 2,
607     .minimum_version_id = 2,
608     .fields = (const VMStateField[]) {
609         VMSTATE_UINT32_ARRAY(regs, AspeedSCUState, ASPEED_AST2600_SCU_NR_REGS),
610         VMSTATE_END_OF_LIST()
611     }
612 };
613 
614 static const Property aspeed_scu_properties[] = {
615     DEFINE_PROP_UINT32("silicon-rev", AspeedSCUState, silicon_rev, 0),
616     DEFINE_PROP_UINT32("hw-strap1", AspeedSCUState, hw_strap1, 0),
617     DEFINE_PROP_UINT32("hw-strap2", AspeedSCUState, hw_strap2, 0),
618     DEFINE_PROP_UINT32("hw-prot-key", AspeedSCUState, hw_prot_key, 0),
619 };
620 
621 static void aspeed_scu_class_init(ObjectClass *klass, void *data)
622 {
623     DeviceClass *dc = DEVICE_CLASS(klass);
624     dc->realize = aspeed_scu_realize;
625     device_class_set_legacy_reset(dc, aspeed_scu_reset);
626     dc->desc = "ASPEED System Control Unit";
627     dc->vmsd = &vmstate_aspeed_scu;
628     device_class_set_props(dc, aspeed_scu_properties);
629 }
630 
631 static const TypeInfo aspeed_scu_info = {
632     .name = TYPE_ASPEED_SCU,
633     .parent = TYPE_SYS_BUS_DEVICE,
634     .instance_size = sizeof(AspeedSCUState),
635     .class_init = aspeed_scu_class_init,
636     .class_size    = sizeof(AspeedSCUClass),
637     .abstract      = true,
638 };
639 
640 static void aspeed_2400_scu_class_init(ObjectClass *klass, void *data)
641 {
642     DeviceClass *dc = DEVICE_CLASS(klass);
643     AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
644 
645     dc->desc = "ASPEED 2400 System Control Unit";
646     asc->resets = ast2400_a0_resets;
647     asc->calc_hpll = aspeed_2400_scu_calc_hpll;
648     asc->get_apb = aspeed_2400_scu_get_apb_freq;
649     asc->apb_divider = 2;
650     asc->nr_regs = ASPEED_SCU_NR_REGS;
651     asc->clkin_25Mhz = false;
652     asc->ops = &aspeed_ast2400_scu_ops;
653 }
654 
655 static const TypeInfo aspeed_2400_scu_info = {
656     .name = TYPE_ASPEED_2400_SCU,
657     .parent = TYPE_ASPEED_SCU,
658     .instance_size = sizeof(AspeedSCUState),
659     .class_init = aspeed_2400_scu_class_init,
660 };
661 
662 static void aspeed_2500_scu_class_init(ObjectClass *klass, void *data)
663 {
664     DeviceClass *dc = DEVICE_CLASS(klass);
665     AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
666 
667     dc->desc = "ASPEED 2500 System Control Unit";
668     asc->resets = ast2500_a1_resets;
669     asc->calc_hpll = aspeed_2500_scu_calc_hpll;
670     asc->get_apb = aspeed_2400_scu_get_apb_freq;
671     asc->apb_divider = 4;
672     asc->nr_regs = ASPEED_SCU_NR_REGS;
673     asc->clkin_25Mhz = false;
674     asc->ops = &aspeed_ast2500_scu_ops;
675 }
676 
677 static const TypeInfo aspeed_2500_scu_info = {
678     .name = TYPE_ASPEED_2500_SCU,
679     .parent = TYPE_ASPEED_SCU,
680     .instance_size = sizeof(AspeedSCUState),
681     .class_init = aspeed_2500_scu_class_init,
682 };
683 
684 static uint64_t aspeed_ast2600_scu_read(void *opaque, hwaddr offset,
685                                         unsigned size)
686 {
687     AspeedSCUState *s = ASPEED_SCU(opaque);
688     int reg = TO_REG(offset);
689 
690     if (reg >= ASPEED_AST2600_SCU_NR_REGS) {
691         qemu_log_mask(LOG_GUEST_ERROR,
692                       "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
693                       __func__, offset);
694         return 0;
695     }
696 
697     switch (reg) {
698     case AST2600_HPLL_EXT:
699     case AST2600_EPLL_EXT:
700     case AST2600_MPLL_EXT:
701         /* PLLs are always "locked" */
702         return s->regs[reg] | BIT(31);
703     case AST2600_RNG_DATA:
704         /*
705          * On hardware, RNG_DATA works regardless of the state of the
706          * enable bit in RNG_CTRL
707          *
708          * TODO: Check this is true for ast2600
709          */
710         s->regs[AST2600_RNG_DATA] = aspeed_scu_get_random();
711         break;
712     }
713 
714     trace_aspeed_scu_read(offset, size, s->regs[reg]);
715     return s->regs[reg];
716 }
717 
718 static void aspeed_ast2600_scu_write(void *opaque, hwaddr offset,
719                                      uint64_t data64, unsigned size)
720 {
721     AspeedSCUState *s = ASPEED_SCU(opaque);
722     int reg = TO_REG(offset);
723     /* Truncate here so bitwise operations below behave as expected */
724     uint32_t data = data64;
725 
726     if (reg >= ASPEED_AST2600_SCU_NR_REGS) {
727         qemu_log_mask(LOG_GUEST_ERROR,
728                       "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
729                       __func__, offset);
730         return;
731     }
732 
733     if (reg > PROT_KEY && !s->regs[PROT_KEY]) {
734         qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__);
735     }
736 
737     trace_aspeed_scu_write(offset, size, data);
738 
739     switch (reg) {
740     case AST2600_PROT_KEY:
741         s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0;
742         return;
743     case AST2600_HW_STRAP1:
744     case AST2600_HW_STRAP2:
745         if (s->regs[reg + 2]) {
746             return;
747         }
748         /* fall through */
749     case AST2600_SYS_RST_CTRL:
750     case AST2600_SYS_RST_CTRL2:
751     case AST2600_CLK_STOP_CTRL:
752     case AST2600_CLK_STOP_CTRL2:
753         /* W1S (Write 1 to set) registers */
754         s->regs[reg] |= data;
755         return;
756     case AST2600_SYS_RST_CTRL_CLR:
757     case AST2600_SYS_RST_CTRL2_CLR:
758     case AST2600_CLK_STOP_CTRL_CLR:
759     case AST2600_CLK_STOP_CTRL2_CLR:
760     case AST2600_HW_STRAP1_CLR:
761     case AST2600_HW_STRAP2_CLR:
762         /*
763          * W1C (Write 1 to clear) registers are offset by one address from
764          * the data register
765          */
766         s->regs[reg - 1] &= ~data;
767         return;
768 
769     case AST2600_RNG_DATA:
770     case AST2600_SILICON_REV:
771     case AST2600_SILICON_REV2:
772     case AST2600_CHIP_ID0:
773     case AST2600_CHIP_ID1:
774         /* Add read only registers here */
775         qemu_log_mask(LOG_GUEST_ERROR,
776                       "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n",
777                       __func__, offset);
778         return;
779     }
780 
781     s->regs[reg] = data;
782 }
783 
784 static const MemoryRegionOps aspeed_ast2600_scu_ops = {
785     .read = aspeed_ast2600_scu_read,
786     .write = aspeed_ast2600_scu_write,
787     .endianness = DEVICE_LITTLE_ENDIAN,
788     .impl.min_access_size = 4,
789     .impl.max_access_size = 4,
790     .valid.min_access_size = 1,
791     .valid.max_access_size = 4,
792     .valid.unaligned = false,
793 };
794 
795 static const uint32_t ast2600_a3_resets[ASPEED_AST2600_SCU_NR_REGS] = {
796     [AST2600_SYS_RST_CTRL]      = 0xF7C3FED8,
797     [AST2600_SYS_RST_CTRL2]     = 0x0DFFFFFC,
798     [AST2600_CLK_STOP_CTRL]     = 0xFFFF7F8A,
799     [AST2600_CLK_STOP_CTRL2]    = 0xFFF0FFF0,
800     [AST2600_DEBUG_CTRL]        = 0x00000FFF,
801     [AST2600_DEBUG_CTRL2]       = 0x000000FF,
802     [AST2600_SDRAM_HANDSHAKE]   = 0x00000000,
803     [AST2600_HPLL_PARAM]        = 0x1000408F,
804     [AST2600_APLL_PARAM]        = 0x1000405F,
805     [AST2600_MPLL_PARAM]        = 0x1008405F,
806     [AST2600_EPLL_PARAM]        = 0x1004077F,
807     [AST2600_DPLL_PARAM]        = 0x1078405F,
808     [AST2600_CLK_SEL]           = 0xF3940000,
809     [AST2600_CLK_SEL2]          = 0x00700000,
810     [AST2600_CLK_SEL3]          = 0x00000000,
811     [AST2600_CLK_SEL4]          = 0xF3F40000,
812     [AST2600_CLK_SEL5]          = 0x30000000,
813     [AST2600_UARTCLK]           = 0x00014506,
814     [AST2600_HUARTCLK]          = 0x000145C0,
815     [AST2600_CHIP_ID0]          = 0x1234ABCD,
816     [AST2600_CHIP_ID1]          = 0x88884444,
817 };
818 
819 static void aspeed_ast2600_scu_reset(DeviceState *dev)
820 {
821     AspeedSCUState *s = ASPEED_SCU(dev);
822     AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
823 
824     memcpy(s->regs, asc->resets, asc->nr_regs * 4);
825 
826     /*
827      * A0 reports A0 in _REV, but subsequent revisions report A1 regardless
828      * of actual revision. QEMU and Linux only support A1 onwards so this is
829      * sufficient.
830      */
831     s->regs[AST2600_SILICON_REV] = AST2600_A3_SILICON_REV;
832     s->regs[AST2600_SILICON_REV2] = s->silicon_rev;
833     s->regs[AST2600_HW_STRAP1] = s->hw_strap1;
834     s->regs[AST2600_HW_STRAP2] = s->hw_strap2;
835     s->regs[PROT_KEY] = s->hw_prot_key;
836 }
837 
838 static void aspeed_2600_scu_class_init(ObjectClass *klass, void *data)
839 {
840     DeviceClass *dc = DEVICE_CLASS(klass);
841     AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
842 
843     dc->desc = "ASPEED 2600 System Control Unit";
844     device_class_set_legacy_reset(dc, aspeed_ast2600_scu_reset);
845     asc->resets = ast2600_a3_resets;
846     asc->calc_hpll = aspeed_2600_scu_calc_hpll;
847     asc->get_apb = aspeed_2600_scu_get_apb_freq;
848     asc->apb_divider = 4;
849     asc->nr_regs = ASPEED_AST2600_SCU_NR_REGS;
850     asc->clkin_25Mhz = true;
851     asc->ops = &aspeed_ast2600_scu_ops;
852 }
853 
854 static const TypeInfo aspeed_2600_scu_info = {
855     .name = TYPE_ASPEED_2600_SCU,
856     .parent = TYPE_ASPEED_SCU,
857     .instance_size = sizeof(AspeedSCUState),
858     .class_init = aspeed_2600_scu_class_init,
859 };
860 
861 static uint64_t aspeed_ast2700_scu_read(void *opaque, hwaddr offset,
862                                         unsigned size)
863 {
864     AspeedSCUState *s = ASPEED_SCU(opaque);
865     int reg = TO_REG(offset);
866 
867     if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
868         qemu_log_mask(LOG_GUEST_ERROR,
869                       "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
870                 __func__, offset);
871         return 0;
872     }
873 
874     switch (reg) {
875     default:
876         qemu_log_mask(LOG_GUEST_ERROR,
877                       "%s: Unhandled read at offset 0x%" HWADDR_PRIx "\n",
878                       __func__, offset);
879     }
880 
881     trace_aspeed_ast2700_scu_read(offset, size, s->regs[reg]);
882     return s->regs[reg];
883 }
884 
885 static void aspeed_ast2700_scu_write(void *opaque, hwaddr offset,
886                                      uint64_t data64, unsigned size)
887 {
888     AspeedSCUState *s = ASPEED_SCU(opaque);
889     int reg = TO_REG(offset);
890     /* Truncate here so bitwise operations below behave as expected */
891     uint32_t data = data64;
892 
893     if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
894         qemu_log_mask(LOG_GUEST_ERROR,
895                       "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
896                 __func__, offset);
897         return;
898     }
899 
900     trace_aspeed_ast2700_scu_write(offset, size, data);
901 
902     switch (reg) {
903     default:
904         qemu_log_mask(LOG_GUEST_ERROR,
905                       "%s: Unhandled write at offset 0x%" HWADDR_PRIx "\n",
906                       __func__, offset);
907         break;
908     }
909 
910     s->regs[reg] = data;
911 }
912 
913 static const MemoryRegionOps aspeed_ast2700_scu_ops = {
914     .read = aspeed_ast2700_scu_read,
915     .write = aspeed_ast2700_scu_write,
916     .endianness = DEVICE_LITTLE_ENDIAN,
917     .impl.min_access_size = 4,
918     .impl.max_access_size = 4,
919     .valid.min_access_size = 1,
920     .valid.max_access_size = 8,
921     .valid.unaligned = false,
922 };
923 
924 static const uint32_t ast2700_a0_resets[ASPEED_AST2700_SCU_NR_REGS] = {
925     [AST2700_HW_STRAP1_CLR]         = 0xFFF0FFF0,
926     [AST2700_HW_STRAP1_LOCK]        = 0x00000FFF,
927     [AST2700_HW_STRAP1_SEC1]        = 0x000000FF,
928     [AST2700_HW_STRAP1_SEC2]        = 0x00000000,
929     [AST2700_HW_STRAP1_SEC3]        = 0x1000408F,
930     [AST2700_SCU_HPLL_PARAM]        = 0x0000009f,
931     [AST2700_SCU_HPLL_EXT_PARAM]    = 0x8000004f,
932     [AST2700_SCU_DPLL_PARAM]        = 0x0080009f,
933     [AST2700_SCU_DPLL_EXT_PARAM]    = 0x8000004f,
934     [AST2700_SCU_MPLL_PARAM]        = 0x00000040,
935     [AST2700_SCU_MPLL_EXT_PARAM]    = 0x80000000,
936     [AST2700_SCU_D1CLK_PARAM]       = 0x00050002,
937     [AST2700_SCU_D2CLK_PARAM]       = 0x00050002,
938     [AST2700_SCU_CRT1CLK_PARAM]     = 0x00050002,
939     [AST2700_SCU_CRT2CLK_PARAM]     = 0x00050002,
940     [AST2700_SCU_MPHYCLK_PARAM]     = 0x0000004c,
941     [AST2700_SCU_FREQ_CNTR]         = 0x000375eb,
942     [AST2700_SCU_CPU_SCRATCH_0]     = 0x00000000,
943     [AST2700_SCU_CPU_SCRATCH_1]     = 0x00000004,
944     [AST2700_SCU_VGA_SCRATCH_0]     = 0x00000040,
945 };
946 
947 static void aspeed_ast2700_scu_reset(DeviceState *dev)
948 {
949     AspeedSCUState *s = ASPEED_SCU(dev);
950     AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
951 
952     memcpy(s->regs, asc->resets, asc->nr_regs * 4);
953     s->regs[AST2700_SILICON_REV] = s->silicon_rev;
954     s->regs[AST2700_HW_STRAP1] = s->hw_strap1;
955 }
956 
957 static void aspeed_2700_scu_class_init(ObjectClass *klass, void *data)
958 {
959     DeviceClass *dc = DEVICE_CLASS(klass);
960     AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
961 
962     dc->desc = "ASPEED 2700 System Control Unit";
963     device_class_set_legacy_reset(dc, aspeed_ast2700_scu_reset);
964     asc->resets = ast2700_a0_resets;
965     asc->calc_hpll = aspeed_2600_scu_calc_hpll;
966     asc->get_apb = aspeed_2700_scu_get_apb_freq;
967     asc->apb_divider = 4;
968     asc->nr_regs = ASPEED_AST2700_SCU_NR_REGS;
969     asc->clkin_25Mhz = true;
970     asc->ops = &aspeed_ast2700_scu_ops;
971 }
972 
973 static uint64_t aspeed_ast2700_scuio_read(void *opaque, hwaddr offset,
974                                         unsigned size)
975 {
976     AspeedSCUState *s = ASPEED_SCU(opaque);
977     int reg = TO_REG(offset);
978     if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
979         qemu_log_mask(LOG_GUEST_ERROR,
980                       "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
981                 __func__, offset);
982         return 0;
983     }
984 
985     switch (reg) {
986     default:
987         qemu_log_mask(LOG_GUEST_ERROR,
988                       "%s: Unhandled read at offset 0x%" HWADDR_PRIx "\n",
989                       __func__, offset);
990     }
991 
992     trace_aspeed_ast2700_scuio_read(offset, size, s->regs[reg]);
993     return s->regs[reg];
994 }
995 
996 static void aspeed_ast2700_scuio_write(void *opaque, hwaddr offset,
997                                      uint64_t data64, unsigned size)
998 {
999     AspeedSCUState *s = ASPEED_SCU(opaque);
1000     int reg = TO_REG(offset);
1001     /* Truncate here so bitwise operations below behave as expected */
1002     uint32_t data = data64;
1003     bool updated = false;
1004 
1005     if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
1006         qemu_log_mask(LOG_GUEST_ERROR,
1007                       "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
1008                 __func__, offset);
1009         return;
1010     }
1011 
1012     trace_aspeed_ast2700_scuio_write(offset, size, data);
1013 
1014     switch (reg) {
1015     case AST2700_SCUIO_CLK_STOP_CTL_1:
1016     case AST2700_SCUIO_CLK_STOP_CTL_2:
1017         s->regs[reg] |= data;
1018         updated = true;
1019         break;
1020     case AST2700_SCUIO_CLK_STOP_CLR_1:
1021     case AST2700_SCUIO_CLK_STOP_CLR_2:
1022         s->regs[reg - 1] ^= data;
1023         updated = true;
1024         break;
1025     default:
1026         qemu_log_mask(LOG_GUEST_ERROR,
1027                       "%s: Unhandled write at offset 0x%" HWADDR_PRIx "\n",
1028                       __func__, offset);
1029         break;
1030     }
1031 
1032     if (!updated) {
1033         s->regs[reg] = data;
1034     }
1035 }
1036 
1037 static const MemoryRegionOps aspeed_ast2700_scuio_ops = {
1038     .read = aspeed_ast2700_scuio_read,
1039     .write = aspeed_ast2700_scuio_write,
1040     .endianness = DEVICE_LITTLE_ENDIAN,
1041     .impl.min_access_size = 4,
1042     .impl.max_access_size = 4,
1043     .valid.min_access_size = 1,
1044     .valid.max_access_size = 8,
1045     .valid.unaligned = false,
1046 };
1047 
1048 static const uint32_t ast2700_a0_resets_io[ASPEED_AST2700_SCU_NR_REGS] = {
1049     [AST2700_HW_STRAP1_CLR]             = 0xFFF0FFF0,
1050     [AST2700_HW_STRAP1_LOCK]            = 0x00000FFF,
1051     [AST2700_HW_STRAP1_SEC1]            = 0x000000FF,
1052     [AST2700_HW_STRAP1_SEC2]            = 0x00000000,
1053     [AST2700_HW_STRAP1_SEC3]            = 0x1000408F,
1054     [AST2700_SCUIO_CLK_STOP_CTL_1]      = 0xffff8400,
1055     [AST2700_SCUIO_CLK_STOP_CTL_2]      = 0x00005f30,
1056     [AST2700_SCUIO_CLK_SEL_1]           = 0x86900000,
1057     [AST2700_SCUIO_CLK_SEL_2]           = 0x00400000,
1058     [AST2700_SCUIO_HPLL_PARAM]          = 0x10000027,
1059     [AST2700_SCUIO_HPLL_EXT_PARAM]      = 0x80000014,
1060     [AST2700_SCUIO_APLL_PARAM]          = 0x1000001f,
1061     [AST2700_SCUIO_APLL_EXT_PARAM]      = 0x8000000f,
1062     [AST2700_SCUIO_DPLL_PARAM]          = 0x106e42ce,
1063     [AST2700_SCUIO_DPLL_EXT_PARAM]      = 0x80000167,
1064     [AST2700_SCUIO_DPLL_PARAM_READ]     = 0x106e42ce,
1065     [AST2700_SCUIO_DPLL_EXT_PARAM_READ] = 0x80000167,
1066     [AST2700_SCUIO_UARTCLK_GEN]         = 0x00014506,
1067     [AST2700_SCUIO_HUARTCLK_GEN]        = 0x000145c0,
1068     [AST2700_SCUIO_CLK_DUTY_MEAS_RST]   = 0x0c9100d2,
1069 };
1070 
1071 static void aspeed_2700_scuio_class_init(ObjectClass *klass, void *data)
1072 {
1073     DeviceClass *dc = DEVICE_CLASS(klass);
1074     AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
1075 
1076     dc->desc = "ASPEED 2700 System Control Unit I/O";
1077     device_class_set_legacy_reset(dc, aspeed_ast2700_scu_reset);
1078     asc->resets = ast2700_a0_resets_io;
1079     asc->calc_hpll = aspeed_2600_scu_calc_hpll;
1080     asc->get_apb = aspeed_2700_scuio_get_apb_freq;
1081     asc->apb_divider = 2;
1082     asc->nr_regs = ASPEED_AST2700_SCU_NR_REGS;
1083     asc->clkin_25Mhz = true;
1084     asc->ops = &aspeed_ast2700_scuio_ops;
1085 }
1086 
1087 static const TypeInfo aspeed_2700_scu_info = {
1088     .name = TYPE_ASPEED_2700_SCU,
1089     .parent = TYPE_ASPEED_SCU,
1090     .instance_size = sizeof(AspeedSCUState),
1091     .class_init = aspeed_2700_scu_class_init,
1092 };
1093 
1094 static const TypeInfo aspeed_2700_scuio_info = {
1095     .name = TYPE_ASPEED_2700_SCUIO,
1096     .parent = TYPE_ASPEED_SCU,
1097     .instance_size = sizeof(AspeedSCUState),
1098     .class_init = aspeed_2700_scuio_class_init,
1099 };
1100 
1101 static const uint32_t ast1030_a1_resets[ASPEED_AST2600_SCU_NR_REGS] = {
1102     [AST2600_SYS_RST_CTRL]      = 0xFFC3FED8,
1103     [AST2600_SYS_RST_CTRL2]     = 0x09FFFFFC,
1104     [AST2600_CLK_STOP_CTRL]     = 0xFFFF7F8A,
1105     [AST2600_CLK_STOP_CTRL2]    = 0xFFF0FFF0,
1106     [AST2600_DEBUG_CTRL2]       = 0x00000000,
1107     [AST2600_HPLL_PARAM]        = 0x10004077,
1108     [AST2600_HPLL_EXT]          = 0x00000031,
1109     [AST2600_CLK_SEL4]          = 0x43F90900,
1110     [AST2600_CLK_SEL5]          = 0x40000000,
1111     [AST2600_CHIP_ID0]          = 0xDEADBEEF,
1112     [AST2600_CHIP_ID1]          = 0x0BADCAFE,
1113 };
1114 
1115 static void aspeed_ast1030_scu_reset(DeviceState *dev)
1116 {
1117     AspeedSCUState *s = ASPEED_SCU(dev);
1118     AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
1119 
1120     memcpy(s->regs, asc->resets, asc->nr_regs * 4);
1121 
1122     s->regs[AST2600_SILICON_REV] = AST1030_A1_SILICON_REV;
1123     s->regs[AST2600_SILICON_REV2] = s->silicon_rev;
1124     s->regs[AST2600_HW_STRAP1] = s->hw_strap1;
1125     s->regs[AST2600_HW_STRAP2] = s->hw_strap2;
1126     s->regs[PROT_KEY] = s->hw_prot_key;
1127 }
1128 
1129 static void aspeed_1030_scu_class_init(ObjectClass *klass, void *data)
1130 {
1131     DeviceClass *dc = DEVICE_CLASS(klass);
1132     AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
1133 
1134     dc->desc = "ASPEED 1030 System Control Unit";
1135     device_class_set_legacy_reset(dc, aspeed_ast1030_scu_reset);
1136     asc->resets = ast1030_a1_resets;
1137     asc->calc_hpll = aspeed_2600_scu_calc_hpll;
1138     asc->get_apb = aspeed_1030_scu_get_apb_freq;
1139     asc->apb_divider = 2;
1140     asc->nr_regs = ASPEED_AST2600_SCU_NR_REGS;
1141     asc->clkin_25Mhz = true;
1142     asc->ops = &aspeed_ast2600_scu_ops;
1143 }
1144 
1145 static const TypeInfo aspeed_1030_scu_info = {
1146     .name = TYPE_ASPEED_1030_SCU,
1147     .parent = TYPE_ASPEED_SCU,
1148     .instance_size = sizeof(AspeedSCUState),
1149     .class_init = aspeed_1030_scu_class_init,
1150 };
1151 
1152 static void aspeed_scu_register_types(void)
1153 {
1154     type_register_static(&aspeed_scu_info);
1155     type_register_static(&aspeed_2400_scu_info);
1156     type_register_static(&aspeed_2500_scu_info);
1157     type_register_static(&aspeed_2600_scu_info);
1158     type_register_static(&aspeed_1030_scu_info);
1159     type_register_static(&aspeed_2700_scu_info);
1160     type_register_static(&aspeed_2700_scuio_info);
1161 }
1162 
1163 type_init(aspeed_scu_register_types);
1164