aboutsummaryrefslogtreecommitdiff
path: root/hw/misc
diff options
context:
space:
mode:
Diffstat (limited to 'hw/misc')
-rw-r--r--hw/misc/aspeed_scu.c306
-rw-r--r--hw/misc/aspeed_sdmc.c220
-rw-r--r--hw/misc/aspeed_sli.c177
-rw-r--r--hw/misc/meson.build3
-rw-r--r--hw/misc/trace-events11
5 files changed, 693 insertions, 24 deletions
diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c
index 1ac04b6..451e837 100644
--- a/hw/misc/aspeed_scu.c
+++ b/hw/misc/aspeed_scu.c
@@ -134,6 +134,48 @@
#define AST2600_CLK TO_REG(0x40)
+#define AST2700_SILICON_REV TO_REG(0x00)
+#define AST2700_HW_STRAP1 TO_REG(0x10)
+#define AST2700_HW_STRAP1_CLR TO_REG(0x14)
+#define AST2700_HW_STRAP1_LOCK TO_REG(0x20)
+#define AST2700_HW_STRAP1_SEC1 TO_REG(0x24)
+#define AST2700_HW_STRAP1_SEC2 TO_REG(0x28)
+#define AST2700_HW_STRAP1_SEC3 TO_REG(0x2C)
+
+#define AST2700_SCU_CLK_SEL_1 TO_REG(0x280)
+#define AST2700_SCU_HPLL_PARAM TO_REG(0x300)
+#define AST2700_SCU_HPLL_EXT_PARAM TO_REG(0x304)
+#define AST2700_SCU_DPLL_PARAM TO_REG(0x308)
+#define AST2700_SCU_DPLL_EXT_PARAM TO_REG(0x30c)
+#define AST2700_SCU_MPLL_PARAM TO_REG(0x310)
+#define AST2700_SCU_MPLL_EXT_PARAM TO_REG(0x314)
+#define AST2700_SCU_D1CLK_PARAM TO_REG(0x320)
+#define AST2700_SCU_D2CLK_PARAM TO_REG(0x330)
+#define AST2700_SCU_CRT1CLK_PARAM TO_REG(0x340)
+#define AST2700_SCU_CRT2CLK_PARAM TO_REG(0x350)
+#define AST2700_SCU_MPHYCLK_PARAM TO_REG(0x360)
+#define AST2700_SCU_FREQ_CNTR TO_REG(0x3b0)
+#define AST2700_SCU_CPU_SCRATCH_0 TO_REG(0x780)
+#define AST2700_SCU_CPU_SCRATCH_1 TO_REG(0x784)
+
+#define AST2700_SCUIO_CLK_STOP_CTL_1 TO_REG(0x240)
+#define AST2700_SCUIO_CLK_STOP_CLR_1 TO_REG(0x244)
+#define AST2700_SCUIO_CLK_STOP_CTL_2 TO_REG(0x260)
+#define AST2700_SCUIO_CLK_STOP_CLR_2 TO_REG(0x264)
+#define AST2700_SCUIO_CLK_SEL_1 TO_REG(0x280)
+#define AST2700_SCUIO_CLK_SEL_2 TO_REG(0x284)
+#define AST2700_SCUIO_HPLL_PARAM TO_REG(0x300)
+#define AST2700_SCUIO_HPLL_EXT_PARAM TO_REG(0x304)
+#define AST2700_SCUIO_APLL_PARAM TO_REG(0x310)
+#define AST2700_SCUIO_APLL_EXT_PARAM TO_REG(0x314)
+#define AST2700_SCUIO_DPLL_PARAM TO_REG(0x320)
+#define AST2700_SCUIO_DPLL_EXT_PARAM TO_REG(0x324)
+#define AST2700_SCUIO_DPLL_PARAM_READ TO_REG(0x328)
+#define AST2700_SCUIO_DPLL_EXT_PARAM_READ TO_REG(0x32c)
+#define AST2700_SCUIO_UARTCLK_GEN TO_REG(0x330)
+#define AST2700_SCUIO_HUARTCLK_GEN TO_REG(0x334)
+#define AST2700_SCUIO_CLK_DUTY_MEAS_RST TO_REG(0x388)
+
#define SCU_IO_REGION_SIZE 0x1000
static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = {
@@ -244,6 +286,25 @@ static uint32_t aspeed_1030_scu_get_apb_freq(AspeedSCUState *s)
/ asc->apb_divider;
}
+static uint32_t aspeed_2700_scu_get_apb_freq(AspeedSCUState *s)
+{
+ AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s);
+ uint32_t hpll = asc->calc_hpll(s, s->regs[AST2700_SCU_HPLL_PARAM]);
+
+ return hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[AST2700_SCU_CLK_SEL_1]) + 1)
+ / asc->apb_divider;
+}
+
+static uint32_t aspeed_2700_scuio_get_apb_freq(AspeedSCUState *s)
+{
+ AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s);
+ uint32_t hpll = asc->calc_hpll(s, s->regs[AST2700_SCUIO_HPLL_PARAM]);
+
+ return hpll /
+ (SCUIO_AST2700_CLK_GET_PCLK_DIV(s->regs[AST2700_SCUIO_CLK_SEL_1]) + 1)
+ / asc->apb_divider;
+}
+
static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size)
{
AspeedSCUState *s = ASPEED_SCU(opaque);
@@ -258,7 +319,8 @@ static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size)
switch (reg) {
case RNG_DATA:
- /* On hardware, RNG_DATA works regardless of
+ /*
+ * On hardware, RNG_DATA works regardless of
* the state of the enable bit in RNG_CTRL
*/
s->regs[RNG_DATA] = aspeed_scu_get_random();
@@ -494,6 +556,9 @@ static uint32_t aspeed_silicon_revs[] = {
AST2600_A3_SILICON_REV,
AST1030_A0_SILICON_REV,
AST1030_A1_SILICON_REV,
+ AST2700_A0_SILICON_REV,
+ AST2720_A0_SILICON_REV,
+ AST2750_A0_SILICON_REV,
};
bool is_supported_silicon_rev(uint32_t silicon_rev)
@@ -783,6 +848,243 @@ static const TypeInfo aspeed_2600_scu_info = {
.class_init = aspeed_2600_scu_class_init,
};
+static uint64_t aspeed_ast2700_scu_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ AspeedSCUState *s = ASPEED_SCU(opaque);
+ int reg = TO_REG(offset);
+
+ if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ return 0;
+ }
+
+ switch (reg) {
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Unhandled read at offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+
+ trace_aspeed_ast2700_scu_read(offset, size, s->regs[reg]);
+ return s->regs[reg];
+}
+
+static void aspeed_ast2700_scu_write(void *opaque, hwaddr offset,
+ uint64_t data64, unsigned size)
+{
+ AspeedSCUState *s = ASPEED_SCU(opaque);
+ int reg = TO_REG(offset);
+ /* Truncate here so bitwise operations below behave as expected */
+ uint32_t data = data64;
+
+ if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ return;
+ }
+
+ trace_aspeed_ast2700_scu_write(offset, size, data);
+
+ switch (reg) {
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Unhandled write at offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ break;
+ }
+
+ s->regs[reg] = data;
+}
+
+static const MemoryRegionOps aspeed_ast2700_scu_ops = {
+ .read = aspeed_ast2700_scu_read,
+ .write = aspeed_ast2700_scu_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 8,
+ .valid.unaligned = false,
+};
+
+static const uint32_t ast2700_a0_resets[ASPEED_AST2700_SCU_NR_REGS] = {
+ [AST2700_SILICON_REV] = AST2700_A0_SILICON_REV,
+ [AST2700_HW_STRAP1] = 0x00000800,
+ [AST2700_HW_STRAP1_CLR] = 0xFFF0FFF0,
+ [AST2700_HW_STRAP1_LOCK] = 0x00000FFF,
+ [AST2700_HW_STRAP1_SEC1] = 0x000000FF,
+ [AST2700_HW_STRAP1_SEC2] = 0x00000000,
+ [AST2700_HW_STRAP1_SEC3] = 0x1000408F,
+ [AST2700_SCU_HPLL_PARAM] = 0x0000009f,
+ [AST2700_SCU_HPLL_EXT_PARAM] = 0x8000004f,
+ [AST2700_SCU_DPLL_PARAM] = 0x0080009f,
+ [AST2700_SCU_DPLL_EXT_PARAM] = 0x8000004f,
+ [AST2700_SCU_MPLL_PARAM] = 0x00000040,
+ [AST2700_SCU_MPLL_EXT_PARAM] = 0x80000000,
+ [AST2700_SCU_D1CLK_PARAM] = 0x00050002,
+ [AST2700_SCU_D2CLK_PARAM] = 0x00050002,
+ [AST2700_SCU_CRT1CLK_PARAM] = 0x00050002,
+ [AST2700_SCU_CRT2CLK_PARAM] = 0x00050002,
+ [AST2700_SCU_MPHYCLK_PARAM] = 0x0000004c,
+ [AST2700_SCU_FREQ_CNTR] = 0x000375eb,
+ [AST2700_SCU_CPU_SCRATCH_0] = 0x00000000,
+ [AST2700_SCU_CPU_SCRATCH_1] = 0x00000004,
+};
+
+static void aspeed_ast2700_scu_reset(DeviceState *dev)
+{
+ AspeedSCUState *s = ASPEED_SCU(dev);
+ AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
+
+ memcpy(s->regs, asc->resets, asc->nr_regs * 4);
+}
+
+static void aspeed_2700_scu_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
+
+ dc->desc = "ASPEED 2700 System Control Unit";
+ dc->reset = aspeed_ast2700_scu_reset;
+ asc->resets = ast2700_a0_resets;
+ asc->calc_hpll = aspeed_2600_scu_calc_hpll;
+ asc->get_apb = aspeed_2700_scu_get_apb_freq;
+ asc->apb_divider = 4;
+ asc->nr_regs = ASPEED_AST2700_SCU_NR_REGS;
+ asc->clkin_25Mhz = true;
+ asc->ops = &aspeed_ast2700_scu_ops;
+}
+
+static uint64_t aspeed_ast2700_scuio_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ AspeedSCUState *s = ASPEED_SCU(opaque);
+ int reg = TO_REG(offset);
+ if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ return 0;
+ }
+
+ switch (reg) {
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Unhandled read at offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+
+ trace_aspeed_ast2700_scuio_read(offset, size, s->regs[reg]);
+ return s->regs[reg];
+}
+
+static void aspeed_ast2700_scuio_write(void *opaque, hwaddr offset,
+ uint64_t data64, unsigned size)
+{
+ AspeedSCUState *s = ASPEED_SCU(opaque);
+ int reg = TO_REG(offset);
+ /* Truncate here so bitwise operations below behave as expected */
+ uint32_t data = data64;
+ bool updated = false;
+
+ if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ return;
+ }
+
+ trace_aspeed_ast2700_scuio_write(offset, size, data);
+
+ switch (reg) {
+ case AST2700_SCUIO_CLK_STOP_CTL_1:
+ case AST2700_SCUIO_CLK_STOP_CTL_2:
+ s->regs[reg] |= data;
+ updated = true;
+ break;
+ case AST2700_SCUIO_CLK_STOP_CLR_1:
+ case AST2700_SCUIO_CLK_STOP_CLR_2:
+ s->regs[reg - 1] ^= data;
+ updated = true;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Unhandled write at offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ break;
+ }
+
+ if (!updated) {
+ s->regs[reg] = data;
+ }
+}
+
+static const MemoryRegionOps aspeed_ast2700_scuio_ops = {
+ .read = aspeed_ast2700_scuio_read,
+ .write = aspeed_ast2700_scuio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 8,
+ .valid.unaligned = false,
+};
+
+static const uint32_t ast2700_a0_resets_io[ASPEED_AST2700_SCU_NR_REGS] = {
+ [AST2700_SILICON_REV] = 0x06000003,
+ [AST2700_HW_STRAP1] = 0x00000504,
+ [AST2700_HW_STRAP1_CLR] = 0xFFF0FFF0,
+ [AST2700_HW_STRAP1_LOCK] = 0x00000FFF,
+ [AST2700_HW_STRAP1_SEC1] = 0x000000FF,
+ [AST2700_HW_STRAP1_SEC2] = 0x00000000,
+ [AST2700_HW_STRAP1_SEC3] = 0x1000408F,
+ [AST2700_SCUIO_CLK_STOP_CTL_1] = 0xffff8400,
+ [AST2700_SCUIO_CLK_STOP_CTL_2] = 0x00005f30,
+ [AST2700_SCUIO_CLK_SEL_1] = 0x86900000,
+ [AST2700_SCUIO_CLK_SEL_2] = 0x00400000,
+ [AST2700_SCUIO_HPLL_PARAM] = 0x10000027,
+ [AST2700_SCUIO_HPLL_EXT_PARAM] = 0x80000014,
+ [AST2700_SCUIO_APLL_PARAM] = 0x1000001f,
+ [AST2700_SCUIO_APLL_EXT_PARAM] = 0x8000000f,
+ [AST2700_SCUIO_DPLL_PARAM] = 0x106e42ce,
+ [AST2700_SCUIO_DPLL_EXT_PARAM] = 0x80000167,
+ [AST2700_SCUIO_DPLL_PARAM_READ] = 0x106e42ce,
+ [AST2700_SCUIO_DPLL_EXT_PARAM_READ] = 0x80000167,
+ [AST2700_SCUIO_UARTCLK_GEN] = 0x00014506,
+ [AST2700_SCUIO_HUARTCLK_GEN] = 0x000145c0,
+ [AST2700_SCUIO_CLK_DUTY_MEAS_RST] = 0x0c9100d2,
+};
+
+static void aspeed_2700_scuio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
+
+ dc->desc = "ASPEED 2700 System Control Unit I/O";
+ dc->reset = aspeed_ast2700_scu_reset;
+ asc->resets = ast2700_a0_resets_io;
+ asc->calc_hpll = aspeed_2600_scu_calc_hpll;
+ asc->get_apb = aspeed_2700_scuio_get_apb_freq;
+ asc->apb_divider = 2;
+ asc->nr_regs = ASPEED_AST2700_SCU_NR_REGS;
+ asc->clkin_25Mhz = true;
+ asc->ops = &aspeed_ast2700_scuio_ops;
+}
+
+static const TypeInfo aspeed_2700_scu_info = {
+ .name = TYPE_ASPEED_2700_SCU,
+ .parent = TYPE_ASPEED_SCU,
+ .instance_size = sizeof(AspeedSCUState),
+ .class_init = aspeed_2700_scu_class_init,
+};
+
+static const TypeInfo aspeed_2700_scuio_info = {
+ .name = TYPE_ASPEED_2700_SCUIO,
+ .parent = TYPE_ASPEED_SCU,
+ .instance_size = sizeof(AspeedSCUState),
+ .class_init = aspeed_2700_scuio_class_init,
+};
+
static const uint32_t ast1030_a1_resets[ASPEED_AST2600_SCU_NR_REGS] = {
[AST2600_SYS_RST_CTRL] = 0xFFC3FED8,
[AST2600_SYS_RST_CTRL2] = 0x09FFFFFC,
@@ -841,6 +1143,8 @@ static void aspeed_scu_register_types(void)
type_register_static(&aspeed_2500_scu_info);
type_register_static(&aspeed_2600_scu_info);
type_register_static(&aspeed_1030_scu_info);
+ type_register_static(&aspeed_2700_scu_info);
+ type_register_static(&aspeed_2700_scuio_info);
}
type_init(aspeed_scu_register_types);
diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
index 64cd1a8..93e2e29 100644
--- a/hw/misc/aspeed_sdmc.c
+++ b/hw/misc/aspeed_sdmc.c
@@ -27,6 +27,7 @@
#define PROT_SOFTLOCKED 0x00
#define PROT_KEY_UNLOCK 0xFC600309
+#define PROT_2700_KEY_UNLOCK 0x1688A8A8
#define PROT_KEY_HARDLOCK 0xDEADDEAD /* AST2600 */
/* Configuration Register */
@@ -54,6 +55,46 @@
#define R_DRAM_TIME (0x8c / 4)
#define R_ECC_ERR_INJECT (0xb4 / 4)
+/* AST2700 Register */
+#define R_2700_PROT (0x00 / 4)
+#define R_INT_STATUS (0x04 / 4)
+#define R_INT_CLEAR (0x08 / 4)
+#define R_INT_MASK (0x0c / 4)
+#define R_MAIN_CONF (0x10 / 4)
+#define R_MAIN_CONTROL (0x14 / 4)
+#define R_MAIN_STATUS (0x18 / 4)
+#define R_ERR_STATUS (0x1c / 4)
+#define R_ECC_FAIL_STATUS (0x78 / 4)
+#define R_ECC_FAIL_ADDR (0x7c / 4)
+#define R_ECC_TESTING_CONTROL (0x80 / 4)
+#define R_PROT_REGION_LOCK_STATUS (0x94 / 4)
+#define R_TEST_FAIL_ADDR (0xd4 / 4)
+#define R_TEST_FAIL_D0 (0xd8 / 4)
+#define R_TEST_FAIL_D1 (0xdc / 4)
+#define R_TEST_FAIL_D2 (0xe0 / 4)
+#define R_TEST_FAIL_D3 (0xe4 / 4)
+#define R_DBG_STATUS (0xf4 / 4)
+#define R_PHY_INTERFACE_STATUS (0xf8 / 4)
+#define R_GRAPHIC_MEM_BASE_ADDR (0x10c / 4)
+#define R_PORT0_INTERFACE_MONITOR0 (0x240 / 4)
+#define R_PORT0_INTERFACE_MONITOR1 (0x244 / 4)
+#define R_PORT0_INTERFACE_MONITOR2 (0x248 / 4)
+#define R_PORT1_INTERFACE_MONITOR0 (0x2c0 / 4)
+#define R_PORT1_INTERFACE_MONITOR1 (0x2c4 / 4)
+#define R_PORT1_INTERFACE_MONITOR2 (0x2c8 / 4)
+#define R_PORT2_INTERFACE_MONITOR0 (0x340 / 4)
+#define R_PORT2_INTERFACE_MONITOR1 (0x344 / 4)
+#define R_PORT2_INTERFACE_MONITOR2 (0x348 / 4)
+#define R_PORT3_INTERFACE_MONITOR0 (0x3c0 / 4)
+#define R_PORT3_INTERFACE_MONITOR1 (0x3c4 / 4)
+#define R_PORT3_INTERFACE_MONITOR2 (0x3c8 / 4)
+#define R_PORT4_INTERFACE_MONITOR0 (0x440 / 4)
+#define R_PORT4_INTERFACE_MONITOR1 (0x444 / 4)
+#define R_PORT4_INTERFACE_MONITOR2 (0x448 / 4)
+#define R_PORT5_INTERFACE_MONITOR0 (0x4c0 / 4)
+#define R_PORT5_INTERFACE_MONITOR1 (0x4c4 / 4)
+#define R_PORT5_INTERFACE_MONITOR2 (0x4c8 / 4)
+
/*
* Configuration register Ox4 (for Aspeed AST2400 SOC)
*
@@ -76,10 +117,6 @@
#define ASPEED_SDMC_VGA_32MB 0x2
#define ASPEED_SDMC_VGA_64MB 0x3
#define ASPEED_SDMC_DRAM_SIZE(x) (x & 0x3)
-#define ASPEED_SDMC_DRAM_64MB 0x0
-#define ASPEED_SDMC_DRAM_128MB 0x1
-#define ASPEED_SDMC_DRAM_256MB 0x2
-#define ASPEED_SDMC_DRAM_512MB 0x3
#define ASPEED_SDMC_READONLY_MASK \
(ASPEED_SDMC_RESERVED | ASPEED_SDMC_VGA_COMPAT | \
@@ -100,22 +137,24 @@
#define ASPEED_SDMC_CACHE_ENABLE (1 << 10) /* differs from AST2400 */
#define ASPEED_SDMC_DRAM_TYPE (1 << 4) /* differs from AST2400 */
-/* DRAM size definitions differs */
-#define ASPEED_SDMC_AST2500_128MB 0x0
-#define ASPEED_SDMC_AST2500_256MB 0x1
-#define ASPEED_SDMC_AST2500_512MB 0x2
-#define ASPEED_SDMC_AST2500_1024MB 0x3
-
-#define ASPEED_SDMC_AST2600_256MB 0x0
-#define ASPEED_SDMC_AST2600_512MB 0x1
-#define ASPEED_SDMC_AST2600_1024MB 0x2
-#define ASPEED_SDMC_AST2600_2048MB 0x3
-
#define ASPEED_SDMC_AST2500_READONLY_MASK \
(ASPEED_SDMC_HW_VERSION(0xf) | ASPEED_SDMC_CACHE_INITIAL_DONE | \
ASPEED_SDMC_AST2500_RESERVED | ASPEED_SDMC_VGA_COMPAT | \
ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB))
+/*
+ * Main Configuration register Ox10 (for Aspeed AST2700 SOC and higher)
+ *
+ */
+#define ASPEED_SDMC_AST2700_RESERVED 0xFFFF2082 /* 31:16, 13, 7, 1 */
+#define ASPEED_SDMC_AST2700_DATA_SCRAMBLE (1 << 8)
+#define ASPEED_SDMC_AST2700_ECC_ENABLE (1 << 6)
+#define ASPEED_SDMC_AST2700_PAGE_MATCHING_ENABLE (1 << 5)
+#define ASPEED_SDMC_AST2700_DRAM_SIZE(x) ((x & 0x7) << 2)
+
+#define ASPEED_SDMC_AST2700_READONLY_MASK \
+ (ASPEED_SDMC_AST2700_RESERVED)
+
static uint64_t aspeed_sdmc_read(void *opaque, hwaddr addr, unsigned size)
{
AspeedSDMCState *s = ASPEED_SDMC(opaque);
@@ -231,7 +270,7 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error **errp)
AspeedSDMCState *s = ASPEED_SDMC(dev);
AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s);
- assert(asc->max_ram_size < 4 * GiB); /* 32-bit address bus */
+ assert(asc->max_ram_size < 4 * GiB || asc->is_bus64bit);
s->max_ram_size = asc->max_ram_size;
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sdmc_ops, s,
@@ -241,8 +280,8 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error **errp)
static const VMStateDescription vmstate_aspeed_sdmc = {
.name = "aspeed.sdmc",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, AspeedSDMCState, ASPEED_SDMC_NR_REGS),
VMSTATE_END_OF_LIST()
@@ -251,6 +290,7 @@ static const VMStateDescription vmstate_aspeed_sdmc = {
static Property aspeed_sdmc_properties[] = {
DEFINE_PROP_UINT64("max-ram-size", AspeedSDMCState, max_ram_size, 0),
+ DEFINE_PROP_BOOL("unlocked", AspeedSDMCState, unlocked, false),
DEFINE_PROP_END_OF_LIST(),
};
@@ -311,7 +351,8 @@ static void aspeed_2400_sdmc_write(AspeedSDMCState *s, uint32_t reg,
uint32_t data)
{
if (reg == R_PROT) {
- s->regs[reg] = (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
+ s->regs[reg] =
+ (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
return;
}
@@ -369,7 +410,8 @@ static void aspeed_2500_sdmc_write(AspeedSDMCState *s, uint32_t reg,
uint32_t data)
{
if (reg == R_PROT) {
- s->regs[reg] = (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
+ s->regs[reg] =
+ (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
return;
}
@@ -449,8 +491,9 @@ static void aspeed_2600_sdmc_write(AspeedSDMCState *s, uint32_t reg,
}
if (s->regs[R_PROT] == PROT_HARDLOCKED) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: SDMC is locked until system reset!\n",
- __func__);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: SDMC is locked until system reset!\n",
+ __func__);
return;
}
@@ -512,12 +555,145 @@ static const TypeInfo aspeed_2600_sdmc_info = {
.class_init = aspeed_2600_sdmc_class_init,
};
+static void aspeed_2700_sdmc_reset(DeviceState *dev)
+{
+ AspeedSDMCState *s = ASPEED_SDMC(dev);
+ AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s);
+
+ memset(s->regs, 0, sizeof(s->regs));
+
+ /* Set ram size bit and defaults values */
+ s->regs[R_MAIN_CONF] = asc->compute_conf(s, 0);
+
+ if (s->unlocked) {
+ s->regs[R_2700_PROT] = PROT_UNLOCKED;
+ }
+}
+
+static uint32_t aspeed_2700_sdmc_compute_conf(AspeedSDMCState *s, uint32_t data)
+{
+ uint32_t fixed_conf = ASPEED_SDMC_AST2700_PAGE_MATCHING_ENABLE |
+ ASPEED_SDMC_AST2700_DRAM_SIZE(aspeed_sdmc_get_ram_bits(s));
+
+ /* Make sure readonly bits are kept */
+ data &= ~ASPEED_SDMC_AST2700_READONLY_MASK;
+
+ return data | fixed_conf;
+}
+
+static void aspeed_2700_sdmc_write(AspeedSDMCState *s, uint32_t reg,
+ uint32_t data)
+{
+ /* Unprotected registers */
+ switch (reg) {
+ case R_INT_STATUS:
+ case R_INT_CLEAR:
+ case R_INT_MASK:
+ case R_MAIN_STATUS:
+ case R_ERR_STATUS:
+ case R_ECC_FAIL_STATUS:
+ case R_ECC_FAIL_ADDR:
+ case R_PROT_REGION_LOCK_STATUS:
+ case R_TEST_FAIL_ADDR:
+ case R_TEST_FAIL_D0:
+ case R_TEST_FAIL_D1:
+ case R_TEST_FAIL_D2:
+ case R_TEST_FAIL_D3:
+ case R_DBG_STATUS:
+ case R_PHY_INTERFACE_STATUS:
+ case R_GRAPHIC_MEM_BASE_ADDR:
+ case R_PORT0_INTERFACE_MONITOR0:
+ case R_PORT0_INTERFACE_MONITOR1:
+ case R_PORT0_INTERFACE_MONITOR2:
+ case R_PORT1_INTERFACE_MONITOR0:
+ case R_PORT1_INTERFACE_MONITOR1:
+ case R_PORT1_INTERFACE_MONITOR2:
+ case R_PORT2_INTERFACE_MONITOR0:
+ case R_PORT2_INTERFACE_MONITOR1:
+ case R_PORT2_INTERFACE_MONITOR2:
+ case R_PORT3_INTERFACE_MONITOR0:
+ case R_PORT3_INTERFACE_MONITOR1:
+ case R_PORT3_INTERFACE_MONITOR2:
+ case R_PORT4_INTERFACE_MONITOR0:
+ case R_PORT4_INTERFACE_MONITOR1:
+ case R_PORT4_INTERFACE_MONITOR2:
+ case R_PORT5_INTERFACE_MONITOR0:
+ case R_PORT5_INTERFACE_MONITOR1:
+ case R_PORT5_INTERFACE_MONITOR2:
+ s->regs[reg] = data;
+ return;
+ }
+
+ if (s->regs[R_2700_PROT] == PROT_HARDLOCKED) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: SDMC is locked until system reset!\n",
+ __func__);
+ return;
+ }
+
+ if (reg != R_2700_PROT && s->regs[R_2700_PROT] == PROT_SOFTLOCKED) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: SDMC is locked! (write to MCR%02x blocked)\n",
+ __func__, reg * 4);
+ return;
+ }
+
+ switch (reg) {
+ case R_2700_PROT:
+ if (data == PROT_2700_KEY_UNLOCK) {
+ data = PROT_UNLOCKED;
+ } else if (data == PROT_KEY_HARDLOCK) {
+ data = PROT_HARDLOCKED;
+ } else {
+ data = PROT_SOFTLOCKED;
+ }
+ break;
+ case R_MAIN_CONF:
+ data = aspeed_2700_sdmc_compute_conf(s, data);
+ break;
+ case R_MAIN_STATUS:
+ /* Will never return 'busy'. */
+ data &= ~PHY_BUSY_STATE;
+ break;
+ default:
+ break;
+ }
+
+ s->regs[reg] = data;
+}
+
+static const uint64_t
+ aspeed_2700_ram_sizes[] = { 256 * MiB, 512 * MiB, 1024 * MiB,
+ 2048 * MiB, 4096 * MiB, 8192 * MiB, 0};
+
+static void aspeed_2700_sdmc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass);
+
+ dc->desc = "ASPEED 2700 SDRAM Memory Controller";
+ dc->reset = aspeed_2700_sdmc_reset;
+
+ asc->is_bus64bit = true;
+ asc->max_ram_size = 8 * GiB;
+ asc->compute_conf = aspeed_2700_sdmc_compute_conf;
+ asc->write = aspeed_2700_sdmc_write;
+ asc->valid_ram_sizes = aspeed_2700_ram_sizes;
+}
+
+static const TypeInfo aspeed_2700_sdmc_info = {
+ .name = TYPE_ASPEED_2700_SDMC,
+ .parent = TYPE_ASPEED_SDMC,
+ .class_init = aspeed_2700_sdmc_class_init,
+};
+
static void aspeed_sdmc_register_types(void)
{
type_register_static(&aspeed_sdmc_info);
type_register_static(&aspeed_2400_sdmc_info);
type_register_static(&aspeed_2500_sdmc_info);
type_register_static(&aspeed_2600_sdmc_info);
+ type_register_static(&aspeed_2700_sdmc_info);
}
type_init(aspeed_sdmc_register_types);
diff --git a/hw/misc/aspeed_sli.c b/hw/misc/aspeed_sli.c
new file mode 100644
index 0000000..fe720ea
--- /dev/null
+++ b/hw/misc/aspeed_sli.c
@@ -0,0 +1,177 @@
+/*
+ * ASPEED SLI Controller
+ *
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+#include "hw/qdev-properties.h"
+#include "hw/misc/aspeed_sli.h"
+#include "qapi/error.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+#define SLI_REGION_SIZE 0x500
+#define TO_REG(addr) ((addr) >> 2)
+
+static uint64_t aspeed_sli_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ AspeedSLIState *s = ASPEED_SLI(opaque);
+ int reg = TO_REG(addr);
+
+ if (reg >= ARRAY_SIZE(s->regs)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+ __func__, addr);
+ return 0;
+ }
+
+ trace_aspeed_sli_read(addr, size, s->regs[reg]);
+ return s->regs[reg];
+}
+
+static void aspeed_sli_write(void *opaque, hwaddr addr, uint64_t data,
+ unsigned int size)
+{
+ AspeedSLIState *s = ASPEED_SLI(opaque);
+ int reg = TO_REG(addr);
+
+ if (reg >= ARRAY_SIZE(s->regs)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
+ __func__, addr);
+ return;
+ }
+
+ trace_aspeed_sli_write(addr, size, data);
+ s->regs[reg] = data;
+}
+
+static uint64_t aspeed_sliio_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ AspeedSLIState *s = ASPEED_SLI(opaque);
+ int reg = TO_REG(addr);
+
+ if (reg >= ARRAY_SIZE(s->regs)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+ __func__, addr);
+ return 0;
+ }
+
+ trace_aspeed_sliio_read(addr, size, s->regs[reg]);
+ return s->regs[reg];
+}
+
+static void aspeed_sliio_write(void *opaque, hwaddr addr, uint64_t data,
+ unsigned int size)
+{
+ AspeedSLIState *s = ASPEED_SLI(opaque);
+ int reg = TO_REG(addr);
+
+ if (reg >= ARRAY_SIZE(s->regs)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
+ __func__, addr);
+ return;
+ }
+
+ trace_aspeed_sliio_write(addr, size, data);
+ s->regs[reg] = data;
+}
+
+static const MemoryRegionOps aspeed_sli_ops = {
+ .read = aspeed_sli_read,
+ .write = aspeed_sli_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+static const MemoryRegionOps aspeed_sliio_ops = {
+ .read = aspeed_sliio_read,
+ .write = aspeed_sliio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+static void aspeed_sli_realize(DeviceState *dev, Error **errp)
+{
+ AspeedSLIState *s = ASPEED_SLI(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sli_ops, s,
+ TYPE_ASPEED_SLI, SLI_REGION_SIZE);
+ sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void aspeed_sliio_realize(DeviceState *dev, Error **errp)
+{
+ AspeedSLIState *s = ASPEED_SLI(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sliio_ops, s,
+ TYPE_ASPEED_SLI, SLI_REGION_SIZE);
+ sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void aspeed_sli_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "Aspeed SLI Controller";
+ dc->realize = aspeed_sli_realize;
+}
+
+static const TypeInfo aspeed_sli_info = {
+ .name = TYPE_ASPEED_SLI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AspeedSLIState),
+ .class_init = aspeed_sli_class_init,
+ .abstract = true,
+};
+
+static void aspeed_2700_sli_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "AST2700 SLI Controller";
+}
+
+static void aspeed_2700_sliio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "AST2700 I/O SLI Controller";
+ dc->realize = aspeed_sliio_realize;
+}
+
+static const TypeInfo aspeed_2700_sli_info = {
+ .name = TYPE_ASPEED_2700_SLI,
+ .parent = TYPE_ASPEED_SLI,
+ .class_init = aspeed_2700_sli_class_init,
+};
+
+static const TypeInfo aspeed_2700_sliio_info = {
+ .name = TYPE_ASPEED_2700_SLIIO,
+ .parent = TYPE_ASPEED_SLI,
+ .class_init = aspeed_2700_sliio_class_init,
+};
+
+static void aspeed_sli_register_types(void)
+{
+ type_register_static(&aspeed_sli_info);
+ type_register_static(&aspeed_2700_sli_info);
+ type_register_static(&aspeed_2700_sliio_info);
+}
+
+type_init(aspeed_sli_register_types);
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 86596a3..2ca8717 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -136,7 +136,8 @@ system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
'aspeed_sbc.c',
'aspeed_sdmc.c',
'aspeed_xdma.c',
- 'aspeed_peci.c'))
+ 'aspeed_peci.c',
+ 'aspeed_sli.c'))
system_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-sysreg.c'))
system_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c'))
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index 5d241cb..1be0717 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -93,6 +93,10 @@ slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED 0x%04x"
# aspeed_scu.c
aspeed_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_scu_read(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_ast2700_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_ast2700_scu_read(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_ast2700_scuio_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_ast2700_scuio_read(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
# mps2-scc.c
mps2_scc_read(uint64_t offset, uint64_t data, unsigned size) "MPS2 SCC read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
@@ -351,3 +355,10 @@ djmemc_write(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRI
# iosb.c
iosb_read(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u"
iosb_write(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u"
+
+# aspeed_sli.c
+aspeed_sli_write(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_sli_read(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_sliio_write(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+aspeed_sliio_read(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
+