qemu/hw/misc/mchp_pfsoc_dmc.c
<<
>>
Prefs
   1/*
   2 * Microchip PolarFire SoC DDR Memory Controller module emulation
   3 *
   4 * Copyright (c) 2020 Wind River Systems, Inc.
   5 *
   6 * Author:
   7 *   Bin Meng <bin.meng@windriver.com>
   8 *
   9 * This program is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU General Public License as
  11 * published by the Free Software Foundation; either version 2 or
  12 * (at your option) version 3 of the License.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License along
  20 * with this program; if not, see <http://www.gnu.org/licenses/>.
  21 */
  22
  23#include "qemu/osdep.h"
  24#include "qemu/bitops.h"
  25#include "qemu/log.h"
  26#include "qapi/error.h"
  27#include "hw/sysbus.h"
  28#include "hw/misc/mchp_pfsoc_dmc.h"
  29
  30/* DDR SGMII PHY module */
  31
  32#define SGMII_PHY_IOC_REG1              0x208
  33#define SGMII_PHY_TRAINING_STATUS       0x814
  34#define SGMII_PHY_DQ_DQS_ERR_DONE       0x834
  35#define SGMII_PHY_DQDQS_STATUS1         0x84c
  36#define SGMII_PHY_PVT_STAT              0xc20
  37
  38static uint64_t mchp_pfsoc_ddr_sgmii_phy_read(void *opaque, hwaddr offset,
  39                                              unsigned size)
  40{
  41    uint32_t val = 0;
  42    static int training_status_bit;
  43
  44    switch (offset) {
  45    case SGMII_PHY_IOC_REG1:
  46        /* See ddr_pvt_calibration() in HSS */
  47        val = BIT(4) | BIT(2);
  48        break;
  49    case SGMII_PHY_TRAINING_STATUS:
  50        /*
  51         * The codes logic emulates the training status change from
  52         * DDR_TRAINING_IP_SM_BCLKSCLK to DDR_TRAINING_IP_SM_DQ_DQS.
  53         *
  54         * See ddr_setup() in mss_ddr.c in the HSS source codes.
  55         */
  56        val = 1 << training_status_bit;
  57        training_status_bit = (training_status_bit + 1) % 5;
  58        break;
  59    case SGMII_PHY_DQ_DQS_ERR_DONE:
  60        /*
  61         * DDR_TRAINING_IP_SM_VERIFY state in ddr_setup(),
  62         * check that DQ/DQS training passed without error.
  63         */
  64        val = 8;
  65        break;
  66    case SGMII_PHY_DQDQS_STATUS1:
  67        /*
  68         * DDR_TRAINING_IP_SM_VERIFY state in ddr_setup(),
  69         * check that DQ/DQS calculated window is above 5 taps.
  70         */
  71        val = 0xff;
  72        break;
  73    case SGMII_PHY_PVT_STAT:
  74        /* See sgmii_channel_setup() in HSS */
  75        val = BIT(14) | BIT(6);
  76        break;
  77    default:
  78        qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
  79                      "(size %d, offset 0x%" HWADDR_PRIx ")\n",
  80                      __func__, size, offset);
  81        break;
  82    }
  83
  84    return val;
  85}
  86
  87static void mchp_pfsoc_ddr_sgmii_phy_write(void *opaque, hwaddr offset,
  88                                           uint64_t value, unsigned size)
  89{
  90    qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
  91                  "(size %d, value 0x%" PRIx64
  92                  ", offset 0x%" HWADDR_PRIx ")\n",
  93                  __func__, size, value, offset);
  94}
  95
  96static const MemoryRegionOps mchp_pfsoc_ddr_sgmii_phy_ops = {
  97    .read = mchp_pfsoc_ddr_sgmii_phy_read,
  98    .write = mchp_pfsoc_ddr_sgmii_phy_write,
  99    .endianness = DEVICE_LITTLE_ENDIAN,
 100};
 101
 102static void mchp_pfsoc_ddr_sgmii_phy_realize(DeviceState *dev, Error **errp)
 103{
 104    MchpPfSoCDdrSgmiiPhyState *s = MCHP_PFSOC_DDR_SGMII_PHY(dev);
 105
 106    memory_region_init_io(&s->sgmii_phy, OBJECT(dev),
 107                          &mchp_pfsoc_ddr_sgmii_phy_ops, s,
 108                          "mchp.pfsoc.ddr_sgmii_phy",
 109                          MCHP_PFSOC_DDR_SGMII_PHY_REG_SIZE);
 110    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->sgmii_phy);
 111}
 112
 113static void mchp_pfsoc_ddr_sgmii_phy_class_init(ObjectClass *klass, void *data)
 114{
 115    DeviceClass *dc = DEVICE_CLASS(klass);
 116
 117    dc->desc = "Microchip PolarFire SoC DDR SGMII PHY module";
 118    dc->realize = mchp_pfsoc_ddr_sgmii_phy_realize;
 119}
 120
 121static const TypeInfo mchp_pfsoc_ddr_sgmii_phy_info = {
 122    .name          = TYPE_MCHP_PFSOC_DDR_SGMII_PHY,
 123    .parent        = TYPE_SYS_BUS_DEVICE,
 124    .instance_size = sizeof(MchpPfSoCDdrSgmiiPhyState),
 125    .class_init    = mchp_pfsoc_ddr_sgmii_phy_class_init,
 126};
 127
 128static void mchp_pfsoc_ddr_sgmii_phy_register_types(void)
 129{
 130    type_register_static(&mchp_pfsoc_ddr_sgmii_phy_info);
 131}
 132
 133type_init(mchp_pfsoc_ddr_sgmii_phy_register_types)
 134
 135/* DDR CFG module */
 136
 137#define CFG_MT_DONE_ACK                 0x4428
 138#define CFG_STAT_DFI_INIT_COMPLETE      0x10034
 139#define CFG_STAT_DFI_TRAINING_COMPLETE  0x10038
 140
 141static uint64_t mchp_pfsoc_ddr_cfg_read(void *opaque, hwaddr offset,
 142                                        unsigned size)
 143{
 144    uint32_t val = 0;
 145
 146    switch (offset) {
 147    case CFG_MT_DONE_ACK:
 148        /* memory test in MTC_test() */
 149        val = BIT(0);
 150        break;
 151    case CFG_STAT_DFI_INIT_COMPLETE:
 152        /* DDR_TRAINING_IP_SM_START_CHECK state in ddr_setup() */
 153        val = BIT(0);
 154        break;
 155    case CFG_STAT_DFI_TRAINING_COMPLETE:
 156        /* DDR_TRAINING_IP_SM_VERIFY state in ddr_setup() */
 157        val = BIT(0);
 158        break;
 159    default:
 160        qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
 161                      "(size %d, offset 0x%" HWADDR_PRIx ")\n",
 162                      __func__, size, offset);
 163        break;
 164    }
 165
 166    return val;
 167}
 168
 169static void mchp_pfsoc_ddr_cfg_write(void *opaque, hwaddr offset,
 170                                     uint64_t value, unsigned size)
 171{
 172    qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
 173                  "(size %d, value 0x%" PRIx64
 174                  ", offset 0x%" HWADDR_PRIx ")\n",
 175                  __func__, size, value, offset);
 176}
 177
 178static const MemoryRegionOps mchp_pfsoc_ddr_cfg_ops = {
 179    .read = mchp_pfsoc_ddr_cfg_read,
 180    .write = mchp_pfsoc_ddr_cfg_write,
 181    .endianness = DEVICE_LITTLE_ENDIAN,
 182};
 183
 184static void mchp_pfsoc_ddr_cfg_realize(DeviceState *dev, Error **errp)
 185{
 186    MchpPfSoCDdrCfgState *s = MCHP_PFSOC_DDR_CFG(dev);
 187
 188    memory_region_init_io(&s->cfg, OBJECT(dev),
 189                          &mchp_pfsoc_ddr_cfg_ops, s,
 190                          "mchp.pfsoc.ddr_cfg",
 191                          MCHP_PFSOC_DDR_CFG_REG_SIZE);
 192    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->cfg);
 193}
 194
 195static void mchp_pfsoc_ddr_cfg_class_init(ObjectClass *klass, void *data)
 196{
 197    DeviceClass *dc = DEVICE_CLASS(klass);
 198
 199    dc->desc = "Microchip PolarFire SoC DDR CFG module";
 200    dc->realize = mchp_pfsoc_ddr_cfg_realize;
 201}
 202
 203static const TypeInfo mchp_pfsoc_ddr_cfg_info = {
 204    .name          = TYPE_MCHP_PFSOC_DDR_CFG,
 205    .parent        = TYPE_SYS_BUS_DEVICE,
 206    .instance_size = sizeof(MchpPfSoCDdrCfgState),
 207    .class_init    = mchp_pfsoc_ddr_cfg_class_init,
 208};
 209
 210static void mchp_pfsoc_ddr_cfg_register_types(void)
 211{
 212    type_register_static(&mchp_pfsoc_ddr_cfg_info);
 213}
 214
 215type_init(mchp_pfsoc_ddr_cfg_register_types)
 216