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
aspeed_scu_get_random(void)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
aspeed_scu_get_apb_freq(AspeedSCUState * s)258 uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s)
259 {
260 return ASPEED_SCU_GET_CLASS(s)->get_apb(s);
261 }
262
aspeed_2400_scu_get_apb_freq(AspeedSCUState * s)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
aspeed_2600_scu_get_apb_freq(AspeedSCUState * s)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
aspeed_1030_scu_get_apb_freq(AspeedSCUState * s)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
aspeed_2700_scu_get_apb_freq(AspeedSCUState * s)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
aspeed_2700_scuio_get_apb_freq(AspeedSCUState * s)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
aspeed_scu_read(void * opaque,hwaddr offset,unsigned size)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
aspeed_ast2400_scu_write(void * opaque,hwaddr offset,uint64_t data,unsigned size)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
aspeed_ast2500_scu_write(void * opaque,hwaddr offset,uint64_t data,unsigned size)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
aspeed_scu_get_clkin(AspeedSCUState * s)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
aspeed_2400_scu_calc_hpll(AspeedSCUState * s,uint32_t hpll_reg)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
aspeed_2500_scu_calc_hpll(AspeedSCUState * s,uint32_t hpll_reg)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
aspeed_2600_scu_calc_hpll(AspeedSCUState * s,uint32_t hpll_reg)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
aspeed_scu_reset(DeviceState * dev)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
is_supported_silicon_rev(uint32_t silicon_rev)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
aspeed_scu_realize(DeviceState * dev,Error ** errp)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
aspeed_scu_class_init(ObjectClass * klass,const void * data)621 static void aspeed_scu_class_init(ObjectClass *klass, const 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
aspeed_2400_scu_class_init(ObjectClass * klass,const void * data)640 static void aspeed_2400_scu_class_init(ObjectClass *klass, const 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
aspeed_2500_scu_class_init(ObjectClass * klass,const void * data)662 static void aspeed_2500_scu_class_init(ObjectClass *klass, const 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
aspeed_ast2600_scu_read(void * opaque,hwaddr offset,unsigned size)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
aspeed_ast2600_scu_write(void * opaque,hwaddr offset,uint64_t data64,unsigned size)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
aspeed_ast2600_scu_reset(DeviceState * dev)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
aspeed_2600_scu_class_init(ObjectClass * klass,const void * data)838 static void aspeed_2600_scu_class_init(ObjectClass *klass, const 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
aspeed_ast2700_scu_read(void * opaque,hwaddr offset,unsigned size)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
aspeed_ast2700_scu_write(void * opaque,hwaddr offset,uint64_t data64,unsigned size)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
aspeed_ast2700_scu_reset(DeviceState * dev)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
aspeed_2700_scu_class_init(ObjectClass * klass,const void * data)957 static void aspeed_2700_scu_class_init(ObjectClass *klass, const 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
aspeed_ast2700_scuio_read(void * opaque,hwaddr offset,unsigned size)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
aspeed_ast2700_scuio_write(void * opaque,hwaddr offset,uint64_t data64,unsigned size)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
aspeed_2700_scuio_class_init(ObjectClass * klass,const void * data)1071 static void aspeed_2700_scuio_class_init(ObjectClass *klass, const 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
aspeed_ast1030_scu_reset(DeviceState * dev)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
aspeed_1030_scu_class_init(ObjectClass * klass,const void * data)1129 static void aspeed_1030_scu_class_init(ObjectClass *klass, const 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
aspeed_scu_register_types(void)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