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/hw.h" 28 #include "hw/sysbus.h" 29 #include "hw/misc/mchp_pfsoc_dmc.h" 30 31 /* DDR SGMII PHY module */ 32 33 #define SGMII_PHY_IOC_REG1 0x208 34 #define SGMII_PHY_TRAINING_STATUS 0x814 35 #define SGMII_PHY_DQ_DQS_ERR_DONE 0x834 36 #define SGMII_PHY_DQDQS_STATUS1 0x84c 37 #define SGMII_PHY_PVT_STAT 0xc20 38 39 static uint64_t mchp_pfsoc_ddr_sgmii_phy_read(void *opaque, hwaddr offset, 40 unsigned size) 41 { 42 uint32_t val = 0; 43 static int training_status_bit; 44 45 switch (offset) { 46 case SGMII_PHY_IOC_REG1: 47 /* See ddr_pvt_calibration() in HSS */ 48 val = BIT(4) | BIT(2); 49 break; 50 case SGMII_PHY_TRAINING_STATUS: 51 /* 52 * The codes logic emulates the training status change from 53 * DDR_TRAINING_IP_SM_BCLKSCLK to DDR_TRAINING_IP_SM_DQ_DQS. 54 * 55 * See ddr_setup() in mss_ddr.c in the HSS source codes. 56 */ 57 val = 1 << training_status_bit; 58 training_status_bit = (training_status_bit + 1) % 5; 59 break; 60 case SGMII_PHY_DQ_DQS_ERR_DONE: 61 /* 62 * DDR_TRAINING_IP_SM_VERIFY state in ddr_setup(), 63 * check that DQ/DQS training passed without error. 64 */ 65 val = 8; 66 break; 67 case SGMII_PHY_DQDQS_STATUS1: 68 /* 69 * DDR_TRAINING_IP_SM_VERIFY state in ddr_setup(), 70 * check that DQ/DQS calculated window is above 5 taps. 71 */ 72 val = 0xff; 73 break; 74 case SGMII_PHY_PVT_STAT: 75 /* See sgmii_channel_setup() in HSS */ 76 val = BIT(14) | BIT(6); 77 break; 78 default: 79 qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read " 80 "(size %d, offset 0x%" HWADDR_PRIx ")\n", 81 __func__, size, offset); 82 break; 83 } 84 85 return val; 86 } 87 88 static void mchp_pfsoc_ddr_sgmii_phy_write(void *opaque, hwaddr offset, 89 uint64_t value, unsigned size) 90 { 91 qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write " 92 "(size %d, value 0x%" PRIx64 93 ", offset 0x%" HWADDR_PRIx ")\n", 94 __func__, size, value, offset); 95 } 96 97 static const MemoryRegionOps mchp_pfsoc_ddr_sgmii_phy_ops = { 98 .read = mchp_pfsoc_ddr_sgmii_phy_read, 99 .write = mchp_pfsoc_ddr_sgmii_phy_write, 100 .endianness = DEVICE_LITTLE_ENDIAN, 101 }; 102 103 static void mchp_pfsoc_ddr_sgmii_phy_realize(DeviceState *dev, Error **errp) 104 { 105 MchpPfSoCDdrSgmiiPhyState *s = MCHP_PFSOC_DDR_SGMII_PHY(dev); 106 107 memory_region_init_io(&s->sgmii_phy, OBJECT(dev), 108 &mchp_pfsoc_ddr_sgmii_phy_ops, s, 109 "mchp.pfsoc.ddr_sgmii_phy", 110 MCHP_PFSOC_DDR_SGMII_PHY_REG_SIZE); 111 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->sgmii_phy); 112 } 113 114 static void mchp_pfsoc_ddr_sgmii_phy_class_init(ObjectClass *klass, void *data) 115 { 116 DeviceClass *dc = DEVICE_CLASS(klass); 117 118 dc->desc = "Microchip PolarFire SoC DDR SGMII PHY module"; 119 dc->realize = mchp_pfsoc_ddr_sgmii_phy_realize; 120 } 121 122 static const TypeInfo mchp_pfsoc_ddr_sgmii_phy_info = { 123 .name = TYPE_MCHP_PFSOC_DDR_SGMII_PHY, 124 .parent = TYPE_SYS_BUS_DEVICE, 125 .instance_size = sizeof(MchpPfSoCDdrSgmiiPhyState), 126 .class_init = mchp_pfsoc_ddr_sgmii_phy_class_init, 127 }; 128 129 static void mchp_pfsoc_ddr_sgmii_phy_register_types(void) 130 { 131 type_register_static(&mchp_pfsoc_ddr_sgmii_phy_info); 132 } 133 134 type_init(mchp_pfsoc_ddr_sgmii_phy_register_types) 135 136 /* DDR CFG module */ 137 138 #define CFG_MT_DONE_ACK 0x4428 139 #define CFG_STAT_DFI_INIT_COMPLETE 0x10034 140 #define CFG_STAT_DFI_TRAINING_COMPLETE 0x10038 141 142 static uint64_t mchp_pfsoc_ddr_cfg_read(void *opaque, hwaddr offset, 143 unsigned size) 144 { 145 uint32_t val = 0; 146 147 switch (offset) { 148 case CFG_MT_DONE_ACK: 149 /* memory test in MTC_test() */ 150 val = BIT(0); 151 break; 152 case CFG_STAT_DFI_INIT_COMPLETE: 153 /* DDR_TRAINING_IP_SM_START_CHECK state in ddr_setup() */ 154 val = BIT(0); 155 break; 156 case CFG_STAT_DFI_TRAINING_COMPLETE: 157 /* DDR_TRAINING_IP_SM_VERIFY state in ddr_setup() */ 158 val = BIT(0); 159 break; 160 default: 161 qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read " 162 "(size %d, offset 0x%" HWADDR_PRIx ")\n", 163 __func__, size, offset); 164 break; 165 } 166 167 return val; 168 } 169 170 static void mchp_pfsoc_ddr_cfg_write(void *opaque, hwaddr offset, 171 uint64_t value, unsigned size) 172 { 173 qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write " 174 "(size %d, value 0x%" PRIx64 175 ", offset 0x%" HWADDR_PRIx ")\n", 176 __func__, size, value, offset); 177 } 178 179 static const MemoryRegionOps mchp_pfsoc_ddr_cfg_ops = { 180 .read = mchp_pfsoc_ddr_cfg_read, 181 .write = mchp_pfsoc_ddr_cfg_write, 182 .endianness = DEVICE_LITTLE_ENDIAN, 183 }; 184 185 static void mchp_pfsoc_ddr_cfg_realize(DeviceState *dev, Error **errp) 186 { 187 MchpPfSoCDdrCfgState *s = MCHP_PFSOC_DDR_CFG(dev); 188 189 memory_region_init_io(&s->cfg, OBJECT(dev), 190 &mchp_pfsoc_ddr_cfg_ops, s, 191 "mchp.pfsoc.ddr_cfg", 192 MCHP_PFSOC_DDR_CFG_REG_SIZE); 193 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->cfg); 194 } 195 196 static void mchp_pfsoc_ddr_cfg_class_init(ObjectClass *klass, void *data) 197 { 198 DeviceClass *dc = DEVICE_CLASS(klass); 199 200 dc->desc = "Microchip PolarFire SoC DDR CFG module"; 201 dc->realize = mchp_pfsoc_ddr_cfg_realize; 202 } 203 204 static const TypeInfo mchp_pfsoc_ddr_cfg_info = { 205 .name = TYPE_MCHP_PFSOC_DDR_CFG, 206 .parent = TYPE_SYS_BUS_DEVICE, 207 .instance_size = sizeof(MchpPfSoCDdrCfgState), 208 .class_init = mchp_pfsoc_ddr_cfg_class_init, 209 }; 210 211 static void mchp_pfsoc_ddr_cfg_register_types(void) 212 { 213 type_register_static(&mchp_pfsoc_ddr_cfg_info); 214 } 215 216 type_init(mchp_pfsoc_ddr_cfg_register_types) 217