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