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 137c491e152SCédric Le Goater #define SCU_IO_REGION_SIZE 0x1000 1381c8a2388SAndrew Jeffery 1391c8a2388SAndrew Jeffery static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = { 1401c8a2388SAndrew Jeffery [SYS_RST_CTRL] = 0xFFCFFEDCU, 1411c8a2388SAndrew Jeffery [CLK_SEL] = 0xF3F40000U, 1421c8a2388SAndrew Jeffery [CLK_STOP_CTRL] = 0x19FC3E8BU, 1431c8a2388SAndrew Jeffery [D2PLL_PARAM] = 0x00026108U, 1441c8a2388SAndrew Jeffery [MPLL_PARAM] = 0x00030291U, 1451c8a2388SAndrew Jeffery [HPLL_PARAM] = 0x00000291U, 1461c8a2388SAndrew Jeffery [MISC_CTRL1] = 0x00000010U, 1471c8a2388SAndrew Jeffery [PCI_CTRL1] = 0x20001A03U, 1481c8a2388SAndrew Jeffery [PCI_CTRL2] = 0x20001A03U, 1491c8a2388SAndrew Jeffery [PCI_CTRL3] = 0x04000030U, 1501c8a2388SAndrew Jeffery [SYS_RST_STATUS] = 0x00000001U, 1511c8a2388SAndrew Jeffery [SOC_SCRATCH1] = 0x000000C0U, /* SoC completed DRAM init */ 1521c8a2388SAndrew Jeffery [MISC_CTRL2] = 0x00000023U, 1531c8a2388SAndrew Jeffery [RNG_CTRL] = 0x0000000EU, 1541c8a2388SAndrew Jeffery [PINMUX_CTRL2] = 0x0000F000U, 1551c8a2388SAndrew Jeffery [PINMUX_CTRL3] = 0x01000000U, 1561c8a2388SAndrew Jeffery [PINMUX_CTRL4] = 0x000000FFU, 1571c8a2388SAndrew Jeffery [PINMUX_CTRL5] = 0x0000A000U, 1581c8a2388SAndrew Jeffery [WDT_RST_CTRL] = 0x003FFFF3U, 1591c8a2388SAndrew Jeffery [PINMUX_CTRL8] = 0xFFFF0000U, 1601c8a2388SAndrew Jeffery [PINMUX_CTRL9] = 0x000FFFFFU, 1611c8a2388SAndrew Jeffery [FREE_CNTR4] = 0x000000FFU, 1621c8a2388SAndrew Jeffery [FREE_CNTR4_EXT] = 0x000000FFU, 1631c8a2388SAndrew Jeffery [CPU2_BASE_SEG1] = 0x80000000U, 1641c8a2388SAndrew Jeffery [CPU2_BASE_SEG4] = 0x1E600000U, 1651c8a2388SAndrew Jeffery [CPU2_BASE_SEG5] = 0xC0000000U, 1661c8a2388SAndrew Jeffery [UART_HPLL_CLK] = 0x00001903U, 1671c8a2388SAndrew Jeffery [PCIE_CTRL] = 0x0000007BU, 1681c8a2388SAndrew Jeffery [BMC_DEV_ID] = 0x00002402U 1691c8a2388SAndrew Jeffery }; 1701c8a2388SAndrew Jeffery 171365aff1eSCédric Le Goater /* SCU70 bit 23: 0 24Mhz. bit 11:9: 0b001 AXI:ABH ratio 2:1 */ 172365aff1eSCédric Le Goater /* AST2500 revision A1 */ 173365aff1eSCédric Le Goater 174365aff1eSCédric Le Goater static const uint32_t ast2500_a1_resets[ASPEED_SCU_NR_REGS] = { 175365aff1eSCédric Le Goater [SYS_RST_CTRL] = 0xFFCFFEDCU, 176365aff1eSCédric Le Goater [CLK_SEL] = 0xF3F40000U, 177365aff1eSCédric Le Goater [CLK_STOP_CTRL] = 0x19FC3E8BU, 178365aff1eSCédric Le Goater [D2PLL_PARAM] = 0x00026108U, 179365aff1eSCédric Le Goater [MPLL_PARAM] = 0x00030291U, 180365aff1eSCédric Le Goater [HPLL_PARAM] = 0x93000400U, 181365aff1eSCédric Le Goater [MISC_CTRL1] = 0x00000010U, 182365aff1eSCédric Le Goater [PCI_CTRL1] = 0x20001A03U, 183365aff1eSCédric Le Goater [PCI_CTRL2] = 0x20001A03U, 184365aff1eSCédric Le Goater [PCI_CTRL3] = 0x04000030U, 185365aff1eSCédric Le Goater [SYS_RST_STATUS] = 0x00000001U, 186365aff1eSCédric Le Goater [SOC_SCRATCH1] = 0x000000C0U, /* SoC completed DRAM init */ 187365aff1eSCédric Le Goater [MISC_CTRL2] = 0x00000023U, 188365aff1eSCédric Le Goater [RNG_CTRL] = 0x0000000EU, 189365aff1eSCédric Le Goater [PINMUX_CTRL2] = 0x0000F000U, 190365aff1eSCédric Le Goater [PINMUX_CTRL3] = 0x03000000U, 191365aff1eSCédric Le Goater [PINMUX_CTRL4] = 0x00000000U, 192365aff1eSCédric Le Goater [PINMUX_CTRL5] = 0x0000A000U, 193365aff1eSCédric Le Goater [WDT_RST_CTRL] = 0x023FFFF3U, 194365aff1eSCédric Le Goater [PINMUX_CTRL8] = 0xFFFF0000U, 195365aff1eSCédric Le Goater [PINMUX_CTRL9] = 0x000FFFFFU, 196365aff1eSCédric Le Goater [FREE_CNTR4] = 0x000000FFU, 197365aff1eSCédric Le Goater [FREE_CNTR4_EXT] = 0x000000FFU, 198365aff1eSCédric Le Goater [CPU2_BASE_SEG1] = 0x80000000U, 199365aff1eSCédric Le Goater [CPU2_BASE_SEG4] = 0x1E600000U, 200365aff1eSCédric Le Goater [CPU2_BASE_SEG5] = 0xC0000000U, 2017ffe647fSJoel Stanley [CHIP_ID0] = 0x1234ABCDU, 2027ffe647fSJoel Stanley [CHIP_ID1] = 0x88884444U, 203365aff1eSCédric Le Goater [UART_HPLL_CLK] = 0x00001903U, 204365aff1eSCédric Le Goater [PCIE_CTRL] = 0x0000007BU, 205365aff1eSCédric Le Goater [BMC_DEV_ID] = 0x00002402U 206365aff1eSCédric Le Goater }; 207365aff1eSCédric Le Goater 208acd9575eSJoel Stanley static uint32_t aspeed_scu_get_random(void) 209acd9575eSJoel Stanley { 210acd9575eSJoel Stanley uint32_t num; 2119d44cb5bSRichard Henderson qemu_guest_getrandom_nofail(&num, sizeof(num)); 212acd9575eSJoel Stanley return num; 213acd9575eSJoel Stanley } 214acd9575eSJoel Stanley 215a8f07376SCédric Le Goater uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s) 216fda9aaa6SCédric Le Goater { 217dd7f19a9SSteven Lee return ASPEED_SCU_GET_CLASS(s)->get_apb(s); 218dd7f19a9SSteven Lee } 219dd7f19a9SSteven Lee 220dd7f19a9SSteven Lee static uint32_t aspeed_2400_scu_get_apb_freq(AspeedSCUState *s) 221dd7f19a9SSteven Lee { 2229a937f6cSCédric Le Goater AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s); 223a8f07376SCédric Le Goater uint32_t hpll = asc->calc_hpll(s, s->regs[HPLL_PARAM]); 224fda9aaa6SCédric Le Goater 225a8f07376SCédric Le Goater return hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[CLK_SEL]) + 1) 2269a937f6cSCédric Le Goater / asc->apb_divider; 227fda9aaa6SCédric Le Goater } 228fda9aaa6SCédric Le Goater 229dd7f19a9SSteven Lee static uint32_t aspeed_2600_scu_get_apb_freq(AspeedSCUState *s) 230dd7f19a9SSteven Lee { 231dd7f19a9SSteven Lee AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s); 232dd7f19a9SSteven Lee uint32_t hpll = asc->calc_hpll(s, s->regs[AST2600_HPLL_PARAM]); 233dd7f19a9SSteven Lee 234dd7f19a9SSteven Lee return hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[AST2600_CLK_SEL]) + 1) 235dd7f19a9SSteven Lee / asc->apb_divider; 236dd7f19a9SSteven Lee } 237dd7f19a9SSteven Lee 238fa541a60SSteven Lee static uint32_t aspeed_1030_scu_get_apb_freq(AspeedSCUState *s) 239fa541a60SSteven Lee { 240fa541a60SSteven Lee AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s); 241fa541a60SSteven Lee uint32_t hpll = asc->calc_hpll(s, s->regs[AST2600_HPLL_PARAM]); 242fa541a60SSteven Lee 243fa541a60SSteven Lee return hpll / (SCU_AST1030_CLK_GET_PCLK_DIV(s->regs[AST2600_CLK_SEL4]) + 1) 244fa541a60SSteven Lee / asc->apb_divider; 245fa541a60SSteven Lee } 246fa541a60SSteven Lee 2471c8a2388SAndrew Jeffery static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size) 2481c8a2388SAndrew Jeffery { 2491c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(opaque); 2501c8a2388SAndrew Jeffery int reg = TO_REG(offset); 2511c8a2388SAndrew Jeffery 252e09cf363SJoel Stanley if (reg >= ASPEED_SCU_NR_REGS) { 2531c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 2541c8a2388SAndrew Jeffery "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", 2551c8a2388SAndrew Jeffery __func__, offset); 2561c8a2388SAndrew Jeffery return 0; 2571c8a2388SAndrew Jeffery } 2581c8a2388SAndrew Jeffery 2591c8a2388SAndrew Jeffery switch (reg) { 260acd9575eSJoel Stanley case RNG_DATA: 261acd9575eSJoel Stanley /* On hardware, RNG_DATA works regardless of 262acd9575eSJoel Stanley * the state of the enable bit in RNG_CTRL 263acd9575eSJoel Stanley */ 264acd9575eSJoel Stanley s->regs[RNG_DATA] = aspeed_scu_get_random(); 265acd9575eSJoel Stanley break; 2661c8a2388SAndrew Jeffery case WAKEUP_EN: 2671c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 2681c8a2388SAndrew Jeffery "%s: Read of write-only offset 0x%" HWADDR_PRIx "\n", 2691c8a2388SAndrew Jeffery __func__, offset); 2701c8a2388SAndrew Jeffery break; 2711c8a2388SAndrew Jeffery } 2721c8a2388SAndrew Jeffery 273673a6d16SCédric Le Goater trace_aspeed_scu_read(offset, size, s->regs[reg]); 2741c8a2388SAndrew Jeffery return s->regs[reg]; 2751c8a2388SAndrew Jeffery } 2761c8a2388SAndrew Jeffery 277c7e1f572SJoel Stanley static void aspeed_ast2400_scu_write(void *opaque, hwaddr offset, 278c7e1f572SJoel Stanley uint64_t data, unsigned size) 279c7e1f572SJoel Stanley { 280c7e1f572SJoel Stanley AspeedSCUState *s = ASPEED_SCU(opaque); 281c7e1f572SJoel Stanley int reg = TO_REG(offset); 282c7e1f572SJoel Stanley 283c7e1f572SJoel Stanley if (reg >= ASPEED_SCU_NR_REGS) { 284c7e1f572SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 285c7e1f572SJoel Stanley "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 286c7e1f572SJoel Stanley __func__, offset); 287c7e1f572SJoel Stanley return; 288c7e1f572SJoel Stanley } 289c7e1f572SJoel Stanley 290c7e1f572SJoel Stanley if (reg > PROT_KEY && reg < CPU2_BASE_SEG1 && 291c7e1f572SJoel Stanley !s->regs[PROT_KEY]) { 292c7e1f572SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__); 293c7e1f572SJoel Stanley } 294c7e1f572SJoel Stanley 295c7e1f572SJoel Stanley trace_aspeed_scu_write(offset, size, data); 296c7e1f572SJoel Stanley 297c7e1f572SJoel Stanley switch (reg) { 298c7e1f572SJoel Stanley case PROT_KEY: 299c7e1f572SJoel Stanley s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0; 300c7e1f572SJoel Stanley return; 301c7e1f572SJoel Stanley case SILICON_REV: 302c7e1f572SJoel Stanley case FREQ_CNTR_EVAL: 303c7e1f572SJoel Stanley case VGA_SCRATCH1 ... VGA_SCRATCH8: 304c7e1f572SJoel Stanley case RNG_DATA: 305c7e1f572SJoel Stanley case FREE_CNTR4: 306c7e1f572SJoel Stanley case FREE_CNTR4_EXT: 307c7e1f572SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 308c7e1f572SJoel Stanley "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n", 309c7e1f572SJoel Stanley __func__, offset); 310c7e1f572SJoel Stanley return; 311c7e1f572SJoel Stanley } 312c7e1f572SJoel Stanley 313c7e1f572SJoel Stanley s->regs[reg] = data; 314c7e1f572SJoel Stanley } 315c7e1f572SJoel Stanley 316c7e1f572SJoel Stanley static void aspeed_ast2500_scu_write(void *opaque, hwaddr offset, 317c7e1f572SJoel Stanley uint64_t data, unsigned size) 3181c8a2388SAndrew Jeffery { 3191c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(opaque); 3201c8a2388SAndrew Jeffery int reg = TO_REG(offset); 3211c8a2388SAndrew Jeffery 322e09cf363SJoel Stanley if (reg >= ASPEED_SCU_NR_REGS) { 3231c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 3241c8a2388SAndrew Jeffery "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 3251c8a2388SAndrew Jeffery __func__, offset); 3261c8a2388SAndrew Jeffery return; 3271c8a2388SAndrew Jeffery } 3281c8a2388SAndrew Jeffery 3291c8a2388SAndrew Jeffery if (reg > PROT_KEY && reg < CPU2_BASE_SEG1 && 3305c1d3a2bSHugo Landau !s->regs[PROT_KEY]) { 3311c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__); 3321c8a2388SAndrew Jeffery return; 3331c8a2388SAndrew Jeffery } 3341c8a2388SAndrew Jeffery 3351c8a2388SAndrew Jeffery trace_aspeed_scu_write(offset, size, data); 3361c8a2388SAndrew Jeffery 3371c8a2388SAndrew Jeffery switch (reg) { 3385c1d3a2bSHugo Landau case PROT_KEY: 3395c1d3a2bSHugo Landau s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0; 3405c1d3a2bSHugo Landau return; 341333b9c8aSAndrew Jeffery case HW_STRAP1: 342333b9c8aSAndrew Jeffery s->regs[HW_STRAP1] |= data; 343333b9c8aSAndrew Jeffery return; 344333b9c8aSAndrew Jeffery case SILICON_REV: 345333b9c8aSAndrew Jeffery s->regs[HW_STRAP1] &= ~data; 346333b9c8aSAndrew Jeffery return; 3471c8a2388SAndrew Jeffery case FREQ_CNTR_EVAL: 3481c8a2388SAndrew Jeffery case VGA_SCRATCH1 ... VGA_SCRATCH8: 3491c8a2388SAndrew Jeffery case RNG_DATA: 3501c8a2388SAndrew Jeffery case FREE_CNTR4: 3511c8a2388SAndrew Jeffery case FREE_CNTR4_EXT: 3527ffe647fSJoel Stanley case CHIP_ID0: 3537ffe647fSJoel Stanley case CHIP_ID1: 3541c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 3551c8a2388SAndrew Jeffery "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n", 3561c8a2388SAndrew Jeffery __func__, offset); 3571c8a2388SAndrew Jeffery return; 3581c8a2388SAndrew Jeffery } 3591c8a2388SAndrew Jeffery 3601c8a2388SAndrew Jeffery s->regs[reg] = data; 3611c8a2388SAndrew Jeffery } 3621c8a2388SAndrew Jeffery 363c7e1f572SJoel Stanley static const MemoryRegionOps aspeed_ast2400_scu_ops = { 3641c8a2388SAndrew Jeffery .read = aspeed_scu_read, 365c7e1f572SJoel Stanley .write = aspeed_ast2400_scu_write, 366c7e1f572SJoel Stanley .endianness = DEVICE_LITTLE_ENDIAN, 367740bc3a7SCédric Le Goater .valid = { 368740bc3a7SCédric Le Goater .min_access_size = 1, 369740bc3a7SCédric Le Goater .max_access_size = 4, 370740bc3a7SCédric Le Goater }, 371c7e1f572SJoel Stanley }; 372c7e1f572SJoel Stanley 373c7e1f572SJoel Stanley static const MemoryRegionOps aspeed_ast2500_scu_ops = { 374c7e1f572SJoel Stanley .read = aspeed_scu_read, 375c7e1f572SJoel Stanley .write = aspeed_ast2500_scu_write, 3761c8a2388SAndrew Jeffery .endianness = DEVICE_LITTLE_ENDIAN, 3771c8a2388SAndrew Jeffery .valid.min_access_size = 4, 3781c8a2388SAndrew Jeffery .valid.max_access_size = 4, 3791c8a2388SAndrew Jeffery .valid.unaligned = false, 3801c8a2388SAndrew Jeffery }; 3811c8a2388SAndrew Jeffery 382fda9aaa6SCédric Le Goater static uint32_t aspeed_scu_get_clkin(AspeedSCUState *s) 383fda9aaa6SCédric Le Goater { 384bad23bb6SSteven Lee if (s->hw_strap1 & SCU_HW_STRAP_CLK_25M_IN || 385bad23bb6SSteven Lee ASPEED_SCU_GET_CLASS(s)->clkin_25Mhz) { 386fda9aaa6SCédric Le Goater return 25000000; 387fda9aaa6SCédric Le Goater } else if (s->hw_strap1 & SCU_HW_STRAP_CLK_48M_IN) { 388fda9aaa6SCédric Le Goater return 48000000; 389fda9aaa6SCédric Le Goater } else { 390fda9aaa6SCédric Le Goater return 24000000; 391fda9aaa6SCédric Le Goater } 392fda9aaa6SCédric Le Goater } 393fda9aaa6SCédric Le Goater 394fda9aaa6SCédric Le Goater /* 395fda9aaa6SCédric Le Goater * Strapped frequencies for the AST2400 in MHz. They depend on the 396fda9aaa6SCédric Le Goater * clkin frequency. 397fda9aaa6SCédric Le Goater */ 398fda9aaa6SCédric Le Goater static const uint32_t hpll_ast2400_freqs[][4] = { 399fda9aaa6SCédric Le Goater { 384, 360, 336, 408 }, /* 24MHz or 48MHz */ 400fda9aaa6SCédric Le Goater { 400, 375, 350, 425 }, /* 25MHz */ 401fda9aaa6SCédric Le Goater }; 402fda9aaa6SCédric Le Goater 403a8f07376SCédric Le Goater static uint32_t aspeed_2400_scu_calc_hpll(AspeedSCUState *s, uint32_t hpll_reg) 404fda9aaa6SCédric Le Goater { 405fda9aaa6SCédric Le Goater uint8_t freq_select; 406fda9aaa6SCédric Le Goater bool clk_25m_in; 407a8f07376SCédric Le Goater uint32_t clkin = aspeed_scu_get_clkin(s); 408fda9aaa6SCédric Le Goater 409fda9aaa6SCédric Le Goater if (hpll_reg & SCU_AST2400_H_PLL_OFF) { 410fda9aaa6SCédric Le Goater return 0; 411fda9aaa6SCédric Le Goater } 412fda9aaa6SCédric Le Goater 413fda9aaa6SCédric Le Goater if (hpll_reg & SCU_AST2400_H_PLL_PROGRAMMED) { 414fda9aaa6SCédric Le Goater uint32_t multiplier = 1; 415fda9aaa6SCédric Le Goater 416fda9aaa6SCédric Le Goater if (!(hpll_reg & SCU_AST2400_H_PLL_BYPASS_EN)) { 417fda9aaa6SCédric Le Goater uint32_t n = (hpll_reg >> 5) & 0x3f; 418fda9aaa6SCédric Le Goater uint32_t od = (hpll_reg >> 4) & 0x1; 419fda9aaa6SCédric Le Goater uint32_t d = hpll_reg & 0xf; 420fda9aaa6SCédric Le Goater 421fda9aaa6SCédric Le Goater multiplier = (2 - od) * ((n + 2) / (d + 1)); 422fda9aaa6SCédric Le Goater } 423fda9aaa6SCédric Le Goater 424a8f07376SCédric Le Goater return clkin * multiplier; 425fda9aaa6SCédric Le Goater } 426fda9aaa6SCédric Le Goater 427fda9aaa6SCédric Le Goater /* HW strapping */ 428fda9aaa6SCédric Le Goater clk_25m_in = !!(s->hw_strap1 & SCU_HW_STRAP_CLK_25M_IN); 429fda9aaa6SCédric Le Goater freq_select = SCU_AST2400_HW_STRAP_GET_H_PLL_CLK(s->hw_strap1); 430fda9aaa6SCédric Le Goater 431fda9aaa6SCédric Le Goater return hpll_ast2400_freqs[clk_25m_in][freq_select] * 1000000; 432fda9aaa6SCédric Le Goater } 433fda9aaa6SCédric Le Goater 434a8f07376SCédric Le Goater static uint32_t aspeed_2500_scu_calc_hpll(AspeedSCUState *s, uint32_t hpll_reg) 435fda9aaa6SCédric Le Goater { 436fda9aaa6SCédric Le Goater uint32_t multiplier = 1; 437a8f07376SCédric Le Goater uint32_t clkin = aspeed_scu_get_clkin(s); 438fda9aaa6SCédric Le Goater 439fda9aaa6SCédric Le Goater if (hpll_reg & SCU_H_PLL_OFF) { 440fda9aaa6SCédric Le Goater return 0; 441fda9aaa6SCédric Le Goater } 442fda9aaa6SCédric Le Goater 443fda9aaa6SCédric Le Goater if (!(hpll_reg & SCU_H_PLL_BYPASS_EN)) { 444fda9aaa6SCédric Le Goater uint32_t p = (hpll_reg >> 13) & 0x3f; 445fda9aaa6SCédric Le Goater uint32_t m = (hpll_reg >> 5) & 0xff; 446fda9aaa6SCédric Le Goater uint32_t n = hpll_reg & 0x1f; 447fda9aaa6SCédric Le Goater 448fda9aaa6SCédric Le Goater multiplier = ((m + 1) / (n + 1)) / (p + 1); 449fda9aaa6SCédric Le Goater } 450fda9aaa6SCédric Le Goater 451a8f07376SCédric Le Goater return clkin * multiplier; 452fda9aaa6SCédric Le Goater } 453fda9aaa6SCédric Le Goater 454dd7f19a9SSteven Lee static uint32_t aspeed_2600_scu_calc_hpll(AspeedSCUState *s, uint32_t hpll_reg) 455dd7f19a9SSteven Lee { 456dd7f19a9SSteven Lee uint32_t multiplier = 1; 457dd7f19a9SSteven Lee uint32_t clkin = aspeed_scu_get_clkin(s); 458dd7f19a9SSteven Lee 459dd7f19a9SSteven Lee if (hpll_reg & SCU_AST2600_H_PLL_OFF) { 460dd7f19a9SSteven Lee return 0; 461dd7f19a9SSteven Lee } 462dd7f19a9SSteven Lee 463dd7f19a9SSteven Lee if (!(hpll_reg & SCU_AST2600_H_PLL_BYPASS_EN)) { 464dd7f19a9SSteven Lee uint32_t p = (hpll_reg >> 19) & 0xf; 465dd7f19a9SSteven Lee uint32_t n = (hpll_reg >> 13) & 0x3f; 466dd7f19a9SSteven Lee uint32_t m = hpll_reg & 0x1fff; 467dd7f19a9SSteven Lee 468dd7f19a9SSteven Lee multiplier = ((m + 1) / (n + 1)) / (p + 1); 469dd7f19a9SSteven Lee } 470dd7f19a9SSteven Lee 471dd7f19a9SSteven Lee return clkin * multiplier; 472dd7f19a9SSteven Lee } 473dd7f19a9SSteven Lee 4741c8a2388SAndrew Jeffery static void aspeed_scu_reset(DeviceState *dev) 4751c8a2388SAndrew Jeffery { 4761c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(dev); 4779a937f6cSCédric Le Goater AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev); 4781c8a2388SAndrew Jeffery 479e09cf363SJoel Stanley memcpy(s->regs, asc->resets, asc->nr_regs * 4); 4801c8a2388SAndrew Jeffery s->regs[SILICON_REV] = s->silicon_rev; 4811c8a2388SAndrew Jeffery s->regs[HW_STRAP1] = s->hw_strap1; 4821c8a2388SAndrew Jeffery s->regs[HW_STRAP2] = s->hw_strap2; 483b6e70d1dSJoel Stanley s->regs[PROT_KEY] = s->hw_prot_key; 4841c8a2388SAndrew Jeffery } 4851c8a2388SAndrew Jeffery 486365aff1eSCédric Le Goater static uint32_t aspeed_silicon_revs[] = { 487365aff1eSCédric Le Goater AST2400_A0_SILICON_REV, 4886efbac90SCédric Le Goater AST2400_A1_SILICON_REV, 489365aff1eSCédric Le Goater AST2500_A0_SILICON_REV, 490365aff1eSCédric Le Goater AST2500_A1_SILICON_REV, 491e09cf363SJoel Stanley AST2600_A0_SILICON_REV, 4927582591aSJoel Stanley AST2600_A1_SILICON_REV, 493c5811bb3SJoel Stanley AST2600_A2_SILICON_REV, 494c5811bb3SJoel Stanley AST2600_A3_SILICON_REV, 495fa541a60SSteven Lee AST1030_A0_SILICON_REV, 496fa541a60SSteven Lee AST1030_A1_SILICON_REV, 497365aff1eSCédric Le Goater }; 4981c8a2388SAndrew Jeffery 49979a9f323SCédric Le Goater bool is_supported_silicon_rev(uint32_t silicon_rev) 5001c8a2388SAndrew Jeffery { 5011c8a2388SAndrew Jeffery int i; 5021c8a2388SAndrew Jeffery 5031c8a2388SAndrew Jeffery for (i = 0; i < ARRAY_SIZE(aspeed_silicon_revs); i++) { 5041c8a2388SAndrew Jeffery if (silicon_rev == aspeed_silicon_revs[i]) { 5051c8a2388SAndrew Jeffery return true; 5061c8a2388SAndrew Jeffery } 5071c8a2388SAndrew Jeffery } 5081c8a2388SAndrew Jeffery 5091c8a2388SAndrew Jeffery return false; 5101c8a2388SAndrew Jeffery } 5111c8a2388SAndrew Jeffery 5121c8a2388SAndrew Jeffery static void aspeed_scu_realize(DeviceState *dev, Error **errp) 5131c8a2388SAndrew Jeffery { 5141c8a2388SAndrew Jeffery SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 5151c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(dev); 516e09cf363SJoel Stanley AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev); 5171c8a2388SAndrew Jeffery 5181c8a2388SAndrew Jeffery if (!is_supported_silicon_rev(s->silicon_rev)) { 5191c8a2388SAndrew Jeffery error_setg(errp, "Unknown silicon revision: 0x%" PRIx32, 5201c8a2388SAndrew Jeffery s->silicon_rev); 5211c8a2388SAndrew Jeffery return; 5221c8a2388SAndrew Jeffery } 5231c8a2388SAndrew Jeffery 524e09cf363SJoel Stanley memory_region_init_io(&s->iomem, OBJECT(s), asc->ops, s, 5251c8a2388SAndrew Jeffery TYPE_ASPEED_SCU, SCU_IO_REGION_SIZE); 5261c8a2388SAndrew Jeffery 5271c8a2388SAndrew Jeffery sysbus_init_mmio(sbd, &s->iomem); 5281c8a2388SAndrew Jeffery } 5291c8a2388SAndrew Jeffery 5301c8a2388SAndrew Jeffery static const VMStateDescription vmstate_aspeed_scu = { 5311c8a2388SAndrew Jeffery .name = "aspeed.scu", 532e09cf363SJoel Stanley .version_id = 2, 533e09cf363SJoel Stanley .minimum_version_id = 2, 534*e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 535e09cf363SJoel Stanley VMSTATE_UINT32_ARRAY(regs, AspeedSCUState, ASPEED_AST2600_SCU_NR_REGS), 5361c8a2388SAndrew Jeffery VMSTATE_END_OF_LIST() 5371c8a2388SAndrew Jeffery } 5381c8a2388SAndrew Jeffery }; 5391c8a2388SAndrew Jeffery 5401c8a2388SAndrew Jeffery static Property aspeed_scu_properties[] = { 5411c8a2388SAndrew Jeffery DEFINE_PROP_UINT32("silicon-rev", AspeedSCUState, silicon_rev, 0), 5421c8a2388SAndrew Jeffery DEFINE_PROP_UINT32("hw-strap1", AspeedSCUState, hw_strap1, 0), 5432ddfa281SCédric Le Goater DEFINE_PROP_UINT32("hw-strap2", AspeedSCUState, hw_strap2, 0), 544b6e70d1dSJoel Stanley DEFINE_PROP_UINT32("hw-prot-key", AspeedSCUState, hw_prot_key, 0), 5451c8a2388SAndrew Jeffery DEFINE_PROP_END_OF_LIST(), 5461c8a2388SAndrew Jeffery }; 5471c8a2388SAndrew Jeffery 5481c8a2388SAndrew Jeffery static void aspeed_scu_class_init(ObjectClass *klass, void *data) 5491c8a2388SAndrew Jeffery { 5501c8a2388SAndrew Jeffery DeviceClass *dc = DEVICE_CLASS(klass); 5511c8a2388SAndrew Jeffery dc->realize = aspeed_scu_realize; 5521c8a2388SAndrew Jeffery dc->reset = aspeed_scu_reset; 5531c8a2388SAndrew Jeffery dc->desc = "ASPEED System Control Unit"; 5541c8a2388SAndrew Jeffery dc->vmsd = &vmstate_aspeed_scu; 5554f67d30bSMarc-André Lureau device_class_set_props(dc, aspeed_scu_properties); 5561c8a2388SAndrew Jeffery } 5571c8a2388SAndrew Jeffery 5581c8a2388SAndrew Jeffery static const TypeInfo aspeed_scu_info = { 5591c8a2388SAndrew Jeffery .name = TYPE_ASPEED_SCU, 5601c8a2388SAndrew Jeffery .parent = TYPE_SYS_BUS_DEVICE, 5611c8a2388SAndrew Jeffery .instance_size = sizeof(AspeedSCUState), 5621c8a2388SAndrew Jeffery .class_init = aspeed_scu_class_init, 5639a937f6cSCédric Le Goater .class_size = sizeof(AspeedSCUClass), 5649a937f6cSCédric Le Goater .abstract = true, 5659a937f6cSCédric Le Goater }; 5669a937f6cSCédric Le Goater 5679a937f6cSCédric Le Goater static void aspeed_2400_scu_class_init(ObjectClass *klass, void *data) 5689a937f6cSCédric Le Goater { 5699a937f6cSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 5709a937f6cSCédric Le Goater AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); 5719a937f6cSCédric Le Goater 5729a937f6cSCédric Le Goater dc->desc = "ASPEED 2400 System Control Unit"; 5739a937f6cSCédric Le Goater asc->resets = ast2400_a0_resets; 5749a937f6cSCédric Le Goater asc->calc_hpll = aspeed_2400_scu_calc_hpll; 575dd7f19a9SSteven Lee asc->get_apb = aspeed_2400_scu_get_apb_freq; 5769a937f6cSCédric Le Goater asc->apb_divider = 2; 577e09cf363SJoel Stanley asc->nr_regs = ASPEED_SCU_NR_REGS; 578bad23bb6SSteven Lee asc->clkin_25Mhz = false; 579c7e1f572SJoel Stanley asc->ops = &aspeed_ast2400_scu_ops; 5809a937f6cSCédric Le Goater } 5819a937f6cSCédric Le Goater 5829a937f6cSCédric Le Goater static const TypeInfo aspeed_2400_scu_info = { 5839a937f6cSCédric Le Goater .name = TYPE_ASPEED_2400_SCU, 5849a937f6cSCédric Le Goater .parent = TYPE_ASPEED_SCU, 5859a937f6cSCédric Le Goater .instance_size = sizeof(AspeedSCUState), 5869a937f6cSCédric Le Goater .class_init = aspeed_2400_scu_class_init, 5879a937f6cSCédric Le Goater }; 5889a937f6cSCédric Le Goater 5899a937f6cSCédric Le Goater static void aspeed_2500_scu_class_init(ObjectClass *klass, void *data) 5909a937f6cSCédric Le Goater { 5919a937f6cSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 5929a937f6cSCédric Le Goater AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); 5939a937f6cSCédric Le Goater 5949a937f6cSCédric Le Goater dc->desc = "ASPEED 2500 System Control Unit"; 5959a937f6cSCédric Le Goater asc->resets = ast2500_a1_resets; 5969a937f6cSCédric Le Goater asc->calc_hpll = aspeed_2500_scu_calc_hpll; 597dd7f19a9SSteven Lee asc->get_apb = aspeed_2400_scu_get_apb_freq; 5989a937f6cSCédric Le Goater asc->apb_divider = 4; 599e09cf363SJoel Stanley asc->nr_regs = ASPEED_SCU_NR_REGS; 600bad23bb6SSteven Lee asc->clkin_25Mhz = false; 601c7e1f572SJoel Stanley asc->ops = &aspeed_ast2500_scu_ops; 6029a937f6cSCédric Le Goater } 6039a937f6cSCédric Le Goater 6049a937f6cSCédric Le Goater static const TypeInfo aspeed_2500_scu_info = { 6059a937f6cSCédric Le Goater .name = TYPE_ASPEED_2500_SCU, 6069a937f6cSCédric Le Goater .parent = TYPE_ASPEED_SCU, 6079a937f6cSCédric Le Goater .instance_size = sizeof(AspeedSCUState), 6089a937f6cSCédric Le Goater .class_init = aspeed_2500_scu_class_init, 6091c8a2388SAndrew Jeffery }; 6101c8a2388SAndrew Jeffery 611e09cf363SJoel Stanley static uint64_t aspeed_ast2600_scu_read(void *opaque, hwaddr offset, 612e09cf363SJoel Stanley unsigned size) 613e09cf363SJoel Stanley { 614e09cf363SJoel Stanley AspeedSCUState *s = ASPEED_SCU(opaque); 615e09cf363SJoel Stanley int reg = TO_REG(offset); 616e09cf363SJoel Stanley 617e09cf363SJoel Stanley if (reg >= ASPEED_AST2600_SCU_NR_REGS) { 618e09cf363SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 619e09cf363SJoel Stanley "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", 620e09cf363SJoel Stanley __func__, offset); 621e09cf363SJoel Stanley return 0; 622e09cf363SJoel Stanley } 623e09cf363SJoel Stanley 624e09cf363SJoel Stanley switch (reg) { 625e09cf363SJoel Stanley case AST2600_HPLL_EXT: 626e09cf363SJoel Stanley case AST2600_EPLL_EXT: 627e09cf363SJoel Stanley case AST2600_MPLL_EXT: 628e09cf363SJoel Stanley /* PLLs are always "locked" */ 629e09cf363SJoel Stanley return s->regs[reg] | BIT(31); 630e09cf363SJoel Stanley case AST2600_RNG_DATA: 631e09cf363SJoel Stanley /* 632e09cf363SJoel Stanley * On hardware, RNG_DATA works regardless of the state of the 633e09cf363SJoel Stanley * enable bit in RNG_CTRL 634e09cf363SJoel Stanley * 635e09cf363SJoel Stanley * TODO: Check this is true for ast2600 636e09cf363SJoel Stanley */ 637e09cf363SJoel Stanley s->regs[AST2600_RNG_DATA] = aspeed_scu_get_random(); 638e09cf363SJoel Stanley break; 639e09cf363SJoel Stanley } 640e09cf363SJoel Stanley 641673a6d16SCédric Le Goater trace_aspeed_scu_read(offset, size, s->regs[reg]); 642e09cf363SJoel Stanley return s->regs[reg]; 643e09cf363SJoel Stanley } 644e09cf363SJoel Stanley 645310b5bc6SJoel Stanley static void aspeed_ast2600_scu_write(void *opaque, hwaddr offset, 646310b5bc6SJoel Stanley uint64_t data64, unsigned size) 647e09cf363SJoel Stanley { 648e09cf363SJoel Stanley AspeedSCUState *s = ASPEED_SCU(opaque); 649e09cf363SJoel Stanley int reg = TO_REG(offset); 650310b5bc6SJoel Stanley /* Truncate here so bitwise operations below behave as expected */ 651310b5bc6SJoel Stanley uint32_t data = data64; 652e09cf363SJoel Stanley 653e09cf363SJoel Stanley if (reg >= ASPEED_AST2600_SCU_NR_REGS) { 654e09cf363SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 655e09cf363SJoel Stanley "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 656e09cf363SJoel Stanley __func__, offset); 657e09cf363SJoel Stanley return; 658e09cf363SJoel Stanley } 659e09cf363SJoel Stanley 660e09cf363SJoel Stanley if (reg > PROT_KEY && !s->regs[PROT_KEY]) { 661e09cf363SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__); 662e09cf363SJoel Stanley } 663e09cf363SJoel Stanley 664e09cf363SJoel Stanley trace_aspeed_scu_write(offset, size, data); 665e09cf363SJoel Stanley 666e09cf363SJoel Stanley switch (reg) { 667e09cf363SJoel Stanley case AST2600_PROT_KEY: 668e09cf363SJoel Stanley s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0; 669e09cf363SJoel Stanley return; 670e09cf363SJoel Stanley case AST2600_HW_STRAP1: 671e09cf363SJoel Stanley case AST2600_HW_STRAP2: 672e09cf363SJoel Stanley if (s->regs[reg + 2]) { 673e09cf363SJoel Stanley return; 674e09cf363SJoel Stanley } 675e09cf363SJoel Stanley /* fall through */ 676e09cf363SJoel Stanley case AST2600_SYS_RST_CTRL: 677e09cf363SJoel Stanley case AST2600_SYS_RST_CTRL2: 678310b5bc6SJoel Stanley case AST2600_CLK_STOP_CTRL: 679310b5bc6SJoel Stanley case AST2600_CLK_STOP_CTRL2: 680e09cf363SJoel Stanley /* W1S (Write 1 to set) registers */ 681e09cf363SJoel Stanley s->regs[reg] |= data; 682e09cf363SJoel Stanley return; 683e09cf363SJoel Stanley case AST2600_SYS_RST_CTRL_CLR: 684e09cf363SJoel Stanley case AST2600_SYS_RST_CTRL2_CLR: 685310b5bc6SJoel Stanley case AST2600_CLK_STOP_CTRL_CLR: 686310b5bc6SJoel Stanley case AST2600_CLK_STOP_CTRL2_CLR: 687e09cf363SJoel Stanley case AST2600_HW_STRAP1_CLR: 688e09cf363SJoel Stanley case AST2600_HW_STRAP2_CLR: 689310b5bc6SJoel Stanley /* 690310b5bc6SJoel Stanley * W1C (Write 1 to clear) registers are offset by one address from 691310b5bc6SJoel Stanley * the data register 692310b5bc6SJoel Stanley */ 693310b5bc6SJoel Stanley s->regs[reg - 1] &= ~data; 694e09cf363SJoel Stanley return; 695e09cf363SJoel Stanley 696e09cf363SJoel Stanley case AST2600_RNG_DATA: 697e09cf363SJoel Stanley case AST2600_SILICON_REV: 698e09cf363SJoel Stanley case AST2600_SILICON_REV2: 6997ffe647fSJoel Stanley case AST2600_CHIP_ID0: 7007ffe647fSJoel Stanley case AST2600_CHIP_ID1: 701e09cf363SJoel Stanley /* Add read only registers here */ 702e09cf363SJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 703e09cf363SJoel Stanley "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n", 704e09cf363SJoel Stanley __func__, offset); 705e09cf363SJoel Stanley return; 706e09cf363SJoel Stanley } 707e09cf363SJoel Stanley 708e09cf363SJoel Stanley s->regs[reg] = data; 709e09cf363SJoel Stanley } 710e09cf363SJoel Stanley 711e09cf363SJoel Stanley static const MemoryRegionOps aspeed_ast2600_scu_ops = { 712e09cf363SJoel Stanley .read = aspeed_ast2600_scu_read, 713e09cf363SJoel Stanley .write = aspeed_ast2600_scu_write, 714e09cf363SJoel Stanley .endianness = DEVICE_LITTLE_ENDIAN, 715e09cf363SJoel Stanley .valid.min_access_size = 4, 716e09cf363SJoel Stanley .valid.max_access_size = 4, 717e09cf363SJoel Stanley .valid.unaligned = false, 718e09cf363SJoel Stanley }; 719e09cf363SJoel Stanley 720c5811bb3SJoel Stanley static const uint32_t ast2600_a3_resets[ASPEED_AST2600_SCU_NR_REGS] = { 7217582591aSJoel Stanley [AST2600_SYS_RST_CTRL] = 0xF7C3FED8, 722c5811bb3SJoel Stanley [AST2600_SYS_RST_CTRL2] = 0x0DFFFFFC, 7237582591aSJoel Stanley [AST2600_CLK_STOP_CTRL] = 0xFFFF7F8A, 724e09cf363SJoel Stanley [AST2600_CLK_STOP_CTRL2] = 0xFFF0FFF0, 725c5811bb3SJoel Stanley [AST2600_DEBUG_CTRL] = 0x00000FFF, 726c5811bb3SJoel Stanley [AST2600_DEBUG_CTRL2] = 0x000000FF, 72714c17954SJoel Stanley [AST2600_SDRAM_HANDSHAKE] = 0x00000000, 728c5811bb3SJoel Stanley [AST2600_HPLL_PARAM] = 0x1000408F, 729c5811bb3SJoel Stanley [AST2600_APLL_PARAM] = 0x1000405F, 730c5811bb3SJoel Stanley [AST2600_MPLL_PARAM] = 0x1008405F, 731c5811bb3SJoel Stanley [AST2600_EPLL_PARAM] = 0x1004077F, 732c5811bb3SJoel Stanley [AST2600_DPLL_PARAM] = 0x1078405F, 733c5811bb3SJoel Stanley [AST2600_CLK_SEL] = 0xF3940000, 734c5811bb3SJoel Stanley [AST2600_CLK_SEL2] = 0x00700000, 735c5811bb3SJoel Stanley [AST2600_CLK_SEL3] = 0x00000000, 736c5811bb3SJoel Stanley [AST2600_CLK_SEL4] = 0xF3F40000, 737c5811bb3SJoel Stanley [AST2600_CLK_SEL5] = 0x30000000, 7389dca4556SPeter Delevoryas [AST2600_UARTCLK] = 0x00014506, 7399dca4556SPeter Delevoryas [AST2600_HUARTCLK] = 0x000145C0, 7407ffe647fSJoel Stanley [AST2600_CHIP_ID0] = 0x1234ABCD, 7417ffe647fSJoel Stanley [AST2600_CHIP_ID1] = 0x88884444, 742e09cf363SJoel Stanley }; 743e09cf363SJoel Stanley 744e09cf363SJoel Stanley static void aspeed_ast2600_scu_reset(DeviceState *dev) 745e09cf363SJoel Stanley { 746e09cf363SJoel Stanley AspeedSCUState *s = ASPEED_SCU(dev); 747e09cf363SJoel Stanley AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev); 748e09cf363SJoel Stanley 749e09cf363SJoel Stanley memcpy(s->regs, asc->resets, asc->nr_regs * 4); 750e09cf363SJoel Stanley 751204dab83SJoel Stanley /* 752204dab83SJoel Stanley * A0 reports A0 in _REV, but subsequent revisions report A1 regardless 753204dab83SJoel Stanley * of actual revision. QEMU and Linux only support A1 onwards so this is 754204dab83SJoel Stanley * sufficient. 755204dab83SJoel Stanley */ 756c5811bb3SJoel Stanley s->regs[AST2600_SILICON_REV] = AST2600_A3_SILICON_REV; 757e09cf363SJoel Stanley s->regs[AST2600_SILICON_REV2] = s->silicon_rev; 758e09cf363SJoel Stanley s->regs[AST2600_HW_STRAP1] = s->hw_strap1; 759e09cf363SJoel Stanley s->regs[AST2600_HW_STRAP2] = s->hw_strap2; 760e09cf363SJoel Stanley s->regs[PROT_KEY] = s->hw_prot_key; 761e09cf363SJoel Stanley } 762e09cf363SJoel Stanley 763e09cf363SJoel Stanley static void aspeed_2600_scu_class_init(ObjectClass *klass, void *data) 764e09cf363SJoel Stanley { 765e09cf363SJoel Stanley DeviceClass *dc = DEVICE_CLASS(klass); 766e09cf363SJoel Stanley AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); 767e09cf363SJoel Stanley 768e09cf363SJoel Stanley dc->desc = "ASPEED 2600 System Control Unit"; 769e09cf363SJoel Stanley dc->reset = aspeed_ast2600_scu_reset; 770c5811bb3SJoel Stanley asc->resets = ast2600_a3_resets; 771dd7f19a9SSteven Lee asc->calc_hpll = aspeed_2600_scu_calc_hpll; 772dd7f19a9SSteven Lee asc->get_apb = aspeed_2600_scu_get_apb_freq; 773e09cf363SJoel Stanley asc->apb_divider = 4; 774e09cf363SJoel Stanley asc->nr_regs = ASPEED_AST2600_SCU_NR_REGS; 775bad23bb6SSteven Lee asc->clkin_25Mhz = true; 776e09cf363SJoel Stanley asc->ops = &aspeed_ast2600_scu_ops; 777e09cf363SJoel Stanley } 778e09cf363SJoel Stanley 779e09cf363SJoel Stanley static const TypeInfo aspeed_2600_scu_info = { 780e09cf363SJoel Stanley .name = TYPE_ASPEED_2600_SCU, 781e09cf363SJoel Stanley .parent = TYPE_ASPEED_SCU, 782e09cf363SJoel Stanley .instance_size = sizeof(AspeedSCUState), 783e09cf363SJoel Stanley .class_init = aspeed_2600_scu_class_init, 784e09cf363SJoel Stanley }; 785e09cf363SJoel Stanley 786fa541a60SSteven Lee static const uint32_t ast1030_a1_resets[ASPEED_AST2600_SCU_NR_REGS] = { 787fa541a60SSteven Lee [AST2600_SYS_RST_CTRL] = 0xFFC3FED8, 788fa541a60SSteven Lee [AST2600_SYS_RST_CTRL2] = 0x09FFFFFC, 789fa541a60SSteven Lee [AST2600_CLK_STOP_CTRL] = 0xFFFF7F8A, 790fa541a60SSteven Lee [AST2600_CLK_STOP_CTRL2] = 0xFFF0FFF0, 791fa541a60SSteven Lee [AST2600_DEBUG_CTRL2] = 0x00000000, 792fa541a60SSteven Lee [AST2600_HPLL_PARAM] = 0x10004077, 793fa541a60SSteven Lee [AST2600_HPLL_EXT] = 0x00000031, 794fa541a60SSteven Lee [AST2600_CLK_SEL4] = 0x43F90900, 795fa541a60SSteven Lee [AST2600_CLK_SEL5] = 0x40000000, 796fa541a60SSteven Lee [AST2600_CHIP_ID0] = 0xDEADBEEF, 797fa541a60SSteven Lee [AST2600_CHIP_ID1] = 0x0BADCAFE, 798fa541a60SSteven Lee }; 799fa541a60SSteven Lee 800fa541a60SSteven Lee static void aspeed_ast1030_scu_reset(DeviceState *dev) 801fa541a60SSteven Lee { 802fa541a60SSteven Lee AspeedSCUState *s = ASPEED_SCU(dev); 803fa541a60SSteven Lee AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev); 804fa541a60SSteven Lee 805fa541a60SSteven Lee memcpy(s->regs, asc->resets, asc->nr_regs * 4); 806fa541a60SSteven Lee 807fa541a60SSteven Lee s->regs[AST2600_SILICON_REV] = AST1030_A1_SILICON_REV; 808fa541a60SSteven Lee s->regs[AST2600_SILICON_REV2] = s->silicon_rev; 809fa541a60SSteven Lee s->regs[AST2600_HW_STRAP1] = s->hw_strap1; 810fa541a60SSteven Lee s->regs[AST2600_HW_STRAP2] = s->hw_strap2; 811fa541a60SSteven Lee s->regs[PROT_KEY] = s->hw_prot_key; 812fa541a60SSteven Lee } 813fa541a60SSteven Lee 814fa541a60SSteven Lee static void aspeed_1030_scu_class_init(ObjectClass *klass, void *data) 815fa541a60SSteven Lee { 816fa541a60SSteven Lee DeviceClass *dc = DEVICE_CLASS(klass); 817fa541a60SSteven Lee AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); 818fa541a60SSteven Lee 819fa541a60SSteven Lee dc->desc = "ASPEED 1030 System Control Unit"; 820fa541a60SSteven Lee dc->reset = aspeed_ast1030_scu_reset; 821fa541a60SSteven Lee asc->resets = ast1030_a1_resets; 822fa541a60SSteven Lee asc->calc_hpll = aspeed_2600_scu_calc_hpll; 823fa541a60SSteven Lee asc->get_apb = aspeed_1030_scu_get_apb_freq; 824fa541a60SSteven Lee asc->apb_divider = 2; 825fa541a60SSteven Lee asc->nr_regs = ASPEED_AST2600_SCU_NR_REGS; 826fa541a60SSteven Lee asc->clkin_25Mhz = true; 827fa541a60SSteven Lee asc->ops = &aspeed_ast2600_scu_ops; 828fa541a60SSteven Lee } 829fa541a60SSteven Lee 830fa541a60SSteven Lee static const TypeInfo aspeed_1030_scu_info = { 831fa541a60SSteven Lee .name = TYPE_ASPEED_1030_SCU, 832fa541a60SSteven Lee .parent = TYPE_ASPEED_SCU, 833fa541a60SSteven Lee .instance_size = sizeof(AspeedSCUState), 834fa541a60SSteven Lee .class_init = aspeed_1030_scu_class_init, 835fa541a60SSteven Lee }; 836fa541a60SSteven Lee 8371c8a2388SAndrew Jeffery static void aspeed_scu_register_types(void) 8381c8a2388SAndrew Jeffery { 8391c8a2388SAndrew Jeffery type_register_static(&aspeed_scu_info); 8409a937f6cSCédric Le Goater type_register_static(&aspeed_2400_scu_info); 8419a937f6cSCédric Le Goater type_register_static(&aspeed_2500_scu_info); 842e09cf363SJoel Stanley type_register_static(&aspeed_2600_scu_info); 843fa541a60SSteven Lee type_register_static(&aspeed_1030_scu_info); 8441c8a2388SAndrew Jeffery } 8451c8a2388SAndrew Jeffery 8461c8a2388SAndrew Jeffery type_init(aspeed_scu_register_types); 847