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) 807ffe647fSJoel Stanley #define CHIP_ID0 TO_REG(0x150) 817ffe647fSJoel Stanley #define CHIP_ID1 TO_REG(0x154) 821c8a2388SAndrew Jeffery #define UART_HPLL_CLK TO_REG(0x160) 831c8a2388SAndrew Jeffery #define PCIE_CTRL TO_REG(0x180) 841c8a2388SAndrew Jeffery #define BMC_MMIO_CTRL TO_REG(0x184) 851c8a2388SAndrew Jeffery #define RELOC_DECODE_BASE1 TO_REG(0x188) 861c8a2388SAndrew Jeffery #define RELOC_DECODE_BASE2 TO_REG(0x18C) 871c8a2388SAndrew Jeffery #define MAILBOX_DECODE_BASE TO_REG(0x190) 881c8a2388SAndrew Jeffery #define SRAM_DECODE_BASE1 TO_REG(0x194) 891c8a2388SAndrew Jeffery #define SRAM_DECODE_BASE2 TO_REG(0x198) 901c8a2388SAndrew Jeffery #define BMC_REV TO_REG(0x19C) 911c8a2388SAndrew Jeffery #define BMC_DEV_ID TO_REG(0x1A4) 921c8a2388SAndrew Jeffery 93e09cf363SJoel Stanley #define AST2600_PROT_KEY TO_REG(0x00) 94e09cf363SJoel Stanley #define AST2600_SILICON_REV TO_REG(0x04) 95e09cf363SJoel Stanley #define AST2600_SILICON_REV2 TO_REG(0x14) 96e09cf363SJoel Stanley #define AST2600_SYS_RST_CTRL TO_REG(0x40) 97e09cf363SJoel Stanley #define AST2600_SYS_RST_CTRL_CLR TO_REG(0x44) 98e09cf363SJoel Stanley #define AST2600_SYS_RST_CTRL2 TO_REG(0x50) 99e09cf363SJoel Stanley #define AST2600_SYS_RST_CTRL2_CLR TO_REG(0x54) 100e09cf363SJoel Stanley #define AST2600_CLK_STOP_CTRL TO_REG(0x80) 101e09cf363SJoel Stanley #define AST2600_CLK_STOP_CTRL_CLR TO_REG(0x84) 102e09cf363SJoel Stanley #define AST2600_CLK_STOP_CTRL2 TO_REG(0x90) 103310b5bc6SJoel Stanley #define AST2600_CLK_STOP_CTRL2_CLR TO_REG(0x94) 104c5811bb3SJoel Stanley #define AST2600_DEBUG_CTRL TO_REG(0xC8) 105c5811bb3SJoel Stanley #define AST2600_DEBUG_CTRL2 TO_REG(0xD8) 1061550d726SJoel Stanley #define AST2600_SDRAM_HANDSHAKE TO_REG(0x100) 107e09cf363SJoel Stanley #define AST2600_HPLL_PARAM TO_REG(0x200) 108e09cf363SJoel Stanley #define AST2600_HPLL_EXT TO_REG(0x204) 109c5811bb3SJoel Stanley #define AST2600_APLL_PARAM TO_REG(0x210) 110c5811bb3SJoel Stanley #define AST2600_APLL_EXT TO_REG(0x214) 111c5811bb3SJoel Stanley #define AST2600_MPLL_PARAM TO_REG(0x220) 112e09cf363SJoel Stanley #define AST2600_MPLL_EXT TO_REG(0x224) 113c5811bb3SJoel Stanley #define AST2600_EPLL_PARAM TO_REG(0x240) 114e09cf363SJoel Stanley #define AST2600_EPLL_EXT TO_REG(0x244) 115c5811bb3SJoel Stanley #define AST2600_DPLL_PARAM TO_REG(0x260) 116c5811bb3SJoel Stanley #define AST2600_DPLL_EXT TO_REG(0x264) 117e09cf363SJoel Stanley #define AST2600_CLK_SEL TO_REG(0x300) 118e09cf363SJoel Stanley #define AST2600_CLK_SEL2 TO_REG(0x304) 119c5811bb3SJoel Stanley #define AST2600_CLK_SEL3 TO_REG(0x308) 120c5811bb3SJoel Stanley #define AST2600_CLK_SEL4 TO_REG(0x310) 121c5811bb3SJoel Stanley #define AST2600_CLK_SEL5 TO_REG(0x314) 1229dca4556SPeter Delevoryas #define AST2600_UARTCLK TO_REG(0x338) 1239dca4556SPeter Delevoryas #define AST2600_HUARTCLK TO_REG(0x33C) 124e09cf363SJoel Stanley #define AST2600_HW_STRAP1 TO_REG(0x500) 125e09cf363SJoel Stanley #define AST2600_HW_STRAP1_CLR TO_REG(0x504) 126e09cf363SJoel Stanley #define AST2600_HW_STRAP1_PROT TO_REG(0x508) 127e09cf363SJoel Stanley #define AST2600_HW_STRAP2 TO_REG(0x510) 128e09cf363SJoel Stanley #define AST2600_HW_STRAP2_CLR TO_REG(0x514) 129e09cf363SJoel Stanley #define AST2600_HW_STRAP2_PROT TO_REG(0x518) 130e09cf363SJoel Stanley #define AST2600_RNG_CTRL TO_REG(0x524) 131e09cf363SJoel Stanley #define AST2600_RNG_DATA TO_REG(0x540) 1327ffe647fSJoel Stanley #define AST2600_CHIP_ID0 TO_REG(0x5B0) 1337ffe647fSJoel Stanley #define AST2600_CHIP_ID1 TO_REG(0x5B4) 134e09cf363SJoel Stanley 135e09cf363SJoel Stanley #define AST2600_CLK TO_REG(0x40) 136e09cf363SJoel Stanley 137e7c8106dSJamin Lin #define AST2700_SILICON_REV TO_REG(0x00) 138e7c8106dSJamin Lin #define AST2700_HW_STRAP1 TO_REG(0x10) 139e7c8106dSJamin Lin #define AST2700_HW_STRAP1_CLR TO_REG(0x14) 140e7c8106dSJamin Lin #define AST2700_HW_STRAP1_LOCK TO_REG(0x20) 141e7c8106dSJamin Lin #define AST2700_HW_STRAP1_SEC1 TO_REG(0x24) 142e7c8106dSJamin Lin #define AST2700_HW_STRAP1_SEC2 TO_REG(0x28) 143e7c8106dSJamin Lin #define AST2700_HW_STRAP1_SEC3 TO_REG(0x2C) 144e7c8106dSJamin Lin 145e7c8106dSJamin Lin #define AST2700_SCU_CLK_SEL_1 TO_REG(0x280) 146e7c8106dSJamin Lin #define AST2700_SCU_HPLL_PARAM TO_REG(0x300) 147e7c8106dSJamin Lin #define AST2700_SCU_HPLL_EXT_PARAM TO_REG(0x304) 148e7c8106dSJamin Lin #define AST2700_SCU_DPLL_PARAM TO_REG(0x308) 149e7c8106dSJamin Lin #define AST2700_SCU_DPLL_EXT_PARAM TO_REG(0x30c) 150e7c8106dSJamin Lin #define AST2700_SCU_MPLL_PARAM TO_REG(0x310) 151e7c8106dSJamin Lin #define AST2700_SCU_MPLL_EXT_PARAM TO_REG(0x314) 152e7c8106dSJamin Lin #define AST2700_SCU_D1CLK_PARAM TO_REG(0x320) 153e7c8106dSJamin Lin #define AST2700_SCU_D2CLK_PARAM TO_REG(0x330) 154e7c8106dSJamin Lin #define AST2700_SCU_CRT1CLK_PARAM TO_REG(0x340) 155e7c8106dSJamin Lin #define AST2700_SCU_CRT2CLK_PARAM TO_REG(0x350) 156e7c8106dSJamin Lin #define AST2700_SCU_MPHYCLK_PARAM TO_REG(0x360) 157e7c8106dSJamin Lin #define AST2700_SCU_FREQ_CNTR TO_REG(0x3b0) 158e7c8106dSJamin Lin #define AST2700_SCU_CPU_SCRATCH_0 TO_REG(0x780) 159e7c8106dSJamin Lin #define AST2700_SCU_CPU_SCRATCH_1 TO_REG(0x784) 1602d082feaSJamin Lin #define AST2700_SCU_VGA_SCRATCH_0 TO_REG(0x900) 161e7c8106dSJamin Lin 162e7c8106dSJamin Lin #define AST2700_SCUIO_CLK_STOP_CTL_1 TO_REG(0x240) 163e7c8106dSJamin Lin #define AST2700_SCUIO_CLK_STOP_CLR_1 TO_REG(0x244) 164e7c8106dSJamin Lin #define AST2700_SCUIO_CLK_STOP_CTL_2 TO_REG(0x260) 165e7c8106dSJamin Lin #define AST2700_SCUIO_CLK_STOP_CLR_2 TO_REG(0x264) 166e7c8106dSJamin Lin #define AST2700_SCUIO_CLK_SEL_1 TO_REG(0x280) 167e7c8106dSJamin Lin #define AST2700_SCUIO_CLK_SEL_2 TO_REG(0x284) 168e7c8106dSJamin Lin #define AST2700_SCUIO_HPLL_PARAM TO_REG(0x300) 169e7c8106dSJamin Lin #define AST2700_SCUIO_HPLL_EXT_PARAM TO_REG(0x304) 170e7c8106dSJamin Lin #define AST2700_SCUIO_APLL_PARAM TO_REG(0x310) 171e7c8106dSJamin Lin #define AST2700_SCUIO_APLL_EXT_PARAM TO_REG(0x314) 172e7c8106dSJamin Lin #define AST2700_SCUIO_DPLL_PARAM TO_REG(0x320) 173e7c8106dSJamin Lin #define AST2700_SCUIO_DPLL_EXT_PARAM TO_REG(0x324) 174e7c8106dSJamin Lin #define AST2700_SCUIO_DPLL_PARAM_READ TO_REG(0x328) 175e7c8106dSJamin Lin #define AST2700_SCUIO_DPLL_EXT_PARAM_READ TO_REG(0x32c) 176e7c8106dSJamin Lin #define AST2700_SCUIO_UARTCLK_GEN TO_REG(0x330) 177e7c8106dSJamin Lin #define AST2700_SCUIO_HUARTCLK_GEN TO_REG(0x334) 178e7c8106dSJamin Lin #define AST2700_SCUIO_CLK_DUTY_MEAS_RST TO_REG(0x388) 179e7c8106dSJamin Lin 180c491e152SCédric Le Goater #define SCU_IO_REGION_SIZE 0x1000 1811c8a2388SAndrew Jeffery 1821c8a2388SAndrew Jeffery static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = { 1831c8a2388SAndrew Jeffery [SYS_RST_CTRL] = 0xFFCFFEDCU, 1841c8a2388SAndrew Jeffery [CLK_SEL] = 0xF3F40000U, 1851c8a2388SAndrew Jeffery [CLK_STOP_CTRL] = 0x19FC3E8BU, 1861c8a2388SAndrew Jeffery [D2PLL_PARAM] = 0x00026108U, 1871c8a2388SAndrew Jeffery [MPLL_PARAM] = 0x00030291U, 1881c8a2388SAndrew Jeffery [HPLL_PARAM] = 0x00000291U, 1891c8a2388SAndrew Jeffery [MISC_CTRL1] = 0x00000010U, 1901c8a2388SAndrew Jeffery [PCI_CTRL1] = 0x20001A03U, 1911c8a2388SAndrew Jeffery [PCI_CTRL2] = 0x20001A03U, 1921c8a2388SAndrew Jeffery [PCI_CTRL3] = 0x04000030U, 1931c8a2388SAndrew Jeffery [SYS_RST_STATUS] = 0x00000001U, 1941c8a2388SAndrew Jeffery [SOC_SCRATCH1] = 0x000000C0U, /* SoC completed DRAM init */ 1951c8a2388SAndrew Jeffery [MISC_CTRL2] = 0x00000023U, 1961c8a2388SAndrew Jeffery [RNG_CTRL] = 0x0000000EU, 1971c8a2388SAndrew Jeffery [PINMUX_CTRL2] = 0x0000F000U, 1981c8a2388SAndrew Jeffery [PINMUX_CTRL3] = 0x01000000U, 1991c8a2388SAndrew Jeffery [PINMUX_CTRL4] = 0x000000FFU, 2001c8a2388SAndrew Jeffery [PINMUX_CTRL5] = 0x0000A000U, 2011c8a2388SAndrew Jeffery [WDT_RST_CTRL] = 0x003FFFF3U, 2021c8a2388SAndrew Jeffery [PINMUX_CTRL8] = 0xFFFF0000U, 2031c8a2388SAndrew Jeffery [PINMUX_CTRL9] = 0x000FFFFFU, 2041c8a2388SAndrew Jeffery [FREE_CNTR4] = 0x000000FFU, 2051c8a2388SAndrew Jeffery [FREE_CNTR4_EXT] = 0x000000FFU, 2061c8a2388SAndrew Jeffery [CPU2_BASE_SEG1] = 0x80000000U, 2071c8a2388SAndrew Jeffery [CPU2_BASE_SEG4] = 0x1E600000U, 2081c8a2388SAndrew Jeffery [CPU2_BASE_SEG5] = 0xC0000000U, 2091c8a2388SAndrew Jeffery [UART_HPLL_CLK] = 0x00001903U, 2101c8a2388SAndrew Jeffery [PCIE_CTRL] = 0x0000007BU, 2111c8a2388SAndrew Jeffery [BMC_DEV_ID] = 0x00002402U 2121c8a2388SAndrew Jeffery }; 2131c8a2388SAndrew Jeffery 214365aff1eSCédric Le Goater /* SCU70 bit 23: 0 24Mhz. bit 11:9: 0b001 AXI:ABH ratio 2:1 */ 215365aff1eSCédric Le Goater /* AST2500 revision A1 */ 216365aff1eSCédric Le Goater 217365aff1eSCédric Le Goater static const uint32_t ast2500_a1_resets[ASPEED_SCU_NR_REGS] = { 218365aff1eSCédric Le Goater [SYS_RST_CTRL] = 0xFFCFFEDCU, 219365aff1eSCédric Le Goater [CLK_SEL] = 0xF3F40000U, 220365aff1eSCédric Le Goater [CLK_STOP_CTRL] = 0x19FC3E8BU, 221365aff1eSCédric Le Goater [D2PLL_PARAM] = 0x00026108U, 222365aff1eSCédric Le Goater [MPLL_PARAM] = 0x00030291U, 223365aff1eSCédric Le Goater [HPLL_PARAM] = 0x93000400U, 224365aff1eSCédric Le Goater [MISC_CTRL1] = 0x00000010U, 225365aff1eSCédric Le Goater [PCI_CTRL1] = 0x20001A03U, 226365aff1eSCédric Le Goater [PCI_CTRL2] = 0x20001A03U, 227365aff1eSCédric Le Goater [PCI_CTRL3] = 0x04000030U, 228365aff1eSCédric Le Goater [SYS_RST_STATUS] = 0x00000001U, 229365aff1eSCédric Le Goater [SOC_SCRATCH1] = 0x000000C0U, /* SoC completed DRAM init */ 230365aff1eSCédric Le Goater [MISC_CTRL2] = 0x00000023U, 231365aff1eSCédric Le Goater [RNG_CTRL] = 0x0000000EU, 232365aff1eSCédric Le Goater [PINMUX_CTRL2] = 0x0000F000U, 233365aff1eSCédric Le Goater [PINMUX_CTRL3] = 0x03000000U, 234365aff1eSCédric Le Goater [PINMUX_CTRL4] = 0x00000000U, 235365aff1eSCédric Le Goater [PINMUX_CTRL5] = 0x0000A000U, 236365aff1eSCédric Le Goater [WDT_RST_CTRL] = 0x023FFFF3U, 237365aff1eSCédric Le Goater [PINMUX_CTRL8] = 0xFFFF0000U, 238365aff1eSCédric Le Goater [PINMUX_CTRL9] = 0x000FFFFFU, 239365aff1eSCédric Le Goater [FREE_CNTR4] = 0x000000FFU, 240365aff1eSCédric Le Goater [FREE_CNTR4_EXT] = 0x000000FFU, 241365aff1eSCédric Le Goater [CPU2_BASE_SEG1] = 0x80000000U, 242365aff1eSCédric Le Goater [CPU2_BASE_SEG4] = 0x1E600000U, 243365aff1eSCédric Le Goater [CPU2_BASE_SEG5] = 0xC0000000U, 2447ffe647fSJoel Stanley [CHIP_ID0] = 0x1234ABCDU, 2457ffe647fSJoel Stanley [CHIP_ID1] = 0x88884444U, 246365aff1eSCédric Le Goater [UART_HPLL_CLK] = 0x00001903U, 247365aff1eSCédric Le Goater [PCIE_CTRL] = 0x0000007BU, 248365aff1eSCédric Le Goater [BMC_DEV_ID] = 0x00002402U 249365aff1eSCédric Le Goater }; 250365aff1eSCédric Le Goater 251acd9575eSJoel Stanley static uint32_t aspeed_scu_get_random(void) 252acd9575eSJoel Stanley { 253acd9575eSJoel Stanley uint32_t num; 2549d44cb5bSRichard Henderson qemu_guest_getrandom_nofail(&num, sizeof(num)); 255acd9575eSJoel Stanley return num; 256acd9575eSJoel Stanley } 257acd9575eSJoel Stanley 258a8f07376SCédric Le Goater uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s) 259fda9aaa6SCédric Le Goater { 260dd7f19a9SSteven Lee return ASPEED_SCU_GET_CLASS(s)->get_apb(s); 261dd7f19a9SSteven Lee } 262dd7f19a9SSteven Lee 263dd7f19a9SSteven Lee static uint32_t aspeed_2400_scu_get_apb_freq(AspeedSCUState *s) 264dd7f19a9SSteven Lee { 2659a937f6cSCédric Le Goater AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s); 266a8f07376SCédric Le Goater uint32_t hpll = asc->calc_hpll(s, s->regs[HPLL_PARAM]); 267fda9aaa6SCédric Le Goater 268a8f07376SCédric Le Goater return hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[CLK_SEL]) + 1) 2699a937f6cSCédric Le Goater / asc->apb_divider; 270fda9aaa6SCédric Le Goater } 271fda9aaa6SCédric Le Goater 272dd7f19a9SSteven Lee static uint32_t aspeed_2600_scu_get_apb_freq(AspeedSCUState *s) 273dd7f19a9SSteven Lee { 274dd7f19a9SSteven Lee AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s); 275dd7f19a9SSteven Lee uint32_t hpll = asc->calc_hpll(s, s->regs[AST2600_HPLL_PARAM]); 276dd7f19a9SSteven Lee 277dd7f19a9SSteven Lee return hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[AST2600_CLK_SEL]) + 1) 278dd7f19a9SSteven Lee / asc->apb_divider; 279dd7f19a9SSteven Lee } 280dd7f19a9SSteven Lee 281fa541a60SSteven Lee static uint32_t aspeed_1030_scu_get_apb_freq(AspeedSCUState *s) 282fa541a60SSteven Lee { 283fa541a60SSteven Lee AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s); 284fa541a60SSteven Lee uint32_t hpll = asc->calc_hpll(s, s->regs[AST2600_HPLL_PARAM]); 285fa541a60SSteven Lee 286fa541a60SSteven Lee return hpll / (SCU_AST1030_CLK_GET_PCLK_DIV(s->regs[AST2600_CLK_SEL4]) + 1) 287fa541a60SSteven Lee / asc->apb_divider; 288fa541a60SSteven Lee } 289fa541a60SSteven Lee 290e7c8106dSJamin Lin static uint32_t aspeed_2700_scu_get_apb_freq(AspeedSCUState *s) 291e7c8106dSJamin Lin { 292e7c8106dSJamin Lin AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s); 293e7c8106dSJamin Lin uint32_t hpll = asc->calc_hpll(s, s->regs[AST2700_SCU_HPLL_PARAM]); 294e7c8106dSJamin Lin 295e7c8106dSJamin Lin return hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[AST2700_SCU_CLK_SEL_1]) + 1) 296e7c8106dSJamin Lin / asc->apb_divider; 297e7c8106dSJamin Lin } 298e7c8106dSJamin Lin 299e7c8106dSJamin Lin static uint32_t aspeed_2700_scuio_get_apb_freq(AspeedSCUState *s) 300e7c8106dSJamin Lin { 301e7c8106dSJamin Lin AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s); 302e7c8106dSJamin Lin uint32_t hpll = asc->calc_hpll(s, s->regs[AST2700_SCUIO_HPLL_PARAM]); 303e7c8106dSJamin Lin 304e7c8106dSJamin Lin return hpll / 305e7c8106dSJamin Lin (SCUIO_AST2700_CLK_GET_PCLK_DIV(s->regs[AST2700_SCUIO_CLK_SEL_1]) + 1) 306e7c8106dSJamin Lin / asc->apb_divider; 307e7c8106dSJamin Lin } 308e7c8106dSJamin Lin 3091c8a2388SAndrew Jeffery static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size) 3101c8a2388SAndrew Jeffery { 3111c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(opaque); 3121c8a2388SAndrew Jeffery int reg = TO_REG(offset); 3131c8a2388SAndrew Jeffery 314e09cf363SJoel Stanley if (reg >= ASPEED_SCU_NR_REGS) { 3151c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 3161c8a2388SAndrew Jeffery "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", 3171c8a2388SAndrew Jeffery __func__, offset); 3181c8a2388SAndrew Jeffery return 0; 3191c8a2388SAndrew Jeffery } 3201c8a2388SAndrew Jeffery 3211c8a2388SAndrew Jeffery switch (reg) { 322acd9575eSJoel Stanley case RNG_DATA: 323e7c8106dSJamin Lin /* 324e7c8106dSJamin Lin * On hardware, RNG_DATA works regardless of 325acd9575eSJoel Stanley * the state of the enable bit in RNG_CTRL 326acd9575eSJoel Stanley */ 327acd9575eSJoel Stanley s->regs[RNG_DATA] = aspeed_scu_get_random(); 328acd9575eSJoel Stanley break; 3291c8a2388SAndrew Jeffery case WAKEUP_EN: 3301c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 3311c8a2388SAndrew Jeffery "%s: Read of write-only offset 0x%" HWADDR_PRIx "\n", 3321c8a2388SAndrew Jeffery __func__, offset); 3331c8a2388SAndrew Jeffery break; 3341c8a2388SAndrew Jeffery } 3351c8a2388SAndrew Jeffery 336673a6d16SCédric Le Goater trace_aspeed_scu_read(offset, size, s->regs[reg]); 3371c8a2388SAndrew Jeffery return s->regs[reg]; 3381c8a2388SAndrew Jeffery } 3391c8a2388SAndrew Jeffery 340c7e1f572SJoel Stanley static void aspeed_ast2400_scu_write(void *opaque, hwaddr offset, 341c7e1f572SJoel Stanley uint64_t data, unsigned size) 342c7e1f572SJoel Stanley { 343c7e1f572SJoel Stanley AspeedSCUState *s = ASPEED_SCU(opaque); 344c7e1f572SJoel Stanley int reg = TO_REG(offset); 345c7e1f572SJoel Stanley 346c7e1f572SJoel Stanley if (reg >= ASPEED_SCU_NR_REGS) { 347c7e1f572SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 348c7e1f572SJoel Stanley "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 349c7e1f572SJoel Stanley __func__, offset); 350c7e1f572SJoel Stanley return; 351c7e1f572SJoel Stanley } 352c7e1f572SJoel Stanley 353c7e1f572SJoel Stanley if (reg > PROT_KEY && reg < CPU2_BASE_SEG1 && 354c7e1f572SJoel Stanley !s->regs[PROT_KEY]) { 355c7e1f572SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__); 356c7e1f572SJoel Stanley } 357c7e1f572SJoel Stanley 358c7e1f572SJoel Stanley trace_aspeed_scu_write(offset, size, data); 359c7e1f572SJoel Stanley 360c7e1f572SJoel Stanley switch (reg) { 361c7e1f572SJoel Stanley case PROT_KEY: 362c7e1f572SJoel Stanley s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0; 363c7e1f572SJoel Stanley return; 364c7e1f572SJoel Stanley case SILICON_REV: 365c7e1f572SJoel Stanley case FREQ_CNTR_EVAL: 366c7e1f572SJoel Stanley case VGA_SCRATCH1 ... VGA_SCRATCH8: 367c7e1f572SJoel Stanley case RNG_DATA: 368c7e1f572SJoel Stanley case FREE_CNTR4: 369c7e1f572SJoel Stanley case FREE_CNTR4_EXT: 370c7e1f572SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 371c7e1f572SJoel Stanley "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n", 372c7e1f572SJoel Stanley __func__, offset); 373c7e1f572SJoel Stanley return; 374c7e1f572SJoel Stanley } 375c7e1f572SJoel Stanley 376c7e1f572SJoel Stanley s->regs[reg] = data; 377c7e1f572SJoel Stanley } 378c7e1f572SJoel Stanley 379c7e1f572SJoel Stanley static void aspeed_ast2500_scu_write(void *opaque, hwaddr offset, 380c7e1f572SJoel Stanley uint64_t data, unsigned size) 3811c8a2388SAndrew Jeffery { 3821c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(opaque); 3831c8a2388SAndrew Jeffery int reg = TO_REG(offset); 3841c8a2388SAndrew Jeffery 385e09cf363SJoel Stanley if (reg >= ASPEED_SCU_NR_REGS) { 3861c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 3871c8a2388SAndrew Jeffery "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 3881c8a2388SAndrew Jeffery __func__, offset); 3891c8a2388SAndrew Jeffery return; 3901c8a2388SAndrew Jeffery } 3911c8a2388SAndrew Jeffery 3921c8a2388SAndrew Jeffery if (reg > PROT_KEY && reg < CPU2_BASE_SEG1 && 3935c1d3a2bSHugo Landau !s->regs[PROT_KEY]) { 3941c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__); 3951c8a2388SAndrew Jeffery return; 3961c8a2388SAndrew Jeffery } 3971c8a2388SAndrew Jeffery 3981c8a2388SAndrew Jeffery trace_aspeed_scu_write(offset, size, data); 3991c8a2388SAndrew Jeffery 4001c8a2388SAndrew Jeffery switch (reg) { 4015c1d3a2bSHugo Landau case PROT_KEY: 4025c1d3a2bSHugo Landau s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0; 4035c1d3a2bSHugo Landau return; 404333b9c8aSAndrew Jeffery case HW_STRAP1: 405333b9c8aSAndrew Jeffery s->regs[HW_STRAP1] |= data; 406333b9c8aSAndrew Jeffery return; 407333b9c8aSAndrew Jeffery case SILICON_REV: 408333b9c8aSAndrew Jeffery s->regs[HW_STRAP1] &= ~data; 409333b9c8aSAndrew Jeffery return; 4101c8a2388SAndrew Jeffery case FREQ_CNTR_EVAL: 4111c8a2388SAndrew Jeffery case VGA_SCRATCH1 ... VGA_SCRATCH8: 4121c8a2388SAndrew Jeffery case RNG_DATA: 4131c8a2388SAndrew Jeffery case FREE_CNTR4: 4141c8a2388SAndrew Jeffery case FREE_CNTR4_EXT: 4157ffe647fSJoel Stanley case CHIP_ID0: 4167ffe647fSJoel Stanley case CHIP_ID1: 4171c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 4181c8a2388SAndrew Jeffery "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n", 4191c8a2388SAndrew Jeffery __func__, offset); 4201c8a2388SAndrew Jeffery return; 4211c8a2388SAndrew Jeffery } 4221c8a2388SAndrew Jeffery 4231c8a2388SAndrew Jeffery s->regs[reg] = data; 4241c8a2388SAndrew Jeffery } 4251c8a2388SAndrew Jeffery 426c7e1f572SJoel Stanley static const MemoryRegionOps aspeed_ast2400_scu_ops = { 4271c8a2388SAndrew Jeffery .read = aspeed_scu_read, 428c7e1f572SJoel Stanley .write = aspeed_ast2400_scu_write, 429c7e1f572SJoel Stanley .endianness = DEVICE_LITTLE_ENDIAN, 430740bc3a7SCédric Le Goater .valid = { 431740bc3a7SCédric Le Goater .min_access_size = 1, 432740bc3a7SCédric Le Goater .max_access_size = 4, 433740bc3a7SCédric Le Goater }, 434c7e1f572SJoel Stanley }; 435c7e1f572SJoel Stanley 436c7e1f572SJoel Stanley static const MemoryRegionOps aspeed_ast2500_scu_ops = { 437c7e1f572SJoel Stanley .read = aspeed_scu_read, 438c7e1f572SJoel Stanley .write = aspeed_ast2500_scu_write, 4391c8a2388SAndrew Jeffery .endianness = DEVICE_LITTLE_ENDIAN, 4401c8a2388SAndrew Jeffery .valid.min_access_size = 4, 4411c8a2388SAndrew Jeffery .valid.max_access_size = 4, 4421c8a2388SAndrew Jeffery .valid.unaligned = false, 4431c8a2388SAndrew Jeffery }; 4441c8a2388SAndrew Jeffery 445fda9aaa6SCédric Le Goater static uint32_t aspeed_scu_get_clkin(AspeedSCUState *s) 446fda9aaa6SCédric Le Goater { 447bad23bb6SSteven Lee if (s->hw_strap1 & SCU_HW_STRAP_CLK_25M_IN || 448bad23bb6SSteven Lee ASPEED_SCU_GET_CLASS(s)->clkin_25Mhz) { 449fda9aaa6SCédric Le Goater return 25000000; 450fda9aaa6SCédric Le Goater } else if (s->hw_strap1 & SCU_HW_STRAP_CLK_48M_IN) { 451fda9aaa6SCédric Le Goater return 48000000; 452fda9aaa6SCédric Le Goater } else { 453fda9aaa6SCédric Le Goater return 24000000; 454fda9aaa6SCédric Le Goater } 455fda9aaa6SCédric Le Goater } 456fda9aaa6SCédric Le Goater 457fda9aaa6SCédric Le Goater /* 458fda9aaa6SCédric Le Goater * Strapped frequencies for the AST2400 in MHz. They depend on the 459fda9aaa6SCédric Le Goater * clkin frequency. 460fda9aaa6SCédric Le Goater */ 461fda9aaa6SCédric Le Goater static const uint32_t hpll_ast2400_freqs[][4] = { 462fda9aaa6SCédric Le Goater { 384, 360, 336, 408 }, /* 24MHz or 48MHz */ 463fda9aaa6SCédric Le Goater { 400, 375, 350, 425 }, /* 25MHz */ 464fda9aaa6SCédric Le Goater }; 465fda9aaa6SCédric Le Goater 466a8f07376SCédric Le Goater static uint32_t aspeed_2400_scu_calc_hpll(AspeedSCUState *s, uint32_t hpll_reg) 467fda9aaa6SCédric Le Goater { 468fda9aaa6SCédric Le Goater uint8_t freq_select; 469fda9aaa6SCédric Le Goater bool clk_25m_in; 470a8f07376SCédric Le Goater uint32_t clkin = aspeed_scu_get_clkin(s); 471fda9aaa6SCédric Le Goater 472fda9aaa6SCédric Le Goater if (hpll_reg & SCU_AST2400_H_PLL_OFF) { 473fda9aaa6SCédric Le Goater return 0; 474fda9aaa6SCédric Le Goater } 475fda9aaa6SCédric Le Goater 476fda9aaa6SCédric Le Goater if (hpll_reg & SCU_AST2400_H_PLL_PROGRAMMED) { 477fda9aaa6SCédric Le Goater uint32_t multiplier = 1; 478fda9aaa6SCédric Le Goater 479fda9aaa6SCédric Le Goater if (!(hpll_reg & SCU_AST2400_H_PLL_BYPASS_EN)) { 480fda9aaa6SCédric Le Goater uint32_t n = (hpll_reg >> 5) & 0x3f; 481fda9aaa6SCédric Le Goater uint32_t od = (hpll_reg >> 4) & 0x1; 482fda9aaa6SCédric Le Goater uint32_t d = hpll_reg & 0xf; 483fda9aaa6SCédric Le Goater 484fda9aaa6SCédric Le Goater multiplier = (2 - od) * ((n + 2) / (d + 1)); 485fda9aaa6SCédric Le Goater } 486fda9aaa6SCédric Le Goater 487a8f07376SCédric Le Goater return clkin * multiplier; 488fda9aaa6SCédric Le Goater } 489fda9aaa6SCédric Le Goater 490fda9aaa6SCédric Le Goater /* HW strapping */ 491fda9aaa6SCédric Le Goater clk_25m_in = !!(s->hw_strap1 & SCU_HW_STRAP_CLK_25M_IN); 492fda9aaa6SCédric Le Goater freq_select = SCU_AST2400_HW_STRAP_GET_H_PLL_CLK(s->hw_strap1); 493fda9aaa6SCédric Le Goater 494fda9aaa6SCédric Le Goater return hpll_ast2400_freqs[clk_25m_in][freq_select] * 1000000; 495fda9aaa6SCédric Le Goater } 496fda9aaa6SCédric Le Goater 497a8f07376SCédric Le Goater static uint32_t aspeed_2500_scu_calc_hpll(AspeedSCUState *s, uint32_t hpll_reg) 498fda9aaa6SCédric Le Goater { 499fda9aaa6SCédric Le Goater uint32_t multiplier = 1; 500a8f07376SCédric Le Goater uint32_t clkin = aspeed_scu_get_clkin(s); 501fda9aaa6SCédric Le Goater 502fda9aaa6SCédric Le Goater if (hpll_reg & SCU_H_PLL_OFF) { 503fda9aaa6SCédric Le Goater return 0; 504fda9aaa6SCédric Le Goater } 505fda9aaa6SCédric Le Goater 506fda9aaa6SCédric Le Goater if (!(hpll_reg & SCU_H_PLL_BYPASS_EN)) { 507fda9aaa6SCédric Le Goater uint32_t p = (hpll_reg >> 13) & 0x3f; 508fda9aaa6SCédric Le Goater uint32_t m = (hpll_reg >> 5) & 0xff; 509fda9aaa6SCédric Le Goater uint32_t n = hpll_reg & 0x1f; 510fda9aaa6SCédric Le Goater 511fda9aaa6SCédric Le Goater multiplier = ((m + 1) / (n + 1)) / (p + 1); 512fda9aaa6SCédric Le Goater } 513fda9aaa6SCédric Le Goater 514a8f07376SCédric Le Goater return clkin * multiplier; 515fda9aaa6SCédric Le Goater } 516fda9aaa6SCédric Le Goater 517dd7f19a9SSteven Lee static uint32_t aspeed_2600_scu_calc_hpll(AspeedSCUState *s, uint32_t hpll_reg) 518dd7f19a9SSteven Lee { 519dd7f19a9SSteven Lee uint32_t multiplier = 1; 520dd7f19a9SSteven Lee uint32_t clkin = aspeed_scu_get_clkin(s); 521dd7f19a9SSteven Lee 522dd7f19a9SSteven Lee if (hpll_reg & SCU_AST2600_H_PLL_OFF) { 523dd7f19a9SSteven Lee return 0; 524dd7f19a9SSteven Lee } 525dd7f19a9SSteven Lee 526dd7f19a9SSteven Lee if (!(hpll_reg & SCU_AST2600_H_PLL_BYPASS_EN)) { 527dd7f19a9SSteven Lee uint32_t p = (hpll_reg >> 19) & 0xf; 528dd7f19a9SSteven Lee uint32_t n = (hpll_reg >> 13) & 0x3f; 529dd7f19a9SSteven Lee uint32_t m = hpll_reg & 0x1fff; 530dd7f19a9SSteven Lee 531dd7f19a9SSteven Lee multiplier = ((m + 1) / (n + 1)) / (p + 1); 532dd7f19a9SSteven Lee } 533dd7f19a9SSteven Lee 534dd7f19a9SSteven Lee return clkin * multiplier; 535dd7f19a9SSteven Lee } 536dd7f19a9SSteven Lee 5371c8a2388SAndrew Jeffery static void aspeed_scu_reset(DeviceState *dev) 5381c8a2388SAndrew Jeffery { 5391c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(dev); 5409a937f6cSCédric Le Goater AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev); 5411c8a2388SAndrew Jeffery 542e09cf363SJoel Stanley memcpy(s->regs, asc->resets, asc->nr_regs * 4); 5431c8a2388SAndrew Jeffery s->regs[SILICON_REV] = s->silicon_rev; 5441c8a2388SAndrew Jeffery s->regs[HW_STRAP1] = s->hw_strap1; 5451c8a2388SAndrew Jeffery s->regs[HW_STRAP2] = s->hw_strap2; 546b6e70d1dSJoel Stanley s->regs[PROT_KEY] = s->hw_prot_key; 5471c8a2388SAndrew Jeffery } 5481c8a2388SAndrew Jeffery 549365aff1eSCédric Le Goater static uint32_t aspeed_silicon_revs[] = { 550365aff1eSCédric Le Goater AST2400_A0_SILICON_REV, 5516efbac90SCédric Le Goater AST2400_A1_SILICON_REV, 552365aff1eSCédric Le Goater AST2500_A0_SILICON_REV, 553365aff1eSCédric Le Goater AST2500_A1_SILICON_REV, 554e09cf363SJoel Stanley AST2600_A0_SILICON_REV, 5557582591aSJoel Stanley AST2600_A1_SILICON_REV, 556c5811bb3SJoel Stanley AST2600_A2_SILICON_REV, 557c5811bb3SJoel Stanley AST2600_A3_SILICON_REV, 558fa541a60SSteven Lee AST1030_A0_SILICON_REV, 559fa541a60SSteven Lee AST1030_A1_SILICON_REV, 560e7c8106dSJamin Lin AST2700_A0_SILICON_REV, 561e7c8106dSJamin Lin AST2720_A0_SILICON_REV, 562e7c8106dSJamin Lin AST2750_A0_SILICON_REV, 563365aff1eSCédric Le Goater }; 5641c8a2388SAndrew Jeffery 56579a9f323SCédric Le Goater bool is_supported_silicon_rev(uint32_t silicon_rev) 5661c8a2388SAndrew Jeffery { 5671c8a2388SAndrew Jeffery int i; 5681c8a2388SAndrew Jeffery 5691c8a2388SAndrew Jeffery for (i = 0; i < ARRAY_SIZE(aspeed_silicon_revs); i++) { 5701c8a2388SAndrew Jeffery if (silicon_rev == aspeed_silicon_revs[i]) { 5711c8a2388SAndrew Jeffery return true; 5721c8a2388SAndrew Jeffery } 5731c8a2388SAndrew Jeffery } 5741c8a2388SAndrew Jeffery 5751c8a2388SAndrew Jeffery return false; 5761c8a2388SAndrew Jeffery } 5771c8a2388SAndrew Jeffery 5781c8a2388SAndrew Jeffery static void aspeed_scu_realize(DeviceState *dev, Error **errp) 5791c8a2388SAndrew Jeffery { 5801c8a2388SAndrew Jeffery SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 5811c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(dev); 582e09cf363SJoel Stanley AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev); 5831c8a2388SAndrew Jeffery 5841c8a2388SAndrew Jeffery if (!is_supported_silicon_rev(s->silicon_rev)) { 5851c8a2388SAndrew Jeffery error_setg(errp, "Unknown silicon revision: 0x%" PRIx32, 5861c8a2388SAndrew Jeffery s->silicon_rev); 5871c8a2388SAndrew Jeffery return; 5881c8a2388SAndrew Jeffery } 5891c8a2388SAndrew Jeffery 590e09cf363SJoel Stanley memory_region_init_io(&s->iomem, OBJECT(s), asc->ops, s, 5911c8a2388SAndrew Jeffery TYPE_ASPEED_SCU, SCU_IO_REGION_SIZE); 5921c8a2388SAndrew Jeffery 5931c8a2388SAndrew Jeffery sysbus_init_mmio(sbd, &s->iomem); 5941c8a2388SAndrew Jeffery } 5951c8a2388SAndrew Jeffery 5961c8a2388SAndrew Jeffery static const VMStateDescription vmstate_aspeed_scu = { 5971c8a2388SAndrew Jeffery .name = "aspeed.scu", 598e09cf363SJoel Stanley .version_id = 2, 599e09cf363SJoel Stanley .minimum_version_id = 2, 600e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 601e09cf363SJoel Stanley VMSTATE_UINT32_ARRAY(regs, AspeedSCUState, ASPEED_AST2600_SCU_NR_REGS), 6021c8a2388SAndrew Jeffery VMSTATE_END_OF_LIST() 6031c8a2388SAndrew Jeffery } 6041c8a2388SAndrew Jeffery }; 6051c8a2388SAndrew Jeffery 60630029973SRichard Henderson static const Property aspeed_scu_properties[] = { 6071c8a2388SAndrew Jeffery DEFINE_PROP_UINT32("silicon-rev", AspeedSCUState, silicon_rev, 0), 6081c8a2388SAndrew Jeffery DEFINE_PROP_UINT32("hw-strap1", AspeedSCUState, hw_strap1, 0), 6092ddfa281SCédric Le Goater DEFINE_PROP_UINT32("hw-strap2", AspeedSCUState, hw_strap2, 0), 610b6e70d1dSJoel Stanley DEFINE_PROP_UINT32("hw-prot-key", AspeedSCUState, hw_prot_key, 0), 6111c8a2388SAndrew Jeffery }; 6121c8a2388SAndrew Jeffery 6131c8a2388SAndrew Jeffery static void aspeed_scu_class_init(ObjectClass *klass, void *data) 6141c8a2388SAndrew Jeffery { 6151c8a2388SAndrew Jeffery DeviceClass *dc = DEVICE_CLASS(klass); 6161c8a2388SAndrew Jeffery dc->realize = aspeed_scu_realize; 617e3d08143SPeter Maydell device_class_set_legacy_reset(dc, aspeed_scu_reset); 6181c8a2388SAndrew Jeffery dc->desc = "ASPEED System Control Unit"; 6191c8a2388SAndrew Jeffery dc->vmsd = &vmstate_aspeed_scu; 6204f67d30bSMarc-André Lureau device_class_set_props(dc, aspeed_scu_properties); 6211c8a2388SAndrew Jeffery } 6221c8a2388SAndrew Jeffery 6231c8a2388SAndrew Jeffery static const TypeInfo aspeed_scu_info = { 6241c8a2388SAndrew Jeffery .name = TYPE_ASPEED_SCU, 6251c8a2388SAndrew Jeffery .parent = TYPE_SYS_BUS_DEVICE, 6261c8a2388SAndrew Jeffery .instance_size = sizeof(AspeedSCUState), 6271c8a2388SAndrew Jeffery .class_init = aspeed_scu_class_init, 6289a937f6cSCédric Le Goater .class_size = sizeof(AspeedSCUClass), 6299a937f6cSCédric Le Goater .abstract = true, 6309a937f6cSCédric Le Goater }; 6319a937f6cSCédric Le Goater 6329a937f6cSCédric Le Goater static void aspeed_2400_scu_class_init(ObjectClass *klass, void *data) 6339a937f6cSCédric Le Goater { 6349a937f6cSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 6359a937f6cSCédric Le Goater AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); 6369a937f6cSCédric Le Goater 6379a937f6cSCédric Le Goater dc->desc = "ASPEED 2400 System Control Unit"; 6389a937f6cSCédric Le Goater asc->resets = ast2400_a0_resets; 6399a937f6cSCédric Le Goater asc->calc_hpll = aspeed_2400_scu_calc_hpll; 640dd7f19a9SSteven Lee asc->get_apb = aspeed_2400_scu_get_apb_freq; 6419a937f6cSCédric Le Goater asc->apb_divider = 2; 642e09cf363SJoel Stanley asc->nr_regs = ASPEED_SCU_NR_REGS; 643bad23bb6SSteven Lee asc->clkin_25Mhz = false; 644c7e1f572SJoel Stanley asc->ops = &aspeed_ast2400_scu_ops; 6459a937f6cSCédric Le Goater } 6469a937f6cSCédric Le Goater 6479a937f6cSCédric Le Goater static const TypeInfo aspeed_2400_scu_info = { 6489a937f6cSCédric Le Goater .name = TYPE_ASPEED_2400_SCU, 6499a937f6cSCédric Le Goater .parent = TYPE_ASPEED_SCU, 6509a937f6cSCédric Le Goater .instance_size = sizeof(AspeedSCUState), 6519a937f6cSCédric Le Goater .class_init = aspeed_2400_scu_class_init, 6529a937f6cSCédric Le Goater }; 6539a937f6cSCédric Le Goater 6549a937f6cSCédric Le Goater static void aspeed_2500_scu_class_init(ObjectClass *klass, void *data) 6559a937f6cSCédric Le Goater { 6569a937f6cSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 6579a937f6cSCédric Le Goater AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); 6589a937f6cSCédric Le Goater 6599a937f6cSCédric Le Goater dc->desc = "ASPEED 2500 System Control Unit"; 6609a937f6cSCédric Le Goater asc->resets = ast2500_a1_resets; 6619a937f6cSCédric Le Goater asc->calc_hpll = aspeed_2500_scu_calc_hpll; 662dd7f19a9SSteven Lee asc->get_apb = aspeed_2400_scu_get_apb_freq; 6639a937f6cSCédric Le Goater asc->apb_divider = 4; 664e09cf363SJoel Stanley asc->nr_regs = ASPEED_SCU_NR_REGS; 665bad23bb6SSteven Lee asc->clkin_25Mhz = false; 666c7e1f572SJoel Stanley asc->ops = &aspeed_ast2500_scu_ops; 6679a937f6cSCédric Le Goater } 6689a937f6cSCédric Le Goater 6699a937f6cSCédric Le Goater static const TypeInfo aspeed_2500_scu_info = { 6709a937f6cSCédric Le Goater .name = TYPE_ASPEED_2500_SCU, 6719a937f6cSCédric Le Goater .parent = TYPE_ASPEED_SCU, 6729a937f6cSCédric Le Goater .instance_size = sizeof(AspeedSCUState), 6739a937f6cSCédric Le Goater .class_init = aspeed_2500_scu_class_init, 6741c8a2388SAndrew Jeffery }; 6751c8a2388SAndrew Jeffery 676e09cf363SJoel Stanley static uint64_t aspeed_ast2600_scu_read(void *opaque, hwaddr offset, 677e09cf363SJoel Stanley unsigned size) 678e09cf363SJoel Stanley { 679e09cf363SJoel Stanley AspeedSCUState *s = ASPEED_SCU(opaque); 680e09cf363SJoel Stanley int reg = TO_REG(offset); 681e09cf363SJoel Stanley 682e09cf363SJoel Stanley if (reg >= ASPEED_AST2600_SCU_NR_REGS) { 683e09cf363SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 684e09cf363SJoel Stanley "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", 685e09cf363SJoel Stanley __func__, offset); 686e09cf363SJoel Stanley return 0; 687e09cf363SJoel Stanley } 688e09cf363SJoel Stanley 689e09cf363SJoel Stanley switch (reg) { 690e09cf363SJoel Stanley case AST2600_HPLL_EXT: 691e09cf363SJoel Stanley case AST2600_EPLL_EXT: 692e09cf363SJoel Stanley case AST2600_MPLL_EXT: 693e09cf363SJoel Stanley /* PLLs are always "locked" */ 694e09cf363SJoel Stanley return s->regs[reg] | BIT(31); 695e09cf363SJoel Stanley case AST2600_RNG_DATA: 696e09cf363SJoel Stanley /* 697e09cf363SJoel Stanley * On hardware, RNG_DATA works regardless of the state of the 698e09cf363SJoel Stanley * enable bit in RNG_CTRL 699e09cf363SJoel Stanley * 700e09cf363SJoel Stanley * TODO: Check this is true for ast2600 701e09cf363SJoel Stanley */ 702e09cf363SJoel Stanley s->regs[AST2600_RNG_DATA] = aspeed_scu_get_random(); 703e09cf363SJoel Stanley break; 704e09cf363SJoel Stanley } 705e09cf363SJoel Stanley 706673a6d16SCédric Le Goater trace_aspeed_scu_read(offset, size, s->regs[reg]); 707e09cf363SJoel Stanley return s->regs[reg]; 708e09cf363SJoel Stanley } 709e09cf363SJoel Stanley 710310b5bc6SJoel Stanley static void aspeed_ast2600_scu_write(void *opaque, hwaddr offset, 711310b5bc6SJoel Stanley uint64_t data64, unsigned size) 712e09cf363SJoel Stanley { 713e09cf363SJoel Stanley AspeedSCUState *s = ASPEED_SCU(opaque); 714e09cf363SJoel Stanley int reg = TO_REG(offset); 715310b5bc6SJoel Stanley /* Truncate here so bitwise operations below behave as expected */ 716310b5bc6SJoel Stanley uint32_t data = data64; 717e09cf363SJoel Stanley 718e09cf363SJoel Stanley if (reg >= ASPEED_AST2600_SCU_NR_REGS) { 719e09cf363SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 720e09cf363SJoel Stanley "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 721e09cf363SJoel Stanley __func__, offset); 722e09cf363SJoel Stanley return; 723e09cf363SJoel Stanley } 724e09cf363SJoel Stanley 725e09cf363SJoel Stanley if (reg > PROT_KEY && !s->regs[PROT_KEY]) { 726e09cf363SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__); 727e09cf363SJoel Stanley } 728e09cf363SJoel Stanley 729e09cf363SJoel Stanley trace_aspeed_scu_write(offset, size, data); 730e09cf363SJoel Stanley 731e09cf363SJoel Stanley switch (reg) { 732e09cf363SJoel Stanley case AST2600_PROT_KEY: 733e09cf363SJoel Stanley s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0; 734e09cf363SJoel Stanley return; 735e09cf363SJoel Stanley case AST2600_HW_STRAP1: 736e09cf363SJoel Stanley case AST2600_HW_STRAP2: 737e09cf363SJoel Stanley if (s->regs[reg + 2]) { 738e09cf363SJoel Stanley return; 739e09cf363SJoel Stanley } 740e09cf363SJoel Stanley /* fall through */ 741e09cf363SJoel Stanley case AST2600_SYS_RST_CTRL: 742e09cf363SJoel Stanley case AST2600_SYS_RST_CTRL2: 743310b5bc6SJoel Stanley case AST2600_CLK_STOP_CTRL: 744310b5bc6SJoel Stanley case AST2600_CLK_STOP_CTRL2: 745e09cf363SJoel Stanley /* W1S (Write 1 to set) registers */ 746e09cf363SJoel Stanley s->regs[reg] |= data; 747e09cf363SJoel Stanley return; 748e09cf363SJoel Stanley case AST2600_SYS_RST_CTRL_CLR: 749e09cf363SJoel Stanley case AST2600_SYS_RST_CTRL2_CLR: 750310b5bc6SJoel Stanley case AST2600_CLK_STOP_CTRL_CLR: 751310b5bc6SJoel Stanley case AST2600_CLK_STOP_CTRL2_CLR: 752e09cf363SJoel Stanley case AST2600_HW_STRAP1_CLR: 753e09cf363SJoel Stanley case AST2600_HW_STRAP2_CLR: 754310b5bc6SJoel Stanley /* 755310b5bc6SJoel Stanley * W1C (Write 1 to clear) registers are offset by one address from 756310b5bc6SJoel Stanley * the data register 757310b5bc6SJoel Stanley */ 758310b5bc6SJoel Stanley s->regs[reg - 1] &= ~data; 759e09cf363SJoel Stanley return; 760e09cf363SJoel Stanley 761e09cf363SJoel Stanley case AST2600_RNG_DATA: 762e09cf363SJoel Stanley case AST2600_SILICON_REV: 763e09cf363SJoel Stanley case AST2600_SILICON_REV2: 7647ffe647fSJoel Stanley case AST2600_CHIP_ID0: 7657ffe647fSJoel Stanley case AST2600_CHIP_ID1: 766e09cf363SJoel Stanley /* Add read only registers here */ 767e09cf363SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 768e09cf363SJoel Stanley "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n", 769e09cf363SJoel Stanley __func__, offset); 770e09cf363SJoel Stanley return; 771e09cf363SJoel Stanley } 772e09cf363SJoel Stanley 773e09cf363SJoel Stanley s->regs[reg] = data; 774e09cf363SJoel Stanley } 775e09cf363SJoel Stanley 776e09cf363SJoel Stanley static const MemoryRegionOps aspeed_ast2600_scu_ops = { 777e09cf363SJoel Stanley .read = aspeed_ast2600_scu_read, 778e09cf363SJoel Stanley .write = aspeed_ast2600_scu_write, 779e09cf363SJoel Stanley .endianness = DEVICE_LITTLE_ENDIAN, 780e09cf363SJoel Stanley .valid.min_access_size = 4, 781e09cf363SJoel Stanley .valid.max_access_size = 4, 782e09cf363SJoel Stanley .valid.unaligned = false, 783e09cf363SJoel Stanley }; 784e09cf363SJoel Stanley 785c5811bb3SJoel Stanley static const uint32_t ast2600_a3_resets[ASPEED_AST2600_SCU_NR_REGS] = { 7867582591aSJoel Stanley [AST2600_SYS_RST_CTRL] = 0xF7C3FED8, 787c5811bb3SJoel Stanley [AST2600_SYS_RST_CTRL2] = 0x0DFFFFFC, 7887582591aSJoel Stanley [AST2600_CLK_STOP_CTRL] = 0xFFFF7F8A, 789e09cf363SJoel Stanley [AST2600_CLK_STOP_CTRL2] = 0xFFF0FFF0, 790c5811bb3SJoel Stanley [AST2600_DEBUG_CTRL] = 0x00000FFF, 791c5811bb3SJoel Stanley [AST2600_DEBUG_CTRL2] = 0x000000FF, 79214c17954SJoel Stanley [AST2600_SDRAM_HANDSHAKE] = 0x00000000, 793c5811bb3SJoel Stanley [AST2600_HPLL_PARAM] = 0x1000408F, 794c5811bb3SJoel Stanley [AST2600_APLL_PARAM] = 0x1000405F, 795c5811bb3SJoel Stanley [AST2600_MPLL_PARAM] = 0x1008405F, 796c5811bb3SJoel Stanley [AST2600_EPLL_PARAM] = 0x1004077F, 797c5811bb3SJoel Stanley [AST2600_DPLL_PARAM] = 0x1078405F, 798c5811bb3SJoel Stanley [AST2600_CLK_SEL] = 0xF3940000, 799c5811bb3SJoel Stanley [AST2600_CLK_SEL2] = 0x00700000, 800c5811bb3SJoel Stanley [AST2600_CLK_SEL3] = 0x00000000, 801c5811bb3SJoel Stanley [AST2600_CLK_SEL4] = 0xF3F40000, 802c5811bb3SJoel Stanley [AST2600_CLK_SEL5] = 0x30000000, 8039dca4556SPeter Delevoryas [AST2600_UARTCLK] = 0x00014506, 8049dca4556SPeter Delevoryas [AST2600_HUARTCLK] = 0x000145C0, 8057ffe647fSJoel Stanley [AST2600_CHIP_ID0] = 0x1234ABCD, 8067ffe647fSJoel Stanley [AST2600_CHIP_ID1] = 0x88884444, 807e09cf363SJoel Stanley }; 808e09cf363SJoel Stanley 809e09cf363SJoel Stanley static void aspeed_ast2600_scu_reset(DeviceState *dev) 810e09cf363SJoel Stanley { 811e09cf363SJoel Stanley AspeedSCUState *s = ASPEED_SCU(dev); 812e09cf363SJoel Stanley AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev); 813e09cf363SJoel Stanley 814e09cf363SJoel Stanley memcpy(s->regs, asc->resets, asc->nr_regs * 4); 815e09cf363SJoel Stanley 816204dab83SJoel Stanley /* 817204dab83SJoel Stanley * A0 reports A0 in _REV, but subsequent revisions report A1 regardless 818204dab83SJoel Stanley * of actual revision. QEMU and Linux only support A1 onwards so this is 819204dab83SJoel Stanley * sufficient. 820204dab83SJoel Stanley */ 821c5811bb3SJoel Stanley s->regs[AST2600_SILICON_REV] = AST2600_A3_SILICON_REV; 822e09cf363SJoel Stanley s->regs[AST2600_SILICON_REV2] = s->silicon_rev; 823e09cf363SJoel Stanley s->regs[AST2600_HW_STRAP1] = s->hw_strap1; 824e09cf363SJoel Stanley s->regs[AST2600_HW_STRAP2] = s->hw_strap2; 825e09cf363SJoel Stanley s->regs[PROT_KEY] = s->hw_prot_key; 826e09cf363SJoel Stanley } 827e09cf363SJoel Stanley 828e09cf363SJoel Stanley static void aspeed_2600_scu_class_init(ObjectClass *klass, void *data) 829e09cf363SJoel Stanley { 830e09cf363SJoel Stanley DeviceClass *dc = DEVICE_CLASS(klass); 831e09cf363SJoel Stanley AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); 832e09cf363SJoel Stanley 833e09cf363SJoel Stanley dc->desc = "ASPEED 2600 System Control Unit"; 834e3d08143SPeter Maydell device_class_set_legacy_reset(dc, aspeed_ast2600_scu_reset); 835c5811bb3SJoel Stanley asc->resets = ast2600_a3_resets; 836dd7f19a9SSteven Lee asc->calc_hpll = aspeed_2600_scu_calc_hpll; 837dd7f19a9SSteven Lee asc->get_apb = aspeed_2600_scu_get_apb_freq; 838e09cf363SJoel Stanley asc->apb_divider = 4; 839e09cf363SJoel Stanley asc->nr_regs = ASPEED_AST2600_SCU_NR_REGS; 840bad23bb6SSteven Lee asc->clkin_25Mhz = true; 841e09cf363SJoel Stanley asc->ops = &aspeed_ast2600_scu_ops; 842e09cf363SJoel Stanley } 843e09cf363SJoel Stanley 844e09cf363SJoel Stanley static const TypeInfo aspeed_2600_scu_info = { 845e09cf363SJoel Stanley .name = TYPE_ASPEED_2600_SCU, 846e09cf363SJoel Stanley .parent = TYPE_ASPEED_SCU, 847e09cf363SJoel Stanley .instance_size = sizeof(AspeedSCUState), 848e09cf363SJoel Stanley .class_init = aspeed_2600_scu_class_init, 849e09cf363SJoel Stanley }; 850e09cf363SJoel Stanley 851e7c8106dSJamin Lin static uint64_t aspeed_ast2700_scu_read(void *opaque, hwaddr offset, 852e7c8106dSJamin Lin unsigned size) 853e7c8106dSJamin Lin { 854e7c8106dSJamin Lin AspeedSCUState *s = ASPEED_SCU(opaque); 855e7c8106dSJamin Lin int reg = TO_REG(offset); 856e7c8106dSJamin Lin 857e7c8106dSJamin Lin if (reg >= ASPEED_AST2700_SCU_NR_REGS) { 858e7c8106dSJamin Lin qemu_log_mask(LOG_GUEST_ERROR, 859e7c8106dSJamin Lin "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", 860e7c8106dSJamin Lin __func__, offset); 861e7c8106dSJamin Lin return 0; 862e7c8106dSJamin Lin } 863e7c8106dSJamin Lin 864e7c8106dSJamin Lin switch (reg) { 865e7c8106dSJamin Lin default: 866e7c8106dSJamin Lin qemu_log_mask(LOG_GUEST_ERROR, 867e7c8106dSJamin Lin "%s: Unhandled read at offset 0x%" HWADDR_PRIx "\n", 868e7c8106dSJamin Lin __func__, offset); 869e7c8106dSJamin Lin } 870e7c8106dSJamin Lin 871e7c8106dSJamin Lin trace_aspeed_ast2700_scu_read(offset, size, s->regs[reg]); 872e7c8106dSJamin Lin return s->regs[reg]; 873e7c8106dSJamin Lin } 874e7c8106dSJamin Lin 875e7c8106dSJamin Lin static void aspeed_ast2700_scu_write(void *opaque, hwaddr offset, 876e7c8106dSJamin Lin uint64_t data64, unsigned size) 877e7c8106dSJamin Lin { 878e7c8106dSJamin Lin AspeedSCUState *s = ASPEED_SCU(opaque); 879e7c8106dSJamin Lin int reg = TO_REG(offset); 880e7c8106dSJamin Lin /* Truncate here so bitwise operations below behave as expected */ 881e7c8106dSJamin Lin uint32_t data = data64; 882e7c8106dSJamin Lin 883e7c8106dSJamin Lin if (reg >= ASPEED_AST2700_SCU_NR_REGS) { 884e7c8106dSJamin Lin qemu_log_mask(LOG_GUEST_ERROR, 885e7c8106dSJamin Lin "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 886e7c8106dSJamin Lin __func__, offset); 887e7c8106dSJamin Lin return; 888e7c8106dSJamin Lin } 889e7c8106dSJamin Lin 890e7c8106dSJamin Lin trace_aspeed_ast2700_scu_write(offset, size, data); 891e7c8106dSJamin Lin 892e7c8106dSJamin Lin switch (reg) { 893e7c8106dSJamin Lin default: 894e7c8106dSJamin Lin qemu_log_mask(LOG_GUEST_ERROR, 895e7c8106dSJamin Lin "%s: Unhandled write at offset 0x%" HWADDR_PRIx "\n", 896e7c8106dSJamin Lin __func__, offset); 897e7c8106dSJamin Lin break; 898e7c8106dSJamin Lin } 899e7c8106dSJamin Lin 900e7c8106dSJamin Lin s->regs[reg] = data; 901e7c8106dSJamin Lin } 902e7c8106dSJamin Lin 903e7c8106dSJamin Lin static const MemoryRegionOps aspeed_ast2700_scu_ops = { 904e7c8106dSJamin Lin .read = aspeed_ast2700_scu_read, 905e7c8106dSJamin Lin .write = aspeed_ast2700_scu_write, 906e7c8106dSJamin Lin .endianness = DEVICE_LITTLE_ENDIAN, 907e7c8106dSJamin Lin .valid.min_access_size = 1, 908e7c8106dSJamin Lin .valid.max_access_size = 8, 909e7c8106dSJamin Lin .valid.unaligned = false, 910e7c8106dSJamin Lin }; 911e7c8106dSJamin Lin 912e7c8106dSJamin Lin static const uint32_t ast2700_a0_resets[ASPEED_AST2700_SCU_NR_REGS] = { 913e7c8106dSJamin Lin [AST2700_HW_STRAP1] = 0x00000800, 914e7c8106dSJamin Lin [AST2700_HW_STRAP1_CLR] = 0xFFF0FFF0, 915e7c8106dSJamin Lin [AST2700_HW_STRAP1_LOCK] = 0x00000FFF, 916e7c8106dSJamin Lin [AST2700_HW_STRAP1_SEC1] = 0x000000FF, 917e7c8106dSJamin Lin [AST2700_HW_STRAP1_SEC2] = 0x00000000, 918e7c8106dSJamin Lin [AST2700_HW_STRAP1_SEC3] = 0x1000408F, 919e7c8106dSJamin Lin [AST2700_SCU_HPLL_PARAM] = 0x0000009f, 920e7c8106dSJamin Lin [AST2700_SCU_HPLL_EXT_PARAM] = 0x8000004f, 921e7c8106dSJamin Lin [AST2700_SCU_DPLL_PARAM] = 0x0080009f, 922e7c8106dSJamin Lin [AST2700_SCU_DPLL_EXT_PARAM] = 0x8000004f, 923e7c8106dSJamin Lin [AST2700_SCU_MPLL_PARAM] = 0x00000040, 924e7c8106dSJamin Lin [AST2700_SCU_MPLL_EXT_PARAM] = 0x80000000, 925e7c8106dSJamin Lin [AST2700_SCU_D1CLK_PARAM] = 0x00050002, 926e7c8106dSJamin Lin [AST2700_SCU_D2CLK_PARAM] = 0x00050002, 927e7c8106dSJamin Lin [AST2700_SCU_CRT1CLK_PARAM] = 0x00050002, 928e7c8106dSJamin Lin [AST2700_SCU_CRT2CLK_PARAM] = 0x00050002, 929e7c8106dSJamin Lin [AST2700_SCU_MPHYCLK_PARAM] = 0x0000004c, 930e7c8106dSJamin Lin [AST2700_SCU_FREQ_CNTR] = 0x000375eb, 931e7c8106dSJamin Lin [AST2700_SCU_CPU_SCRATCH_0] = 0x00000000, 932e7c8106dSJamin Lin [AST2700_SCU_CPU_SCRATCH_1] = 0x00000004, 9332d082feaSJamin Lin [AST2700_SCU_VGA_SCRATCH_0] = 0x00000040, 934e7c8106dSJamin Lin }; 935e7c8106dSJamin Lin 936e7c8106dSJamin Lin static void aspeed_ast2700_scu_reset(DeviceState *dev) 937e7c8106dSJamin Lin { 938e7c8106dSJamin Lin AspeedSCUState *s = ASPEED_SCU(dev); 939e7c8106dSJamin Lin AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev); 940e7c8106dSJamin Lin 941e7c8106dSJamin Lin memcpy(s->regs, asc->resets, asc->nr_regs * 4); 942*801e0dadSJamin Lin s->regs[AST2700_SILICON_REV] = s->silicon_rev; 943e7c8106dSJamin Lin } 944e7c8106dSJamin Lin 945e7c8106dSJamin Lin static void aspeed_2700_scu_class_init(ObjectClass *klass, void *data) 946e7c8106dSJamin Lin { 947e7c8106dSJamin Lin DeviceClass *dc = DEVICE_CLASS(klass); 948e7c8106dSJamin Lin AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); 949e7c8106dSJamin Lin 950e7c8106dSJamin Lin dc->desc = "ASPEED 2700 System Control Unit"; 951e3d08143SPeter Maydell device_class_set_legacy_reset(dc, aspeed_ast2700_scu_reset); 952e7c8106dSJamin Lin asc->resets = ast2700_a0_resets; 953e7c8106dSJamin Lin asc->calc_hpll = aspeed_2600_scu_calc_hpll; 954e7c8106dSJamin Lin asc->get_apb = aspeed_2700_scu_get_apb_freq; 955e7c8106dSJamin Lin asc->apb_divider = 4; 956e7c8106dSJamin Lin asc->nr_regs = ASPEED_AST2700_SCU_NR_REGS; 957e7c8106dSJamin Lin asc->clkin_25Mhz = true; 958e7c8106dSJamin Lin asc->ops = &aspeed_ast2700_scu_ops; 959e7c8106dSJamin Lin } 960e7c8106dSJamin Lin 961e7c8106dSJamin Lin static uint64_t aspeed_ast2700_scuio_read(void *opaque, hwaddr offset, 962e7c8106dSJamin Lin unsigned size) 963e7c8106dSJamin Lin { 964e7c8106dSJamin Lin AspeedSCUState *s = ASPEED_SCU(opaque); 965e7c8106dSJamin Lin int reg = TO_REG(offset); 966e7c8106dSJamin Lin if (reg >= ASPEED_AST2700_SCU_NR_REGS) { 967e7c8106dSJamin Lin qemu_log_mask(LOG_GUEST_ERROR, 968e7c8106dSJamin Lin "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", 969e7c8106dSJamin Lin __func__, offset); 970e7c8106dSJamin Lin return 0; 971e7c8106dSJamin Lin } 972e7c8106dSJamin Lin 973e7c8106dSJamin Lin switch (reg) { 974e7c8106dSJamin Lin default: 975e7c8106dSJamin Lin qemu_log_mask(LOG_GUEST_ERROR, 976e7c8106dSJamin Lin "%s: Unhandled read at offset 0x%" HWADDR_PRIx "\n", 977e7c8106dSJamin Lin __func__, offset); 978e7c8106dSJamin Lin } 979e7c8106dSJamin Lin 980e7c8106dSJamin Lin trace_aspeed_ast2700_scuio_read(offset, size, s->regs[reg]); 981e7c8106dSJamin Lin return s->regs[reg]; 982e7c8106dSJamin Lin } 983e7c8106dSJamin Lin 984e7c8106dSJamin Lin static void aspeed_ast2700_scuio_write(void *opaque, hwaddr offset, 985e7c8106dSJamin Lin uint64_t data64, unsigned size) 986e7c8106dSJamin Lin { 987e7c8106dSJamin Lin AspeedSCUState *s = ASPEED_SCU(opaque); 988e7c8106dSJamin Lin int reg = TO_REG(offset); 989e7c8106dSJamin Lin /* Truncate here so bitwise operations below behave as expected */ 990e7c8106dSJamin Lin uint32_t data = data64; 991e7c8106dSJamin Lin bool updated = false; 992e7c8106dSJamin Lin 993e7c8106dSJamin Lin if (reg >= ASPEED_AST2700_SCU_NR_REGS) { 994e7c8106dSJamin Lin qemu_log_mask(LOG_GUEST_ERROR, 995e7c8106dSJamin Lin "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 996e7c8106dSJamin Lin __func__, offset); 997e7c8106dSJamin Lin return; 998e7c8106dSJamin Lin } 999e7c8106dSJamin Lin 1000e7c8106dSJamin Lin trace_aspeed_ast2700_scuio_write(offset, size, data); 1001e7c8106dSJamin Lin 1002e7c8106dSJamin Lin switch (reg) { 1003e7c8106dSJamin Lin case AST2700_SCUIO_CLK_STOP_CTL_1: 1004e7c8106dSJamin Lin case AST2700_SCUIO_CLK_STOP_CTL_2: 1005e7c8106dSJamin Lin s->regs[reg] |= data; 1006e7c8106dSJamin Lin updated = true; 1007e7c8106dSJamin Lin break; 1008e7c8106dSJamin Lin case AST2700_SCUIO_CLK_STOP_CLR_1: 1009e7c8106dSJamin Lin case AST2700_SCUIO_CLK_STOP_CLR_2: 1010e7c8106dSJamin Lin s->regs[reg - 1] ^= data; 1011e7c8106dSJamin Lin updated = true; 1012e7c8106dSJamin Lin break; 1013e7c8106dSJamin Lin default: 1014e7c8106dSJamin Lin qemu_log_mask(LOG_GUEST_ERROR, 1015e7c8106dSJamin Lin "%s: Unhandled write at offset 0x%" HWADDR_PRIx "\n", 1016e7c8106dSJamin Lin __func__, offset); 1017e7c8106dSJamin Lin break; 1018e7c8106dSJamin Lin } 1019e7c8106dSJamin Lin 1020e7c8106dSJamin Lin if (!updated) { 1021e7c8106dSJamin Lin s->regs[reg] = data; 1022e7c8106dSJamin Lin } 1023e7c8106dSJamin Lin } 1024e7c8106dSJamin Lin 1025e7c8106dSJamin Lin static const MemoryRegionOps aspeed_ast2700_scuio_ops = { 1026e7c8106dSJamin Lin .read = aspeed_ast2700_scuio_read, 1027e7c8106dSJamin Lin .write = aspeed_ast2700_scuio_write, 1028e7c8106dSJamin Lin .endianness = DEVICE_LITTLE_ENDIAN, 1029e7c8106dSJamin Lin .valid.min_access_size = 1, 1030e7c8106dSJamin Lin .valid.max_access_size = 8, 1031e7c8106dSJamin Lin .valid.unaligned = false, 1032e7c8106dSJamin Lin }; 1033e7c8106dSJamin Lin 1034e7c8106dSJamin Lin static const uint32_t ast2700_a0_resets_io[ASPEED_AST2700_SCU_NR_REGS] = { 1035e7c8106dSJamin Lin [AST2700_HW_STRAP1] = 0x00000504, 1036e7c8106dSJamin Lin [AST2700_HW_STRAP1_CLR] = 0xFFF0FFF0, 1037e7c8106dSJamin Lin [AST2700_HW_STRAP1_LOCK] = 0x00000FFF, 1038e7c8106dSJamin Lin [AST2700_HW_STRAP1_SEC1] = 0x000000FF, 1039e7c8106dSJamin Lin [AST2700_HW_STRAP1_SEC2] = 0x00000000, 1040e7c8106dSJamin Lin [AST2700_HW_STRAP1_SEC3] = 0x1000408F, 1041e7c8106dSJamin Lin [AST2700_SCUIO_CLK_STOP_CTL_1] = 0xffff8400, 1042e7c8106dSJamin Lin [AST2700_SCUIO_CLK_STOP_CTL_2] = 0x00005f30, 1043e7c8106dSJamin Lin [AST2700_SCUIO_CLK_SEL_1] = 0x86900000, 1044e7c8106dSJamin Lin [AST2700_SCUIO_CLK_SEL_2] = 0x00400000, 1045e7c8106dSJamin Lin [AST2700_SCUIO_HPLL_PARAM] = 0x10000027, 1046e7c8106dSJamin Lin [AST2700_SCUIO_HPLL_EXT_PARAM] = 0x80000014, 1047e7c8106dSJamin Lin [AST2700_SCUIO_APLL_PARAM] = 0x1000001f, 1048e7c8106dSJamin Lin [AST2700_SCUIO_APLL_EXT_PARAM] = 0x8000000f, 1049e7c8106dSJamin Lin [AST2700_SCUIO_DPLL_PARAM] = 0x106e42ce, 1050e7c8106dSJamin Lin [AST2700_SCUIO_DPLL_EXT_PARAM] = 0x80000167, 1051e7c8106dSJamin Lin [AST2700_SCUIO_DPLL_PARAM_READ] = 0x106e42ce, 1052e7c8106dSJamin Lin [AST2700_SCUIO_DPLL_EXT_PARAM_READ] = 0x80000167, 1053e7c8106dSJamin Lin [AST2700_SCUIO_UARTCLK_GEN] = 0x00014506, 1054e7c8106dSJamin Lin [AST2700_SCUIO_HUARTCLK_GEN] = 0x000145c0, 1055e7c8106dSJamin Lin [AST2700_SCUIO_CLK_DUTY_MEAS_RST] = 0x0c9100d2, 1056e7c8106dSJamin Lin }; 1057e7c8106dSJamin Lin 1058e7c8106dSJamin Lin static void aspeed_2700_scuio_class_init(ObjectClass *klass, void *data) 1059e7c8106dSJamin Lin { 1060e7c8106dSJamin Lin DeviceClass *dc = DEVICE_CLASS(klass); 1061e7c8106dSJamin Lin AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); 1062e7c8106dSJamin Lin 1063e7c8106dSJamin Lin dc->desc = "ASPEED 2700 System Control Unit I/O"; 1064e3d08143SPeter Maydell device_class_set_legacy_reset(dc, aspeed_ast2700_scu_reset); 1065e7c8106dSJamin Lin asc->resets = ast2700_a0_resets_io; 1066e7c8106dSJamin Lin asc->calc_hpll = aspeed_2600_scu_calc_hpll; 1067e7c8106dSJamin Lin asc->get_apb = aspeed_2700_scuio_get_apb_freq; 1068e7c8106dSJamin Lin asc->apb_divider = 2; 1069e7c8106dSJamin Lin asc->nr_regs = ASPEED_AST2700_SCU_NR_REGS; 1070e7c8106dSJamin Lin asc->clkin_25Mhz = true; 1071e7c8106dSJamin Lin asc->ops = &aspeed_ast2700_scuio_ops; 1072e7c8106dSJamin Lin } 1073e7c8106dSJamin Lin 1074e7c8106dSJamin Lin static const TypeInfo aspeed_2700_scu_info = { 1075e7c8106dSJamin Lin .name = TYPE_ASPEED_2700_SCU, 1076e7c8106dSJamin Lin .parent = TYPE_ASPEED_SCU, 1077e7c8106dSJamin Lin .instance_size = sizeof(AspeedSCUState), 1078e7c8106dSJamin Lin .class_init = aspeed_2700_scu_class_init, 1079e7c8106dSJamin Lin }; 1080e7c8106dSJamin Lin 1081e7c8106dSJamin Lin static const TypeInfo aspeed_2700_scuio_info = { 1082e7c8106dSJamin Lin .name = TYPE_ASPEED_2700_SCUIO, 1083e7c8106dSJamin Lin .parent = TYPE_ASPEED_SCU, 1084e7c8106dSJamin Lin .instance_size = sizeof(AspeedSCUState), 1085e7c8106dSJamin Lin .class_init = aspeed_2700_scuio_class_init, 1086e7c8106dSJamin Lin }; 1087e7c8106dSJamin Lin 1088fa541a60SSteven Lee static const uint32_t ast1030_a1_resets[ASPEED_AST2600_SCU_NR_REGS] = { 1089fa541a60SSteven Lee [AST2600_SYS_RST_CTRL] = 0xFFC3FED8, 1090fa541a60SSteven Lee [AST2600_SYS_RST_CTRL2] = 0x09FFFFFC, 1091fa541a60SSteven Lee [AST2600_CLK_STOP_CTRL] = 0xFFFF7F8A, 1092fa541a60SSteven Lee [AST2600_CLK_STOP_CTRL2] = 0xFFF0FFF0, 1093fa541a60SSteven Lee [AST2600_DEBUG_CTRL2] = 0x00000000, 1094fa541a60SSteven Lee [AST2600_HPLL_PARAM] = 0x10004077, 1095fa541a60SSteven Lee [AST2600_HPLL_EXT] = 0x00000031, 1096fa541a60SSteven Lee [AST2600_CLK_SEL4] = 0x43F90900, 1097fa541a60SSteven Lee [AST2600_CLK_SEL5] = 0x40000000, 1098fa541a60SSteven Lee [AST2600_CHIP_ID0] = 0xDEADBEEF, 1099fa541a60SSteven Lee [AST2600_CHIP_ID1] = 0x0BADCAFE, 1100fa541a60SSteven Lee }; 1101fa541a60SSteven Lee 1102fa541a60SSteven Lee static void aspeed_ast1030_scu_reset(DeviceState *dev) 1103fa541a60SSteven Lee { 1104fa541a60SSteven Lee AspeedSCUState *s = ASPEED_SCU(dev); 1105fa541a60SSteven Lee AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev); 1106fa541a60SSteven Lee 1107fa541a60SSteven Lee memcpy(s->regs, asc->resets, asc->nr_regs * 4); 1108fa541a60SSteven Lee 1109fa541a60SSteven Lee s->regs[AST2600_SILICON_REV] = AST1030_A1_SILICON_REV; 1110fa541a60SSteven Lee s->regs[AST2600_SILICON_REV2] = s->silicon_rev; 1111fa541a60SSteven Lee s->regs[AST2600_HW_STRAP1] = s->hw_strap1; 1112fa541a60SSteven Lee s->regs[AST2600_HW_STRAP2] = s->hw_strap2; 1113fa541a60SSteven Lee s->regs[PROT_KEY] = s->hw_prot_key; 1114fa541a60SSteven Lee } 1115fa541a60SSteven Lee 1116fa541a60SSteven Lee static void aspeed_1030_scu_class_init(ObjectClass *klass, void *data) 1117fa541a60SSteven Lee { 1118fa541a60SSteven Lee DeviceClass *dc = DEVICE_CLASS(klass); 1119fa541a60SSteven Lee AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); 1120fa541a60SSteven Lee 1121fa541a60SSteven Lee dc->desc = "ASPEED 1030 System Control Unit"; 1122e3d08143SPeter Maydell device_class_set_legacy_reset(dc, aspeed_ast1030_scu_reset); 1123fa541a60SSteven Lee asc->resets = ast1030_a1_resets; 1124fa541a60SSteven Lee asc->calc_hpll = aspeed_2600_scu_calc_hpll; 1125fa541a60SSteven Lee asc->get_apb = aspeed_1030_scu_get_apb_freq; 1126fa541a60SSteven Lee asc->apb_divider = 2; 1127fa541a60SSteven Lee asc->nr_regs = ASPEED_AST2600_SCU_NR_REGS; 1128fa541a60SSteven Lee asc->clkin_25Mhz = true; 1129fa541a60SSteven Lee asc->ops = &aspeed_ast2600_scu_ops; 1130fa541a60SSteven Lee } 1131fa541a60SSteven Lee 1132fa541a60SSteven Lee static const TypeInfo aspeed_1030_scu_info = { 1133fa541a60SSteven Lee .name = TYPE_ASPEED_1030_SCU, 1134fa541a60SSteven Lee .parent = TYPE_ASPEED_SCU, 1135fa541a60SSteven Lee .instance_size = sizeof(AspeedSCUState), 1136fa541a60SSteven Lee .class_init = aspeed_1030_scu_class_init, 1137fa541a60SSteven Lee }; 1138fa541a60SSteven Lee 11391c8a2388SAndrew Jeffery static void aspeed_scu_register_types(void) 11401c8a2388SAndrew Jeffery { 11411c8a2388SAndrew Jeffery type_register_static(&aspeed_scu_info); 11429a937f6cSCédric Le Goater type_register_static(&aspeed_2400_scu_info); 11439a937f6cSCédric Le Goater type_register_static(&aspeed_2500_scu_info); 1144e09cf363SJoel Stanley type_register_static(&aspeed_2600_scu_info); 1145fa541a60SSteven Lee type_register_static(&aspeed_1030_scu_info); 1146e7c8106dSJamin Lin type_register_static(&aspeed_2700_scu_info); 1147e7c8106dSJamin Lin type_register_static(&aspeed_2700_scuio_info); 11481c8a2388SAndrew Jeffery } 11491c8a2388SAndrew Jeffery 11501c8a2388SAndrew Jeffery type_init(aspeed_scu_register_types); 1151