11c8a2388SAndrew Jeffery /* 21c8a2388SAndrew Jeffery * ASPEED System Control Unit 31c8a2388SAndrew Jeffery * 41c8a2388SAndrew Jeffery * Andrew Jeffery <andrew@aj.id.au> 51c8a2388SAndrew Jeffery * 61c8a2388SAndrew Jeffery * Copyright 2016 IBM Corp. 71c8a2388SAndrew Jeffery * 81c8a2388SAndrew Jeffery * This code is licensed under the GPL version 2 or later. See 91c8a2388SAndrew Jeffery * the COPYING file in the top-level directory. 101c8a2388SAndrew Jeffery */ 111c8a2388SAndrew Jeffery 121c8a2388SAndrew Jeffery #include "qemu/osdep.h" 131c8a2388SAndrew Jeffery #include "hw/misc/aspeed_scu.h" 141c8a2388SAndrew Jeffery #include "hw/qdev-properties.h" 15d6454270SMarkus Armbruster #include "migration/vmstate.h" 161c8a2388SAndrew Jeffery #include "qapi/error.h" 171c8a2388SAndrew Jeffery #include "qapi/visitor.h" 181c8a2388SAndrew Jeffery #include "qemu/bitops.h" 19aa4b04a0SPranith Kumar #include "qemu/log.h" 209d44cb5bSRichard Henderson #include "qemu/guest-random.h" 210b8fa32fSMarkus Armbruster #include "qemu/module.h" 221c8a2388SAndrew Jeffery #include "trace.h" 231c8a2388SAndrew Jeffery 241c8a2388SAndrew Jeffery #define TO_REG(offset) ((offset) >> 2) 251c8a2388SAndrew Jeffery 261c8a2388SAndrew Jeffery #define PROT_KEY TO_REG(0x00) 271c8a2388SAndrew Jeffery #define SYS_RST_CTRL TO_REG(0x04) 281c8a2388SAndrew Jeffery #define CLK_SEL TO_REG(0x08) 291c8a2388SAndrew Jeffery #define CLK_STOP_CTRL TO_REG(0x0C) 301c8a2388SAndrew Jeffery #define FREQ_CNTR_CTRL TO_REG(0x10) 311c8a2388SAndrew Jeffery #define FREQ_CNTR_EVAL TO_REG(0x14) 321c8a2388SAndrew Jeffery #define IRQ_CTRL TO_REG(0x18) 331c8a2388SAndrew Jeffery #define D2PLL_PARAM TO_REG(0x1C) 341c8a2388SAndrew Jeffery #define MPLL_PARAM TO_REG(0x20) 351c8a2388SAndrew Jeffery #define HPLL_PARAM TO_REG(0x24) 361c8a2388SAndrew Jeffery #define FREQ_CNTR_RANGE TO_REG(0x28) 371c8a2388SAndrew Jeffery #define MISC_CTRL1 TO_REG(0x2C) 381c8a2388SAndrew Jeffery #define PCI_CTRL1 TO_REG(0x30) 391c8a2388SAndrew Jeffery #define PCI_CTRL2 TO_REG(0x34) 401c8a2388SAndrew Jeffery #define PCI_CTRL3 TO_REG(0x38) 411c8a2388SAndrew Jeffery #define SYS_RST_STATUS TO_REG(0x3C) 421c8a2388SAndrew Jeffery #define SOC_SCRATCH1 TO_REG(0x40) 431c8a2388SAndrew Jeffery #define SOC_SCRATCH2 TO_REG(0x44) 441c8a2388SAndrew Jeffery #define MAC_CLK_DELAY TO_REG(0x48) 451c8a2388SAndrew Jeffery #define MISC_CTRL2 TO_REG(0x4C) 461c8a2388SAndrew Jeffery #define VGA_SCRATCH1 TO_REG(0x50) 471c8a2388SAndrew Jeffery #define VGA_SCRATCH2 TO_REG(0x54) 481c8a2388SAndrew Jeffery #define VGA_SCRATCH3 TO_REG(0x58) 491c8a2388SAndrew Jeffery #define VGA_SCRATCH4 TO_REG(0x5C) 501c8a2388SAndrew Jeffery #define VGA_SCRATCH5 TO_REG(0x60) 511c8a2388SAndrew Jeffery #define VGA_SCRATCH6 TO_REG(0x64) 521c8a2388SAndrew Jeffery #define VGA_SCRATCH7 TO_REG(0x68) 531c8a2388SAndrew Jeffery #define VGA_SCRATCH8 TO_REG(0x6C) 541c8a2388SAndrew Jeffery #define HW_STRAP1 TO_REG(0x70) 551c8a2388SAndrew Jeffery #define RNG_CTRL TO_REG(0x74) 561c8a2388SAndrew Jeffery #define RNG_DATA TO_REG(0x78) 571c8a2388SAndrew Jeffery #define SILICON_REV TO_REG(0x7C) 581c8a2388SAndrew Jeffery #define PINMUX_CTRL1 TO_REG(0x80) 591c8a2388SAndrew Jeffery #define PINMUX_CTRL2 TO_REG(0x84) 601c8a2388SAndrew Jeffery #define PINMUX_CTRL3 TO_REG(0x88) 611c8a2388SAndrew Jeffery #define PINMUX_CTRL4 TO_REG(0x8C) 621c8a2388SAndrew Jeffery #define PINMUX_CTRL5 TO_REG(0x90) 631c8a2388SAndrew Jeffery #define PINMUX_CTRL6 TO_REG(0x94) 641c8a2388SAndrew Jeffery #define WDT_RST_CTRL TO_REG(0x9C) 651c8a2388SAndrew Jeffery #define PINMUX_CTRL7 TO_REG(0xA0) 661c8a2388SAndrew Jeffery #define PINMUX_CTRL8 TO_REG(0xA4) 671c8a2388SAndrew Jeffery #define PINMUX_CTRL9 TO_REG(0xA8) 681c8a2388SAndrew Jeffery #define WAKEUP_EN TO_REG(0xC0) 691c8a2388SAndrew Jeffery #define WAKEUP_CTRL TO_REG(0xC4) 701c8a2388SAndrew Jeffery #define HW_STRAP2 TO_REG(0xD0) 711c8a2388SAndrew Jeffery #define FREE_CNTR4 TO_REG(0xE0) 721c8a2388SAndrew Jeffery #define FREE_CNTR4_EXT TO_REG(0xE4) 731c8a2388SAndrew Jeffery #define CPU2_CTRL TO_REG(0x100) 741c8a2388SAndrew Jeffery #define CPU2_BASE_SEG1 TO_REG(0x104) 751c8a2388SAndrew Jeffery #define CPU2_BASE_SEG2 TO_REG(0x108) 761c8a2388SAndrew Jeffery #define CPU2_BASE_SEG3 TO_REG(0x10C) 771c8a2388SAndrew Jeffery #define CPU2_BASE_SEG4 TO_REG(0x110) 781c8a2388SAndrew Jeffery #define CPU2_BASE_SEG5 TO_REG(0x114) 791c8a2388SAndrew Jeffery #define CPU2_CACHE_CTRL TO_REG(0x118) 801c8a2388SAndrew Jeffery #define UART_HPLL_CLK TO_REG(0x160) 811c8a2388SAndrew Jeffery #define PCIE_CTRL TO_REG(0x180) 821c8a2388SAndrew Jeffery #define BMC_MMIO_CTRL TO_REG(0x184) 831c8a2388SAndrew Jeffery #define RELOC_DECODE_BASE1 TO_REG(0x188) 841c8a2388SAndrew Jeffery #define RELOC_DECODE_BASE2 TO_REG(0x18C) 851c8a2388SAndrew Jeffery #define MAILBOX_DECODE_BASE TO_REG(0x190) 861c8a2388SAndrew Jeffery #define SRAM_DECODE_BASE1 TO_REG(0x194) 871c8a2388SAndrew Jeffery #define SRAM_DECODE_BASE2 TO_REG(0x198) 881c8a2388SAndrew Jeffery #define BMC_REV TO_REG(0x19C) 891c8a2388SAndrew Jeffery #define BMC_DEV_ID TO_REG(0x1A4) 901c8a2388SAndrew Jeffery 91e09cf363SJoel Stanley #define AST2600_PROT_KEY TO_REG(0x00) 92e09cf363SJoel Stanley #define AST2600_SILICON_REV TO_REG(0x04) 93e09cf363SJoel Stanley #define AST2600_SILICON_REV2 TO_REG(0x14) 94e09cf363SJoel Stanley #define AST2600_SYS_RST_CTRL TO_REG(0x40) 95e09cf363SJoel Stanley #define AST2600_SYS_RST_CTRL_CLR TO_REG(0x44) 96e09cf363SJoel Stanley #define AST2600_SYS_RST_CTRL2 TO_REG(0x50) 97e09cf363SJoel Stanley #define AST2600_SYS_RST_CTRL2_CLR TO_REG(0x54) 98e09cf363SJoel Stanley #define AST2600_CLK_STOP_CTRL TO_REG(0x80) 99e09cf363SJoel Stanley #define AST2600_CLK_STOP_CTRL_CLR TO_REG(0x84) 100e09cf363SJoel Stanley #define AST2600_CLK_STOP_CTRL2 TO_REG(0x90) 101310b5bc6SJoel Stanley #define AST2600_CLK_STOP_CTRL2_CLR TO_REG(0x94) 1021550d726SJoel Stanley #define AST2600_SDRAM_HANDSHAKE TO_REG(0x100) 103e09cf363SJoel Stanley #define AST2600_HPLL_PARAM TO_REG(0x200) 104e09cf363SJoel Stanley #define AST2600_HPLL_EXT TO_REG(0x204) 105e09cf363SJoel Stanley #define AST2600_MPLL_EXT TO_REG(0x224) 106e09cf363SJoel Stanley #define AST2600_EPLL_EXT TO_REG(0x244) 107e09cf363SJoel Stanley #define AST2600_CLK_SEL TO_REG(0x300) 108e09cf363SJoel Stanley #define AST2600_CLK_SEL2 TO_REG(0x304) 109e09cf363SJoel Stanley #define AST2600_CLK_SEL3 TO_REG(0x310) 110e09cf363SJoel Stanley #define AST2600_HW_STRAP1 TO_REG(0x500) 111e09cf363SJoel Stanley #define AST2600_HW_STRAP1_CLR TO_REG(0x504) 112e09cf363SJoel Stanley #define AST2600_HW_STRAP1_PROT TO_REG(0x508) 113e09cf363SJoel Stanley #define AST2600_HW_STRAP2 TO_REG(0x510) 114e09cf363SJoel Stanley #define AST2600_HW_STRAP2_CLR TO_REG(0x514) 115e09cf363SJoel Stanley #define AST2600_HW_STRAP2_PROT TO_REG(0x518) 116e09cf363SJoel Stanley #define AST2600_RNG_CTRL TO_REG(0x524) 117e09cf363SJoel Stanley #define AST2600_RNG_DATA TO_REG(0x540) 118e09cf363SJoel Stanley 119e09cf363SJoel Stanley #define AST2600_CLK TO_REG(0x40) 120e09cf363SJoel Stanley 121c491e152SCédric Le Goater #define SCU_IO_REGION_SIZE 0x1000 1221c8a2388SAndrew Jeffery 1231c8a2388SAndrew Jeffery static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = { 1241c8a2388SAndrew Jeffery [SYS_RST_CTRL] = 0xFFCFFEDCU, 1251c8a2388SAndrew Jeffery [CLK_SEL] = 0xF3F40000U, 1261c8a2388SAndrew Jeffery [CLK_STOP_CTRL] = 0x19FC3E8BU, 1271c8a2388SAndrew Jeffery [D2PLL_PARAM] = 0x00026108U, 1281c8a2388SAndrew Jeffery [MPLL_PARAM] = 0x00030291U, 1291c8a2388SAndrew Jeffery [HPLL_PARAM] = 0x00000291U, 1301c8a2388SAndrew Jeffery [MISC_CTRL1] = 0x00000010U, 1311c8a2388SAndrew Jeffery [PCI_CTRL1] = 0x20001A03U, 1321c8a2388SAndrew Jeffery [PCI_CTRL2] = 0x20001A03U, 1331c8a2388SAndrew Jeffery [PCI_CTRL3] = 0x04000030U, 1341c8a2388SAndrew Jeffery [SYS_RST_STATUS] = 0x00000001U, 1351c8a2388SAndrew Jeffery [SOC_SCRATCH1] = 0x000000C0U, /* SoC completed DRAM init */ 1361c8a2388SAndrew Jeffery [MISC_CTRL2] = 0x00000023U, 1371c8a2388SAndrew Jeffery [RNG_CTRL] = 0x0000000EU, 1381c8a2388SAndrew Jeffery [PINMUX_CTRL2] = 0x0000F000U, 1391c8a2388SAndrew Jeffery [PINMUX_CTRL3] = 0x01000000U, 1401c8a2388SAndrew Jeffery [PINMUX_CTRL4] = 0x000000FFU, 1411c8a2388SAndrew Jeffery [PINMUX_CTRL5] = 0x0000A000U, 1421c8a2388SAndrew Jeffery [WDT_RST_CTRL] = 0x003FFFF3U, 1431c8a2388SAndrew Jeffery [PINMUX_CTRL8] = 0xFFFF0000U, 1441c8a2388SAndrew Jeffery [PINMUX_CTRL9] = 0x000FFFFFU, 1451c8a2388SAndrew Jeffery [FREE_CNTR4] = 0x000000FFU, 1461c8a2388SAndrew Jeffery [FREE_CNTR4_EXT] = 0x000000FFU, 1471c8a2388SAndrew Jeffery [CPU2_BASE_SEG1] = 0x80000000U, 1481c8a2388SAndrew Jeffery [CPU2_BASE_SEG4] = 0x1E600000U, 1491c8a2388SAndrew Jeffery [CPU2_BASE_SEG5] = 0xC0000000U, 1501c8a2388SAndrew Jeffery [UART_HPLL_CLK] = 0x00001903U, 1511c8a2388SAndrew Jeffery [PCIE_CTRL] = 0x0000007BU, 1521c8a2388SAndrew Jeffery [BMC_DEV_ID] = 0x00002402U 1531c8a2388SAndrew Jeffery }; 1541c8a2388SAndrew Jeffery 155365aff1eSCédric Le Goater /* SCU70 bit 23: 0 24Mhz. bit 11:9: 0b001 AXI:ABH ratio 2:1 */ 156365aff1eSCédric Le Goater /* AST2500 revision A1 */ 157365aff1eSCédric Le Goater 158365aff1eSCédric Le Goater static const uint32_t ast2500_a1_resets[ASPEED_SCU_NR_REGS] = { 159365aff1eSCédric Le Goater [SYS_RST_CTRL] = 0xFFCFFEDCU, 160365aff1eSCédric Le Goater [CLK_SEL] = 0xF3F40000U, 161365aff1eSCédric Le Goater [CLK_STOP_CTRL] = 0x19FC3E8BU, 162365aff1eSCédric Le Goater [D2PLL_PARAM] = 0x00026108U, 163365aff1eSCédric Le Goater [MPLL_PARAM] = 0x00030291U, 164365aff1eSCédric Le Goater [HPLL_PARAM] = 0x93000400U, 165365aff1eSCédric Le Goater [MISC_CTRL1] = 0x00000010U, 166365aff1eSCédric Le Goater [PCI_CTRL1] = 0x20001A03U, 167365aff1eSCédric Le Goater [PCI_CTRL2] = 0x20001A03U, 168365aff1eSCédric Le Goater [PCI_CTRL3] = 0x04000030U, 169365aff1eSCédric Le Goater [SYS_RST_STATUS] = 0x00000001U, 170365aff1eSCédric Le Goater [SOC_SCRATCH1] = 0x000000C0U, /* SoC completed DRAM init */ 171365aff1eSCédric Le Goater [MISC_CTRL2] = 0x00000023U, 172365aff1eSCédric Le Goater [RNG_CTRL] = 0x0000000EU, 173365aff1eSCédric Le Goater [PINMUX_CTRL2] = 0x0000F000U, 174365aff1eSCédric Le Goater [PINMUX_CTRL3] = 0x03000000U, 175365aff1eSCédric Le Goater [PINMUX_CTRL4] = 0x00000000U, 176365aff1eSCédric Le Goater [PINMUX_CTRL5] = 0x0000A000U, 177365aff1eSCédric Le Goater [WDT_RST_CTRL] = 0x023FFFF3U, 178365aff1eSCédric Le Goater [PINMUX_CTRL8] = 0xFFFF0000U, 179365aff1eSCédric Le Goater [PINMUX_CTRL9] = 0x000FFFFFU, 180365aff1eSCédric Le Goater [FREE_CNTR4] = 0x000000FFU, 181365aff1eSCédric Le Goater [FREE_CNTR4_EXT] = 0x000000FFU, 182365aff1eSCédric Le Goater [CPU2_BASE_SEG1] = 0x80000000U, 183365aff1eSCédric Le Goater [CPU2_BASE_SEG4] = 0x1E600000U, 184365aff1eSCédric Le Goater [CPU2_BASE_SEG5] = 0xC0000000U, 185365aff1eSCédric Le Goater [UART_HPLL_CLK] = 0x00001903U, 186365aff1eSCédric Le Goater [PCIE_CTRL] = 0x0000007BU, 187365aff1eSCédric Le Goater [BMC_DEV_ID] = 0x00002402U 188365aff1eSCédric Le Goater }; 189365aff1eSCédric Le Goater 190acd9575eSJoel Stanley static uint32_t aspeed_scu_get_random(void) 191acd9575eSJoel Stanley { 192acd9575eSJoel Stanley uint32_t num; 1939d44cb5bSRichard Henderson qemu_guest_getrandom_nofail(&num, sizeof(num)); 194acd9575eSJoel Stanley return num; 195acd9575eSJoel Stanley } 196acd9575eSJoel Stanley 197a8f07376SCédric Le Goater uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s) 198fda9aaa6SCédric Le Goater { 1999a937f6cSCédric Le Goater AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s); 200a8f07376SCédric Le Goater uint32_t hpll = asc->calc_hpll(s, s->regs[HPLL_PARAM]); 201fda9aaa6SCédric Le Goater 202a8f07376SCédric Le Goater return hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[CLK_SEL]) + 1) 2039a937f6cSCédric Le Goater / asc->apb_divider; 204fda9aaa6SCédric Le Goater } 205fda9aaa6SCédric Le Goater 2061c8a2388SAndrew Jeffery static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size) 2071c8a2388SAndrew Jeffery { 2081c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(opaque); 2091c8a2388SAndrew Jeffery int reg = TO_REG(offset); 2101c8a2388SAndrew Jeffery 211e09cf363SJoel Stanley if (reg >= ASPEED_SCU_NR_REGS) { 2121c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 2131c8a2388SAndrew Jeffery "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", 2141c8a2388SAndrew Jeffery __func__, offset); 2151c8a2388SAndrew Jeffery return 0; 2161c8a2388SAndrew Jeffery } 2171c8a2388SAndrew Jeffery 2181c8a2388SAndrew Jeffery switch (reg) { 219acd9575eSJoel Stanley case RNG_DATA: 220acd9575eSJoel Stanley /* On hardware, RNG_DATA works regardless of 221acd9575eSJoel Stanley * the state of the enable bit in RNG_CTRL 222acd9575eSJoel Stanley */ 223acd9575eSJoel Stanley s->regs[RNG_DATA] = aspeed_scu_get_random(); 224acd9575eSJoel Stanley break; 2251c8a2388SAndrew Jeffery case WAKEUP_EN: 2261c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 2271c8a2388SAndrew Jeffery "%s: Read of write-only offset 0x%" HWADDR_PRIx "\n", 2281c8a2388SAndrew Jeffery __func__, offset); 2291c8a2388SAndrew Jeffery break; 2301c8a2388SAndrew Jeffery } 2311c8a2388SAndrew Jeffery 2321c8a2388SAndrew Jeffery return s->regs[reg]; 2331c8a2388SAndrew Jeffery } 2341c8a2388SAndrew Jeffery 235*c7e1f572SJoel Stanley static void aspeed_ast2400_scu_write(void *opaque, hwaddr offset, 236*c7e1f572SJoel Stanley uint64_t data, unsigned size) 237*c7e1f572SJoel Stanley { 238*c7e1f572SJoel Stanley AspeedSCUState *s = ASPEED_SCU(opaque); 239*c7e1f572SJoel Stanley int reg = TO_REG(offset); 240*c7e1f572SJoel Stanley 241*c7e1f572SJoel Stanley if (reg >= ASPEED_SCU_NR_REGS) { 242*c7e1f572SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 243*c7e1f572SJoel Stanley "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 244*c7e1f572SJoel Stanley __func__, offset); 245*c7e1f572SJoel Stanley return; 246*c7e1f572SJoel Stanley } 247*c7e1f572SJoel Stanley 248*c7e1f572SJoel Stanley if (reg > PROT_KEY && reg < CPU2_BASE_SEG1 && 249*c7e1f572SJoel Stanley !s->regs[PROT_KEY]) { 250*c7e1f572SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__); 251*c7e1f572SJoel Stanley } 252*c7e1f572SJoel Stanley 253*c7e1f572SJoel Stanley trace_aspeed_scu_write(offset, size, data); 254*c7e1f572SJoel Stanley 255*c7e1f572SJoel Stanley switch (reg) { 256*c7e1f572SJoel Stanley case PROT_KEY: 257*c7e1f572SJoel Stanley s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0; 258*c7e1f572SJoel Stanley return; 259*c7e1f572SJoel Stanley case SILICON_REV: 260*c7e1f572SJoel Stanley case FREQ_CNTR_EVAL: 261*c7e1f572SJoel Stanley case VGA_SCRATCH1 ... VGA_SCRATCH8: 262*c7e1f572SJoel Stanley case RNG_DATA: 263*c7e1f572SJoel Stanley case FREE_CNTR4: 264*c7e1f572SJoel Stanley case FREE_CNTR4_EXT: 265*c7e1f572SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 266*c7e1f572SJoel Stanley "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n", 267*c7e1f572SJoel Stanley __func__, offset); 268*c7e1f572SJoel Stanley return; 269*c7e1f572SJoel Stanley } 270*c7e1f572SJoel Stanley 271*c7e1f572SJoel Stanley s->regs[reg] = data; 272*c7e1f572SJoel Stanley } 273*c7e1f572SJoel Stanley 274*c7e1f572SJoel Stanley static void aspeed_ast2500_scu_write(void *opaque, hwaddr offset, 275*c7e1f572SJoel Stanley uint64_t data, unsigned size) 2761c8a2388SAndrew Jeffery { 2771c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(opaque); 2781c8a2388SAndrew Jeffery int reg = TO_REG(offset); 2791c8a2388SAndrew Jeffery 280e09cf363SJoel Stanley if (reg >= ASPEED_SCU_NR_REGS) { 2811c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 2821c8a2388SAndrew Jeffery "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 2831c8a2388SAndrew Jeffery __func__, offset); 2841c8a2388SAndrew Jeffery return; 2851c8a2388SAndrew Jeffery } 2861c8a2388SAndrew Jeffery 2871c8a2388SAndrew Jeffery if (reg > PROT_KEY && reg < CPU2_BASE_SEG1 && 2885c1d3a2bSHugo Landau !s->regs[PROT_KEY]) { 2891c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__); 2901c8a2388SAndrew Jeffery return; 2911c8a2388SAndrew Jeffery } 2921c8a2388SAndrew Jeffery 2931c8a2388SAndrew Jeffery trace_aspeed_scu_write(offset, size, data); 2941c8a2388SAndrew Jeffery 2951c8a2388SAndrew Jeffery switch (reg) { 2965c1d3a2bSHugo Landau case PROT_KEY: 2975c1d3a2bSHugo Landau s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0; 2985c1d3a2bSHugo Landau return; 299333b9c8aSAndrew Jeffery case HW_STRAP1: 300333b9c8aSAndrew Jeffery s->regs[HW_STRAP1] |= data; 301333b9c8aSAndrew Jeffery return; 302333b9c8aSAndrew Jeffery case SILICON_REV: 303333b9c8aSAndrew Jeffery s->regs[HW_STRAP1] &= ~data; 304333b9c8aSAndrew Jeffery return; 3051c8a2388SAndrew Jeffery case FREQ_CNTR_EVAL: 3061c8a2388SAndrew Jeffery case VGA_SCRATCH1 ... VGA_SCRATCH8: 3071c8a2388SAndrew Jeffery case RNG_DATA: 3081c8a2388SAndrew Jeffery case FREE_CNTR4: 3091c8a2388SAndrew Jeffery case FREE_CNTR4_EXT: 3101c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 3111c8a2388SAndrew Jeffery "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n", 3121c8a2388SAndrew Jeffery __func__, offset); 3131c8a2388SAndrew Jeffery return; 3141c8a2388SAndrew Jeffery } 3151c8a2388SAndrew Jeffery 3161c8a2388SAndrew Jeffery s->regs[reg] = data; 3171c8a2388SAndrew Jeffery } 3181c8a2388SAndrew Jeffery 319*c7e1f572SJoel Stanley static const MemoryRegionOps aspeed_ast2400_scu_ops = { 3201c8a2388SAndrew Jeffery .read = aspeed_scu_read, 321*c7e1f572SJoel Stanley .write = aspeed_ast2400_scu_write, 322*c7e1f572SJoel Stanley .endianness = DEVICE_LITTLE_ENDIAN, 323*c7e1f572SJoel Stanley .valid.min_access_size = 4, 324*c7e1f572SJoel Stanley .valid.max_access_size = 4, 325*c7e1f572SJoel Stanley .valid.unaligned = false, 326*c7e1f572SJoel Stanley }; 327*c7e1f572SJoel Stanley 328*c7e1f572SJoel Stanley static const MemoryRegionOps aspeed_ast2500_scu_ops = { 329*c7e1f572SJoel Stanley .read = aspeed_scu_read, 330*c7e1f572SJoel Stanley .write = aspeed_ast2500_scu_write, 3311c8a2388SAndrew Jeffery .endianness = DEVICE_LITTLE_ENDIAN, 3321c8a2388SAndrew Jeffery .valid.min_access_size = 4, 3331c8a2388SAndrew Jeffery .valid.max_access_size = 4, 3341c8a2388SAndrew Jeffery .valid.unaligned = false, 3351c8a2388SAndrew Jeffery }; 3361c8a2388SAndrew Jeffery 337fda9aaa6SCédric Le Goater static uint32_t aspeed_scu_get_clkin(AspeedSCUState *s) 338fda9aaa6SCédric Le Goater { 339fda9aaa6SCédric Le Goater if (s->hw_strap1 & SCU_HW_STRAP_CLK_25M_IN) { 340fda9aaa6SCédric Le Goater return 25000000; 341fda9aaa6SCédric Le Goater } else if (s->hw_strap1 & SCU_HW_STRAP_CLK_48M_IN) { 342fda9aaa6SCédric Le Goater return 48000000; 343fda9aaa6SCédric Le Goater } else { 344fda9aaa6SCédric Le Goater return 24000000; 345fda9aaa6SCédric Le Goater } 346fda9aaa6SCédric Le Goater } 347fda9aaa6SCédric Le Goater 348fda9aaa6SCédric Le Goater /* 349fda9aaa6SCédric Le Goater * Strapped frequencies for the AST2400 in MHz. They depend on the 350fda9aaa6SCédric Le Goater * clkin frequency. 351fda9aaa6SCédric Le Goater */ 352fda9aaa6SCédric Le Goater static const uint32_t hpll_ast2400_freqs[][4] = { 353fda9aaa6SCédric Le Goater { 384, 360, 336, 408 }, /* 24MHz or 48MHz */ 354fda9aaa6SCédric Le Goater { 400, 375, 350, 425 }, /* 25MHz */ 355fda9aaa6SCédric Le Goater }; 356fda9aaa6SCédric Le Goater 357a8f07376SCédric Le Goater static uint32_t aspeed_2400_scu_calc_hpll(AspeedSCUState *s, uint32_t hpll_reg) 358fda9aaa6SCédric Le Goater { 359fda9aaa6SCédric Le Goater uint8_t freq_select; 360fda9aaa6SCédric Le Goater bool clk_25m_in; 361a8f07376SCédric Le Goater uint32_t clkin = aspeed_scu_get_clkin(s); 362fda9aaa6SCédric Le Goater 363fda9aaa6SCédric Le Goater if (hpll_reg & SCU_AST2400_H_PLL_OFF) { 364fda9aaa6SCédric Le Goater return 0; 365fda9aaa6SCédric Le Goater } 366fda9aaa6SCédric Le Goater 367fda9aaa6SCédric Le Goater if (hpll_reg & SCU_AST2400_H_PLL_PROGRAMMED) { 368fda9aaa6SCédric Le Goater uint32_t multiplier = 1; 369fda9aaa6SCédric Le Goater 370fda9aaa6SCédric Le Goater if (!(hpll_reg & SCU_AST2400_H_PLL_BYPASS_EN)) { 371fda9aaa6SCédric Le Goater uint32_t n = (hpll_reg >> 5) & 0x3f; 372fda9aaa6SCédric Le Goater uint32_t od = (hpll_reg >> 4) & 0x1; 373fda9aaa6SCédric Le Goater uint32_t d = hpll_reg & 0xf; 374fda9aaa6SCédric Le Goater 375fda9aaa6SCédric Le Goater multiplier = (2 - od) * ((n + 2) / (d + 1)); 376fda9aaa6SCédric Le Goater } 377fda9aaa6SCédric Le Goater 378a8f07376SCédric Le Goater return clkin * multiplier; 379fda9aaa6SCédric Le Goater } 380fda9aaa6SCédric Le Goater 381fda9aaa6SCédric Le Goater /* HW strapping */ 382fda9aaa6SCédric Le Goater clk_25m_in = !!(s->hw_strap1 & SCU_HW_STRAP_CLK_25M_IN); 383fda9aaa6SCédric Le Goater freq_select = SCU_AST2400_HW_STRAP_GET_H_PLL_CLK(s->hw_strap1); 384fda9aaa6SCédric Le Goater 385fda9aaa6SCédric Le Goater return hpll_ast2400_freqs[clk_25m_in][freq_select] * 1000000; 386fda9aaa6SCédric Le Goater } 387fda9aaa6SCédric Le Goater 388a8f07376SCédric Le Goater static uint32_t aspeed_2500_scu_calc_hpll(AspeedSCUState *s, uint32_t hpll_reg) 389fda9aaa6SCédric Le Goater { 390fda9aaa6SCédric Le Goater uint32_t multiplier = 1; 391a8f07376SCédric Le Goater uint32_t clkin = aspeed_scu_get_clkin(s); 392fda9aaa6SCédric Le Goater 393fda9aaa6SCédric Le Goater if (hpll_reg & SCU_H_PLL_OFF) { 394fda9aaa6SCédric Le Goater return 0; 395fda9aaa6SCédric Le Goater } 396fda9aaa6SCédric Le Goater 397fda9aaa6SCédric Le Goater if (!(hpll_reg & SCU_H_PLL_BYPASS_EN)) { 398fda9aaa6SCédric Le Goater uint32_t p = (hpll_reg >> 13) & 0x3f; 399fda9aaa6SCédric Le Goater uint32_t m = (hpll_reg >> 5) & 0xff; 400fda9aaa6SCédric Le Goater uint32_t n = hpll_reg & 0x1f; 401fda9aaa6SCédric Le Goater 402fda9aaa6SCédric Le Goater multiplier = ((m + 1) / (n + 1)) / (p + 1); 403fda9aaa6SCédric Le Goater } 404fda9aaa6SCédric Le Goater 405a8f07376SCédric Le Goater return clkin * multiplier; 406fda9aaa6SCédric Le Goater } 407fda9aaa6SCédric Le Goater 4081c8a2388SAndrew Jeffery static void aspeed_scu_reset(DeviceState *dev) 4091c8a2388SAndrew Jeffery { 4101c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(dev); 4119a937f6cSCédric Le Goater AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev); 4121c8a2388SAndrew Jeffery 413e09cf363SJoel Stanley memcpy(s->regs, asc->resets, asc->nr_regs * 4); 4141c8a2388SAndrew Jeffery s->regs[SILICON_REV] = s->silicon_rev; 4151c8a2388SAndrew Jeffery s->regs[HW_STRAP1] = s->hw_strap1; 4161c8a2388SAndrew Jeffery s->regs[HW_STRAP2] = s->hw_strap2; 417b6e70d1dSJoel Stanley s->regs[PROT_KEY] = s->hw_prot_key; 4181c8a2388SAndrew Jeffery } 4191c8a2388SAndrew Jeffery 420365aff1eSCédric Le Goater static uint32_t aspeed_silicon_revs[] = { 421365aff1eSCédric Le Goater AST2400_A0_SILICON_REV, 4226efbac90SCédric Le Goater AST2400_A1_SILICON_REV, 423365aff1eSCédric Le Goater AST2500_A0_SILICON_REV, 424365aff1eSCédric Le Goater AST2500_A1_SILICON_REV, 425e09cf363SJoel Stanley AST2600_A0_SILICON_REV, 426365aff1eSCédric Le Goater }; 4271c8a2388SAndrew Jeffery 42879a9f323SCédric Le Goater bool is_supported_silicon_rev(uint32_t silicon_rev) 4291c8a2388SAndrew Jeffery { 4301c8a2388SAndrew Jeffery int i; 4311c8a2388SAndrew Jeffery 4321c8a2388SAndrew Jeffery for (i = 0; i < ARRAY_SIZE(aspeed_silicon_revs); i++) { 4331c8a2388SAndrew Jeffery if (silicon_rev == aspeed_silicon_revs[i]) { 4341c8a2388SAndrew Jeffery return true; 4351c8a2388SAndrew Jeffery } 4361c8a2388SAndrew Jeffery } 4371c8a2388SAndrew Jeffery 4381c8a2388SAndrew Jeffery return false; 4391c8a2388SAndrew Jeffery } 4401c8a2388SAndrew Jeffery 4411c8a2388SAndrew Jeffery static void aspeed_scu_realize(DeviceState *dev, Error **errp) 4421c8a2388SAndrew Jeffery { 4431c8a2388SAndrew Jeffery SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 4441c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(dev); 445e09cf363SJoel Stanley AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev); 4461c8a2388SAndrew Jeffery 4471c8a2388SAndrew Jeffery if (!is_supported_silicon_rev(s->silicon_rev)) { 4481c8a2388SAndrew Jeffery error_setg(errp, "Unknown silicon revision: 0x%" PRIx32, 4491c8a2388SAndrew Jeffery s->silicon_rev); 4501c8a2388SAndrew Jeffery return; 4511c8a2388SAndrew Jeffery } 4521c8a2388SAndrew Jeffery 453e09cf363SJoel Stanley memory_region_init_io(&s->iomem, OBJECT(s), asc->ops, s, 4541c8a2388SAndrew Jeffery TYPE_ASPEED_SCU, SCU_IO_REGION_SIZE); 4551c8a2388SAndrew Jeffery 4561c8a2388SAndrew Jeffery sysbus_init_mmio(sbd, &s->iomem); 4571c8a2388SAndrew Jeffery } 4581c8a2388SAndrew Jeffery 4591c8a2388SAndrew Jeffery static const VMStateDescription vmstate_aspeed_scu = { 4601c8a2388SAndrew Jeffery .name = "aspeed.scu", 461e09cf363SJoel Stanley .version_id = 2, 462e09cf363SJoel Stanley .minimum_version_id = 2, 4631c8a2388SAndrew Jeffery .fields = (VMStateField[]) { 464e09cf363SJoel Stanley VMSTATE_UINT32_ARRAY(regs, AspeedSCUState, ASPEED_AST2600_SCU_NR_REGS), 4651c8a2388SAndrew Jeffery VMSTATE_END_OF_LIST() 4661c8a2388SAndrew Jeffery } 4671c8a2388SAndrew Jeffery }; 4681c8a2388SAndrew Jeffery 4691c8a2388SAndrew Jeffery static Property aspeed_scu_properties[] = { 4701c8a2388SAndrew Jeffery DEFINE_PROP_UINT32("silicon-rev", AspeedSCUState, silicon_rev, 0), 4711c8a2388SAndrew Jeffery DEFINE_PROP_UINT32("hw-strap1", AspeedSCUState, hw_strap1, 0), 4722ddfa281SCédric Le Goater DEFINE_PROP_UINT32("hw-strap2", AspeedSCUState, hw_strap2, 0), 473b6e70d1dSJoel Stanley DEFINE_PROP_UINT32("hw-prot-key", AspeedSCUState, hw_prot_key, 0), 4741c8a2388SAndrew Jeffery DEFINE_PROP_END_OF_LIST(), 4751c8a2388SAndrew Jeffery }; 4761c8a2388SAndrew Jeffery 4771c8a2388SAndrew Jeffery static void aspeed_scu_class_init(ObjectClass *klass, void *data) 4781c8a2388SAndrew Jeffery { 4791c8a2388SAndrew Jeffery DeviceClass *dc = DEVICE_CLASS(klass); 4801c8a2388SAndrew Jeffery dc->realize = aspeed_scu_realize; 4811c8a2388SAndrew Jeffery dc->reset = aspeed_scu_reset; 4821c8a2388SAndrew Jeffery dc->desc = "ASPEED System Control Unit"; 4831c8a2388SAndrew Jeffery dc->vmsd = &vmstate_aspeed_scu; 4844f67d30bSMarc-André Lureau device_class_set_props(dc, aspeed_scu_properties); 4851c8a2388SAndrew Jeffery } 4861c8a2388SAndrew Jeffery 4871c8a2388SAndrew Jeffery static const TypeInfo aspeed_scu_info = { 4881c8a2388SAndrew Jeffery .name = TYPE_ASPEED_SCU, 4891c8a2388SAndrew Jeffery .parent = TYPE_SYS_BUS_DEVICE, 4901c8a2388SAndrew Jeffery .instance_size = sizeof(AspeedSCUState), 4911c8a2388SAndrew Jeffery .class_init = aspeed_scu_class_init, 4929a937f6cSCédric Le Goater .class_size = sizeof(AspeedSCUClass), 4939a937f6cSCédric Le Goater .abstract = true, 4949a937f6cSCédric Le Goater }; 4959a937f6cSCédric Le Goater 4969a937f6cSCédric Le Goater static void aspeed_2400_scu_class_init(ObjectClass *klass, void *data) 4979a937f6cSCédric Le Goater { 4989a937f6cSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 4999a937f6cSCédric Le Goater AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); 5009a937f6cSCédric Le Goater 5019a937f6cSCédric Le Goater dc->desc = "ASPEED 2400 System Control Unit"; 5029a937f6cSCédric Le Goater asc->resets = ast2400_a0_resets; 5039a937f6cSCédric Le Goater asc->calc_hpll = aspeed_2400_scu_calc_hpll; 5049a937f6cSCédric Le Goater asc->apb_divider = 2; 505e09cf363SJoel Stanley asc->nr_regs = ASPEED_SCU_NR_REGS; 506*c7e1f572SJoel Stanley asc->ops = &aspeed_ast2400_scu_ops; 5079a937f6cSCédric Le Goater } 5089a937f6cSCédric Le Goater 5099a937f6cSCédric Le Goater static const TypeInfo aspeed_2400_scu_info = { 5109a937f6cSCédric Le Goater .name = TYPE_ASPEED_2400_SCU, 5119a937f6cSCédric Le Goater .parent = TYPE_ASPEED_SCU, 5129a937f6cSCédric Le Goater .instance_size = sizeof(AspeedSCUState), 5139a937f6cSCédric Le Goater .class_init = aspeed_2400_scu_class_init, 5149a937f6cSCédric Le Goater }; 5159a937f6cSCédric Le Goater 5169a937f6cSCédric Le Goater static void aspeed_2500_scu_class_init(ObjectClass *klass, void *data) 5179a937f6cSCédric Le Goater { 5189a937f6cSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 5199a937f6cSCédric Le Goater AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); 5209a937f6cSCédric Le Goater 5219a937f6cSCédric Le Goater dc->desc = "ASPEED 2500 System Control Unit"; 5229a937f6cSCédric Le Goater asc->resets = ast2500_a1_resets; 5239a937f6cSCédric Le Goater asc->calc_hpll = aspeed_2500_scu_calc_hpll; 5249a937f6cSCédric Le Goater asc->apb_divider = 4; 525e09cf363SJoel Stanley asc->nr_regs = ASPEED_SCU_NR_REGS; 526*c7e1f572SJoel Stanley asc->ops = &aspeed_ast2500_scu_ops; 5279a937f6cSCédric Le Goater } 5289a937f6cSCédric Le Goater 5299a937f6cSCédric Le Goater static const TypeInfo aspeed_2500_scu_info = { 5309a937f6cSCédric Le Goater .name = TYPE_ASPEED_2500_SCU, 5319a937f6cSCédric Le Goater .parent = TYPE_ASPEED_SCU, 5329a937f6cSCédric Le Goater .instance_size = sizeof(AspeedSCUState), 5339a937f6cSCédric Le Goater .class_init = aspeed_2500_scu_class_init, 5341c8a2388SAndrew Jeffery }; 5351c8a2388SAndrew Jeffery 536e09cf363SJoel Stanley static uint64_t aspeed_ast2600_scu_read(void *opaque, hwaddr offset, 537e09cf363SJoel Stanley unsigned size) 538e09cf363SJoel Stanley { 539e09cf363SJoel Stanley AspeedSCUState *s = ASPEED_SCU(opaque); 540e09cf363SJoel Stanley int reg = TO_REG(offset); 541e09cf363SJoel Stanley 542e09cf363SJoel Stanley if (reg >= ASPEED_AST2600_SCU_NR_REGS) { 543e09cf363SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 544e09cf363SJoel Stanley "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", 545e09cf363SJoel Stanley __func__, offset); 546e09cf363SJoel Stanley return 0; 547e09cf363SJoel Stanley } 548e09cf363SJoel Stanley 549e09cf363SJoel Stanley switch (reg) { 550e09cf363SJoel Stanley case AST2600_HPLL_EXT: 551e09cf363SJoel Stanley case AST2600_EPLL_EXT: 552e09cf363SJoel Stanley case AST2600_MPLL_EXT: 553e09cf363SJoel Stanley /* PLLs are always "locked" */ 554e09cf363SJoel Stanley return s->regs[reg] | BIT(31); 555e09cf363SJoel Stanley case AST2600_RNG_DATA: 556e09cf363SJoel Stanley /* 557e09cf363SJoel Stanley * On hardware, RNG_DATA works regardless of the state of the 558e09cf363SJoel Stanley * enable bit in RNG_CTRL 559e09cf363SJoel Stanley * 560e09cf363SJoel Stanley * TODO: Check this is true for ast2600 561e09cf363SJoel Stanley */ 562e09cf363SJoel Stanley s->regs[AST2600_RNG_DATA] = aspeed_scu_get_random(); 563e09cf363SJoel Stanley break; 564e09cf363SJoel Stanley } 565e09cf363SJoel Stanley 566e09cf363SJoel Stanley return s->regs[reg]; 567e09cf363SJoel Stanley } 568e09cf363SJoel Stanley 569310b5bc6SJoel Stanley static void aspeed_ast2600_scu_write(void *opaque, hwaddr offset, 570310b5bc6SJoel Stanley uint64_t data64, unsigned size) 571e09cf363SJoel Stanley { 572e09cf363SJoel Stanley AspeedSCUState *s = ASPEED_SCU(opaque); 573e09cf363SJoel Stanley int reg = TO_REG(offset); 574310b5bc6SJoel Stanley /* Truncate here so bitwise operations below behave as expected */ 575310b5bc6SJoel Stanley uint32_t data = data64; 576e09cf363SJoel Stanley 577e09cf363SJoel Stanley if (reg >= ASPEED_AST2600_SCU_NR_REGS) { 578e09cf363SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 579e09cf363SJoel Stanley "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 580e09cf363SJoel Stanley __func__, offset); 581e09cf363SJoel Stanley return; 582e09cf363SJoel Stanley } 583e09cf363SJoel Stanley 584e09cf363SJoel Stanley if (reg > PROT_KEY && !s->regs[PROT_KEY]) { 585e09cf363SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__); 586e09cf363SJoel Stanley } 587e09cf363SJoel Stanley 588e09cf363SJoel Stanley trace_aspeed_scu_write(offset, size, data); 589e09cf363SJoel Stanley 590e09cf363SJoel Stanley switch (reg) { 591e09cf363SJoel Stanley case AST2600_PROT_KEY: 592e09cf363SJoel Stanley s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0; 593e09cf363SJoel Stanley return; 594e09cf363SJoel Stanley case AST2600_HW_STRAP1: 595e09cf363SJoel Stanley case AST2600_HW_STRAP2: 596e09cf363SJoel Stanley if (s->regs[reg + 2]) { 597e09cf363SJoel Stanley return; 598e09cf363SJoel Stanley } 599e09cf363SJoel Stanley /* fall through */ 600e09cf363SJoel Stanley case AST2600_SYS_RST_CTRL: 601e09cf363SJoel Stanley case AST2600_SYS_RST_CTRL2: 602310b5bc6SJoel Stanley case AST2600_CLK_STOP_CTRL: 603310b5bc6SJoel Stanley case AST2600_CLK_STOP_CTRL2: 604e09cf363SJoel Stanley /* W1S (Write 1 to set) registers */ 605e09cf363SJoel Stanley s->regs[reg] |= data; 606e09cf363SJoel Stanley return; 607e09cf363SJoel Stanley case AST2600_SYS_RST_CTRL_CLR: 608e09cf363SJoel Stanley case AST2600_SYS_RST_CTRL2_CLR: 609310b5bc6SJoel Stanley case AST2600_CLK_STOP_CTRL_CLR: 610310b5bc6SJoel Stanley case AST2600_CLK_STOP_CTRL2_CLR: 611e09cf363SJoel Stanley case AST2600_HW_STRAP1_CLR: 612e09cf363SJoel Stanley case AST2600_HW_STRAP2_CLR: 613310b5bc6SJoel Stanley /* 614310b5bc6SJoel Stanley * W1C (Write 1 to clear) registers are offset by one address from 615310b5bc6SJoel Stanley * the data register 616310b5bc6SJoel Stanley */ 617310b5bc6SJoel Stanley s->regs[reg - 1] &= ~data; 618e09cf363SJoel Stanley return; 619e09cf363SJoel Stanley 620e09cf363SJoel Stanley case AST2600_RNG_DATA: 621e09cf363SJoel Stanley case AST2600_SILICON_REV: 622e09cf363SJoel Stanley case AST2600_SILICON_REV2: 623e09cf363SJoel Stanley /* Add read only registers here */ 624e09cf363SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 625e09cf363SJoel Stanley "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n", 626e09cf363SJoel Stanley __func__, offset); 627e09cf363SJoel Stanley return; 628e09cf363SJoel Stanley } 629e09cf363SJoel Stanley 630e09cf363SJoel Stanley s->regs[reg] = data; 631e09cf363SJoel Stanley } 632e09cf363SJoel Stanley 633e09cf363SJoel Stanley static const MemoryRegionOps aspeed_ast2600_scu_ops = { 634e09cf363SJoel Stanley .read = aspeed_ast2600_scu_read, 635e09cf363SJoel Stanley .write = aspeed_ast2600_scu_write, 636e09cf363SJoel Stanley .endianness = DEVICE_LITTLE_ENDIAN, 637e09cf363SJoel Stanley .valid.min_access_size = 4, 638e09cf363SJoel Stanley .valid.max_access_size = 4, 639e09cf363SJoel Stanley .valid.unaligned = false, 640e09cf363SJoel Stanley }; 641e09cf363SJoel Stanley 642e09cf363SJoel Stanley static const uint32_t ast2600_a0_resets[ASPEED_AST2600_SCU_NR_REGS] = { 643e09cf363SJoel Stanley [AST2600_SILICON_REV] = AST2600_SILICON_REV, 644e09cf363SJoel Stanley [AST2600_SILICON_REV2] = AST2600_SILICON_REV, 645e09cf363SJoel Stanley [AST2600_SYS_RST_CTRL] = 0xF7CFFEDC | 0x100, 646e09cf363SJoel Stanley [AST2600_SYS_RST_CTRL2] = 0xFFFFFFFC, 647e09cf363SJoel Stanley [AST2600_CLK_STOP_CTRL] = 0xEFF43E8B, 648e09cf363SJoel Stanley [AST2600_CLK_STOP_CTRL2] = 0xFFF0FFF0, 6491550d726SJoel Stanley [AST2600_SDRAM_HANDSHAKE] = 0x00000040, /* SoC completed DRAM init */ 650e09cf363SJoel Stanley [AST2600_HPLL_PARAM] = 0x1000405F, 651e09cf363SJoel Stanley }; 652e09cf363SJoel Stanley 653e09cf363SJoel Stanley static void aspeed_ast2600_scu_reset(DeviceState *dev) 654e09cf363SJoel Stanley { 655e09cf363SJoel Stanley AspeedSCUState *s = ASPEED_SCU(dev); 656e09cf363SJoel Stanley AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev); 657e09cf363SJoel Stanley 658e09cf363SJoel Stanley memcpy(s->regs, asc->resets, asc->nr_regs * 4); 659e09cf363SJoel Stanley 660e09cf363SJoel Stanley s->regs[AST2600_SILICON_REV] = s->silicon_rev; 661e09cf363SJoel Stanley s->regs[AST2600_SILICON_REV2] = s->silicon_rev; 662e09cf363SJoel Stanley s->regs[AST2600_HW_STRAP1] = s->hw_strap1; 663e09cf363SJoel Stanley s->regs[AST2600_HW_STRAP2] = s->hw_strap2; 664e09cf363SJoel Stanley s->regs[PROT_KEY] = s->hw_prot_key; 665e09cf363SJoel Stanley } 666e09cf363SJoel Stanley 667e09cf363SJoel Stanley static void aspeed_2600_scu_class_init(ObjectClass *klass, void *data) 668e09cf363SJoel Stanley { 669e09cf363SJoel Stanley DeviceClass *dc = DEVICE_CLASS(klass); 670e09cf363SJoel Stanley AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); 671e09cf363SJoel Stanley 672e09cf363SJoel Stanley dc->desc = "ASPEED 2600 System Control Unit"; 673e09cf363SJoel Stanley dc->reset = aspeed_ast2600_scu_reset; 674e09cf363SJoel Stanley asc->resets = ast2600_a0_resets; 675e09cf363SJoel Stanley asc->calc_hpll = aspeed_2500_scu_calc_hpll; /* No change since AST2500 */ 676e09cf363SJoel Stanley asc->apb_divider = 4; 677e09cf363SJoel Stanley asc->nr_regs = ASPEED_AST2600_SCU_NR_REGS; 678e09cf363SJoel Stanley asc->ops = &aspeed_ast2600_scu_ops; 679e09cf363SJoel Stanley } 680e09cf363SJoel Stanley 681e09cf363SJoel Stanley static const TypeInfo aspeed_2600_scu_info = { 682e09cf363SJoel Stanley .name = TYPE_ASPEED_2600_SCU, 683e09cf363SJoel Stanley .parent = TYPE_ASPEED_SCU, 684e09cf363SJoel Stanley .instance_size = sizeof(AspeedSCUState), 685e09cf363SJoel Stanley .class_init = aspeed_2600_scu_class_init, 686e09cf363SJoel Stanley }; 687e09cf363SJoel Stanley 6881c8a2388SAndrew Jeffery static void aspeed_scu_register_types(void) 6891c8a2388SAndrew Jeffery { 6901c8a2388SAndrew Jeffery type_register_static(&aspeed_scu_info); 6919a937f6cSCédric Le Goater type_register_static(&aspeed_2400_scu_info); 6929a937f6cSCédric Le Goater type_register_static(&aspeed_2500_scu_info); 693e09cf363SJoel Stanley type_register_static(&aspeed_2600_scu_info); 6941c8a2388SAndrew Jeffery } 6951c8a2388SAndrew Jeffery 6961c8a2388SAndrew Jeffery type_init(aspeed_scu_register_types); 697