qemu/hw/misc/aspeed_sdmc.c
<<
>>
Prefs
   1/*
   2 * ASPEED SDRAM Memory Controller
   3 *
   4 * Copyright (C) 2016 IBM Corp.
   5 *
   6 * This code is licensed under the GPL version 2 or later.  See
   7 * the COPYING file in the top-level directory.
   8 */
   9
  10#include "qemu/osdep.h"
  11#include "qemu/log.h"
  12#include "qemu/error-report.h"
  13#include "hw/misc/aspeed_sdmc.h"
  14#include "hw/misc/aspeed_scu.h"
  15#include "hw/qdev-properties.h"
  16#include "qapi/error.h"
  17#include "trace.h"
  18
  19/* Protection Key Register */
  20#define R_PROT            (0x00 / 4)
  21#define   PROT_KEY_UNLOCK     0xFC600309
  22
  23/* Configuration Register */
  24#define R_CONF            (0x04 / 4)
  25
  26/*
  27 * Configuration register Ox4 (for Aspeed AST2400 SOC)
  28 *
  29 * These are for the record and future use. ASPEED_SDMC_DRAM_SIZE is
  30 * what we care about right now as it is checked by U-Boot to
  31 * determine the RAM size.
  32 */
  33
  34#define ASPEED_SDMC_RESERVED            0xFFFFF800 /* 31:11 reserved */
  35#define ASPEED_SDMC_AST2300_COMPAT      (1 << 10)
  36#define ASPEED_SDMC_SCRAMBLE_PATTERN    (1 << 9)
  37#define ASPEED_SDMC_DATA_SCRAMBLE       (1 << 8)
  38#define ASPEED_SDMC_ECC_ENABLE          (1 << 7)
  39#define ASPEED_SDMC_VGA_COMPAT          (1 << 6) /* readonly */
  40#define ASPEED_SDMC_DRAM_BANK           (1 << 5)
  41#define ASPEED_SDMC_DRAM_BURST          (1 << 4)
  42#define ASPEED_SDMC_VGA_APERTURE(x)     ((x & 0x3) << 2) /* readonly */
  43#define     ASPEED_SDMC_VGA_8MB             0x0
  44#define     ASPEED_SDMC_VGA_16MB            0x1
  45#define     ASPEED_SDMC_VGA_32MB            0x2
  46#define     ASPEED_SDMC_VGA_64MB            0x3
  47#define ASPEED_SDMC_DRAM_SIZE(x)        (x & 0x3)
  48#define     ASPEED_SDMC_DRAM_64MB           0x0
  49#define     ASPEED_SDMC_DRAM_128MB          0x1
  50#define     ASPEED_SDMC_DRAM_256MB          0x2
  51#define     ASPEED_SDMC_DRAM_512MB          0x3
  52
  53#define ASPEED_SDMC_READONLY_MASK                       \
  54    (ASPEED_SDMC_RESERVED | ASPEED_SDMC_VGA_COMPAT |    \
  55     ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB))
  56/*
  57 * Configuration register Ox4 (for Aspeed AST2500 SOC and higher)
  58 *
  59 * Incompatibilities are annotated in the list. ASPEED_SDMC_HW_VERSION
  60 * should be set to 1 for the AST2500 SOC.
  61 */
  62#define ASPEED_SDMC_HW_VERSION(x)       ((x & 0xf) << 28) /* readonly */
  63#define ASPEED_SDMC_SW_VERSION          ((x & 0xff) << 20)
  64#define ASPEED_SDMC_CACHE_INITIAL_DONE  (1 << 19)  /* readonly */
  65#define ASPEED_SDMC_AST2500_RESERVED    0x7C000 /* 18:14 reserved */
  66#define ASPEED_SDMC_CACHE_DDR4_CONF     (1 << 13)
  67#define ASPEED_SDMC_CACHE_INITIAL       (1 << 12)
  68#define ASPEED_SDMC_CACHE_RANGE_CTRL    (1 << 11)
  69#define ASPEED_SDMC_CACHE_ENABLE        (1 << 10) /* differs from AST2400 */
  70#define ASPEED_SDMC_DRAM_TYPE           (1 << 4)  /* differs from AST2400 */
  71
  72/* DRAM size definitions differs */
  73#define     ASPEED_SDMC_AST2500_128MB       0x0
  74#define     ASPEED_SDMC_AST2500_256MB       0x1
  75#define     ASPEED_SDMC_AST2500_512MB       0x2
  76#define     ASPEED_SDMC_AST2500_1024MB      0x3
  77
  78#define ASPEED_SDMC_AST2500_READONLY_MASK                               \
  79    (ASPEED_SDMC_HW_VERSION(0xf) | ASPEED_SDMC_CACHE_INITIAL_DONE |     \
  80     ASPEED_SDMC_AST2500_RESERVED | ASPEED_SDMC_VGA_COMPAT |            \
  81     ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB))
  82
  83static uint64_t aspeed_sdmc_read(void *opaque, hwaddr addr, unsigned size)
  84{
  85    AspeedSDMCState *s = ASPEED_SDMC(opaque);
  86
  87    addr >>= 2;
  88
  89    if (addr >= ARRAY_SIZE(s->regs)) {
  90        qemu_log_mask(LOG_GUEST_ERROR,
  91                      "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
  92                      __func__, addr);
  93        return 0;
  94    }
  95
  96    return s->regs[addr];
  97}
  98
  99static void aspeed_sdmc_write(void *opaque, hwaddr addr, uint64_t data,
 100                             unsigned int size)
 101{
 102    AspeedSDMCState *s = ASPEED_SDMC(opaque);
 103
 104    addr >>= 2;
 105
 106    if (addr >= ARRAY_SIZE(s->regs)) {
 107        qemu_log_mask(LOG_GUEST_ERROR,
 108                      "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
 109                      __func__, addr);
 110        return;
 111    }
 112
 113    if (addr != R_PROT && s->regs[R_PROT] != PROT_KEY_UNLOCK) {
 114        qemu_log_mask(LOG_GUEST_ERROR, "%s: SDMC is locked!\n", __func__);
 115        return;
 116    }
 117
 118    if (addr == R_CONF) {
 119        /* Make sure readonly bits are kept */
 120        switch (s->silicon_rev) {
 121        case AST2400_A0_SILICON_REV:
 122        case AST2400_A1_SILICON_REV:
 123            data &= ~ASPEED_SDMC_READONLY_MASK;
 124            break;
 125        case AST2500_A0_SILICON_REV:
 126            data &= ~ASPEED_SDMC_AST2500_READONLY_MASK;
 127            break;
 128        default:
 129            g_assert_not_reached();
 130        }
 131    }
 132
 133    s->regs[addr] = data;
 134}
 135
 136static const MemoryRegionOps aspeed_sdmc_ops = {
 137    .read = aspeed_sdmc_read,
 138    .write = aspeed_sdmc_write,
 139    .endianness = DEVICE_LITTLE_ENDIAN,
 140    .valid.min_access_size = 4,
 141    .valid.max_access_size = 4,
 142};
 143
 144static int ast2400_rambits(AspeedSDMCState *s)
 145{
 146    switch (s->ram_size >> 20) {
 147    case 64:
 148        return ASPEED_SDMC_DRAM_64MB;
 149    case 128:
 150        return ASPEED_SDMC_DRAM_128MB;
 151    case 256:
 152        return ASPEED_SDMC_DRAM_256MB;
 153    case 512:
 154        return ASPEED_SDMC_DRAM_512MB;
 155    default:
 156        break;
 157    }
 158
 159    /* use a common default */
 160    error_report("warning: Invalid RAM size 0x%" PRIx64
 161                 ". Using default 256M", s->ram_size);
 162    s->ram_size = 256 << 20;
 163    return ASPEED_SDMC_DRAM_256MB;
 164}
 165
 166static int ast2500_rambits(AspeedSDMCState *s)
 167{
 168    switch (s->ram_size >> 20) {
 169    case 128:
 170        return ASPEED_SDMC_AST2500_128MB;
 171    case 256:
 172        return ASPEED_SDMC_AST2500_256MB;
 173    case 512:
 174        return ASPEED_SDMC_AST2500_512MB;
 175    case 1024:
 176        return ASPEED_SDMC_AST2500_1024MB;
 177    default:
 178        break;
 179    }
 180
 181    /* use a common default */
 182    error_report("warning: Invalid RAM size 0x%" PRIx64
 183                 ". Using default 512M", s->ram_size);
 184    s->ram_size = 512 << 20;
 185    return ASPEED_SDMC_AST2500_512MB;
 186}
 187
 188static void aspeed_sdmc_reset(DeviceState *dev)
 189{
 190    AspeedSDMCState *s = ASPEED_SDMC(dev);
 191
 192    memset(s->regs, 0, sizeof(s->regs));
 193
 194    /* Set ram size bit and defaults values */
 195    switch (s->silicon_rev) {
 196    case AST2400_A0_SILICON_REV:
 197    case AST2400_A1_SILICON_REV:
 198        s->regs[R_CONF] |=
 199            ASPEED_SDMC_VGA_COMPAT |
 200            ASPEED_SDMC_DRAM_SIZE(s->ram_bits);
 201        break;
 202
 203    case AST2500_A0_SILICON_REV:
 204    case AST2500_A1_SILICON_REV:
 205        s->regs[R_CONF] |=
 206            ASPEED_SDMC_HW_VERSION(1) |
 207            ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB) |
 208            ASPEED_SDMC_DRAM_SIZE(s->ram_bits);
 209        break;
 210
 211    default:
 212        g_assert_not_reached();
 213    }
 214}
 215
 216static void aspeed_sdmc_realize(DeviceState *dev, Error **errp)
 217{
 218    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 219    AspeedSDMCState *s = ASPEED_SDMC(dev);
 220
 221    if (!is_supported_silicon_rev(s->silicon_rev)) {
 222        error_setg(errp, "Unknown silicon revision: 0x%" PRIx32,
 223                s->silicon_rev);
 224        return;
 225    }
 226
 227    switch (s->silicon_rev) {
 228    case AST2400_A0_SILICON_REV:
 229    case AST2400_A1_SILICON_REV:
 230        s->ram_bits = ast2400_rambits(s);
 231        break;
 232    case AST2500_A0_SILICON_REV:
 233    case AST2500_A1_SILICON_REV:
 234        s->ram_bits = ast2500_rambits(s);
 235        break;
 236    default:
 237        g_assert_not_reached();
 238    }
 239
 240    memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sdmc_ops, s,
 241                          TYPE_ASPEED_SDMC, 0x1000);
 242    sysbus_init_mmio(sbd, &s->iomem);
 243}
 244
 245static const VMStateDescription vmstate_aspeed_sdmc = {
 246    .name = "aspeed.sdmc",
 247    .version_id = 1,
 248    .minimum_version_id = 1,
 249    .fields = (VMStateField[]) {
 250        VMSTATE_UINT32_ARRAY(regs, AspeedSDMCState, ASPEED_SDMC_NR_REGS),
 251        VMSTATE_END_OF_LIST()
 252    }
 253};
 254
 255static Property aspeed_sdmc_properties[] = {
 256    DEFINE_PROP_UINT32("silicon-rev", AspeedSDMCState, silicon_rev, 0),
 257    DEFINE_PROP_UINT64("ram-size", AspeedSDMCState, ram_size, 0),
 258    DEFINE_PROP_END_OF_LIST(),
 259};
 260
 261static void aspeed_sdmc_class_init(ObjectClass *klass, void *data)
 262{
 263    DeviceClass *dc = DEVICE_CLASS(klass);
 264    dc->realize = aspeed_sdmc_realize;
 265    dc->reset = aspeed_sdmc_reset;
 266    dc->desc = "ASPEED SDRAM Memory Controller";
 267    dc->vmsd = &vmstate_aspeed_sdmc;
 268    dc->props = aspeed_sdmc_properties;
 269}
 270
 271static const TypeInfo aspeed_sdmc_info = {
 272    .name = TYPE_ASPEED_SDMC,
 273    .parent = TYPE_SYS_BUS_DEVICE,
 274    .instance_size = sizeof(AspeedSDMCState),
 275    .class_init = aspeed_sdmc_class_init,
 276};
 277
 278static void aspeed_sdmc_register_types(void)
 279{
 280    type_register_static(&aspeed_sdmc_info);
 281}
 282
 283type_init(aspeed_sdmc_register_types);
 284