qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

mchp_pfsoc_dmc.c (6909B)


      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 
     38 static 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 
     87 static 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 
     96 static 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 
    102 static 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 
    113 static 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 
    121 static 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 
    128 static void mchp_pfsoc_ddr_sgmii_phy_register_types(void)
    129 {
    130     type_register_static(&mchp_pfsoc_ddr_sgmii_phy_info);
    131 }
    132 
    133 type_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 
    141 static 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 
    169 static 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 
    178 static 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 
    184 static 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 
    195 static 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 
    203 static 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 
    210 static void mchp_pfsoc_ddr_cfg_register_types(void)
    211 {
    212     type_register_static(&mchp_pfsoc_ddr_cfg_info);
    213 }
    214 
    215 type_init(mchp_pfsoc_ddr_cfg_register_types)