1034c2e69SAlistair Francis /* 2034c2e69SAlistair Francis * QEMU model of the Xilinx Zynq Devcfg Interface 3034c2e69SAlistair Francis * 4034c2e69SAlistair Francis * (C) 2011 PetaLogix Pty Ltd 5034c2e69SAlistair Francis * (C) 2014 Xilinx Inc. 6034c2e69SAlistair Francis * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com> 7034c2e69SAlistair Francis * 8034c2e69SAlistair Francis * Permission is hereby granted, free of charge, to any person obtaining a copy 9034c2e69SAlistair Francis * of this software and associated documentation files (the "Software"), to deal 10034c2e69SAlistair Francis * in the Software without restriction, including without limitation the rights 11034c2e69SAlistair Francis * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12034c2e69SAlistair Francis * copies of the Software, and to permit persons to whom the Software is 13034c2e69SAlistair Francis * furnished to do so, subject to the following conditions: 14034c2e69SAlistair Francis * 15034c2e69SAlistair Francis * The above copyright notice and this permission notice shall be included in 16034c2e69SAlistair Francis * all copies or substantial portions of the Software. 17034c2e69SAlistair Francis * 18034c2e69SAlistair Francis * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19034c2e69SAlistair Francis * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20034c2e69SAlistair Francis * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21034c2e69SAlistair Francis * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22034c2e69SAlistair Francis * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23034c2e69SAlistair Francis * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24034c2e69SAlistair Francis * THE SOFTWARE. 25034c2e69SAlistair Francis */ 26034c2e69SAlistair Francis 27034c2e69SAlistair Francis #include "qemu/osdep.h" 28034c2e69SAlistair Francis #include "hw/dma/xlnx-zynq-devcfg.h" 2964552b6bSMarkus Armbruster #include "hw/irq.h" 30d6454270SMarkus Armbruster #include "migration/vmstate.h" 31034c2e69SAlistair Francis #include "qemu/bitops.h" 32034c2e69SAlistair Francis #include "sysemu/dma.h" 33034c2e69SAlistair Francis #include "qemu/log.h" 340b8fa32fSMarkus Armbruster #include "qemu/module.h" 35034c2e69SAlistair Francis 36034c2e69SAlistair Francis #define FREQ_HZ 900000000 37034c2e69SAlistair Francis 38034c2e69SAlistair Francis #define BTT_MAX 0x400 39034c2e69SAlistair Francis 40034c2e69SAlistair Francis #ifndef XLNX_ZYNQ_DEVCFG_ERR_DEBUG 41034c2e69SAlistair Francis #define XLNX_ZYNQ_DEVCFG_ERR_DEBUG 0 42034c2e69SAlistair Francis #endif 43034c2e69SAlistair Francis 44034c2e69SAlistair Francis #define DB_PRINT(fmt, args...) do { \ 45034c2e69SAlistair Francis if (XLNX_ZYNQ_DEVCFG_ERR_DEBUG) { \ 46034c2e69SAlistair Francis qemu_log("%s: " fmt, __func__, ## args); \ 47034c2e69SAlistair Francis } \ 482562755eSEric Blake } while (0) 49034c2e69SAlistair Francis 50034c2e69SAlistair Francis REG32(CTRL, 0x00) 51034c2e69SAlistair Francis FIELD(CTRL, FORCE_RST, 31, 1) /* Not supported, wr ignored */ 52034c2e69SAlistair Francis FIELD(CTRL, PCAP_PR, 27, 1) /* Forced to 0 on bad unlock */ 53034c2e69SAlistair Francis FIELD(CTRL, PCAP_MODE, 26, 1) 54034c2e69SAlistair Francis FIELD(CTRL, MULTIBOOT_EN, 24, 1) 55034c2e69SAlistair Francis FIELD(CTRL, USER_MODE, 15, 1) 56034c2e69SAlistair Francis FIELD(CTRL, PCFG_AES_FUSE, 12, 1) 57034c2e69SAlistair Francis FIELD(CTRL, PCFG_AES_EN, 9, 3) 58034c2e69SAlistair Francis FIELD(CTRL, SEU_EN, 8, 1) 59034c2e69SAlistair Francis FIELD(CTRL, SEC_EN, 7, 1) 60034c2e69SAlistair Francis FIELD(CTRL, SPNIDEN, 6, 1) 61034c2e69SAlistair Francis FIELD(CTRL, SPIDEN, 5, 1) 62034c2e69SAlistair Francis FIELD(CTRL, NIDEN, 4, 1) 63034c2e69SAlistair Francis FIELD(CTRL, DBGEN, 3, 1) 64034c2e69SAlistair Francis FIELD(CTRL, DAP_EN, 0, 3) 65034c2e69SAlistair Francis 66034c2e69SAlistair Francis REG32(LOCK, 0x04) 67034c2e69SAlistair Francis #define AES_FUSE_LOCK 4 68034c2e69SAlistair Francis #define AES_EN_LOCK 3 69034c2e69SAlistair Francis #define SEU_LOCK 2 70034c2e69SAlistair Francis #define SEC_LOCK 1 71034c2e69SAlistair Francis #define DBG_LOCK 0 72034c2e69SAlistair Francis 73034c2e69SAlistair Francis /* mapping bits in R_LOCK to what they lock in R_CTRL */ 74034c2e69SAlistair Francis static const uint32_t lock_ctrl_map[] = { 75034c2e69SAlistair Francis [AES_FUSE_LOCK] = R_CTRL_PCFG_AES_FUSE_MASK, 76034c2e69SAlistair Francis [AES_EN_LOCK] = R_CTRL_PCFG_AES_EN_MASK, 77034c2e69SAlistair Francis [SEU_LOCK] = R_CTRL_SEU_EN_MASK, 78034c2e69SAlistair Francis [SEC_LOCK] = R_CTRL_SEC_EN_MASK, 79034c2e69SAlistair Francis [DBG_LOCK] = R_CTRL_SPNIDEN_MASK | R_CTRL_SPIDEN_MASK | 80034c2e69SAlistair Francis R_CTRL_NIDEN_MASK | R_CTRL_DBGEN_MASK | 81034c2e69SAlistair Francis R_CTRL_DAP_EN_MASK, 82034c2e69SAlistair Francis }; 83034c2e69SAlistair Francis 84034c2e69SAlistair Francis REG32(CFG, 0x08) 85034c2e69SAlistair Francis FIELD(CFG, RFIFO_TH, 10, 2) 86034c2e69SAlistair Francis FIELD(CFG, WFIFO_TH, 8, 2) 87034c2e69SAlistair Francis FIELD(CFG, RCLK_EDGE, 7, 1) 88034c2e69SAlistair Francis FIELD(CFG, WCLK_EDGE, 6, 1) 89034c2e69SAlistair Francis FIELD(CFG, DISABLE_SRC_INC, 5, 1) 90034c2e69SAlistair Francis FIELD(CFG, DISABLE_DST_INC, 4, 1) 91034c2e69SAlistair Francis #define R_CFG_RESET 0x50B 92034c2e69SAlistair Francis 93034c2e69SAlistair Francis REG32(INT_STS, 0x0C) 94034c2e69SAlistair Francis FIELD(INT_STS, PSS_GTS_USR_B, 31, 1) 95034c2e69SAlistair Francis FIELD(INT_STS, PSS_FST_CFG_B, 30, 1) 96034c2e69SAlistair Francis FIELD(INT_STS, PSS_CFG_RESET_B, 27, 1) 97034c2e69SAlistair Francis FIELD(INT_STS, RX_FIFO_OV, 18, 1) 98034c2e69SAlistair Francis FIELD(INT_STS, WR_FIFO_LVL, 17, 1) 99034c2e69SAlistair Francis FIELD(INT_STS, RD_FIFO_LVL, 16, 1) 100034c2e69SAlistair Francis FIELD(INT_STS, DMA_CMD_ERR, 15, 1) 101034c2e69SAlistair Francis FIELD(INT_STS, DMA_Q_OV, 14, 1) 102034c2e69SAlistair Francis FIELD(INT_STS, DMA_DONE, 13, 1) 103034c2e69SAlistair Francis FIELD(INT_STS, DMA_P_DONE, 12, 1) 104034c2e69SAlistair Francis FIELD(INT_STS, P2D_LEN_ERR, 11, 1) 105034c2e69SAlistair Francis FIELD(INT_STS, PCFG_DONE, 2, 1) 106034c2e69SAlistair Francis #define R_INT_STS_RSVD ((0x7 << 24) | (0x1 << 19) | (0xF < 7)) 107034c2e69SAlistair Francis 108034c2e69SAlistair Francis REG32(INT_MASK, 0x10) 109034c2e69SAlistair Francis 110034c2e69SAlistair Francis REG32(STATUS, 0x14) 111034c2e69SAlistair Francis FIELD(STATUS, DMA_CMD_Q_F, 31, 1) 112034c2e69SAlistair Francis FIELD(STATUS, DMA_CMD_Q_E, 30, 1) 113034c2e69SAlistair Francis FIELD(STATUS, DMA_DONE_CNT, 28, 2) 114034c2e69SAlistair Francis FIELD(STATUS, RX_FIFO_LVL, 20, 5) 115034c2e69SAlistair Francis FIELD(STATUS, TX_FIFO_LVL, 12, 7) 116034c2e69SAlistair Francis FIELD(STATUS, PSS_GTS_USR_B, 11, 1) 117034c2e69SAlistair Francis FIELD(STATUS, PSS_FST_CFG_B, 10, 1) 118034c2e69SAlistair Francis FIELD(STATUS, PSS_CFG_RESET_B, 5, 1) 119034c2e69SAlistair Francis 120034c2e69SAlistair Francis REG32(DMA_SRC_ADDR, 0x18) 121034c2e69SAlistair Francis REG32(DMA_DST_ADDR, 0x1C) 122034c2e69SAlistair Francis REG32(DMA_SRC_LEN, 0x20) 123034c2e69SAlistair Francis REG32(DMA_DST_LEN, 0x24) 124034c2e69SAlistair Francis REG32(ROM_SHADOW, 0x28) 125034c2e69SAlistair Francis REG32(SW_ID, 0x30) 126034c2e69SAlistair Francis REG32(UNLOCK, 0x34) 127034c2e69SAlistair Francis 128034c2e69SAlistair Francis #define R_UNLOCK_MAGIC 0x757BDF0D 129034c2e69SAlistair Francis 130034c2e69SAlistair Francis REG32(MCTRL, 0x80) 131034c2e69SAlistair Francis FIELD(MCTRL, PS_VERSION, 28, 4) 132034c2e69SAlistair Francis FIELD(MCTRL, PCFG_POR_B, 8, 1) 133034c2e69SAlistair Francis FIELD(MCTRL, INT_PCAP_LPBK, 4, 1) 134034c2e69SAlistair Francis FIELD(MCTRL, QEMU, 3, 1) 135034c2e69SAlistair Francis 136034c2e69SAlistair Francis static void xlnx_zynq_devcfg_update_ixr(XlnxZynqDevcfg *s) 137034c2e69SAlistair Francis { 138034c2e69SAlistair Francis qemu_set_irq(s->irq, ~s->regs[R_INT_MASK] & s->regs[R_INT_STS]); 139034c2e69SAlistair Francis } 140034c2e69SAlistair Francis 141034c2e69SAlistair Francis static void xlnx_zynq_devcfg_reset(DeviceState *dev) 142034c2e69SAlistair Francis { 143034c2e69SAlistair Francis XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(dev); 144034c2e69SAlistair Francis int i; 145034c2e69SAlistair Francis 146034c2e69SAlistair Francis for (i = 0; i < XLNX_ZYNQ_DEVCFG_R_MAX; ++i) { 147034c2e69SAlistair Francis register_reset(&s->regs_info[i]); 148034c2e69SAlistair Francis } 149034c2e69SAlistair Francis } 150034c2e69SAlistair Francis 151034c2e69SAlistair Francis static void xlnx_zynq_devcfg_dma_go(XlnxZynqDevcfg *s) 152034c2e69SAlistair Francis { 153034c2e69SAlistair Francis do { 154034c2e69SAlistair Francis uint8_t buf[BTT_MAX]; 155034c2e69SAlistair Francis XlnxZynqDevcfgDMACmd *dmah = s->dma_cmd_fifo; 156034c2e69SAlistair Francis uint32_t btt = BTT_MAX; 157034c2e69SAlistair Francis bool loopback = s->regs[R_MCTRL] & R_MCTRL_INT_PCAP_LPBK_MASK; 158034c2e69SAlistair Francis 159034c2e69SAlistair Francis btt = MIN(btt, dmah->src_len); 160034c2e69SAlistair Francis if (loopback) { 161034c2e69SAlistair Francis btt = MIN(btt, dmah->dest_len); 162034c2e69SAlistair Francis } 163034c2e69SAlistair Francis DB_PRINT("reading %x bytes from %x\n", btt, dmah->src_addr); 164ba06fe8aSPhilippe Mathieu-Daudé dma_memory_read(&address_space_memory, dmah->src_addr, buf, btt, 165ba06fe8aSPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED); 166034c2e69SAlistair Francis dmah->src_len -= btt; 167034c2e69SAlistair Francis dmah->src_addr += btt; 168034c2e69SAlistair Francis if (loopback && (dmah->src_len || dmah->dest_len)) { 169034c2e69SAlistair Francis DB_PRINT("writing %x bytes from %x\n", btt, dmah->dest_addr); 170ba06fe8aSPhilippe Mathieu-Daudé dma_memory_write(&address_space_memory, dmah->dest_addr, buf, btt, 171ba06fe8aSPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED); 172034c2e69SAlistair Francis dmah->dest_len -= btt; 173034c2e69SAlistair Francis dmah->dest_addr += btt; 174034c2e69SAlistair Francis } 175034c2e69SAlistair Francis if (!dmah->src_len && !dmah->dest_len) { 176034c2e69SAlistair Francis DB_PRINT("dma operation finished\n"); 177034c2e69SAlistair Francis s->regs[R_INT_STS] |= R_INT_STS_DMA_DONE_MASK | 178034c2e69SAlistair Francis R_INT_STS_DMA_P_DONE_MASK; 179034c2e69SAlistair Francis s->dma_cmd_fifo_num--; 180034c2e69SAlistair Francis memmove(s->dma_cmd_fifo, &s->dma_cmd_fifo[1], 181034c2e69SAlistair Francis sizeof(s->dma_cmd_fifo) - sizeof(s->dma_cmd_fifo[0])); 182034c2e69SAlistair Francis } 183034c2e69SAlistair Francis xlnx_zynq_devcfg_update_ixr(s); 184034c2e69SAlistair Francis } while (s->dma_cmd_fifo_num); 185034c2e69SAlistair Francis } 186034c2e69SAlistair Francis 187034c2e69SAlistair Francis static void r_ixr_post_write(RegisterInfo *reg, uint64_t val) 188034c2e69SAlistair Francis { 189034c2e69SAlistair Francis XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque); 190034c2e69SAlistair Francis 191034c2e69SAlistair Francis xlnx_zynq_devcfg_update_ixr(s); 192034c2e69SAlistair Francis } 193034c2e69SAlistair Francis 194034c2e69SAlistair Francis static uint64_t r_ctrl_pre_write(RegisterInfo *reg, uint64_t val) 195034c2e69SAlistair Francis { 196034c2e69SAlistair Francis XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque); 197034c2e69SAlistair Francis int i; 198034c2e69SAlistair Francis 199034c2e69SAlistair Francis for (i = 0; i < ARRAY_SIZE(lock_ctrl_map); ++i) { 200034c2e69SAlistair Francis if (s->regs[R_LOCK] & 1 << i) { 201034c2e69SAlistair Francis val &= ~lock_ctrl_map[i]; 202034c2e69SAlistair Francis val |= lock_ctrl_map[i] & s->regs[R_CTRL]; 203034c2e69SAlistair Francis } 204034c2e69SAlistair Francis } 205034c2e69SAlistair Francis return val; 206034c2e69SAlistair Francis } 207034c2e69SAlistair Francis 208034c2e69SAlistair Francis static void r_ctrl_post_write(RegisterInfo *reg, uint64_t val) 209034c2e69SAlistair Francis { 210034c2e69SAlistair Francis const char *device_prefix = object_get_typename(OBJECT(reg->opaque)); 211034c2e69SAlistair Francis uint32_t aes_en = FIELD_EX32(val, CTRL, PCFG_AES_EN); 212034c2e69SAlistair Francis 213034c2e69SAlistair Francis if (aes_en != 0 && aes_en != 7) { 214034c2e69SAlistair Francis qemu_log_mask(LOG_UNIMP, "%s: warning, aes-en bits inconsistent," 215034c2e69SAlistair Francis "unimplemented security reset should happen!\n", 216034c2e69SAlistair Francis device_prefix); 217034c2e69SAlistair Francis } 218034c2e69SAlistair Francis } 219034c2e69SAlistair Francis 220034c2e69SAlistair Francis static void r_unlock_post_write(RegisterInfo *reg, uint64_t val) 221034c2e69SAlistair Francis { 222034c2e69SAlistair Francis XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque); 223034c2e69SAlistair Francis const char *device_prefix = object_get_typename(OBJECT(s)); 224034c2e69SAlistair Francis 225034c2e69SAlistair Francis if (val == R_UNLOCK_MAGIC) { 226034c2e69SAlistair Francis DB_PRINT("successful unlock\n"); 227034c2e69SAlistair Francis s->regs[R_CTRL] |= R_CTRL_PCAP_PR_MASK; 228034c2e69SAlistair Francis s->regs[R_CTRL] |= R_CTRL_PCFG_AES_EN_MASK; 229034c2e69SAlistair Francis memory_region_set_enabled(&s->iomem, true); 230034c2e69SAlistair Francis } else { /* bad unlock attempt */ 231034c2e69SAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, "%s: failed unlock\n", device_prefix); 232034c2e69SAlistair Francis s->regs[R_CTRL] &= ~R_CTRL_PCAP_PR_MASK; 233034c2e69SAlistair Francis s->regs[R_CTRL] &= ~R_CTRL_PCFG_AES_EN_MASK; 234034c2e69SAlistair Francis /* core becomes inaccessible */ 235034c2e69SAlistair Francis memory_region_set_enabled(&s->iomem, false); 236034c2e69SAlistair Francis } 237034c2e69SAlistair Francis } 238034c2e69SAlistair Francis 239034c2e69SAlistair Francis static uint64_t r_lock_pre_write(RegisterInfo *reg, uint64_t val) 240034c2e69SAlistair Francis { 241034c2e69SAlistair Francis XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque); 242034c2e69SAlistair Francis 243034c2e69SAlistair Francis /* once bits are locked they stay locked */ 244034c2e69SAlistair Francis return s->regs[R_LOCK] | val; 245034c2e69SAlistair Francis } 246034c2e69SAlistair Francis 247034c2e69SAlistair Francis static void r_dma_dst_len_post_write(RegisterInfo *reg, uint64_t val) 248034c2e69SAlistair Francis { 249034c2e69SAlistair Francis XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque); 250034c2e69SAlistair Francis 251034c2e69SAlistair Francis s->dma_cmd_fifo[s->dma_cmd_fifo_num] = (XlnxZynqDevcfgDMACmd) { 252034c2e69SAlistair Francis .src_addr = s->regs[R_DMA_SRC_ADDR] & ~0x3UL, 253034c2e69SAlistair Francis .dest_addr = s->regs[R_DMA_DST_ADDR] & ~0x3UL, 254034c2e69SAlistair Francis .src_len = s->regs[R_DMA_SRC_LEN] << 2, 255034c2e69SAlistair Francis .dest_len = s->regs[R_DMA_DST_LEN] << 2, 256034c2e69SAlistair Francis }; 257034c2e69SAlistair Francis s->dma_cmd_fifo_num++; 258034c2e69SAlistair Francis DB_PRINT("dma transfer started; %d total transfers pending\n", 259034c2e69SAlistair Francis s->dma_cmd_fifo_num); 260034c2e69SAlistair Francis xlnx_zynq_devcfg_dma_go(s); 261034c2e69SAlistair Francis } 262034c2e69SAlistair Francis 263034c2e69SAlistair Francis static const RegisterAccessInfo xlnx_zynq_devcfg_regs_info[] = { 264034c2e69SAlistair Francis { .name = "CTRL", .addr = A_CTRL, 265034c2e69SAlistair Francis .reset = R_CTRL_PCAP_PR_MASK | R_CTRL_PCAP_MODE_MASK | 0x3 << 13, 266034c2e69SAlistair Francis .rsvd = 0x1 << 28 | 0x3ff << 13 | 0x3 << 13, 267034c2e69SAlistair Francis .pre_write = r_ctrl_pre_write, 268034c2e69SAlistair Francis .post_write = r_ctrl_post_write, 269034c2e69SAlistair Francis }, 270034c2e69SAlistair Francis { .name = "LOCK", .addr = A_LOCK, 271034c2e69SAlistair Francis .rsvd = MAKE_64BIT_MASK(5, 64 - 5), 272034c2e69SAlistair Francis .pre_write = r_lock_pre_write, 273034c2e69SAlistair Francis }, 274034c2e69SAlistair Francis { .name = "CFG", .addr = A_CFG, 275034c2e69SAlistair Francis .reset = R_CFG_RESET, 276034c2e69SAlistair Francis .rsvd = 0xfffff00f, 277034c2e69SAlistair Francis }, 278034c2e69SAlistair Francis { .name = "INT_STS", .addr = A_INT_STS, 279034c2e69SAlistair Francis .w1c = ~R_INT_STS_RSVD, 280034c2e69SAlistair Francis .reset = R_INT_STS_PSS_GTS_USR_B_MASK | 281034c2e69SAlistair Francis R_INT_STS_PSS_CFG_RESET_B_MASK | 282034c2e69SAlistair Francis R_INT_STS_WR_FIFO_LVL_MASK, 283034c2e69SAlistair Francis .rsvd = R_INT_STS_RSVD, 284034c2e69SAlistair Francis .post_write = r_ixr_post_write, 285034c2e69SAlistair Francis }, 286034c2e69SAlistair Francis { .name = "INT_MASK", .addr = A_INT_MASK, 287034c2e69SAlistair Francis .reset = ~0, 288034c2e69SAlistair Francis .rsvd = R_INT_STS_RSVD, 289034c2e69SAlistair Francis .post_write = r_ixr_post_write, 290034c2e69SAlistair Francis }, 291034c2e69SAlistair Francis { .name = "STATUS", .addr = A_STATUS, 292034c2e69SAlistair Francis .reset = R_STATUS_DMA_CMD_Q_E_MASK | 293034c2e69SAlistair Francis R_STATUS_PSS_GTS_USR_B_MASK | 294034c2e69SAlistair Francis R_STATUS_PSS_CFG_RESET_B_MASK, 295034c2e69SAlistair Francis .ro = ~0, 296034c2e69SAlistair Francis }, 297034c2e69SAlistair Francis { .name = "DMA_SRC_ADDR", .addr = A_DMA_SRC_ADDR, }, 298034c2e69SAlistair Francis { .name = "DMA_DST_ADDR", .addr = A_DMA_DST_ADDR, }, 299034c2e69SAlistair Francis { .name = "DMA_SRC_LEN", .addr = A_DMA_SRC_LEN, 300034c2e69SAlistair Francis .ro = MAKE_64BIT_MASK(27, 64 - 27) }, 301034c2e69SAlistair Francis { .name = "DMA_DST_LEN", .addr = A_DMA_DST_LEN, 302034c2e69SAlistair Francis .ro = MAKE_64BIT_MASK(27, 64 - 27), 303034c2e69SAlistair Francis .post_write = r_dma_dst_len_post_write, 304034c2e69SAlistair Francis }, 305034c2e69SAlistair Francis { .name = "ROM_SHADOW", .addr = A_ROM_SHADOW, 306034c2e69SAlistair Francis .rsvd = ~0ull, 307034c2e69SAlistair Francis }, 308034c2e69SAlistair Francis { .name = "SW_ID", .addr = A_SW_ID, }, 309034c2e69SAlistair Francis { .name = "UNLOCK", .addr = A_UNLOCK, 310034c2e69SAlistair Francis .post_write = r_unlock_post_write, 311034c2e69SAlistair Francis }, 312034c2e69SAlistair Francis { .name = "MCTRL", .addr = R_MCTRL * 4, 313034c2e69SAlistair Francis /* Silicon 3.0 for version field, the mysterious reserved bit 23 314034c2e69SAlistair Francis * and QEMU platform identifier. 315034c2e69SAlistair Francis */ 316034c2e69SAlistair Francis .reset = 0x2 << R_MCTRL_PS_VERSION_SHIFT | 1 << 23 | R_MCTRL_QEMU_MASK, 317034c2e69SAlistair Francis .ro = ~R_MCTRL_INT_PCAP_LPBK_MASK, 318034c2e69SAlistair Francis .rsvd = 0x00f00303, 319034c2e69SAlistair Francis }, 320034c2e69SAlistair Francis }; 321034c2e69SAlistair Francis 322034c2e69SAlistair Francis static const MemoryRegionOps xlnx_zynq_devcfg_reg_ops = { 323034c2e69SAlistair Francis .read = register_read_memory, 324034c2e69SAlistair Francis .write = register_write_memory, 325034c2e69SAlistair Francis .endianness = DEVICE_LITTLE_ENDIAN, 326034c2e69SAlistair Francis .valid = { 327034c2e69SAlistair Francis .min_access_size = 4, 328034c2e69SAlistair Francis .max_access_size = 4, 329034c2e69SAlistair Francis } 330034c2e69SAlistair Francis }; 331034c2e69SAlistair Francis 332034c2e69SAlistair Francis static const VMStateDescription vmstate_xlnx_zynq_devcfg_dma_cmd = { 333034c2e69SAlistair Francis .name = "xlnx_zynq_devcfg_dma_cmd", 334034c2e69SAlistair Francis .version_id = 1, 335034c2e69SAlistair Francis .minimum_version_id = 1, 33663e6b564SRichard Henderson .fields = (const VMStateField[]) { 337034c2e69SAlistair Francis VMSTATE_UINT32(src_addr, XlnxZynqDevcfgDMACmd), 338034c2e69SAlistair Francis VMSTATE_UINT32(dest_addr, XlnxZynqDevcfgDMACmd), 339034c2e69SAlistair Francis VMSTATE_UINT32(src_len, XlnxZynqDevcfgDMACmd), 340034c2e69SAlistair Francis VMSTATE_UINT32(dest_len, XlnxZynqDevcfgDMACmd), 341034c2e69SAlistair Francis VMSTATE_END_OF_LIST() 342034c2e69SAlistair Francis } 343034c2e69SAlistair Francis }; 344034c2e69SAlistair Francis 345034c2e69SAlistair Francis static const VMStateDescription vmstate_xlnx_zynq_devcfg = { 346034c2e69SAlistair Francis .name = "xlnx_zynq_devcfg", 347034c2e69SAlistair Francis .version_id = 1, 348034c2e69SAlistair Francis .minimum_version_id = 1, 34963e6b564SRichard Henderson .fields = (const VMStateField[]) { 350034c2e69SAlistair Francis VMSTATE_STRUCT_ARRAY(dma_cmd_fifo, XlnxZynqDevcfg, 351034c2e69SAlistair Francis XLNX_ZYNQ_DEVCFG_DMA_CMD_FIFO_LEN, 0, 352034c2e69SAlistair Francis vmstate_xlnx_zynq_devcfg_dma_cmd, 353034c2e69SAlistair Francis XlnxZynqDevcfgDMACmd), 354034c2e69SAlistair Francis VMSTATE_UINT8(dma_cmd_fifo_num, XlnxZynqDevcfg), 355034c2e69SAlistair Francis VMSTATE_UINT32_ARRAY(regs, XlnxZynqDevcfg, XLNX_ZYNQ_DEVCFG_R_MAX), 356034c2e69SAlistair Francis VMSTATE_END_OF_LIST() 357034c2e69SAlistair Francis } 358034c2e69SAlistair Francis }; 359034c2e69SAlistair Francis 360034c2e69SAlistair Francis static void xlnx_zynq_devcfg_init(Object *obj) 361034c2e69SAlistair Francis { 362034c2e69SAlistair Francis SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 363034c2e69SAlistair Francis XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(obj); 364034c2e69SAlistair Francis RegisterInfoArray *reg_array; 365034c2e69SAlistair Francis 366034c2e69SAlistair Francis sysbus_init_irq(sbd, &s->irq); 367034c2e69SAlistair Francis 368034c2e69SAlistair Francis memory_region_init(&s->iomem, obj, "devcfg", XLNX_ZYNQ_DEVCFG_R_MAX * 4); 369034c2e69SAlistair Francis reg_array = 370034c2e69SAlistair Francis register_init_block32(DEVICE(obj), xlnx_zynq_devcfg_regs_info, 371034c2e69SAlistair Francis ARRAY_SIZE(xlnx_zynq_devcfg_regs_info), 372034c2e69SAlistair Francis s->regs_info, s->regs, 373034c2e69SAlistair Francis &xlnx_zynq_devcfg_reg_ops, 374034c2e69SAlistair Francis XLNX_ZYNQ_DEVCFG_ERR_DEBUG, 375034c2e69SAlistair Francis XLNX_ZYNQ_DEVCFG_R_MAX); 376034c2e69SAlistair Francis memory_region_add_subregion(&s->iomem, 377034c2e69SAlistair Francis A_CTRL, 378034c2e69SAlistair Francis ®_array->mem); 379034c2e69SAlistair Francis 380034c2e69SAlistair Francis sysbus_init_mmio(sbd, &s->iomem); 381034c2e69SAlistair Francis } 382034c2e69SAlistair Francis 383034c2e69SAlistair Francis static void xlnx_zynq_devcfg_class_init(ObjectClass *klass, void *data) 384034c2e69SAlistair Francis { 385034c2e69SAlistair Francis DeviceClass *dc = DEVICE_CLASS(klass); 386034c2e69SAlistair Francis 387*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, xlnx_zynq_devcfg_reset); 388034c2e69SAlistair Francis dc->vmsd = &vmstate_xlnx_zynq_devcfg; 389034c2e69SAlistair Francis } 390034c2e69SAlistair Francis 391034c2e69SAlistair Francis static const TypeInfo xlnx_zynq_devcfg_info = { 392034c2e69SAlistair Francis .name = TYPE_XLNX_ZYNQ_DEVCFG, 393034c2e69SAlistair Francis .parent = TYPE_SYS_BUS_DEVICE, 394034c2e69SAlistair Francis .instance_size = sizeof(XlnxZynqDevcfg), 395034c2e69SAlistair Francis .instance_init = xlnx_zynq_devcfg_init, 396034c2e69SAlistair Francis .class_init = xlnx_zynq_devcfg_class_init, 397034c2e69SAlistair Francis }; 398034c2e69SAlistair Francis 399034c2e69SAlistair Francis static void xlnx_zynq_devcfg_register_types(void) 400034c2e69SAlistair Francis { 401034c2e69SAlistair Francis type_register_static(&xlnx_zynq_devcfg_info); 402034c2e69SAlistair Francis } 403034c2e69SAlistair Francis 404034c2e69SAlistair Francis type_init(xlnx_zynq_devcfg_register_types) 405