aboutsummaryrefslogtreecommitdiff
path: root/hw/misc/aspeed_sdmc.c
diff options
context:
space:
mode:
authorJoel Stanley <joel@jms.id.au>2019-09-25 16:32:34 +0200
committerPeter Maydell <peter.maydell@linaro.org>2019-10-15 18:09:04 +0100
commit1550d7267984b19796089f767832c30da80494ec (patch)
treee7087c085654aac7cacc02942dea1f58ae043e18 /hw/misc/aspeed_sdmc.c
parent8e00d1a97d1d0b416527debb9a0759ab8c49ec51 (diff)
aspeed/sdmc: Add AST2600 support
The AST2600 SDMC controller is slightly different from its predecessor (DRAM training). Max memory is now 2G on the AST2600. Signed-off-by: Joel Stanley <joel@jms.id.au> Signed-off-by: Cédric Le Goater <clg@kaod.org> Message-id: 20190925143248.10000-10-clg@kaod.org [clg: - improved commit log - reworked model integration into new object class ] Signed-off-by: Cédric Le Goater <clg@kaod.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
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 60c99e7734..f3a63a2e01 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);