aboutsummaryrefslogtreecommitdiff
path: root/hw/misc/aspeed_sdmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/misc/aspeed_sdmc.c')
-rw-r--r--hw/misc/aspeed_sdmc.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
index 60c99e7..f3a63a2 100644
--- a/hw/misc/aspeed_sdmc.c
+++ b/hw/misc/aspeed_sdmc.c
@@ -28,6 +28,7 @@
/* Control/Status Register #1 (ast2500) */
#define R_STATUS1 (0x60 / 4)
#define PHY_BUSY_STATE BIT(0)
+#define PHY_PLL_LOCK_STATUS BIT(4)
#define R_ECC_TEST_CTRL (0x70 / 4)
#define ECC_TEST_FINISHED BIT(12)
@@ -85,6 +86,11 @@
#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 | \
@@ -186,6 +192,28 @@ static int ast2500_rambits(AspeedSDMCState *s)
return ASPEED_SDMC_AST2500_512MB;
}
+static int ast2600_rambits(AspeedSDMCState *s)
+{
+ switch (s->ram_size >> 20) {
+ case 256:
+ return ASPEED_SDMC_AST2600_256MB;
+ case 512:
+ return ASPEED_SDMC_AST2600_512MB;
+ case 1024:
+ return ASPEED_SDMC_AST2600_1024MB;
+ case 2048:
+ return ASPEED_SDMC_AST2600_2048MB;
+ default:
+ break;
+ }
+
+ /* use a common default */
+ warn_report("Invalid RAM size 0x%" PRIx64 ". Using default 512M",
+ s->ram_size);
+ s->ram_size = 512 << 20;
+ return ASPEED_SDMC_AST2600_512MB;
+}
+
static void aspeed_sdmc_reset(DeviceState *dev)
{
AspeedSDMCState *s = ASPEED_SDMC(dev);
@@ -340,11 +368,65 @@ static const TypeInfo aspeed_2500_sdmc_info = {
.class_init = aspeed_2500_sdmc_class_init,
};
+static uint32_t aspeed_2600_sdmc_compute_conf(AspeedSDMCState *s, uint32_t data)
+{
+ uint32_t fixed_conf = ASPEED_SDMC_HW_VERSION(3) |
+ ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB) |
+ ASPEED_SDMC_DRAM_SIZE(ast2600_rambits(s));
+
+ /* Make sure readonly bits are kept (use ast2500 mask) */
+ data &= ~ASPEED_SDMC_AST2500_READONLY_MASK;
+
+ return data | fixed_conf;
+}
+
+static void aspeed_2600_sdmc_write(AspeedSDMCState *s, uint32_t reg,
+ uint32_t data)
+{
+ switch (reg) {
+ case R_CONF:
+ data = aspeed_2600_sdmc_compute_conf(s, data);
+ break;
+ case R_STATUS1:
+ /* Will never return 'busy'. 'lock status' is always set */
+ data &= ~PHY_BUSY_STATE;
+ data |= PHY_PLL_LOCK_STATUS;
+ break;
+ case R_ECC_TEST_CTRL:
+ /* Always done, always happy */
+ data |= ECC_TEST_FINISHED;
+ data &= ~ECC_TEST_FAIL;
+ break;
+ default:
+ break;
+ }
+
+ s->regs[reg] = data;
+}
+
+static void aspeed_2600_sdmc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass);
+
+ dc->desc = "ASPEED 2600 SDRAM Memory Controller";
+ asc->max_ram_size = 2048 << 20;
+ asc->compute_conf = aspeed_2600_sdmc_compute_conf;
+ asc->write = aspeed_2600_sdmc_write;
+}
+
+static const TypeInfo aspeed_2600_sdmc_info = {
+ .name = TYPE_ASPEED_2600_SDMC,
+ .parent = TYPE_ASPEED_SDMC,
+ .class_init = aspeed_2600_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_init(aspeed_sdmc_register_types);