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" 151c8a2388SAndrew Jeffery #include "qapi/error.h" 161c8a2388SAndrew Jeffery #include "qapi/visitor.h" 171c8a2388SAndrew Jeffery #include "qemu/bitops.h" 18aa4b04a0SPranith Kumar #include "qemu/log.h" 19acd9575eSJoel Stanley #include "crypto/random.h" 201c8a2388SAndrew Jeffery #include "trace.h" 211c8a2388SAndrew Jeffery 221c8a2388SAndrew Jeffery #define TO_REG(offset) ((offset) >> 2) 231c8a2388SAndrew Jeffery 241c8a2388SAndrew Jeffery #define PROT_KEY TO_REG(0x00) 251c8a2388SAndrew Jeffery #define SYS_RST_CTRL TO_REG(0x04) 261c8a2388SAndrew Jeffery #define CLK_SEL TO_REG(0x08) 271c8a2388SAndrew Jeffery #define CLK_STOP_CTRL TO_REG(0x0C) 281c8a2388SAndrew Jeffery #define FREQ_CNTR_CTRL TO_REG(0x10) 291c8a2388SAndrew Jeffery #define FREQ_CNTR_EVAL TO_REG(0x14) 301c8a2388SAndrew Jeffery #define IRQ_CTRL TO_REG(0x18) 311c8a2388SAndrew Jeffery #define D2PLL_PARAM TO_REG(0x1C) 321c8a2388SAndrew Jeffery #define MPLL_PARAM TO_REG(0x20) 331c8a2388SAndrew Jeffery #define HPLL_PARAM TO_REG(0x24) 341c8a2388SAndrew Jeffery #define FREQ_CNTR_RANGE TO_REG(0x28) 351c8a2388SAndrew Jeffery #define MISC_CTRL1 TO_REG(0x2C) 361c8a2388SAndrew Jeffery #define PCI_CTRL1 TO_REG(0x30) 371c8a2388SAndrew Jeffery #define PCI_CTRL2 TO_REG(0x34) 381c8a2388SAndrew Jeffery #define PCI_CTRL3 TO_REG(0x38) 391c8a2388SAndrew Jeffery #define SYS_RST_STATUS TO_REG(0x3C) 401c8a2388SAndrew Jeffery #define SOC_SCRATCH1 TO_REG(0x40) 411c8a2388SAndrew Jeffery #define SOC_SCRATCH2 TO_REG(0x44) 421c8a2388SAndrew Jeffery #define MAC_CLK_DELAY TO_REG(0x48) 431c8a2388SAndrew Jeffery #define MISC_CTRL2 TO_REG(0x4C) 441c8a2388SAndrew Jeffery #define VGA_SCRATCH1 TO_REG(0x50) 451c8a2388SAndrew Jeffery #define VGA_SCRATCH2 TO_REG(0x54) 461c8a2388SAndrew Jeffery #define VGA_SCRATCH3 TO_REG(0x58) 471c8a2388SAndrew Jeffery #define VGA_SCRATCH4 TO_REG(0x5C) 481c8a2388SAndrew Jeffery #define VGA_SCRATCH5 TO_REG(0x60) 491c8a2388SAndrew Jeffery #define VGA_SCRATCH6 TO_REG(0x64) 501c8a2388SAndrew Jeffery #define VGA_SCRATCH7 TO_REG(0x68) 511c8a2388SAndrew Jeffery #define VGA_SCRATCH8 TO_REG(0x6C) 521c8a2388SAndrew Jeffery #define HW_STRAP1 TO_REG(0x70) 531c8a2388SAndrew Jeffery #define RNG_CTRL TO_REG(0x74) 541c8a2388SAndrew Jeffery #define RNG_DATA TO_REG(0x78) 551c8a2388SAndrew Jeffery #define SILICON_REV TO_REG(0x7C) 561c8a2388SAndrew Jeffery #define PINMUX_CTRL1 TO_REG(0x80) 571c8a2388SAndrew Jeffery #define PINMUX_CTRL2 TO_REG(0x84) 581c8a2388SAndrew Jeffery #define PINMUX_CTRL3 TO_REG(0x88) 591c8a2388SAndrew Jeffery #define PINMUX_CTRL4 TO_REG(0x8C) 601c8a2388SAndrew Jeffery #define PINMUX_CTRL5 TO_REG(0x90) 611c8a2388SAndrew Jeffery #define PINMUX_CTRL6 TO_REG(0x94) 621c8a2388SAndrew Jeffery #define WDT_RST_CTRL TO_REG(0x9C) 631c8a2388SAndrew Jeffery #define PINMUX_CTRL7 TO_REG(0xA0) 641c8a2388SAndrew Jeffery #define PINMUX_CTRL8 TO_REG(0xA4) 651c8a2388SAndrew Jeffery #define PINMUX_CTRL9 TO_REG(0xA8) 661c8a2388SAndrew Jeffery #define WAKEUP_EN TO_REG(0xC0) 671c8a2388SAndrew Jeffery #define WAKEUP_CTRL TO_REG(0xC4) 681c8a2388SAndrew Jeffery #define HW_STRAP2 TO_REG(0xD0) 691c8a2388SAndrew Jeffery #define FREE_CNTR4 TO_REG(0xE0) 701c8a2388SAndrew Jeffery #define FREE_CNTR4_EXT TO_REG(0xE4) 711c8a2388SAndrew Jeffery #define CPU2_CTRL TO_REG(0x100) 721c8a2388SAndrew Jeffery #define CPU2_BASE_SEG1 TO_REG(0x104) 731c8a2388SAndrew Jeffery #define CPU2_BASE_SEG2 TO_REG(0x108) 741c8a2388SAndrew Jeffery #define CPU2_BASE_SEG3 TO_REG(0x10C) 751c8a2388SAndrew Jeffery #define CPU2_BASE_SEG4 TO_REG(0x110) 761c8a2388SAndrew Jeffery #define CPU2_BASE_SEG5 TO_REG(0x114) 771c8a2388SAndrew Jeffery #define CPU2_CACHE_CTRL TO_REG(0x118) 781c8a2388SAndrew Jeffery #define UART_HPLL_CLK TO_REG(0x160) 791c8a2388SAndrew Jeffery #define PCIE_CTRL TO_REG(0x180) 801c8a2388SAndrew Jeffery #define BMC_MMIO_CTRL TO_REG(0x184) 811c8a2388SAndrew Jeffery #define RELOC_DECODE_BASE1 TO_REG(0x188) 821c8a2388SAndrew Jeffery #define RELOC_DECODE_BASE2 TO_REG(0x18C) 831c8a2388SAndrew Jeffery #define MAILBOX_DECODE_BASE TO_REG(0x190) 841c8a2388SAndrew Jeffery #define SRAM_DECODE_BASE1 TO_REG(0x194) 851c8a2388SAndrew Jeffery #define SRAM_DECODE_BASE2 TO_REG(0x198) 861c8a2388SAndrew Jeffery #define BMC_REV TO_REG(0x19C) 871c8a2388SAndrew Jeffery #define BMC_DEV_ID TO_REG(0x1A4) 881c8a2388SAndrew Jeffery 89c491e152SCédric Le Goater #define SCU_IO_REGION_SIZE 0x1000 901c8a2388SAndrew Jeffery 911c8a2388SAndrew Jeffery static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = { 921c8a2388SAndrew Jeffery [SYS_RST_CTRL] = 0xFFCFFEDCU, 931c8a2388SAndrew Jeffery [CLK_SEL] = 0xF3F40000U, 941c8a2388SAndrew Jeffery [CLK_STOP_CTRL] = 0x19FC3E8BU, 951c8a2388SAndrew Jeffery [D2PLL_PARAM] = 0x00026108U, 961c8a2388SAndrew Jeffery [MPLL_PARAM] = 0x00030291U, 971c8a2388SAndrew Jeffery [HPLL_PARAM] = 0x00000291U, 981c8a2388SAndrew Jeffery [MISC_CTRL1] = 0x00000010U, 991c8a2388SAndrew Jeffery [PCI_CTRL1] = 0x20001A03U, 1001c8a2388SAndrew Jeffery [PCI_CTRL2] = 0x20001A03U, 1011c8a2388SAndrew Jeffery [PCI_CTRL3] = 0x04000030U, 1021c8a2388SAndrew Jeffery [SYS_RST_STATUS] = 0x00000001U, 1031c8a2388SAndrew Jeffery [SOC_SCRATCH1] = 0x000000C0U, /* SoC completed DRAM init */ 1041c8a2388SAndrew Jeffery [MISC_CTRL2] = 0x00000023U, 1051c8a2388SAndrew Jeffery [RNG_CTRL] = 0x0000000EU, 1061c8a2388SAndrew Jeffery [PINMUX_CTRL2] = 0x0000F000U, 1071c8a2388SAndrew Jeffery [PINMUX_CTRL3] = 0x01000000U, 1081c8a2388SAndrew Jeffery [PINMUX_CTRL4] = 0x000000FFU, 1091c8a2388SAndrew Jeffery [PINMUX_CTRL5] = 0x0000A000U, 1101c8a2388SAndrew Jeffery [WDT_RST_CTRL] = 0x003FFFF3U, 1111c8a2388SAndrew Jeffery [PINMUX_CTRL8] = 0xFFFF0000U, 1121c8a2388SAndrew Jeffery [PINMUX_CTRL9] = 0x000FFFFFU, 1131c8a2388SAndrew Jeffery [FREE_CNTR4] = 0x000000FFU, 1141c8a2388SAndrew Jeffery [FREE_CNTR4_EXT] = 0x000000FFU, 1151c8a2388SAndrew Jeffery [CPU2_BASE_SEG1] = 0x80000000U, 1161c8a2388SAndrew Jeffery [CPU2_BASE_SEG4] = 0x1E600000U, 1171c8a2388SAndrew Jeffery [CPU2_BASE_SEG5] = 0xC0000000U, 1181c8a2388SAndrew Jeffery [UART_HPLL_CLK] = 0x00001903U, 1191c8a2388SAndrew Jeffery [PCIE_CTRL] = 0x0000007BU, 1201c8a2388SAndrew Jeffery [BMC_DEV_ID] = 0x00002402U 1211c8a2388SAndrew Jeffery }; 1221c8a2388SAndrew Jeffery 123365aff1eSCédric Le Goater /* SCU70 bit 23: 0 24Mhz. bit 11:9: 0b001 AXI:ABH ratio 2:1 */ 124365aff1eSCédric Le Goater /* AST2500 revision A1 */ 125365aff1eSCédric Le Goater 126365aff1eSCédric Le Goater static const uint32_t ast2500_a1_resets[ASPEED_SCU_NR_REGS] = { 127365aff1eSCédric Le Goater [SYS_RST_CTRL] = 0xFFCFFEDCU, 128365aff1eSCédric Le Goater [CLK_SEL] = 0xF3F40000U, 129365aff1eSCédric Le Goater [CLK_STOP_CTRL] = 0x19FC3E8BU, 130365aff1eSCédric Le Goater [D2PLL_PARAM] = 0x00026108U, 131365aff1eSCédric Le Goater [MPLL_PARAM] = 0x00030291U, 132365aff1eSCédric Le Goater [HPLL_PARAM] = 0x93000400U, 133365aff1eSCédric Le Goater [MISC_CTRL1] = 0x00000010U, 134365aff1eSCédric Le Goater [PCI_CTRL1] = 0x20001A03U, 135365aff1eSCédric Le Goater [PCI_CTRL2] = 0x20001A03U, 136365aff1eSCédric Le Goater [PCI_CTRL3] = 0x04000030U, 137365aff1eSCédric Le Goater [SYS_RST_STATUS] = 0x00000001U, 138365aff1eSCédric Le Goater [SOC_SCRATCH1] = 0x000000C0U, /* SoC completed DRAM init */ 139365aff1eSCédric Le Goater [MISC_CTRL2] = 0x00000023U, 140365aff1eSCédric Le Goater [RNG_CTRL] = 0x0000000EU, 141365aff1eSCédric Le Goater [PINMUX_CTRL2] = 0x0000F000U, 142365aff1eSCédric Le Goater [PINMUX_CTRL3] = 0x03000000U, 143365aff1eSCédric Le Goater [PINMUX_CTRL4] = 0x00000000U, 144365aff1eSCédric Le Goater [PINMUX_CTRL5] = 0x0000A000U, 145365aff1eSCédric Le Goater [WDT_RST_CTRL] = 0x023FFFF3U, 146365aff1eSCédric Le Goater [PINMUX_CTRL8] = 0xFFFF0000U, 147365aff1eSCédric Le Goater [PINMUX_CTRL9] = 0x000FFFFFU, 148365aff1eSCédric Le Goater [FREE_CNTR4] = 0x000000FFU, 149365aff1eSCédric Le Goater [FREE_CNTR4_EXT] = 0x000000FFU, 150365aff1eSCédric Le Goater [CPU2_BASE_SEG1] = 0x80000000U, 151365aff1eSCédric Le Goater [CPU2_BASE_SEG4] = 0x1E600000U, 152365aff1eSCédric Le Goater [CPU2_BASE_SEG5] = 0xC0000000U, 153365aff1eSCédric Le Goater [UART_HPLL_CLK] = 0x00001903U, 154365aff1eSCédric Le Goater [PCIE_CTRL] = 0x0000007BU, 155365aff1eSCédric Le Goater [BMC_DEV_ID] = 0x00002402U 156365aff1eSCédric Le Goater }; 157365aff1eSCédric Le Goater 158acd9575eSJoel Stanley static uint32_t aspeed_scu_get_random(void) 159acd9575eSJoel Stanley { 160acd9575eSJoel Stanley Error *err = NULL; 161acd9575eSJoel Stanley uint32_t num; 162acd9575eSJoel Stanley 163acd9575eSJoel Stanley if (qcrypto_random_bytes((uint8_t *)&num, sizeof(num), &err)) { 164acd9575eSJoel Stanley error_report_err(err); 165acd9575eSJoel Stanley exit(1); 166acd9575eSJoel Stanley } 167acd9575eSJoel Stanley 168acd9575eSJoel Stanley return num; 169acd9575eSJoel Stanley } 170acd9575eSJoel Stanley 171*fda9aaa6SCédric Le Goater static void aspeed_scu_set_apb_freq(AspeedSCUState *s) 172*fda9aaa6SCédric Le Goater { 173*fda9aaa6SCédric Le Goater uint32_t apb_divider; 174*fda9aaa6SCédric Le Goater 175*fda9aaa6SCédric Le Goater switch (s->silicon_rev) { 176*fda9aaa6SCédric Le Goater case AST2400_A0_SILICON_REV: 177*fda9aaa6SCédric Le Goater case AST2400_A1_SILICON_REV: 178*fda9aaa6SCédric Le Goater apb_divider = 2; 179*fda9aaa6SCédric Le Goater break; 180*fda9aaa6SCédric Le Goater case AST2500_A0_SILICON_REV: 181*fda9aaa6SCédric Le Goater case AST2500_A1_SILICON_REV: 182*fda9aaa6SCédric Le Goater apb_divider = 4; 183*fda9aaa6SCédric Le Goater break; 184*fda9aaa6SCédric Le Goater default: 185*fda9aaa6SCédric Le Goater g_assert_not_reached(); 186*fda9aaa6SCédric Le Goater } 187*fda9aaa6SCédric Le Goater 188*fda9aaa6SCédric Le Goater s->apb_freq = s->hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[CLK_SEL]) + 1) 189*fda9aaa6SCédric Le Goater / apb_divider; 190*fda9aaa6SCédric Le Goater } 191*fda9aaa6SCédric Le Goater 1921c8a2388SAndrew Jeffery static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size) 1931c8a2388SAndrew Jeffery { 1941c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(opaque); 1951c8a2388SAndrew Jeffery int reg = TO_REG(offset); 1961c8a2388SAndrew Jeffery 1971c8a2388SAndrew Jeffery if (reg >= ARRAY_SIZE(s->regs)) { 1981c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 1991c8a2388SAndrew Jeffery "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", 2001c8a2388SAndrew Jeffery __func__, offset); 2011c8a2388SAndrew Jeffery return 0; 2021c8a2388SAndrew Jeffery } 2031c8a2388SAndrew Jeffery 2041c8a2388SAndrew Jeffery switch (reg) { 205acd9575eSJoel Stanley case RNG_DATA: 206acd9575eSJoel Stanley /* On hardware, RNG_DATA works regardless of 207acd9575eSJoel Stanley * the state of the enable bit in RNG_CTRL 208acd9575eSJoel Stanley */ 209acd9575eSJoel Stanley s->regs[RNG_DATA] = aspeed_scu_get_random(); 210acd9575eSJoel Stanley break; 2111c8a2388SAndrew Jeffery case WAKEUP_EN: 2121c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 2131c8a2388SAndrew Jeffery "%s: Read of write-only offset 0x%" HWADDR_PRIx "\n", 2141c8a2388SAndrew Jeffery __func__, offset); 2151c8a2388SAndrew Jeffery break; 2161c8a2388SAndrew Jeffery } 2171c8a2388SAndrew Jeffery 2181c8a2388SAndrew Jeffery return s->regs[reg]; 2191c8a2388SAndrew Jeffery } 2201c8a2388SAndrew Jeffery 2211c8a2388SAndrew Jeffery static void aspeed_scu_write(void *opaque, hwaddr offset, uint64_t data, 2221c8a2388SAndrew Jeffery unsigned size) 2231c8a2388SAndrew Jeffery { 2241c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(opaque); 2251c8a2388SAndrew Jeffery int reg = TO_REG(offset); 2261c8a2388SAndrew Jeffery 2271c8a2388SAndrew Jeffery if (reg >= ARRAY_SIZE(s->regs)) { 2281c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 2291c8a2388SAndrew Jeffery "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 2301c8a2388SAndrew Jeffery __func__, offset); 2311c8a2388SAndrew Jeffery return; 2321c8a2388SAndrew Jeffery } 2331c8a2388SAndrew Jeffery 2341c8a2388SAndrew Jeffery if (reg > PROT_KEY && reg < CPU2_BASE_SEG1 && 2355c1d3a2bSHugo Landau !s->regs[PROT_KEY]) { 2361c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__); 2371c8a2388SAndrew Jeffery return; 2381c8a2388SAndrew Jeffery } 2391c8a2388SAndrew Jeffery 2401c8a2388SAndrew Jeffery trace_aspeed_scu_write(offset, size, data); 2411c8a2388SAndrew Jeffery 2421c8a2388SAndrew Jeffery switch (reg) { 2435c1d3a2bSHugo Landau case PROT_KEY: 2445c1d3a2bSHugo Landau s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0; 2455c1d3a2bSHugo Landau return; 246*fda9aaa6SCédric Le Goater case CLK_SEL: 247*fda9aaa6SCédric Le Goater s->regs[reg] = data; 248*fda9aaa6SCédric Le Goater aspeed_scu_set_apb_freq(s); 249*fda9aaa6SCédric Le Goater break; 2505c1d3a2bSHugo Landau 2511c8a2388SAndrew Jeffery case FREQ_CNTR_EVAL: 2521c8a2388SAndrew Jeffery case VGA_SCRATCH1 ... VGA_SCRATCH8: 2531c8a2388SAndrew Jeffery case RNG_DATA: 2541c8a2388SAndrew Jeffery case SILICON_REV: 2551c8a2388SAndrew Jeffery case FREE_CNTR4: 2561c8a2388SAndrew Jeffery case FREE_CNTR4_EXT: 2571c8a2388SAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 2581c8a2388SAndrew Jeffery "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n", 2591c8a2388SAndrew Jeffery __func__, offset); 2601c8a2388SAndrew Jeffery return; 2611c8a2388SAndrew Jeffery } 2621c8a2388SAndrew Jeffery 2631c8a2388SAndrew Jeffery s->regs[reg] = data; 2641c8a2388SAndrew Jeffery } 2651c8a2388SAndrew Jeffery 2661c8a2388SAndrew Jeffery static const MemoryRegionOps aspeed_scu_ops = { 2671c8a2388SAndrew Jeffery .read = aspeed_scu_read, 2681c8a2388SAndrew Jeffery .write = aspeed_scu_write, 2691c8a2388SAndrew Jeffery .endianness = DEVICE_LITTLE_ENDIAN, 2701c8a2388SAndrew Jeffery .valid.min_access_size = 4, 2711c8a2388SAndrew Jeffery .valid.max_access_size = 4, 2721c8a2388SAndrew Jeffery .valid.unaligned = false, 2731c8a2388SAndrew Jeffery }; 2741c8a2388SAndrew Jeffery 275*fda9aaa6SCédric Le Goater static uint32_t aspeed_scu_get_clkin(AspeedSCUState *s) 276*fda9aaa6SCédric Le Goater { 277*fda9aaa6SCédric Le Goater if (s->hw_strap1 & SCU_HW_STRAP_CLK_25M_IN) { 278*fda9aaa6SCédric Le Goater return 25000000; 279*fda9aaa6SCédric Le Goater } else if (s->hw_strap1 & SCU_HW_STRAP_CLK_48M_IN) { 280*fda9aaa6SCédric Le Goater return 48000000; 281*fda9aaa6SCédric Le Goater } else { 282*fda9aaa6SCédric Le Goater return 24000000; 283*fda9aaa6SCédric Le Goater } 284*fda9aaa6SCédric Le Goater } 285*fda9aaa6SCédric Le Goater 286*fda9aaa6SCédric Le Goater /* 287*fda9aaa6SCédric Le Goater * Strapped frequencies for the AST2400 in MHz. They depend on the 288*fda9aaa6SCédric Le Goater * clkin frequency. 289*fda9aaa6SCédric Le Goater */ 290*fda9aaa6SCédric Le Goater static const uint32_t hpll_ast2400_freqs[][4] = { 291*fda9aaa6SCédric Le Goater { 384, 360, 336, 408 }, /* 24MHz or 48MHz */ 292*fda9aaa6SCédric Le Goater { 400, 375, 350, 425 }, /* 25MHz */ 293*fda9aaa6SCédric Le Goater }; 294*fda9aaa6SCédric Le Goater 295*fda9aaa6SCédric Le Goater static uint32_t aspeed_scu_calc_hpll_ast2400(AspeedSCUState *s) 296*fda9aaa6SCédric Le Goater { 297*fda9aaa6SCédric Le Goater uint32_t hpll_reg = s->regs[HPLL_PARAM]; 298*fda9aaa6SCédric Le Goater uint8_t freq_select; 299*fda9aaa6SCédric Le Goater bool clk_25m_in; 300*fda9aaa6SCédric Le Goater 301*fda9aaa6SCédric Le Goater if (hpll_reg & SCU_AST2400_H_PLL_OFF) { 302*fda9aaa6SCédric Le Goater return 0; 303*fda9aaa6SCédric Le Goater } 304*fda9aaa6SCédric Le Goater 305*fda9aaa6SCédric Le Goater if (hpll_reg & SCU_AST2400_H_PLL_PROGRAMMED) { 306*fda9aaa6SCédric Le Goater uint32_t multiplier = 1; 307*fda9aaa6SCédric Le Goater 308*fda9aaa6SCédric Le Goater if (!(hpll_reg & SCU_AST2400_H_PLL_BYPASS_EN)) { 309*fda9aaa6SCédric Le Goater uint32_t n = (hpll_reg >> 5) & 0x3f; 310*fda9aaa6SCédric Le Goater uint32_t od = (hpll_reg >> 4) & 0x1; 311*fda9aaa6SCédric Le Goater uint32_t d = hpll_reg & 0xf; 312*fda9aaa6SCédric Le Goater 313*fda9aaa6SCédric Le Goater multiplier = (2 - od) * ((n + 2) / (d + 1)); 314*fda9aaa6SCédric Le Goater } 315*fda9aaa6SCédric Le Goater 316*fda9aaa6SCédric Le Goater return s->clkin * multiplier; 317*fda9aaa6SCédric Le Goater } 318*fda9aaa6SCédric Le Goater 319*fda9aaa6SCédric Le Goater /* HW strapping */ 320*fda9aaa6SCédric Le Goater clk_25m_in = !!(s->hw_strap1 & SCU_HW_STRAP_CLK_25M_IN); 321*fda9aaa6SCédric Le Goater freq_select = SCU_AST2400_HW_STRAP_GET_H_PLL_CLK(s->hw_strap1); 322*fda9aaa6SCédric Le Goater 323*fda9aaa6SCédric Le Goater return hpll_ast2400_freqs[clk_25m_in][freq_select] * 1000000; 324*fda9aaa6SCédric Le Goater } 325*fda9aaa6SCédric Le Goater 326*fda9aaa6SCédric Le Goater static uint32_t aspeed_scu_calc_hpll_ast2500(AspeedSCUState *s) 327*fda9aaa6SCédric Le Goater { 328*fda9aaa6SCédric Le Goater uint32_t hpll_reg = s->regs[HPLL_PARAM]; 329*fda9aaa6SCédric Le Goater uint32_t multiplier = 1; 330*fda9aaa6SCédric Le Goater 331*fda9aaa6SCédric Le Goater if (hpll_reg & SCU_H_PLL_OFF) { 332*fda9aaa6SCédric Le Goater return 0; 333*fda9aaa6SCédric Le Goater } 334*fda9aaa6SCédric Le Goater 335*fda9aaa6SCédric Le Goater if (!(hpll_reg & SCU_H_PLL_BYPASS_EN)) { 336*fda9aaa6SCédric Le Goater uint32_t p = (hpll_reg >> 13) & 0x3f; 337*fda9aaa6SCédric Le Goater uint32_t m = (hpll_reg >> 5) & 0xff; 338*fda9aaa6SCédric Le Goater uint32_t n = hpll_reg & 0x1f; 339*fda9aaa6SCédric Le Goater 340*fda9aaa6SCédric Le Goater multiplier = ((m + 1) / (n + 1)) / (p + 1); 341*fda9aaa6SCédric Le Goater } 342*fda9aaa6SCédric Le Goater 343*fda9aaa6SCédric Le Goater return s->clkin * multiplier; 344*fda9aaa6SCédric Le Goater } 345*fda9aaa6SCédric Le Goater 3461c8a2388SAndrew Jeffery static void aspeed_scu_reset(DeviceState *dev) 3471c8a2388SAndrew Jeffery { 3481c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(dev); 3491c8a2388SAndrew Jeffery const uint32_t *reset; 350*fda9aaa6SCédric Le Goater uint32_t (*calc_hpll)(AspeedSCUState *s); 3511c8a2388SAndrew Jeffery 3521c8a2388SAndrew Jeffery switch (s->silicon_rev) { 3531c8a2388SAndrew Jeffery case AST2400_A0_SILICON_REV: 3546efbac90SCédric Le Goater case AST2400_A1_SILICON_REV: 3551c8a2388SAndrew Jeffery reset = ast2400_a0_resets; 356*fda9aaa6SCédric Le Goater calc_hpll = aspeed_scu_calc_hpll_ast2400; 3571c8a2388SAndrew Jeffery break; 358365aff1eSCédric Le Goater case AST2500_A0_SILICON_REV: 359365aff1eSCédric Le Goater case AST2500_A1_SILICON_REV: 360365aff1eSCédric Le Goater reset = ast2500_a1_resets; 361*fda9aaa6SCédric Le Goater calc_hpll = aspeed_scu_calc_hpll_ast2500; 362365aff1eSCédric Le Goater break; 3631c8a2388SAndrew Jeffery default: 3641c8a2388SAndrew Jeffery g_assert_not_reached(); 3651c8a2388SAndrew Jeffery } 3661c8a2388SAndrew Jeffery 3671c8a2388SAndrew Jeffery memcpy(s->regs, reset, sizeof(s->regs)); 3681c8a2388SAndrew Jeffery s->regs[SILICON_REV] = s->silicon_rev; 3691c8a2388SAndrew Jeffery s->regs[HW_STRAP1] = s->hw_strap1; 3701c8a2388SAndrew Jeffery s->regs[HW_STRAP2] = s->hw_strap2; 371b6e70d1dSJoel Stanley s->regs[PROT_KEY] = s->hw_prot_key; 372*fda9aaa6SCédric Le Goater 373*fda9aaa6SCédric Le Goater /* 374*fda9aaa6SCédric Le Goater * All registers are set. Now compute the frequencies of the main clocks 375*fda9aaa6SCédric Le Goater */ 376*fda9aaa6SCédric Le Goater s->clkin = aspeed_scu_get_clkin(s); 377*fda9aaa6SCédric Le Goater s->hpll = calc_hpll(s); 378*fda9aaa6SCédric Le Goater aspeed_scu_set_apb_freq(s); 3791c8a2388SAndrew Jeffery } 3801c8a2388SAndrew Jeffery 381365aff1eSCédric Le Goater static uint32_t aspeed_silicon_revs[] = { 382365aff1eSCédric Le Goater AST2400_A0_SILICON_REV, 3836efbac90SCédric Le Goater AST2400_A1_SILICON_REV, 384365aff1eSCédric Le Goater AST2500_A0_SILICON_REV, 385365aff1eSCédric Le Goater AST2500_A1_SILICON_REV, 386365aff1eSCédric Le Goater }; 3871c8a2388SAndrew Jeffery 38879a9f323SCédric Le Goater bool is_supported_silicon_rev(uint32_t silicon_rev) 3891c8a2388SAndrew Jeffery { 3901c8a2388SAndrew Jeffery int i; 3911c8a2388SAndrew Jeffery 3921c8a2388SAndrew Jeffery for (i = 0; i < ARRAY_SIZE(aspeed_silicon_revs); i++) { 3931c8a2388SAndrew Jeffery if (silicon_rev == aspeed_silicon_revs[i]) { 3941c8a2388SAndrew Jeffery return true; 3951c8a2388SAndrew Jeffery } 3961c8a2388SAndrew Jeffery } 3971c8a2388SAndrew Jeffery 3981c8a2388SAndrew Jeffery return false; 3991c8a2388SAndrew Jeffery } 4001c8a2388SAndrew Jeffery 4011c8a2388SAndrew Jeffery static void aspeed_scu_realize(DeviceState *dev, Error **errp) 4021c8a2388SAndrew Jeffery { 4031c8a2388SAndrew Jeffery SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 4041c8a2388SAndrew Jeffery AspeedSCUState *s = ASPEED_SCU(dev); 4051c8a2388SAndrew Jeffery 4061c8a2388SAndrew Jeffery if (!is_supported_silicon_rev(s->silicon_rev)) { 4071c8a2388SAndrew Jeffery error_setg(errp, "Unknown silicon revision: 0x%" PRIx32, 4081c8a2388SAndrew Jeffery s->silicon_rev); 4091c8a2388SAndrew Jeffery return; 4101c8a2388SAndrew Jeffery } 4111c8a2388SAndrew Jeffery 4121c8a2388SAndrew Jeffery memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_scu_ops, s, 4131c8a2388SAndrew Jeffery TYPE_ASPEED_SCU, SCU_IO_REGION_SIZE); 4141c8a2388SAndrew Jeffery 4151c8a2388SAndrew Jeffery sysbus_init_mmio(sbd, &s->iomem); 4161c8a2388SAndrew Jeffery } 4171c8a2388SAndrew Jeffery 4181c8a2388SAndrew Jeffery static const VMStateDescription vmstate_aspeed_scu = { 4191c8a2388SAndrew Jeffery .name = "aspeed.scu", 4201c8a2388SAndrew Jeffery .version_id = 1, 4211c8a2388SAndrew Jeffery .minimum_version_id = 1, 4221c8a2388SAndrew Jeffery .fields = (VMStateField[]) { 4231c8a2388SAndrew Jeffery VMSTATE_UINT32_ARRAY(regs, AspeedSCUState, ASPEED_SCU_NR_REGS), 4241c8a2388SAndrew Jeffery VMSTATE_END_OF_LIST() 4251c8a2388SAndrew Jeffery } 4261c8a2388SAndrew Jeffery }; 4271c8a2388SAndrew Jeffery 4281c8a2388SAndrew Jeffery static Property aspeed_scu_properties[] = { 4291c8a2388SAndrew Jeffery DEFINE_PROP_UINT32("silicon-rev", AspeedSCUState, silicon_rev, 0), 4301c8a2388SAndrew Jeffery DEFINE_PROP_UINT32("hw-strap1", AspeedSCUState, hw_strap1, 0), 4312ddfa281SCédric Le Goater DEFINE_PROP_UINT32("hw-strap2", AspeedSCUState, hw_strap2, 0), 432b6e70d1dSJoel Stanley DEFINE_PROP_UINT32("hw-prot-key", AspeedSCUState, hw_prot_key, 0), 4331c8a2388SAndrew Jeffery DEFINE_PROP_END_OF_LIST(), 4341c8a2388SAndrew Jeffery }; 4351c8a2388SAndrew Jeffery 4361c8a2388SAndrew Jeffery static void aspeed_scu_class_init(ObjectClass *klass, void *data) 4371c8a2388SAndrew Jeffery { 4381c8a2388SAndrew Jeffery DeviceClass *dc = DEVICE_CLASS(klass); 4391c8a2388SAndrew Jeffery dc->realize = aspeed_scu_realize; 4401c8a2388SAndrew Jeffery dc->reset = aspeed_scu_reset; 4411c8a2388SAndrew Jeffery dc->desc = "ASPEED System Control Unit"; 4421c8a2388SAndrew Jeffery dc->vmsd = &vmstate_aspeed_scu; 4431c8a2388SAndrew Jeffery dc->props = aspeed_scu_properties; 4441c8a2388SAndrew Jeffery } 4451c8a2388SAndrew Jeffery 4461c8a2388SAndrew Jeffery static const TypeInfo aspeed_scu_info = { 4471c8a2388SAndrew Jeffery .name = TYPE_ASPEED_SCU, 4481c8a2388SAndrew Jeffery .parent = TYPE_SYS_BUS_DEVICE, 4491c8a2388SAndrew Jeffery .instance_size = sizeof(AspeedSCUState), 4501c8a2388SAndrew Jeffery .class_init = aspeed_scu_class_init, 4511c8a2388SAndrew Jeffery }; 4521c8a2388SAndrew Jeffery 4531c8a2388SAndrew Jeffery static void aspeed_scu_register_types(void) 4541c8a2388SAndrew Jeffery { 4551c8a2388SAndrew Jeffery type_register_static(&aspeed_scu_info); 4561c8a2388SAndrew Jeffery } 4571c8a2388SAndrew Jeffery 4581c8a2388SAndrew Jeffery type_init(aspeed_scu_register_types); 459