| 1 | /* |
| 2 | * QEMU model of Xilinx Versal's OSPI controller. |
| 3 | * |
| 4 | * Copyright (c) 2021 Xilinx Inc. |
| 5 | * Written by Francisco Iglesias <francisco.iglesias@xilinx.com> |
| 6 | * |
| 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 8 | * of this software and associated documentation files (the "Software"), to deal |
| 9 | * in the Software without restriction, including without limitation the rights |
| 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 11 | * copies of the Software, and to permit persons to whom the Software is |
| 12 | * furnished to do so, subject to the following conditions: |
| 13 | * |
| 14 | * The above copyright notice and this permission notice shall be included in |
| 15 | * all copies or substantial portions of the Software. |
| 16 | * |
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 23 | * THE SOFTWARE. |
| 24 | */ |
| 25 | #include "qemu/osdep.h" |
| 26 | #include "hw/core/sysbus.h" |
| 27 | #include "migration/vmstate.h" |
| 28 | #include "hw/core/qdev-properties.h" |
| 29 | #include "qemu/bitops.h" |
| 30 | #include "qemu/log.h" |
| 31 | #include "hw/core/irq.h" |
| 32 | #include "hw/ssi/xlnx-versal-ospi.h" |
| 33 | |
| 34 | #ifndef XILINX_VERSAL_OSPI_ERR_DEBUG |
| 35 | #define XILINX_VERSAL_OSPI_ERR_DEBUG 0 |
| 36 | #endif |
| 37 | |
| 38 | REG32(CONFIG_REG, 0x0) |
| 39 | FIELD(CONFIG_REG, IDLE_FLD, 31, 1) |
| 40 | FIELD(CONFIG_REG, DUAL_BYTE_OPCODE_EN_FLD, 30, 1) |
| 41 | FIELD(CONFIG_REG, CRC_ENABLE_FLD, 29, 1) |
| 42 | FIELD(CONFIG_REG, CONFIG_RESV2_FLD, 26, 3) |
| 43 | FIELD(CONFIG_REG, PIPELINE_PHY_FLD, 25, 1) |
| 44 | FIELD(CONFIG_REG, ENABLE_DTR_PROTOCOL_FLD, 24, 1) |
| 45 | FIELD(CONFIG_REG, ENABLE_AHB_DECODER_FLD, 23, 1) |
| 46 | FIELD(CONFIG_REG, MSTR_BAUD_DIV_FLD, 19, 4) |
| 47 | FIELD(CONFIG_REG, ENTER_XIP_MODE_IMM_FLD, 18, 1) |
| 48 | FIELD(CONFIG_REG, ENTER_XIP_MODE_FLD, 17, 1) |
| 49 | FIELD(CONFIG_REG, ENB_AHB_ADDR_REMAP_FLD, 16, 1) |
| 50 | FIELD(CONFIG_REG, ENB_DMA_IF_FLD, 15, 1) |
| 51 | FIELD(CONFIG_REG, WR_PROT_FLASH_FLD, 14, 1) |
| 52 | FIELD(CONFIG_REG, PERIPH_CS_LINES_FLD, 10, 4) |
| 53 | FIELD(CONFIG_REG, PERIPH_SEL_DEC_FLD, 9, 1) |
| 54 | FIELD(CONFIG_REG, ENB_LEGACY_IP_MODE_FLD, 8, 1) |
| 55 | FIELD(CONFIG_REG, ENB_DIR_ACC_CTLR_FLD, 7, 1) |
| 56 | FIELD(CONFIG_REG, RESET_CFG_FLD, 6, 1) |
| 57 | FIELD(CONFIG_REG, RESET_PIN_FLD, 5, 1) |
| 58 | FIELD(CONFIG_REG, HOLD_PIN_FLD, 4, 1) |
| 59 | FIELD(CONFIG_REG, PHY_MODE_ENABLE_FLD, 3, 1) |
| 60 | FIELD(CONFIG_REG, SEL_CLK_PHASE_FLD, 2, 1) |
| 61 | FIELD(CONFIG_REG, SEL_CLK_POL_FLD, 1, 1) |
| 62 | FIELD(CONFIG_REG, ENB_SPI_FLD, 0, 1) |
| 63 | REG32(DEV_INSTR_RD_CONFIG_REG, 0x4) |
| 64 | FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV5_FLD, 29, 3) |
| 65 | FIELD(DEV_INSTR_RD_CONFIG_REG, DUMMY_RD_CLK_CYCLES_FLD, 24, 5) |
| 66 | FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV4_FLD, 21, 3) |
| 67 | FIELD(DEV_INSTR_RD_CONFIG_REG, MODE_BIT_ENABLE_FLD, 20, 1) |
| 68 | FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV3_FLD, 18, 2) |
| 69 | FIELD(DEV_INSTR_RD_CONFIG_REG, DATA_XFER_TYPE_EXT_MODE_FLD, 16, 2) |
| 70 | FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV2_FLD, 14, 2) |
| 71 | FIELD(DEV_INSTR_RD_CONFIG_REG, ADDR_XFER_TYPE_STD_MODE_FLD, 12, 2) |
| 72 | FIELD(DEV_INSTR_RD_CONFIG_REG, PRED_DIS_FLD, 11, 1) |
| 73 | FIELD(DEV_INSTR_RD_CONFIG_REG, DDR_EN_FLD, 10, 1) |
| 74 | FIELD(DEV_INSTR_RD_CONFIG_REG, INSTR_TYPE_FLD, 8, 2) |
| 75 | FIELD(DEV_INSTR_RD_CONFIG_REG, RD_OPCODE_NON_XIP_FLD, 0, 8) |
| 76 | REG32(DEV_INSTR_WR_CONFIG_REG, 0x8) |
| 77 | FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV4_FLD, 29, 3) |
| 78 | FIELD(DEV_INSTR_WR_CONFIG_REG, DUMMY_WR_CLK_CYCLES_FLD, 24, 5) |
| 79 | FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV3_FLD, 18, 6) |
| 80 | FIELD(DEV_INSTR_WR_CONFIG_REG, DATA_XFER_TYPE_EXT_MODE_FLD, 16, 2) |
| 81 | FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV2_FLD, 14, 2) |
| 82 | FIELD(DEV_INSTR_WR_CONFIG_REG, ADDR_XFER_TYPE_STD_MODE_FLD, 12, 2) |
| 83 | FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV1_FLD, 9, 3) |
| 84 | FIELD(DEV_INSTR_WR_CONFIG_REG, WEL_DIS_FLD, 8, 1) |
| 85 | FIELD(DEV_INSTR_WR_CONFIG_REG, WR_OPCODE_FLD, 0, 8) |
| 86 | REG32(DEV_DELAY_REG, 0xc) |
| 87 | FIELD(DEV_DELAY_REG, D_NSS_FLD, 24, 8) |
| 88 | FIELD(DEV_DELAY_REG, D_BTWN_FLD, 16, 8) |
| 89 | FIELD(DEV_DELAY_REG, D_AFTER_FLD, 8, 8) |
| 90 | FIELD(DEV_DELAY_REG, D_INIT_FLD, 0, 8) |
| 91 | REG32(RD_DATA_CAPTURE_REG, 0x10) |
| 92 | FIELD(RD_DATA_CAPTURE_REG, RD_DATA_RESV3_FLD, 20, 12) |
| 93 | FIELD(RD_DATA_CAPTURE_REG, DDR_READ_DELAY_FLD, 16, 4) |
| 94 | FIELD(RD_DATA_CAPTURE_REG, RD_DATA_RESV2_FLD, 9, 7) |
| 95 | FIELD(RD_DATA_CAPTURE_REG, DQS_ENABLE_FLD, 8, 1) |
| 96 | FIELD(RD_DATA_CAPTURE_REG, RD_DATA_RESV1_FLD, 6, 2) |
| 97 | FIELD(RD_DATA_CAPTURE_REG, SAMPLE_EDGE_SEL_FLD, 5, 1) |
| 98 | FIELD(RD_DATA_CAPTURE_REG, DELAY_FLD, 1, 4) |
| 99 | FIELD(RD_DATA_CAPTURE_REG, BYPASS_FLD, 0, 1) |
| 100 | REG32(DEV_SIZE_CONFIG_REG, 0x14) |
| 101 | FIELD(DEV_SIZE_CONFIG_REG, DEV_SIZE_RESV_FLD, 29, 3) |
| 102 | FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS3_FLD, 27, 2) |
| 103 | FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS2_FLD, 25, 2) |
| 104 | FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS1_FLD, 23, 2) |
| 105 | FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS0_FLD, 21, 2) |
| 106 | FIELD(DEV_SIZE_CONFIG_REG, BYTES_PER_SUBSECTOR_FLD, 16, 5) |
| 107 | FIELD(DEV_SIZE_CONFIG_REG, BYTES_PER_DEVICE_PAGE_FLD, 4, 12) |
| 108 | FIELD(DEV_SIZE_CONFIG_REG, NUM_ADDR_BYTES_FLD, 0, 4) |
| 109 | REG32(SRAM_PARTITION_CFG_REG, 0x18) |
| 110 | FIELD(SRAM_PARTITION_CFG_REG, SRAM_PARTITION_RESV_FLD, 8, 24) |
| 111 | FIELD(SRAM_PARTITION_CFG_REG, ADDR_FLD, 0, 8) |
| 112 | REG32(IND_AHB_ADDR_TRIGGER_REG, 0x1c) |
| 113 | REG32(DMA_PERIPH_CONFIG_REG, 0x20) |
| 114 | FIELD(DMA_PERIPH_CONFIG_REG, DMA_PERIPH_RESV2_FLD, 12, 20) |
| 115 | FIELD(DMA_PERIPH_CONFIG_REG, NUM_BURST_REQ_BYTES_FLD, 8, 4) |
| 116 | FIELD(DMA_PERIPH_CONFIG_REG, DMA_PERIPH_RESV1_FLD, 4, 4) |
| 117 | FIELD(DMA_PERIPH_CONFIG_REG, NUM_SINGLE_REQ_BYTES_FLD, 0, 4) |
| 118 | REG32(REMAP_ADDR_REG, 0x24) |
| 119 | REG32(MODE_BIT_CONFIG_REG, 0x28) |
| 120 | FIELD(MODE_BIT_CONFIG_REG, RX_CRC_DATA_LOW_FLD, 24, 8) |
| 121 | FIELD(MODE_BIT_CONFIG_REG, RX_CRC_DATA_UP_FLD, 16, 8) |
| 122 | FIELD(MODE_BIT_CONFIG_REG, CRC_OUT_ENABLE_FLD, 15, 1) |
| 123 | FIELD(MODE_BIT_CONFIG_REG, MODE_BIT_RESV1_FLD, 11, 4) |
| 124 | FIELD(MODE_BIT_CONFIG_REG, CHUNK_SIZE_FLD, 8, 3) |
| 125 | FIELD(MODE_BIT_CONFIG_REG, MODE_FLD, 0, 8) |
| 126 | REG32(SRAM_FILL_REG, 0x2c) |
| 127 | FIELD(SRAM_FILL_REG, SRAM_FILL_INDAC_WRITE_FLD, 16, 16) |
| 128 | FIELD(SRAM_FILL_REG, SRAM_FILL_INDAC_READ_FLD, 0, 16) |
| 129 | REG32(TX_THRESH_REG, 0x30) |
| 130 | FIELD(TX_THRESH_REG, TX_THRESH_RESV_FLD, 5, 27) |
| 131 | FIELD(TX_THRESH_REG, LEVEL_FLD, 0, 5) |
| 132 | REG32(RX_THRESH_REG, 0x34) |
| 133 | FIELD(RX_THRESH_REG, RX_THRESH_RESV_FLD, 5, 27) |
| 134 | FIELD(RX_THRESH_REG, LEVEL_FLD, 0, 5) |
| 135 | REG32(WRITE_COMPLETION_CTRL_REG, 0x38) |
| 136 | FIELD(WRITE_COMPLETION_CTRL_REG, POLL_REP_DELAY_FLD, 24, 8) |
| 137 | FIELD(WRITE_COMPLETION_CTRL_REG, POLL_COUNT_FLD, 16, 8) |
| 138 | FIELD(WRITE_COMPLETION_CTRL_REG, ENABLE_POLLING_EXP_FLD, 15, 1) |
| 139 | FIELD(WRITE_COMPLETION_CTRL_REG, DISABLE_POLLING_FLD, 14, 1) |
| 140 | FIELD(WRITE_COMPLETION_CTRL_REG, POLLING_POLARITY_FLD, 13, 1) |
| 141 | FIELD(WRITE_COMPLETION_CTRL_REG, WR_COMP_CTRL_RESV1_FLD, 12, 1) |
| 142 | FIELD(WRITE_COMPLETION_CTRL_REG, POLLING_ADDR_EN_FLD, 11, 1) |
| 143 | FIELD(WRITE_COMPLETION_CTRL_REG, POLLING_BIT_INDEX_FLD, 8, 3) |
| 144 | FIELD(WRITE_COMPLETION_CTRL_REG, OPCODE_FLD, 0, 8) |
| 145 | REG32(NO_OF_POLLS_BEF_EXP_REG, 0x3c) |
| 146 | REG32(IRQ_STATUS_REG, 0x40) |
| 147 | FIELD(IRQ_STATUS_REG, IRQ_STAT_RESV_FLD, 20, 12) |
| 148 | FIELD(IRQ_STATUS_REG, ECC_FAIL_FLD, 19, 1) |
| 149 | FIELD(IRQ_STATUS_REG, TX_CRC_CHUNK_BRK_FLD, 18, 1) |
| 150 | FIELD(IRQ_STATUS_REG, RX_CRC_DATA_VAL_FLD, 17, 1) |
| 151 | FIELD(IRQ_STATUS_REG, RX_CRC_DATA_ERR_FLD, 16, 1) |
| 152 | FIELD(IRQ_STATUS_REG, IRQ_STAT_RESV1_FLD, 15, 1) |
| 153 | FIELD(IRQ_STATUS_REG, STIG_REQ_INT_FLD, 14, 1) |
| 154 | FIELD(IRQ_STATUS_REG, POLL_EXP_INT_FLD, 13, 1) |
| 155 | FIELD(IRQ_STATUS_REG, INDRD_SRAM_FULL_FLD, 12, 1) |
| 156 | FIELD(IRQ_STATUS_REG, RX_FIFO_FULL_FLD, 11, 1) |
| 157 | FIELD(IRQ_STATUS_REG, RX_FIFO_NOT_EMPTY_FLD, 10, 1) |
| 158 | FIELD(IRQ_STATUS_REG, TX_FIFO_FULL_FLD, 9, 1) |
| 159 | FIELD(IRQ_STATUS_REG, TX_FIFO_NOT_FULL_FLD, 8, 1) |
| 160 | FIELD(IRQ_STATUS_REG, RECV_OVERFLOW_FLD, 7, 1) |
| 161 | FIELD(IRQ_STATUS_REG, INDIRECT_XFER_LEVEL_BREACH_FLD, 6, 1) |
| 162 | FIELD(IRQ_STATUS_REG, ILLEGAL_ACCESS_DET_FLD, 5, 1) |
| 163 | FIELD(IRQ_STATUS_REG, PROT_WR_ATTEMPT_FLD, 4, 1) |
| 164 | FIELD(IRQ_STATUS_REG, INDIRECT_TRANSFER_REJECT_FLD, 3, 1) |
| 165 | FIELD(IRQ_STATUS_REG, INDIRECT_OP_DONE_FLD, 2, 1) |
| 166 | FIELD(IRQ_STATUS_REG, UNDERFLOW_DET_FLD, 1, 1) |
| 167 | FIELD(IRQ_STATUS_REG, MODE_M_FAIL_FLD, 0, 1) |
| 168 | REG32(IRQ_MASK_REG, 0x44) |
| 169 | FIELD(IRQ_MASK_REG, IRQ_MASK_RESV_FLD, 20, 12) |
| 170 | FIELD(IRQ_MASK_REG, ECC_FAIL_MASK_FLD, 19, 1) |
| 171 | FIELD(IRQ_MASK_REG, TX_CRC_CHUNK_BRK_MASK_FLD, 18, 1) |
| 172 | FIELD(IRQ_MASK_REG, RX_CRC_DATA_VAL_MASK_FLD, 17, 1) |
| 173 | FIELD(IRQ_MASK_REG, RX_CRC_DATA_ERR_MASK_FLD, 16, 1) |
| 174 | FIELD(IRQ_MASK_REG, IRQ_MASK_RESV1_FLD, 15, 1) |
| 175 | FIELD(IRQ_MASK_REG, STIG_REQ_MASK_FLD, 14, 1) |
| 176 | FIELD(IRQ_MASK_REG, POLL_EXP_INT_MASK_FLD, 13, 1) |
| 177 | FIELD(IRQ_MASK_REG, INDRD_SRAM_FULL_MASK_FLD, 12, 1) |
| 178 | FIELD(IRQ_MASK_REG, RX_FIFO_FULL_MASK_FLD, 11, 1) |
| 179 | FIELD(IRQ_MASK_REG, RX_FIFO_NOT_EMPTY_MASK_FLD, 10, 1) |
| 180 | FIELD(IRQ_MASK_REG, TX_FIFO_FULL_MASK_FLD, 9, 1) |
| 181 | FIELD(IRQ_MASK_REG, TX_FIFO_NOT_FULL_MASK_FLD, 8, 1) |
| 182 | FIELD(IRQ_MASK_REG, RECV_OVERFLOW_MASK_FLD, 7, 1) |
| 183 | FIELD(IRQ_MASK_REG, INDIRECT_XFER_LEVEL_BREACH_MASK_FLD, 6, 1) |
| 184 | FIELD(IRQ_MASK_REG, ILLEGAL_ACCESS_DET_MASK_FLD, 5, 1) |
| 185 | FIELD(IRQ_MASK_REG, PROT_WR_ATTEMPT_MASK_FLD, 4, 1) |
| 186 | FIELD(IRQ_MASK_REG, INDIRECT_TRANSFER_REJECT_MASK_FLD, 3, 1) |
| 187 | FIELD(IRQ_MASK_REG, INDIRECT_OP_DONE_MASK_FLD, 2, 1) |
| 188 | FIELD(IRQ_MASK_REG, UNDERFLOW_DET_MASK_FLD, 1, 1) |
| 189 | FIELD(IRQ_MASK_REG, MODE_M_FAIL_MASK_FLD, 0, 1) |
| 190 | REG32(LOWER_WR_PROT_REG, 0x50) |
| 191 | REG32(UPPER_WR_PROT_REG, 0x54) |
| 192 | REG32(WR_PROT_CTRL_REG, 0x58) |
| 193 | FIELD(WR_PROT_CTRL_REG, WR_PROT_CTRL_RESV_FLD, 2, 30) |
| 194 | FIELD(WR_PROT_CTRL_REG, ENB_FLD, 1, 1) |
| 195 | FIELD(WR_PROT_CTRL_REG, INV_FLD, 0, 1) |
| 196 | REG32(INDIRECT_READ_XFER_CTRL_REG, 0x60) |
| 197 | FIELD(INDIRECT_READ_XFER_CTRL_REG, INDIR_RD_XFER_RESV_FLD, 8, 24) |
| 198 | FIELD(INDIRECT_READ_XFER_CTRL_REG, NUM_IND_OPS_DONE_FLD, 6, 2) |
| 199 | FIELD(INDIRECT_READ_XFER_CTRL_REG, IND_OPS_DONE_STATUS_FLD, 5, 1) |
| 200 | FIELD(INDIRECT_READ_XFER_CTRL_REG, RD_QUEUED_FLD, 4, 1) |
| 201 | FIELD(INDIRECT_READ_XFER_CTRL_REG, SRAM_FULL_FLD, 3, 1) |
| 202 | FIELD(INDIRECT_READ_XFER_CTRL_REG, RD_STATUS_FLD, 2, 1) |
| 203 | FIELD(INDIRECT_READ_XFER_CTRL_REG, CANCEL_FLD, 1, 1) |
| 204 | FIELD(INDIRECT_READ_XFER_CTRL_REG, START_FLD, 0, 1) |
| 205 | REG32(INDIRECT_READ_XFER_WATERMARK_REG, 0x64) |
| 206 | REG32(INDIRECT_READ_XFER_START_REG, 0x68) |
| 207 | REG32(INDIRECT_READ_XFER_NUM_BYTES_REG, 0x6c) |
| 208 | REG32(INDIRECT_WRITE_XFER_CTRL_REG, 0x70) |
| 209 | FIELD(INDIRECT_WRITE_XFER_CTRL_REG, INDIR_WR_XFER_RESV2_FLD, 8, 24) |
| 210 | FIELD(INDIRECT_WRITE_XFER_CTRL_REG, NUM_IND_OPS_DONE_FLD, 6, 2) |
| 211 | FIELD(INDIRECT_WRITE_XFER_CTRL_REG, IND_OPS_DONE_STATUS_FLD, 5, 1) |
| 212 | FIELD(INDIRECT_WRITE_XFER_CTRL_REG, WR_QUEUED_FLD, 4, 1) |
| 213 | FIELD(INDIRECT_WRITE_XFER_CTRL_REG, INDIR_WR_XFER_RESV1_FLD, 3, 1) |
| 214 | FIELD(INDIRECT_WRITE_XFER_CTRL_REG, WR_STATUS_FLD, 2, 1) |
| 215 | FIELD(INDIRECT_WRITE_XFER_CTRL_REG, CANCEL_FLD, 1, 1) |
| 216 | FIELD(INDIRECT_WRITE_XFER_CTRL_REG, START_FLD, 0, 1) |
| 217 | REG32(INDIRECT_WRITE_XFER_WATERMARK_REG, 0x74) |
| 218 | REG32(INDIRECT_WRITE_XFER_START_REG, 0x78) |
| 219 | REG32(INDIRECT_WRITE_XFER_NUM_BYTES_REG, 0x7c) |
| 220 | REG32(INDIRECT_TRIGGER_ADDR_RANGE_REG, 0x80) |
| 221 | FIELD(INDIRECT_TRIGGER_ADDR_RANGE_REG, IND_RANGE_RESV1_FLD, 4, 28) |
| 222 | FIELD(INDIRECT_TRIGGER_ADDR_RANGE_REG, IND_RANGE_WIDTH_FLD, 0, 4) |
| 223 | REG32(FLASH_COMMAND_CTRL_MEM_REG, 0x8c) |
| 224 | FIELD(FLASH_COMMAND_CTRL_MEM_REG, FLASH_COMMAND_CTRL_MEM_RESV1_FLD, 29, 3) |
| 225 | FIELD(FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_ADDR_FLD, 20, 9) |
| 226 | FIELD(FLASH_COMMAND_CTRL_MEM_REG, FLASH_COMMAND_CTRL_MEM_RESV2_FLD, 19, 1) |
| 227 | FIELD(FLASH_COMMAND_CTRL_MEM_REG, NB_OF_STIG_READ_BYTES_FLD, 16, 3) |
| 228 | FIELD(FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_READ_DATA_FLD, 8, 8) |
| 229 | FIELD(FLASH_COMMAND_CTRL_MEM_REG, FLASH_COMMAND_CTRL_MEM_RESV3_FLD, 2, 6) |
| 230 | FIELD(FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_REQ_IN_PROGRESS_FLD, 1, 1) |
| 231 | FIELD(FLASH_COMMAND_CTRL_MEM_REG, TRIGGER_MEM_BANK_REQ_FLD, 0, 1) |
| 232 | REG32(FLASH_CMD_CTRL_REG, 0x90) |
| 233 | FIELD(FLASH_CMD_CTRL_REG, CMD_OPCODE_FLD, 24, 8) |
| 234 | FIELD(FLASH_CMD_CTRL_REG, ENB_READ_DATA_FLD, 23, 1) |
| 235 | FIELD(FLASH_CMD_CTRL_REG, NUM_RD_DATA_BYTES_FLD, 20, 3) |
| 236 | FIELD(FLASH_CMD_CTRL_REG, ENB_COMD_ADDR_FLD, 19, 1) |
| 237 | FIELD(FLASH_CMD_CTRL_REG, ENB_MODE_BIT_FLD, 18, 1) |
| 238 | FIELD(FLASH_CMD_CTRL_REG, NUM_ADDR_BYTES_FLD, 16, 2) |
| 239 | FIELD(FLASH_CMD_CTRL_REG, ENB_WRITE_DATA_FLD, 15, 1) |
| 240 | FIELD(FLASH_CMD_CTRL_REG, NUM_WR_DATA_BYTES_FLD, 12, 3) |
| 241 | FIELD(FLASH_CMD_CTRL_REG, NUM_DUMMY_CYCLES_FLD, 7, 5) |
| 242 | FIELD(FLASH_CMD_CTRL_REG, FLASH_CMD_CTRL_RESV1_FLD, 3, 4) |
| 243 | FIELD(FLASH_CMD_CTRL_REG, STIG_MEM_BANK_EN_FLD, 2, 1) |
| 244 | FIELD(FLASH_CMD_CTRL_REG, CMD_EXEC_STATUS_FLD, 1, 1) |
| 245 | FIELD(FLASH_CMD_CTRL_REG, CMD_EXEC_FLD, 0, 1) |
| 246 | REG32(FLASH_CMD_ADDR_REG, 0x94) |
| 247 | REG32(FLASH_RD_DATA_LOWER_REG, 0xa0) |
| 248 | REG32(FLASH_RD_DATA_UPPER_REG, 0xa4) |
| 249 | REG32(FLASH_WR_DATA_LOWER_REG, 0xa8) |
| 250 | REG32(FLASH_WR_DATA_UPPER_REG, 0xac) |
| 251 | REG32(POLLING_FLASH_STATUS_REG, 0xb0) |
| 252 | FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_RSVD_FLD2, 21, 11) |
| 253 | FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_NB_DUMMY, 16, 5) |
| 254 | FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_RSVD_FLD1, 9, 7) |
| 255 | FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_VALID_FLD, 8, 1) |
| 256 | FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_FLD, 0, 8) |
| 257 | REG32(PHY_CONFIGURATION_REG, 0xb4) |
| 258 | FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESYNC_FLD, 31, 1) |
| 259 | FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESET_FLD, 30, 1) |
| 260 | FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RX_DLL_BYPASS_FLD, 29, 1) |
| 261 | FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESV2_FLD, 23, 6) |
| 262 | FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_TX_DLL_DELAY_FLD, 16, 7) |
| 263 | FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESV1_FLD, 7, 9) |
| 264 | FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RX_DLL_DELAY_FLD, 0, 7) |
| 265 | REG32(PHY_MASTER_CONTROL_REG, 0xb8) |
| 266 | FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_CONTROL_RESV3_FLD, 25, 7) |
| 267 | FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_LOCK_MODE_FLD, 24, 1) |
| 268 | FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_BYPASS_MODE_FLD, 23, 1) |
| 269 | FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_PHASE_DETECT_SELECTOR_FLD, 20, 3) |
| 270 | FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_CONTROL_RESV2_FLD, 19, 1) |
| 271 | FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_NB_INDICATIONS_FLD, 16, 3) |
| 272 | FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_CONTROL_RESV1_FLD, 7, 9) |
| 273 | FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_INITIAL_DELAY_FLD, 0, 7) |
| 274 | REG32(DLL_OBSERVABLE_LOWER_REG, 0xbc) |
| 275 | FIELD(DLL_OBSERVABLE_LOWER_REG, |
| 276 | DLL_OBSERVABLE_LOWER_DLL_LOCK_INC_FLD, 24, 8) |
| 277 | FIELD(DLL_OBSERVABLE_LOWER_REG, |
| 278 | DLL_OBSERVABLE_LOWER_DLL_LOCK_DEC_FLD, 16, 8) |
| 279 | FIELD(DLL_OBSERVABLE_LOWER_REG, |
| 280 | DLL_OBSERVABLE_LOWER_LOOPBACK_LOCK_FLD, 15, 1) |
| 281 | FIELD(DLL_OBSERVABLE_LOWER_REG, |
| 282 | DLL_OBSERVABLE_LOWER_LOCK_VALUE_FLD, 8, 7) |
| 283 | FIELD(DLL_OBSERVABLE_LOWER_REG, |
| 284 | DLL_OBSERVABLE_LOWER_UNLOCK_COUNTER_FLD, 3, 5) |
| 285 | FIELD(DLL_OBSERVABLE_LOWER_REG, |
| 286 | DLL_OBSERVABLE_LOWER_LOCK_MODE_FLD, 1, 2) |
| 287 | FIELD(DLL_OBSERVABLE_LOWER_REG, |
| 288 | DLL_OBSERVABLE_LOWER_DLL_LOCK_FLD, 0, 1) |
| 289 | REG32(DLL_OBSERVABLE_UPPER_REG, 0xc0) |
| 290 | FIELD(DLL_OBSERVABLE_UPPER_REG, |
| 291 | DLL_OBSERVABLE_UPPER_RESV2_FLD, 23, 9) |
| 292 | FIELD(DLL_OBSERVABLE_UPPER_REG, |
| 293 | DLL_OBSERVABLE_UPPER_TX_DECODER_OUTPUT_FLD, 16, 7) |
| 294 | FIELD(DLL_OBSERVABLE_UPPER_REG, |
| 295 | DLL_OBSERVABLE_UPPER_RESV1_FLD, 7, 9) |
| 296 | FIELD(DLL_OBSERVABLE_UPPER_REG, |
| 297 | DLL_OBSERVABLE__UPPER_RX_DECODER_OUTPUT_FLD, 0, 7) |
| 298 | REG32(OPCODE_EXT_LOWER_REG, 0xe0) |
| 299 | FIELD(OPCODE_EXT_LOWER_REG, EXT_READ_OPCODE_FLD, 24, 8) |
| 300 | FIELD(OPCODE_EXT_LOWER_REG, EXT_WRITE_OPCODE_FLD, 16, 8) |
| 301 | FIELD(OPCODE_EXT_LOWER_REG, EXT_POLL_OPCODE_FLD, 8, 8) |
| 302 | FIELD(OPCODE_EXT_LOWER_REG, EXT_STIG_OPCODE_FLD, 0, 8) |
| 303 | REG32(OPCODE_EXT_UPPER_REG, 0xe4) |
| 304 | FIELD(OPCODE_EXT_UPPER_REG, WEL_OPCODE_FLD, 24, 8) |
| 305 | FIELD(OPCODE_EXT_UPPER_REG, EXT_WEL_OPCODE_FLD, 16, 8) |
| 306 | FIELD(OPCODE_EXT_UPPER_REG, OPCODE_EXT_UPPER_RESV1_FLD, 0, 16) |
| 307 | REG32(MODULE_ID_REG, 0xfc) |
| 308 | FIELD(MODULE_ID_REG, FIX_PATCH_FLD, 24, 8) |
| 309 | FIELD(MODULE_ID_REG, MODULE_ID_FLD, 8, 16) |
| 310 | FIELD(MODULE_ID_REG, MODULE_ID_RESV_FLD, 2, 6) |
| 311 | FIELD(MODULE_ID_REG, CONF_FLD, 0, 2) |
| 312 | |
| 313 | #define RXFF_SZ 1024 |
| 314 | #define TXFF_SZ 1024 |
| 315 | |
| 316 | #define MAX_RX_DEC_OUT 8 |
| 317 | |
| 318 | #define SZ_512MBIT (512 * 1024 * 1024) |
| 319 | #define SZ_1GBIT (1024 * 1024 * 1024) |
| 320 | #define SZ_2GBIT (2ULL * SZ_1GBIT) |
| 321 | #define SZ_4GBIT (4ULL * SZ_1GBIT) |
| 322 | |
| 323 | #define IS_IND_DMA_START(op) (op->done_bytes == 0) |
| 324 | /* |
| 325 | * Bit field size of R_INDIRECT_WRITE_XFER_CTRL_REG_NUM_IND_OPS_DONE_FLD |
| 326 | * is 2 bits, which can record max of 3 indac operations. |
| 327 | */ |
| 328 | #define IND_OPS_DONE_MAX 3 |
| 329 | |
| 330 | typedef enum { |
| 331 | WREN = 0x6, |
| 332 | } FlashCMD; |
| 333 | |
| 334 | static unsigned int ospi_stig_addr_len(XlnxVersalOspi *s) |
| 335 | { |
| 336 | /* Num address bytes is NUM_ADDR_BYTES_FLD + 1 */ |
| 337 | return ARRAY_FIELD_EX32(s->regs, |
| 338 | FLASH_CMD_CTRL_REG, NUM_ADDR_BYTES_FLD) + 1; |
| 339 | } |
| 340 | |
| 341 | static unsigned int ospi_stig_wr_data_len(XlnxVersalOspi *s) |
| 342 | { |
| 343 | /* Num write data bytes is NUM_WR_DATA_BYTES_FLD + 1 */ |
| 344 | return ARRAY_FIELD_EX32(s->regs, |
| 345 | FLASH_CMD_CTRL_REG, NUM_WR_DATA_BYTES_FLD) + 1; |
| 346 | } |
| 347 | |
| 348 | static unsigned int ospi_stig_rd_data_len(XlnxVersalOspi *s) |
| 349 | { |
| 350 | /* Num read data bytes is NUM_RD_DATA_BYTES_FLD + 1 */ |
| 351 | return ARRAY_FIELD_EX32(s->regs, |
| 352 | FLASH_CMD_CTRL_REG, NUM_RD_DATA_BYTES_FLD) + 1; |
| 353 | } |
| 354 | |
| 355 | /* |
| 356 | * Status bits in R_IRQ_STATUS_REG are set when the event occurs and the |
| 357 | * interrupt is enabled in the mask register ([1] Section 2.3.17) |
| 358 | */ |
| 359 | static void set_irq(XlnxVersalOspi *s, uint32_t set_mask) |
| 360 | { |
| 361 | s->regs[R_IRQ_STATUS_REG] |= s->regs[R_IRQ_MASK_REG] & set_mask; |
| 362 | } |
| 363 | |
| 364 | static void ospi_update_irq_line(XlnxVersalOspi *s) |
| 365 | { |
| 366 | qemu_set_irq(s->irq, !!(s->regs[R_IRQ_STATUS_REG] & |
| 367 | s->regs[R_IRQ_MASK_REG])); |
| 368 | } |
| 369 | |
| 370 | static uint8_t ospi_get_wr_opcode(XlnxVersalOspi *s) |
| 371 | { |
| 372 | return ARRAY_FIELD_EX32(s->regs, |
| 373 | DEV_INSTR_WR_CONFIG_REG, WR_OPCODE_FLD); |
| 374 | } |
| 375 | |
| 376 | static uint8_t ospi_get_rd_opcode(XlnxVersalOspi *s) |
| 377 | { |
| 378 | return ARRAY_FIELD_EX32(s->regs, |
| 379 | DEV_INSTR_RD_CONFIG_REG, RD_OPCODE_NON_XIP_FLD); |
| 380 | } |
| 381 | |
| 382 | static uint32_t ospi_get_num_addr_bytes(XlnxVersalOspi *s) |
| 383 | { |
| 384 | /* Num address bytes is NUM_ADDR_BYTES_FLD + 1 */ |
| 385 | return ARRAY_FIELD_EX32(s->regs, |
| 386 | DEV_SIZE_CONFIG_REG, NUM_ADDR_BYTES_FLD) + 1; |
| 387 | } |
| 388 | |
| 389 | static void ospi_stig_membank_req(XlnxVersalOspi *s) |
| 390 | { |
| 391 | int idx = ARRAY_FIELD_EX32(s->regs, |
| 392 | FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_ADDR_FLD); |
| 393 | |
| 394 | ARRAY_FIELD_DP32(s->regs, FLASH_COMMAND_CTRL_MEM_REG, |
| 395 | MEM_BANK_READ_DATA_FLD, s->stig_membank[idx]); |
| 396 | } |
| 397 | |
| 398 | static int ospi_stig_membank_rd_bytes(XlnxVersalOspi *s) |
| 399 | { |
| 400 | int rd_data_fld = ARRAY_FIELD_EX32(s->regs, FLASH_COMMAND_CTRL_MEM_REG, |
| 401 | NB_OF_STIG_READ_BYTES_FLD); |
| 402 | static const int sizes[6] = { 16, 32, 64, 128, 256, 512 }; |
| 403 | return (rd_data_fld < 6) ? sizes[rd_data_fld] : 0; |
| 404 | } |
| 405 | |
| 406 | static uint32_t ospi_get_page_sz(XlnxVersalOspi *s) |
| 407 | { |
| 408 | return ARRAY_FIELD_EX32(s->regs, |
| 409 | DEV_SIZE_CONFIG_REG, BYTES_PER_DEVICE_PAGE_FLD); |
| 410 | } |
| 411 | |
| 412 | static bool ospi_ind_rd_watermark_enabled(XlnxVersalOspi *s) |
| 413 | { |
| 414 | return s->regs[R_INDIRECT_READ_XFER_WATERMARK_REG]; |
| 415 | } |
| 416 | |
| 417 | static void ind_op_advance(IndOp *op, unsigned int len) |
| 418 | { |
| 419 | op->done_bytes += len; |
| 420 | assert(op->done_bytes <= op->num_bytes); |
| 421 | if (op->done_bytes == op->num_bytes) { |
| 422 | op->completed = true; |
| 423 | } |
| 424 | } |
| 425 | |
| 426 | static uint32_t ind_op_next_byte(IndOp *op) |
| 427 | { |
| 428 | return op->flash_addr + op->done_bytes; |
| 429 | } |
| 430 | |
| 431 | static uint32_t ind_op_end_byte(IndOp *op) |
| 432 | { |
| 433 | return op->flash_addr + op->num_bytes; |
| 434 | } |
| 435 | |
| 436 | static void ospi_ind_op_next(IndOp *op) |
| 437 | { |
| 438 | op[0] = op[1]; |
| 439 | op[1].completed = true; |
| 440 | } |
| 441 | |
| 442 | static void ind_op_setup(IndOp *op, uint32_t flash_addr, uint32_t num_bytes) |
| 443 | { |
| 444 | if (num_bytes & 0x3) { |
| 445 | qemu_log_mask(LOG_GUEST_ERROR, |
| 446 | "OSPI indirect op num bytes not word aligned\n"); |
| 447 | } |
| 448 | op->flash_addr = flash_addr; |
| 449 | op->num_bytes = num_bytes; |
| 450 | op->done_bytes = 0; |
| 451 | op->completed = false; |
| 452 | } |
| 453 | |
| 454 | static bool ospi_ind_op_completed(IndOp *op) |
| 455 | { |
| 456 | return op->completed; |
| 457 | } |
| 458 | |
| 459 | static bool ospi_ind_op_all_completed(XlnxVersalOspi *s) |
| 460 | { |
| 461 | return s->rd_ind_op[0].completed && s->wr_ind_op[0].completed; |
| 462 | } |
| 463 | |
| 464 | static void ospi_ind_op_cancel(IndOp *op) |
| 465 | { |
| 466 | op[0].completed = true; |
| 467 | op[1].completed = true; |
| 468 | } |
| 469 | |
| 470 | static bool ospi_ind_op_add(IndOp *op, Fifo8 *fifo, |
| 471 | uint32_t flash_addr, uint32_t num_bytes) |
| 472 | { |
| 473 | /* Check if first indirect op has been completed */ |
| 474 | if (op->completed) { |
| 475 | fifo8_reset(fifo); |
| 476 | ind_op_setup(op, flash_addr, num_bytes); |
| 477 | return false; |
| 478 | } |
| 479 | |
| 480 | /* Check if second indirect op has been completed */ |
| 481 | op++; |
| 482 | if (op->completed) { |
| 483 | ind_op_setup(op, flash_addr, num_bytes); |
| 484 | return false; |
| 485 | } |
| 486 | return true; |
| 487 | } |
| 488 | |
| 489 | static void ospi_ind_op_queue_up_rd(XlnxVersalOspi *s) |
| 490 | { |
| 491 | uint32_t num_bytes = s->regs[R_INDIRECT_READ_XFER_NUM_BYTES_REG]; |
| 492 | uint32_t flash_addr = s->regs[R_INDIRECT_READ_XFER_START_REG]; |
| 493 | bool failed; |
| 494 | |
| 495 | failed = ospi_ind_op_add(s->rd_ind_op, &s->rx_sram, flash_addr, num_bytes); |
| 496 | /* If two already queued set rd reject interrupt */ |
| 497 | if (failed) { |
| 498 | set_irq(s, R_IRQ_STATUS_REG_INDIRECT_TRANSFER_REJECT_FLD_MASK); |
| 499 | } |
| 500 | } |
| 501 | |
| 502 | static void ospi_ind_op_queue_up_wr(XlnxVersalOspi *s) |
| 503 | { |
| 504 | uint32_t num_bytes = s->regs[R_INDIRECT_WRITE_XFER_NUM_BYTES_REG]; |
| 505 | uint32_t flash_addr = s->regs[R_INDIRECT_WRITE_XFER_START_REG]; |
| 506 | bool failed; |
| 507 | |
| 508 | failed = ospi_ind_op_add(s->wr_ind_op, &s->tx_sram, flash_addr, num_bytes); |
| 509 | /* If two already queued set rd reject interrupt */ |
| 510 | if (failed) { |
| 511 | set_irq(s, R_IRQ_STATUS_REG_INDIRECT_TRANSFER_REJECT_FLD_MASK); |
| 512 | } |
| 513 | } |
| 514 | |
| 515 | static uint64_t flash_sz(XlnxVersalOspi *s, unsigned int cs) |
| 516 | { |
| 517 | /* Flash sizes in MB */ |
| 518 | static const uint64_t sizes[4] = { SZ_512MBIT / 8, SZ_1GBIT / 8, |
| 519 | SZ_2GBIT / 8, SZ_4GBIT / 8 }; |
| 520 | uint32_t v = s->regs[R_DEV_SIZE_CONFIG_REG]; |
| 521 | |
| 522 | v >>= cs * R_DEV_SIZE_CONFIG_REG_MEM_SIZE_ON_CS0_FLD_LENGTH; |
| 523 | return sizes[FIELD_EX32(v, DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS0_FLD)]; |
| 524 | } |
| 525 | |
| 526 | static unsigned int ospi_get_block_sz(XlnxVersalOspi *s) |
| 527 | { |
| 528 | unsigned int block_fld = ARRAY_FIELD_EX32(s->regs, |
| 529 | DEV_SIZE_CONFIG_REG, |
| 530 | BYTES_PER_SUBSECTOR_FLD); |
| 531 | return 1 << block_fld; |
| 532 | } |
| 533 | |
| 534 | static unsigned int flash_blocks(XlnxVersalOspi *s, unsigned int cs) |
| 535 | { |
| 536 | unsigned int b_sz = ospi_get_block_sz(s); |
| 537 | unsigned int f_sz = flash_sz(s, cs); |
| 538 | |
| 539 | return f_sz / b_sz; |
| 540 | } |
| 541 | |
| 542 | static int ospi_ahb_decoder_cs(XlnxVersalOspi *s, hwaddr addr) |
| 543 | { |
| 544 | uint64_t end_addr = 0; |
| 545 | int cs; |
| 546 | |
| 547 | for (cs = 0; cs < s->num_cs; cs++) { |
| 548 | end_addr += flash_sz(s, cs); |
| 549 | if (addr < end_addr) { |
| 550 | break; |
| 551 | } |
| 552 | } |
| 553 | |
| 554 | if (cs == s->num_cs) { |
| 555 | /* Address is out of range */ |
| 556 | qemu_log_mask(LOG_GUEST_ERROR, |
| 557 | "OSPI flash address does not fit in configuration\n"); |
| 558 | return -1; |
| 559 | } |
| 560 | return cs; |
| 561 | } |
| 562 | |
| 563 | static void ospi_ahb_decoder_enable_cs(XlnxVersalOspi *s, hwaddr addr) |
| 564 | { |
| 565 | int cs = ospi_ahb_decoder_cs(s, addr); |
| 566 | |
| 567 | if (cs >= 0) { |
| 568 | for (int i = 0; i < s->num_cs; i++) { |
| 569 | qemu_set_irq(s->cs_lines[i], cs != i); |
| 570 | } |
| 571 | } |
| 572 | } |
| 573 | |
| 574 | static unsigned int single_cs(XlnxVersalOspi *s) |
| 575 | { |
| 576 | unsigned int field = ARRAY_FIELD_EX32(s->regs, |
| 577 | CONFIG_REG, PERIPH_CS_LINES_FLD); |
| 578 | |
| 579 | /* |
| 580 | * Below one liner is a trick that finds the rightmost zero and makes sure |
| 581 | * all other bits are turned to 1. It is a variant of the 'Isolate the |
| 582 | * rightmost 0-bit' trick found below at the time of writing: |
| 583 | * |
| 584 | * https://emre.me/computer-science/bit-manipulation-tricks/ |
| 585 | * |
| 586 | * 4'bXXX0 -> 4'b1110 |
| 587 | * 4'bXX01 -> 4'b1101 |
| 588 | * 4'bX011 -> 4'b1011 |
| 589 | * 4'b0111 -> 4'b0111 |
| 590 | * 4'b1111 -> 4'b1111 |
| 591 | */ |
| 592 | return (field | ~(field + 1)) & 0xf; |
| 593 | } |
| 594 | |
| 595 | static void ospi_update_cs_lines(XlnxVersalOspi *s) |
| 596 | { |
| 597 | unsigned int all_cs; |
| 598 | int i; |
| 599 | |
| 600 | if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, PERIPH_SEL_DEC_FLD)) { |
| 601 | all_cs = ARRAY_FIELD_EX32(s->regs, CONFIG_REG, PERIPH_CS_LINES_FLD); |
| 602 | } else { |
| 603 | all_cs = single_cs(s); |
| 604 | } |
| 605 | |
| 606 | for (i = 0; i < s->num_cs; i++) { |
| 607 | bool cs = (all_cs >> i) & 1; |
| 608 | |
| 609 | qemu_set_irq(s->cs_lines[i], cs); |
| 610 | } |
| 611 | } |
| 612 | |
| 613 | static void ospi_dac_cs(XlnxVersalOspi *s, hwaddr addr) |
| 614 | { |
| 615 | if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENABLE_AHB_DECODER_FLD)) { |
| 616 | ospi_ahb_decoder_enable_cs(s, addr); |
| 617 | } else { |
| 618 | ospi_update_cs_lines(s); |
| 619 | } |
| 620 | } |
| 621 | |
| 622 | static void ospi_disable_cs(XlnxVersalOspi *s) |
| 623 | { |
| 624 | int i; |
| 625 | |
| 626 | for (i = 0; i < s->num_cs; i++) { |
| 627 | qemu_set_irq(s->cs_lines[i], 1); |
| 628 | } |
| 629 | } |
| 630 | |
| 631 | static void ospi_flush_txfifo(XlnxVersalOspi *s) |
| 632 | { |
| 633 | while (!fifo8_is_empty(&s->tx_fifo)) { |
| 634 | uint32_t tx_rx = fifo8_pop(&s->tx_fifo); |
| 635 | |
| 636 | tx_rx = ssi_transfer(s->spi, tx_rx); |
| 637 | fifo8_push(&s->rx_fifo, tx_rx); |
| 638 | } |
| 639 | } |
| 640 | |
| 641 | static void ospi_tx_fifo_push_address_raw(XlnxVersalOspi *s, |
| 642 | uint32_t flash_addr, |
| 643 | unsigned int addr_bytes) |
| 644 | { |
| 645 | /* Push write address */ |
| 646 | if (addr_bytes == 4) { |
| 647 | fifo8_push(&s->tx_fifo, flash_addr >> 24); |
| 648 | } |
| 649 | if (addr_bytes >= 3) { |
| 650 | fifo8_push(&s->tx_fifo, flash_addr >> 16); |
| 651 | } |
| 652 | if (addr_bytes >= 2) { |
| 653 | fifo8_push(&s->tx_fifo, flash_addr >> 8); |
| 654 | } |
| 655 | fifo8_push(&s->tx_fifo, flash_addr); |
| 656 | } |
| 657 | |
| 658 | static void ospi_tx_fifo_push_address(XlnxVersalOspi *s, uint32_t flash_addr) |
| 659 | { |
| 660 | /* Push write address */ |
| 661 | int addr_bytes = ospi_get_num_addr_bytes(s); |
| 662 | |
| 663 | ospi_tx_fifo_push_address_raw(s, flash_addr, addr_bytes); |
| 664 | } |
| 665 | |
| 666 | static void ospi_tx_fifo_push_stig_addr(XlnxVersalOspi *s) |
| 667 | { |
| 668 | uint32_t flash_addr = s->regs[R_FLASH_CMD_ADDR_REG]; |
| 669 | unsigned int addr_bytes = ospi_stig_addr_len(s); |
| 670 | |
| 671 | ospi_tx_fifo_push_address_raw(s, flash_addr, addr_bytes); |
| 672 | } |
| 673 | |
| 674 | static void ospi_tx_fifo_push_rd_op_addr(XlnxVersalOspi *s, uint32_t flash_addr) |
| 675 | { |
| 676 | uint8_t inst_code = ospi_get_rd_opcode(s); |
| 677 | |
| 678 | fifo8_reset(&s->tx_fifo); |
| 679 | |
| 680 | /* Push read opcode */ |
| 681 | fifo8_push(&s->tx_fifo, inst_code); |
| 682 | |
| 683 | /* Push read address */ |
| 684 | ospi_tx_fifo_push_address(s, flash_addr); |
| 685 | } |
| 686 | |
| 687 | static void ospi_tx_fifo_push_stig_wr_data(XlnxVersalOspi *s) |
| 688 | { |
| 689 | uint64_t data = s->regs[R_FLASH_WR_DATA_LOWER_REG]; |
| 690 | int wr_data_len = ospi_stig_wr_data_len(s); |
| 691 | int i; |
| 692 | |
| 693 | data |= (uint64_t) s->regs[R_FLASH_WR_DATA_UPPER_REG] << 32; |
| 694 | for (i = 0; i < wr_data_len; i++) { |
| 695 | int shift = i * 8; |
| 696 | fifo8_push(&s->tx_fifo, data >> shift); |
| 697 | } |
| 698 | } |
| 699 | |
| 700 | static void ospi_tx_fifo_push_stig_rd_data(XlnxVersalOspi *s) |
| 701 | { |
| 702 | int rd_data_len; |
| 703 | int i; |
| 704 | |
| 705 | if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, STIG_MEM_BANK_EN_FLD)) { |
| 706 | rd_data_len = ospi_stig_membank_rd_bytes(s); |
| 707 | } else { |
| 708 | rd_data_len = ospi_stig_rd_data_len(s); |
| 709 | } |
| 710 | |
| 711 | /* transmit second part (data) */ |
| 712 | for (i = 0; i < rd_data_len; ++i) { |
| 713 | fifo8_push(&s->tx_fifo, 0); |
| 714 | } |
| 715 | } |
| 716 | |
| 717 | static void ospi_rx_fifo_pop_stig_rd_data(XlnxVersalOspi *s) |
| 718 | { |
| 719 | int size = ospi_stig_rd_data_len(s); |
| 720 | uint8_t bytes[8] = {}; |
| 721 | int i; |
| 722 | |
| 723 | size = MIN(fifo8_num_used(&s->rx_fifo), size); |
| 724 | |
| 725 | assert(size <= 8); |
| 726 | |
| 727 | for (i = 0; i < size; i++) { |
| 728 | bytes[i] = fifo8_pop(&s->rx_fifo); |
| 729 | } |
| 730 | |
| 731 | s->regs[R_FLASH_RD_DATA_LOWER_REG] = ldl_le_p(bytes); |
| 732 | s->regs[R_FLASH_RD_DATA_UPPER_REG] = ldl_le_p(bytes + 4); |
| 733 | } |
| 734 | |
| 735 | static void ospi_ind_read(XlnxVersalOspi *s, uint32_t flash_addr, uint32_t len) |
| 736 | { |
| 737 | int i; |
| 738 | |
| 739 | /* Create first section of read cmd */ |
| 740 | ospi_tx_fifo_push_rd_op_addr(s, flash_addr); |
| 741 | |
| 742 | /* transmit first part */ |
| 743 | ospi_update_cs_lines(s); |
| 744 | ospi_flush_txfifo(s); |
| 745 | |
| 746 | fifo8_reset(&s->rx_fifo); |
| 747 | |
| 748 | /* transmit second part (data) */ |
| 749 | for (i = 0; i < len; ++i) { |
| 750 | fifo8_push(&s->tx_fifo, 0); |
| 751 | } |
| 752 | ospi_flush_txfifo(s); |
| 753 | |
| 754 | for (i = 0; i < len; ++i) { |
| 755 | fifo8_push(&s->rx_sram, fifo8_pop(&s->rx_fifo)); |
| 756 | } |
| 757 | |
| 758 | /* done */ |
| 759 | ospi_disable_cs(s); |
| 760 | } |
| 761 | |
| 762 | static unsigned int ospi_dma_burst_size(XlnxVersalOspi *s) |
| 763 | { |
| 764 | return 1 << ARRAY_FIELD_EX32(s->regs, |
| 765 | DMA_PERIPH_CONFIG_REG, |
| 766 | NUM_BURST_REQ_BYTES_FLD); |
| 767 | } |
| 768 | |
| 769 | static unsigned int ospi_dma_single_size(XlnxVersalOspi *s) |
| 770 | { |
| 771 | return 1 << ARRAY_FIELD_EX32(s->regs, |
| 772 | DMA_PERIPH_CONFIG_REG, |
| 773 | NUM_SINGLE_REQ_BYTES_FLD); |
| 774 | } |
| 775 | |
| 776 | static void ind_rd_inc_num_done(XlnxVersalOspi *s) |
| 777 | { |
| 778 | unsigned int done = ARRAY_FIELD_EX32(s->regs, |
| 779 | INDIRECT_READ_XFER_CTRL_REG, |
| 780 | NUM_IND_OPS_DONE_FLD); |
| 781 | if (done < IND_OPS_DONE_MAX) { |
| 782 | done++; |
| 783 | } |
| 784 | done &= 0x3; |
| 785 | ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG, |
| 786 | NUM_IND_OPS_DONE_FLD, done); |
| 787 | } |
| 788 | |
| 789 | static void ospi_ind_rd_completed(XlnxVersalOspi *s) |
| 790 | { |
| 791 | ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG, |
| 792 | IND_OPS_DONE_STATUS_FLD, 1); |
| 793 | |
| 794 | ind_rd_inc_num_done(s); |
| 795 | ospi_ind_op_next(s->rd_ind_op); |
| 796 | if (ospi_ind_op_all_completed(s)) { |
| 797 | set_irq(s, R_IRQ_STATUS_REG_INDIRECT_OP_DONE_FLD_MASK); |
| 798 | } |
| 799 | } |
| 800 | |
| 801 | static void ospi_dma_read(XlnxVersalOspi *s) |
| 802 | { |
| 803 | IndOp *op = s->rd_ind_op; |
| 804 | uint32_t dma_len = op->num_bytes; |
| 805 | uint32_t burst_sz = ospi_dma_burst_size(s); |
| 806 | uint32_t single_sz = ospi_dma_single_size(s); |
| 807 | uint32_t ind_trig_range; |
| 808 | uint32_t remainder; |
| 809 | XlnxCSUDMAClass *xcdc = XLNX_CSU_DMA_GET_CLASS(s->dma_src); |
| 810 | |
| 811 | ind_trig_range = (1 << ARRAY_FIELD_EX32(s->regs, |
| 812 | INDIRECT_TRIGGER_ADDR_RANGE_REG, |
| 813 | IND_RANGE_WIDTH_FLD)); |
| 814 | remainder = dma_len % burst_sz; |
| 815 | remainder = remainder % single_sz; |
| 816 | if (burst_sz > ind_trig_range || single_sz > ind_trig_range || |
| 817 | remainder != 0) { |
| 818 | qemu_log_mask(LOG_GUEST_ERROR, |
| 819 | "OSPI DMA burst size / single size config error\n"); |
| 820 | } |
| 821 | |
| 822 | s->src_dma_inprog = true; |
| 823 | if (xcdc->read(s->dma_src, 0, dma_len) != MEMTX_OK) { |
| 824 | qemu_log_mask(LOG_GUEST_ERROR, "OSPI DMA configuration error\n"); |
| 825 | } |
| 826 | s->src_dma_inprog = false; |
| 827 | } |
| 828 | |
| 829 | static void ospi_do_ind_read(XlnxVersalOspi *s) |
| 830 | { |
| 831 | IndOp *op = s->rd_ind_op; |
| 832 | uint32_t next_b; |
| 833 | uint32_t end_b; |
| 834 | uint32_t len; |
| 835 | bool start_dma = IS_IND_DMA_START(op) && !s->src_dma_inprog; |
| 836 | |
| 837 | /* Continue to read flash until we run out of space in sram */ |
| 838 | while (!ospi_ind_op_completed(op) && |
| 839 | !fifo8_is_full(&s->rx_sram)) { |
| 840 | /* Read requested number of bytes, max bytes limited to size of sram */ |
| 841 | next_b = ind_op_next_byte(op); |
| 842 | end_b = next_b + fifo8_num_free(&s->rx_sram); |
| 843 | end_b = MIN(end_b, ind_op_end_byte(op)); |
| 844 | |
| 845 | len = end_b - next_b; |
| 846 | ospi_ind_read(s, next_b, len); |
| 847 | ind_op_advance(op, len); |
| 848 | |
| 849 | if (ospi_ind_rd_watermark_enabled(s)) { |
| 850 | ARRAY_FIELD_DP32(s->regs, IRQ_STATUS_REG, |
| 851 | INDIRECT_XFER_LEVEL_BREACH_FLD, 1); |
| 852 | set_irq(s, |
| 853 | R_IRQ_STATUS_REG_INDIRECT_XFER_LEVEL_BREACH_FLD_MASK); |
| 854 | } |
| 855 | |
| 856 | if (!s->src_dma_inprog && |
| 857 | ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DMA_IF_FLD)) { |
| 858 | ospi_dma_read(s); |
| 859 | } |
| 860 | } |
| 861 | |
| 862 | /* Set sram full */ |
| 863 | if (fifo8_num_used(&s->rx_sram) == RXFF_SZ) { |
| 864 | ARRAY_FIELD_DP32(s->regs, |
| 865 | INDIRECT_READ_XFER_CTRL_REG, SRAM_FULL_FLD, 1); |
| 866 | set_irq(s, R_IRQ_STATUS_REG_INDRD_SRAM_FULL_FLD_MASK); |
| 867 | } |
| 868 | |
| 869 | /* Signal completion if done, unless inside recursion via ospi_dma_read */ |
| 870 | if (!ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DMA_IF_FLD) || start_dma) { |
| 871 | if (ospi_ind_op_completed(op)) { |
| 872 | ospi_ind_rd_completed(s); |
| 873 | } |
| 874 | } |
| 875 | } |
| 876 | |
| 877 | /* Transmit write enable instruction */ |
| 878 | static void ospi_transmit_wel(XlnxVersalOspi *s, bool ahb_decoder_cs, |
| 879 | hwaddr addr) |
| 880 | { |
| 881 | fifo8_reset(&s->tx_fifo); |
| 882 | fifo8_push(&s->tx_fifo, WREN); |
| 883 | |
| 884 | if (ahb_decoder_cs) { |
| 885 | ospi_ahb_decoder_enable_cs(s, addr); |
| 886 | } else { |
| 887 | ospi_update_cs_lines(s); |
| 888 | } |
| 889 | |
| 890 | ospi_flush_txfifo(s); |
| 891 | ospi_disable_cs(s); |
| 892 | |
| 893 | fifo8_reset(&s->rx_fifo); |
| 894 | } |
| 895 | |
| 896 | static void ospi_ind_write(XlnxVersalOspi *s, uint32_t flash_addr, uint32_t len) |
| 897 | { |
| 898 | bool ahb_decoder_cs = false; |
| 899 | uint8_t inst_code; |
| 900 | int i; |
| 901 | |
| 902 | assert(fifo8_num_used(&s->tx_sram) >= len); |
| 903 | |
| 904 | if (!ARRAY_FIELD_EX32(s->regs, DEV_INSTR_WR_CONFIG_REG, WEL_DIS_FLD)) { |
| 905 | ospi_transmit_wel(s, ahb_decoder_cs, 0); |
| 906 | } |
| 907 | |
| 908 | /* reset fifos */ |
| 909 | fifo8_reset(&s->tx_fifo); |
| 910 | fifo8_reset(&s->rx_fifo); |
| 911 | |
| 912 | /* Push write opcode */ |
| 913 | inst_code = ospi_get_wr_opcode(s); |
| 914 | fifo8_push(&s->tx_fifo, inst_code); |
| 915 | |
| 916 | /* Push write address */ |
| 917 | ospi_tx_fifo_push_address(s, flash_addr); |
| 918 | |
| 919 | /* data */ |
| 920 | for (i = 0; i < len; i++) { |
| 921 | fifo8_push(&s->tx_fifo, fifo8_pop(&s->tx_sram)); |
| 922 | } |
| 923 | |
| 924 | /* transmit */ |
| 925 | ospi_update_cs_lines(s); |
| 926 | ospi_flush_txfifo(s); |
| 927 | |
| 928 | /* done */ |
| 929 | ospi_disable_cs(s); |
| 930 | fifo8_reset(&s->rx_fifo); |
| 931 | } |
| 932 | |
| 933 | static void ind_wr_inc_num_done(XlnxVersalOspi *s) |
| 934 | { |
| 935 | unsigned int done = ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, |
| 936 | NUM_IND_OPS_DONE_FLD); |
| 937 | if (done < IND_OPS_DONE_MAX) { |
| 938 | done++; |
| 939 | } |
| 940 | done &= 0x3; |
| 941 | ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, |
| 942 | NUM_IND_OPS_DONE_FLD, done); |
| 943 | } |
| 944 | |
| 945 | static void ospi_ind_wr_completed(XlnxVersalOspi *s) |
| 946 | { |
| 947 | ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, |
| 948 | IND_OPS_DONE_STATUS_FLD, 1); |
| 949 | ind_wr_inc_num_done(s); |
| 950 | ospi_ind_op_next(s->wr_ind_op); |
| 951 | /* Set indirect op done interrupt if enabled */ |
| 952 | if (ospi_ind_op_all_completed(s)) { |
| 953 | set_irq(s, R_IRQ_STATUS_REG_INDIRECT_OP_DONE_FLD_MASK); |
| 954 | } |
| 955 | } |
| 956 | |
| 957 | static void ospi_do_indirect_write(XlnxVersalOspi *s) |
| 958 | { |
| 959 | uint32_t write_watermark = s->regs[R_INDIRECT_WRITE_XFER_WATERMARK_REG]; |
| 960 | uint32_t pagesz = ospi_get_page_sz(s); |
| 961 | uint32_t page_mask = ~(pagesz - 1); |
| 962 | IndOp *op = s->wr_ind_op; |
| 963 | uint32_t next_b; |
| 964 | uint32_t end_b; |
| 965 | uint32_t len; |
| 966 | |
| 967 | /* Write out tx_fifo in maximum page sz chunks */ |
| 968 | while (!ospi_ind_op_completed(op) && fifo8_num_used(&s->tx_sram) > 0) { |
| 969 | next_b = ind_op_next_byte(op); |
| 970 | end_b = next_b + MIN(fifo8_num_used(&s->tx_sram), pagesz); |
| 971 | |
| 972 | /* Dont cross page boundary */ |
| 973 | if ((end_b & page_mask) > next_b) { |
| 974 | end_b &= page_mask; |
| 975 | } |
| 976 | |
| 977 | len = end_b - next_b; |
| 978 | len = MIN(len, op->num_bytes - op->done_bytes); |
| 979 | ospi_ind_write(s, next_b, len); |
| 980 | ind_op_advance(op, len); |
| 981 | } |
| 982 | |
| 983 | /* |
| 984 | * Always set indirect transfer level breached interrupt if enabled |
| 985 | * (write watermark > 0) since the tx_sram always will be emptied |
| 986 | */ |
| 987 | if (write_watermark > 0) { |
| 988 | set_irq(s, R_IRQ_STATUS_REG_INDIRECT_XFER_LEVEL_BREACH_FLD_MASK); |
| 989 | } |
| 990 | |
| 991 | /* Signal completions if done */ |
| 992 | if (ospi_ind_op_completed(op)) { |
| 993 | ospi_ind_wr_completed(s); |
| 994 | } |
| 995 | } |
| 996 | |
| 997 | static void ospi_stig_fill_membank(XlnxVersalOspi *s) |
| 998 | { |
| 999 | int num_rd_bytes = ospi_stig_membank_rd_bytes(s); |
| 1000 | int idx = num_rd_bytes - 8; /* first of last 8 */ |
| 1001 | int i; |
| 1002 | |
| 1003 | for (i = 0; i < num_rd_bytes; i++) { |
| 1004 | s->stig_membank[i] = fifo8_pop(&s->rx_fifo); |
| 1005 | } |
| 1006 | |
| 1007 | g_assert((idx + 4) < ARRAY_SIZE(s->stig_membank)); |
| 1008 | |
| 1009 | /* Fill in lower upper regs */ |
| 1010 | s->regs[R_FLASH_RD_DATA_LOWER_REG] = ldl_le_p(&s->stig_membank[idx]); |
| 1011 | s->regs[R_FLASH_RD_DATA_UPPER_REG] = ldl_le_p(&s->stig_membank[idx + 4]); |
| 1012 | } |
| 1013 | |
| 1014 | static void ospi_stig_cmd_exec(XlnxVersalOspi *s) |
| 1015 | { |
| 1016 | uint8_t inst_code; |
| 1017 | |
| 1018 | /* Reset fifos */ |
| 1019 | fifo8_reset(&s->tx_fifo); |
| 1020 | fifo8_reset(&s->rx_fifo); |
| 1021 | |
| 1022 | /* Push write opcode */ |
| 1023 | inst_code = ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, CMD_OPCODE_FLD); |
| 1024 | fifo8_push(&s->tx_fifo, inst_code); |
| 1025 | |
| 1026 | /* Push address if enabled */ |
| 1027 | if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, ENB_COMD_ADDR_FLD)) { |
| 1028 | ospi_tx_fifo_push_stig_addr(s); |
| 1029 | } |
| 1030 | |
| 1031 | /* Enable cs */ |
| 1032 | ospi_update_cs_lines(s); |
| 1033 | |
| 1034 | /* Data */ |
| 1035 | if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, ENB_WRITE_DATA_FLD)) { |
| 1036 | ospi_tx_fifo_push_stig_wr_data(s); |
| 1037 | } else if (ARRAY_FIELD_EX32(s->regs, |
| 1038 | FLASH_CMD_CTRL_REG, ENB_READ_DATA_FLD)) { |
| 1039 | /* transmit first part */ |
| 1040 | ospi_flush_txfifo(s); |
| 1041 | fifo8_reset(&s->rx_fifo); |
| 1042 | ospi_tx_fifo_push_stig_rd_data(s); |
| 1043 | } |
| 1044 | |
| 1045 | /* Transmit */ |
| 1046 | ospi_flush_txfifo(s); |
| 1047 | ospi_disable_cs(s); |
| 1048 | |
| 1049 | if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, ENB_READ_DATA_FLD)) { |
| 1050 | if (ARRAY_FIELD_EX32(s->regs, |
| 1051 | FLASH_CMD_CTRL_REG, STIG_MEM_BANK_EN_FLD)) { |
| 1052 | ospi_stig_fill_membank(s); |
| 1053 | } else { |
| 1054 | ospi_rx_fifo_pop_stig_rd_data(s); |
| 1055 | } |
| 1056 | } |
| 1057 | } |
| 1058 | |
| 1059 | static uint32_t ospi_block_address(XlnxVersalOspi *s, unsigned int block) |
| 1060 | { |
| 1061 | unsigned int block_sz = ospi_get_block_sz(s); |
| 1062 | unsigned int cs = 0; |
| 1063 | uint32_t addr = 0; |
| 1064 | |
| 1065 | while (cs < s->num_cs && block >= flash_blocks(s, cs)) { |
| 1066 | block -= flash_blocks(s, 0); |
| 1067 | addr += flash_sz(s, cs); |
| 1068 | } |
| 1069 | addr += block * block_sz; |
| 1070 | return addr; |
| 1071 | } |
| 1072 | |
| 1073 | static uint32_t ospi_get_wr_prot_addr_low(XlnxVersalOspi *s) |
| 1074 | { |
| 1075 | unsigned int block = s->regs[R_LOWER_WR_PROT_REG]; |
| 1076 | |
| 1077 | return ospi_block_address(s, block); |
| 1078 | } |
| 1079 | |
| 1080 | static uint32_t ospi_get_wr_prot_addr_upper(XlnxVersalOspi *s) |
| 1081 | { |
| 1082 | unsigned int block = s->regs[R_UPPER_WR_PROT_REG]; |
| 1083 | |
| 1084 | /* Get address of first block out of defined range */ |
| 1085 | return ospi_block_address(s, block + 1); |
| 1086 | } |
| 1087 | |
| 1088 | static bool ospi_is_write_protected(XlnxVersalOspi *s, hwaddr addr) |
| 1089 | { |
| 1090 | uint32_t wr_prot_addr_upper = ospi_get_wr_prot_addr_upper(s); |
| 1091 | uint32_t wr_prot_addr_low = ospi_get_wr_prot_addr_low(s); |
| 1092 | bool in_range = false; |
| 1093 | |
| 1094 | if (addr >= wr_prot_addr_low && addr < wr_prot_addr_upper) { |
| 1095 | in_range = true; |
| 1096 | } |
| 1097 | |
| 1098 | if (ARRAY_FIELD_EX32(s->regs, WR_PROT_CTRL_REG, INV_FLD)) { |
| 1099 | in_range = !in_range; |
| 1100 | } |
| 1101 | return in_range; |
| 1102 | } |
| 1103 | |
| 1104 | static uint64_t ospi_rx_sram_read(XlnxVersalOspi *s, unsigned int size) |
| 1105 | { |
| 1106 | uint8_t bytes[8] = {}; |
| 1107 | int i; |
| 1108 | |
| 1109 | if (size < 4 && fifo8_num_used(&s->rx_sram) >= 4) { |
| 1110 | qemu_log_mask(LOG_GUEST_ERROR, |
| 1111 | "OSPI only last read of internal " |
| 1112 | "sram is allowed to be < 32 bits\n"); |
| 1113 | } |
| 1114 | |
| 1115 | size = MIN(fifo8_num_used(&s->rx_sram), size); |
| 1116 | |
| 1117 | assert(size <= 8); |
| 1118 | |
| 1119 | for (i = 0; i < size; i++) { |
| 1120 | bytes[i] = fifo8_pop(&s->rx_sram); |
| 1121 | } |
| 1122 | |
| 1123 | return ldq_le_p(bytes); |
| 1124 | } |
| 1125 | |
| 1126 | static void ospi_tx_sram_write(XlnxVersalOspi *s, uint64_t value, |
| 1127 | unsigned int size) |
| 1128 | { |
| 1129 | int i; |
| 1130 | for (i = 0; i < size && !fifo8_is_full(&s->tx_sram); i++) { |
| 1131 | fifo8_push(&s->tx_sram, value >> 8 * i); |
| 1132 | } |
| 1133 | } |
| 1134 | |
| 1135 | static uint64_t ospi_do_dac_read(void *opaque, hwaddr addr, unsigned int size) |
| 1136 | { |
| 1137 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque); |
| 1138 | uint8_t bytes[8] = {}; |
| 1139 | int i; |
| 1140 | |
| 1141 | /* Create first section of read cmd */ |
| 1142 | ospi_tx_fifo_push_rd_op_addr(s, (uint32_t) addr); |
| 1143 | |
| 1144 | /* Enable cs and transmit first part */ |
| 1145 | ospi_dac_cs(s, addr); |
| 1146 | ospi_flush_txfifo(s); |
| 1147 | |
| 1148 | fifo8_reset(&s->rx_fifo); |
| 1149 | |
| 1150 | /* transmit second part (data) */ |
| 1151 | for (i = 0; i < size; ++i) { |
| 1152 | fifo8_push(&s->tx_fifo, 0); |
| 1153 | } |
| 1154 | ospi_flush_txfifo(s); |
| 1155 | |
| 1156 | /* fill in result */ |
| 1157 | size = MIN(fifo8_num_used(&s->rx_fifo), size); |
| 1158 | |
| 1159 | assert(size <= 8); |
| 1160 | |
| 1161 | for (i = 0; i < size; i++) { |
| 1162 | bytes[i] = fifo8_pop(&s->rx_fifo); |
| 1163 | } |
| 1164 | |
| 1165 | /* done */ |
| 1166 | ospi_disable_cs(s); |
| 1167 | |
| 1168 | return ldq_le_p(bytes); |
| 1169 | } |
| 1170 | |
| 1171 | static void ospi_do_dac_write(void *opaque, |
| 1172 | hwaddr addr, |
| 1173 | uint64_t value, |
| 1174 | unsigned int size) |
| 1175 | { |
| 1176 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque); |
| 1177 | bool ahb_decoder_cs = ARRAY_FIELD_EX32(s->regs, CONFIG_REG, |
| 1178 | ENABLE_AHB_DECODER_FLD); |
| 1179 | uint8_t inst_code; |
| 1180 | unsigned int i; |
| 1181 | |
| 1182 | if (!ARRAY_FIELD_EX32(s->regs, DEV_INSTR_WR_CONFIG_REG, WEL_DIS_FLD)) { |
| 1183 | ospi_transmit_wel(s, ahb_decoder_cs, addr); |
| 1184 | } |
| 1185 | |
| 1186 | /* reset fifos */ |
| 1187 | fifo8_reset(&s->tx_fifo); |
| 1188 | fifo8_reset(&s->rx_fifo); |
| 1189 | |
| 1190 | /* Push write opcode */ |
| 1191 | inst_code = ospi_get_wr_opcode(s); |
| 1192 | fifo8_push(&s->tx_fifo, inst_code); |
| 1193 | |
| 1194 | /* Push write address */ |
| 1195 | ospi_tx_fifo_push_address(s, addr); |
| 1196 | |
| 1197 | /* data */ |
| 1198 | for (i = 0; i < size; i++) { |
| 1199 | fifo8_push(&s->tx_fifo, value >> 8 * i); |
| 1200 | } |
| 1201 | |
| 1202 | /* Enable cs and transmit */ |
| 1203 | ospi_dac_cs(s, addr); |
| 1204 | ospi_flush_txfifo(s); |
| 1205 | ospi_disable_cs(s); |
| 1206 | |
| 1207 | fifo8_reset(&s->rx_fifo); |
| 1208 | } |
| 1209 | |
| 1210 | static void flash_cmd_ctrl_mem_reg_post_write(RegisterInfo *reg, |
| 1211 | uint64_t val) |
| 1212 | { |
| 1213 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque); |
| 1214 | if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD)) { |
| 1215 | if (ARRAY_FIELD_EX32(s->regs, |
| 1216 | FLASH_COMMAND_CTRL_MEM_REG, |
| 1217 | TRIGGER_MEM_BANK_REQ_FLD)) { |
| 1218 | ospi_stig_membank_req(s); |
| 1219 | ARRAY_FIELD_DP32(s->regs, FLASH_COMMAND_CTRL_MEM_REG, |
| 1220 | TRIGGER_MEM_BANK_REQ_FLD, 0); |
| 1221 | } |
| 1222 | } |
| 1223 | } |
| 1224 | |
| 1225 | static void flash_cmd_ctrl_reg_post_write(RegisterInfo *reg, uint64_t val) |
| 1226 | { |
| 1227 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque); |
| 1228 | |
| 1229 | if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD) && |
| 1230 | ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, CMD_EXEC_FLD)) { |
| 1231 | ospi_stig_cmd_exec(s); |
| 1232 | set_irq(s, R_IRQ_STATUS_REG_STIG_REQ_INT_FLD_MASK); |
| 1233 | ARRAY_FIELD_DP32(s->regs, FLASH_CMD_CTRL_REG, CMD_EXEC_FLD, 0); |
| 1234 | } |
| 1235 | } |
| 1236 | |
| 1237 | static uint64_t ind_wr_dec_num_done(XlnxVersalOspi *s, uint64_t val) |
| 1238 | { |
| 1239 | unsigned int done = ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, |
| 1240 | NUM_IND_OPS_DONE_FLD); |
| 1241 | done--; |
| 1242 | done &= 0x3; |
| 1243 | val = FIELD_DP32(val, INDIRECT_WRITE_XFER_CTRL_REG, |
| 1244 | NUM_IND_OPS_DONE_FLD, done); |
| 1245 | return val; |
| 1246 | } |
| 1247 | |
| 1248 | static bool ind_wr_clearing_op_done(XlnxVersalOspi *s, uint64_t new_val) |
| 1249 | { |
| 1250 | bool set_in_reg = ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, |
| 1251 | IND_OPS_DONE_STATUS_FLD); |
| 1252 | bool set_in_new_val = FIELD_EX32(new_val, INDIRECT_WRITE_XFER_CTRL_REG, |
| 1253 | IND_OPS_DONE_STATUS_FLD); |
| 1254 | /* return true if clearing bit */ |
| 1255 | return set_in_reg && !set_in_new_val; |
| 1256 | } |
| 1257 | |
| 1258 | static uint64_t ind_wr_xfer_ctrl_reg_pre_write(RegisterInfo *reg, |
| 1259 | uint64_t val) |
| 1260 | { |
| 1261 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque); |
| 1262 | |
| 1263 | if (ind_wr_clearing_op_done(s, val)) { |
| 1264 | val = ind_wr_dec_num_done(s, val); |
| 1265 | } |
| 1266 | return val; |
| 1267 | } |
| 1268 | |
| 1269 | static void ind_wr_xfer_ctrl_reg_post_write(RegisterInfo *reg, uint64_t val) |
| 1270 | { |
| 1271 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque); |
| 1272 | |
| 1273 | if (s->ind_write_disabled) { |
| 1274 | return; |
| 1275 | } |
| 1276 | |
| 1277 | if (ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, START_FLD)) { |
| 1278 | ospi_ind_op_queue_up_wr(s); |
| 1279 | ospi_do_indirect_write(s); |
| 1280 | ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, START_FLD, 0); |
| 1281 | } |
| 1282 | |
| 1283 | if (ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, CANCEL_FLD)) { |
| 1284 | ospi_ind_op_cancel(s->wr_ind_op); |
| 1285 | fifo8_reset(&s->tx_sram); |
| 1286 | ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, CANCEL_FLD, 0); |
| 1287 | } |
| 1288 | } |
| 1289 | |
| 1290 | static uint64_t ind_wr_xfer_ctrl_reg_post_read(RegisterInfo *reg, |
| 1291 | uint64_t val) |
| 1292 | { |
| 1293 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque); |
| 1294 | IndOp *op = s->wr_ind_op; |
| 1295 | |
| 1296 | /* Check if ind ops is ongoing */ |
| 1297 | if (!ospi_ind_op_completed(&op[0])) { |
| 1298 | /* Check if two ind ops are queued */ |
| 1299 | if (!ospi_ind_op_completed(&op[1])) { |
| 1300 | val = FIELD_DP32(val, INDIRECT_WRITE_XFER_CTRL_REG, |
| 1301 | WR_QUEUED_FLD, 1); |
| 1302 | } |
| 1303 | val = FIELD_DP32(val, INDIRECT_WRITE_XFER_CTRL_REG, WR_STATUS_FLD, 1); |
| 1304 | } |
| 1305 | return val; |
| 1306 | } |
| 1307 | |
| 1308 | static uint64_t ind_rd_dec_num_done(XlnxVersalOspi *s, uint64_t val) |
| 1309 | { |
| 1310 | unsigned int done = ARRAY_FIELD_EX32(s->regs, INDIRECT_READ_XFER_CTRL_REG, |
| 1311 | NUM_IND_OPS_DONE_FLD); |
| 1312 | done--; |
| 1313 | done &= 0x3; |
| 1314 | val = FIELD_DP32(val, INDIRECT_READ_XFER_CTRL_REG, |
| 1315 | NUM_IND_OPS_DONE_FLD, done); |
| 1316 | return val; |
| 1317 | } |
| 1318 | |
| 1319 | static uint64_t ind_rd_xfer_ctrl_reg_pre_write(RegisterInfo *reg, |
| 1320 | uint64_t val) |
| 1321 | { |
| 1322 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque); |
| 1323 | |
| 1324 | if (FIELD_EX32(val, INDIRECT_READ_XFER_CTRL_REG, |
| 1325 | IND_OPS_DONE_STATUS_FLD)) { |
| 1326 | val = ind_rd_dec_num_done(s, val); |
| 1327 | val &= ~R_INDIRECT_READ_XFER_CTRL_REG_IND_OPS_DONE_STATUS_FLD_MASK; |
| 1328 | } |
| 1329 | return val; |
| 1330 | } |
| 1331 | |
| 1332 | static void ind_rd_xfer_ctrl_reg_post_write(RegisterInfo *reg, uint64_t val) |
| 1333 | { |
| 1334 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque); |
| 1335 | |
| 1336 | if (ARRAY_FIELD_EX32(s->regs, INDIRECT_READ_XFER_CTRL_REG, START_FLD)) { |
| 1337 | ospi_ind_op_queue_up_rd(s); |
| 1338 | ospi_do_ind_read(s); |
| 1339 | ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG, START_FLD, 0); |
| 1340 | } |
| 1341 | |
| 1342 | if (ARRAY_FIELD_EX32(s->regs, INDIRECT_READ_XFER_CTRL_REG, CANCEL_FLD)) { |
| 1343 | ospi_ind_op_cancel(s->rd_ind_op); |
| 1344 | fifo8_reset(&s->rx_sram); |
| 1345 | ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG, CANCEL_FLD, 0); |
| 1346 | } |
| 1347 | } |
| 1348 | |
| 1349 | static uint64_t ind_rd_xfer_ctrl_reg_post_read(RegisterInfo *reg, |
| 1350 | uint64_t val) |
| 1351 | { |
| 1352 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque); |
| 1353 | IndOp *op = s->rd_ind_op; |
| 1354 | |
| 1355 | /* Check if ind ops is ongoing */ |
| 1356 | if (!ospi_ind_op_completed(&op[0])) { |
| 1357 | /* Check if two ind ops are queued */ |
| 1358 | if (!ospi_ind_op_completed(&op[1])) { |
| 1359 | val = FIELD_DP32(val, INDIRECT_READ_XFER_CTRL_REG, |
| 1360 | RD_QUEUED_FLD, 1); |
| 1361 | } |
| 1362 | val = FIELD_DP32(val, INDIRECT_READ_XFER_CTRL_REG, RD_STATUS_FLD, 1); |
| 1363 | } |
| 1364 | return val; |
| 1365 | } |
| 1366 | |
| 1367 | static uint64_t sram_fill_reg_post_read(RegisterInfo *reg, uint64_t val) |
| 1368 | { |
| 1369 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque); |
| 1370 | val = ((fifo8_num_used(&s->tx_sram) & 0xFFFF) << 16) | |
| 1371 | (fifo8_num_used(&s->rx_sram) & 0xFFFF); |
| 1372 | return val; |
| 1373 | } |
| 1374 | |
| 1375 | static uint64_t dll_obs_upper_reg_post_read(RegisterInfo *reg, uint64_t val) |
| 1376 | { |
| 1377 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque); |
| 1378 | uint32_t rx_dec_out; |
| 1379 | |
| 1380 | rx_dec_out = FIELD_EX32(val, DLL_OBSERVABLE_UPPER_REG, |
| 1381 | DLL_OBSERVABLE__UPPER_RX_DECODER_OUTPUT_FLD); |
| 1382 | |
| 1383 | if (rx_dec_out < MAX_RX_DEC_OUT) { |
| 1384 | ARRAY_FIELD_DP32(s->regs, DLL_OBSERVABLE_UPPER_REG, |
| 1385 | DLL_OBSERVABLE__UPPER_RX_DECODER_OUTPUT_FLD, |
| 1386 | rx_dec_out + 1); |
| 1387 | } |
| 1388 | |
| 1389 | return val; |
| 1390 | } |
| 1391 | |
| 1392 | |
| 1393 | static void xlnx_versal_ospi_reset(DeviceState *dev) |
| 1394 | { |
| 1395 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(dev); |
| 1396 | unsigned int i; |
| 1397 | |
| 1398 | for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { |
| 1399 | register_reset(&s->regs_info[i]); |
| 1400 | } |
| 1401 | |
| 1402 | fifo8_reset(&s->rx_fifo); |
| 1403 | fifo8_reset(&s->tx_fifo); |
| 1404 | fifo8_reset(&s->rx_sram); |
| 1405 | fifo8_reset(&s->tx_sram); |
| 1406 | |
| 1407 | s->rd_ind_op[0].completed = true; |
| 1408 | s->rd_ind_op[1].completed = true; |
| 1409 | s->wr_ind_op[0].completed = true; |
| 1410 | s->wr_ind_op[1].completed = true; |
| 1411 | ARRAY_FIELD_DP32(s->regs, DLL_OBSERVABLE_LOWER_REG, |
| 1412 | DLL_OBSERVABLE_LOWER_DLL_LOCK_FLD, 1); |
| 1413 | ARRAY_FIELD_DP32(s->regs, DLL_OBSERVABLE_LOWER_REG, |
| 1414 | DLL_OBSERVABLE_LOWER_LOOPBACK_LOCK_FLD, 1); |
| 1415 | } |
| 1416 | |
| 1417 | static RegisterAccessInfo ospi_regs_info[] = { |
| 1418 | { .name = "CONFIG_REG", |
| 1419 | .addr = A_CONFIG_REG, |
| 1420 | .reset = 0x80780081, |
| 1421 | .ro = 0x9c000000, |
| 1422 | },{ .name = "DEV_INSTR_RD_CONFIG_REG", |
| 1423 | .addr = A_DEV_INSTR_RD_CONFIG_REG, |
| 1424 | .reset = 0x3, |
| 1425 | .ro = 0xe0ecc800, |
| 1426 | },{ .name = "DEV_INSTR_WR_CONFIG_REG", |
| 1427 | .addr = A_DEV_INSTR_WR_CONFIG_REG, |
| 1428 | .reset = 0x2, |
| 1429 | .ro = 0xe0fcce00, |
| 1430 | },{ .name = "DEV_DELAY_REG", |
| 1431 | .addr = A_DEV_DELAY_REG, |
| 1432 | },{ .name = "RD_DATA_CAPTURE_REG", |
| 1433 | .addr = A_RD_DATA_CAPTURE_REG, |
| 1434 | .reset = 0x1, |
| 1435 | .ro = 0xfff0fec0, |
| 1436 | },{ .name = "DEV_SIZE_CONFIG_REG", |
| 1437 | .addr = A_DEV_SIZE_CONFIG_REG, |
| 1438 | .reset = 0x101002, |
| 1439 | .ro = 0xe0000000, |
| 1440 | },{ .name = "SRAM_PARTITION_CFG_REG", |
| 1441 | .addr = A_SRAM_PARTITION_CFG_REG, |
| 1442 | .reset = 0x80, |
| 1443 | .ro = 0xffffff00, |
| 1444 | },{ .name = "IND_AHB_ADDR_TRIGGER_REG", |
| 1445 | .addr = A_IND_AHB_ADDR_TRIGGER_REG, |
| 1446 | },{ .name = "DMA_PERIPH_CONFIG_REG", |
| 1447 | .addr = A_DMA_PERIPH_CONFIG_REG, |
| 1448 | .ro = 0xfffff0f0, |
| 1449 | },{ .name = "REMAP_ADDR_REG", |
| 1450 | .addr = A_REMAP_ADDR_REG, |
| 1451 | },{ .name = "MODE_BIT_CONFIG_REG", |
| 1452 | .addr = A_MODE_BIT_CONFIG_REG, |
| 1453 | .reset = 0x200, |
| 1454 | .ro = 0xffff7800, |
| 1455 | },{ .name = "SRAM_FILL_REG", |
| 1456 | .addr = A_SRAM_FILL_REG, |
| 1457 | .ro = 0xffffffff, |
| 1458 | .post_read = sram_fill_reg_post_read, |
| 1459 | },{ .name = "TX_THRESH_REG", |
| 1460 | .addr = A_TX_THRESH_REG, |
| 1461 | .reset = 0x1, |
| 1462 | .ro = 0xffffffe0, |
| 1463 | },{ .name = "RX_THRESH_REG", |
| 1464 | .addr = A_RX_THRESH_REG, |
| 1465 | .reset = 0x1, |
| 1466 | .ro = 0xffffffe0, |
| 1467 | },{ .name = "WRITE_COMPLETION_CTRL_REG", |
| 1468 | .addr = A_WRITE_COMPLETION_CTRL_REG, |
| 1469 | .reset = 0x10005, |
| 1470 | .ro = 0x1800, |
| 1471 | },{ .name = "NO_OF_POLLS_BEF_EXP_REG", |
| 1472 | .addr = A_NO_OF_POLLS_BEF_EXP_REG, |
| 1473 | .reset = 0xffffffff, |
| 1474 | },{ .name = "IRQ_STATUS_REG", |
| 1475 | .addr = A_IRQ_STATUS_REG, |
| 1476 | .ro = 0xfff08000, |
| 1477 | .w1c = 0xf7fff, |
| 1478 | },{ .name = "IRQ_MASK_REG", |
| 1479 | .addr = A_IRQ_MASK_REG, |
| 1480 | .ro = 0xfff08000, |
| 1481 | },{ .name = "LOWER_WR_PROT_REG", |
| 1482 | .addr = A_LOWER_WR_PROT_REG, |
| 1483 | },{ .name = "UPPER_WR_PROT_REG", |
| 1484 | .addr = A_UPPER_WR_PROT_REG, |
| 1485 | },{ .name = "WR_PROT_CTRL_REG", |
| 1486 | .addr = A_WR_PROT_CTRL_REG, |
| 1487 | .ro = 0xfffffffc, |
| 1488 | },{ .name = "INDIRECT_READ_XFER_CTRL_REG", |
| 1489 | .addr = A_INDIRECT_READ_XFER_CTRL_REG, |
| 1490 | .ro = 0xffffffd4, |
| 1491 | .w1c = 0x08, |
| 1492 | .pre_write = ind_rd_xfer_ctrl_reg_pre_write, |
| 1493 | .post_write = ind_rd_xfer_ctrl_reg_post_write, |
| 1494 | .post_read = ind_rd_xfer_ctrl_reg_post_read, |
| 1495 | },{ .name = "INDIRECT_READ_XFER_WATERMARK_REG", |
| 1496 | .addr = A_INDIRECT_READ_XFER_WATERMARK_REG, |
| 1497 | },{ .name = "INDIRECT_READ_XFER_START_REG", |
| 1498 | .addr = A_INDIRECT_READ_XFER_START_REG, |
| 1499 | },{ .name = "INDIRECT_READ_XFER_NUM_BYTES_REG", |
| 1500 | .addr = A_INDIRECT_READ_XFER_NUM_BYTES_REG, |
| 1501 | },{ .name = "INDIRECT_WRITE_XFER_CTRL_REG", |
| 1502 | .addr = A_INDIRECT_WRITE_XFER_CTRL_REG, |
| 1503 | .ro = 0xffffffdc, |
| 1504 | .w1c = 0x20, |
| 1505 | .pre_write = ind_wr_xfer_ctrl_reg_pre_write, |
| 1506 | .post_write = ind_wr_xfer_ctrl_reg_post_write, |
| 1507 | .post_read = ind_wr_xfer_ctrl_reg_post_read, |
| 1508 | },{ .name = "INDIRECT_WRITE_XFER_WATERMARK_REG", |
| 1509 | .addr = A_INDIRECT_WRITE_XFER_WATERMARK_REG, |
| 1510 | .reset = 0xffffffff, |
| 1511 | },{ .name = "INDIRECT_WRITE_XFER_START_REG", |
| 1512 | .addr = A_INDIRECT_WRITE_XFER_START_REG, |
| 1513 | },{ .name = "INDIRECT_WRITE_XFER_NUM_BYTES_REG", |
| 1514 | .addr = A_INDIRECT_WRITE_XFER_NUM_BYTES_REG, |
| 1515 | },{ .name = "INDIRECT_TRIGGER_ADDR_RANGE_REG", |
| 1516 | .addr = A_INDIRECT_TRIGGER_ADDR_RANGE_REG, |
| 1517 | .reset = 0x4, |
| 1518 | .ro = 0xfffffff0, |
| 1519 | },{ .name = "FLASH_COMMAND_CTRL_MEM_REG", |
| 1520 | .addr = A_FLASH_COMMAND_CTRL_MEM_REG, |
| 1521 | .ro = 0xe008fffe, |
| 1522 | .post_write = flash_cmd_ctrl_mem_reg_post_write, |
| 1523 | },{ .name = "FLASH_CMD_CTRL_REG", |
| 1524 | .addr = A_FLASH_CMD_CTRL_REG, |
| 1525 | .ro = 0x7a, |
| 1526 | .post_write = flash_cmd_ctrl_reg_post_write, |
| 1527 | },{ .name = "FLASH_CMD_ADDR_REG", |
| 1528 | .addr = A_FLASH_CMD_ADDR_REG, |
| 1529 | },{ .name = "FLASH_RD_DATA_LOWER_REG", |
| 1530 | .addr = A_FLASH_RD_DATA_LOWER_REG, |
| 1531 | .ro = 0xffffffff, |
| 1532 | },{ .name = "FLASH_RD_DATA_UPPER_REG", |
| 1533 | .addr = A_FLASH_RD_DATA_UPPER_REG, |
| 1534 | .ro = 0xffffffff, |
| 1535 | },{ .name = "FLASH_WR_DATA_LOWER_REG", |
| 1536 | .addr = A_FLASH_WR_DATA_LOWER_REG, |
| 1537 | },{ .name = "FLASH_WR_DATA_UPPER_REG", |
| 1538 | .addr = A_FLASH_WR_DATA_UPPER_REG, |
| 1539 | },{ .name = "POLLING_FLASH_STATUS_REG", |
| 1540 | .addr = A_POLLING_FLASH_STATUS_REG, |
| 1541 | .ro = 0xfff0ffff, |
| 1542 | },{ .name = "PHY_CONFIGURATION_REG", |
| 1543 | .addr = A_PHY_CONFIGURATION_REG, |
| 1544 | .reset = 0x40000000, |
| 1545 | .ro = 0x1f80ff80, |
| 1546 | },{ .name = "PHY_MASTER_CONTROL_REG", |
| 1547 | .addr = A_PHY_MASTER_CONTROL_REG, |
| 1548 | .reset = 0x800000, |
| 1549 | .ro = 0xfe08ff80, |
| 1550 | },{ .name = "DLL_OBSERVABLE_LOWER_REG", |
| 1551 | .addr = A_DLL_OBSERVABLE_LOWER_REG, |
| 1552 | .ro = 0xffffffff, |
| 1553 | },{ .name = "DLL_OBSERVABLE_UPPER_REG", |
| 1554 | .addr = A_DLL_OBSERVABLE_UPPER_REG, |
| 1555 | .ro = 0xffffffff, |
| 1556 | .post_read = dll_obs_upper_reg_post_read, |
| 1557 | },{ .name = "OPCODE_EXT_LOWER_REG", |
| 1558 | .addr = A_OPCODE_EXT_LOWER_REG, |
| 1559 | .reset = 0x13edfa00, |
| 1560 | },{ .name = "OPCODE_EXT_UPPER_REG", |
| 1561 | .addr = A_OPCODE_EXT_UPPER_REG, |
| 1562 | .reset = 0x6f90000, |
| 1563 | .ro = 0xffff, |
| 1564 | },{ .name = "MODULE_ID_REG", |
| 1565 | .addr = A_MODULE_ID_REG, |
| 1566 | .reset = 0x300, |
| 1567 | .ro = 0xffffffff, |
| 1568 | } |
| 1569 | }; |
| 1570 | |
| 1571 | /* Return dev-obj from reg-region created by register_init_block32 */ |
| 1572 | static XlnxVersalOspi *xilinx_ospi_of_mr(void *opaque) |
| 1573 | { |
| 1574 | RegisterInfoArray *reg_array = REGISTER_ARRAY(opaque); |
| 1575 | |
| 1576 | return XILINX_VERSAL_OSPI(register_array_get_owner(reg_array)); |
| 1577 | } |
| 1578 | |
| 1579 | static void ospi_write(void *opaque, hwaddr addr, uint64_t value, |
| 1580 | unsigned int size) |
| 1581 | { |
| 1582 | XlnxVersalOspi *s = xilinx_ospi_of_mr(opaque); |
| 1583 | |
| 1584 | register_write_memory(opaque, addr, value, size); |
| 1585 | ospi_update_irq_line(s); |
| 1586 | } |
| 1587 | |
| 1588 | static const MemoryRegionOps ospi_ops = { |
| 1589 | .read = register_read_memory, |
| 1590 | .write = ospi_write, |
| 1591 | .endianness = DEVICE_LITTLE_ENDIAN, |
| 1592 | .valid = { |
| 1593 | .min_access_size = 4, |
| 1594 | .max_access_size = 4, |
| 1595 | }, |
| 1596 | }; |
| 1597 | |
| 1598 | static uint64_t ospi_indac_read(void *opaque, unsigned int size) |
| 1599 | { |
| 1600 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque); |
| 1601 | uint64_t ret = ospi_rx_sram_read(s, size); |
| 1602 | |
| 1603 | if (!ospi_ind_op_completed(s->rd_ind_op)) { |
| 1604 | ospi_do_ind_read(s); |
| 1605 | } |
| 1606 | return ret; |
| 1607 | } |
| 1608 | |
| 1609 | static void ospi_indac_write(void *opaque, uint64_t value, unsigned int size) |
| 1610 | { |
| 1611 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque); |
| 1612 | |
| 1613 | g_assert(!s->ind_write_disabled); |
| 1614 | |
| 1615 | if (!ospi_ind_op_completed(s->wr_ind_op)) { |
| 1616 | ospi_tx_sram_write(s, value, size); |
| 1617 | ospi_do_indirect_write(s); |
| 1618 | } else { |
| 1619 | qemu_log_mask(LOG_GUEST_ERROR, |
| 1620 | "OSPI wr into indac area while no ongoing indac wr\n"); |
| 1621 | } |
| 1622 | } |
| 1623 | |
| 1624 | static bool is_inside_indac_range(XlnxVersalOspi *s, hwaddr addr) |
| 1625 | { |
| 1626 | uint32_t range_start; |
| 1627 | uint32_t range_end; |
| 1628 | |
| 1629 | if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DMA_IF_FLD)) { |
| 1630 | return true; |
| 1631 | } |
| 1632 | |
| 1633 | range_start = s->regs[R_IND_AHB_ADDR_TRIGGER_REG]; |
| 1634 | range_end = range_start + |
| 1635 | (1 << ARRAY_FIELD_EX32(s->regs, |
| 1636 | INDIRECT_TRIGGER_ADDR_RANGE_REG, |
| 1637 | IND_RANGE_WIDTH_FLD)); |
| 1638 | |
| 1639 | addr += s->regs[R_IND_AHB_ADDR_TRIGGER_REG] & 0xF0000000; |
| 1640 | |
| 1641 | return addr >= range_start && addr < range_end; |
| 1642 | } |
| 1643 | |
| 1644 | static bool ospi_is_indac_active(XlnxVersalOspi *s) |
| 1645 | { |
| 1646 | /* |
| 1647 | * When dac and indac cannot be active at the same time, |
| 1648 | * return true when dac is disabled. |
| 1649 | */ |
| 1650 | return s->dac_with_indac || !s->dac_enable; |
| 1651 | } |
| 1652 | |
| 1653 | static uint64_t ospi_dac_read(void *opaque, hwaddr addr, unsigned int size) |
| 1654 | { |
| 1655 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque); |
| 1656 | |
| 1657 | if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD)) { |
| 1658 | if (ospi_is_indac_active(s) && |
| 1659 | is_inside_indac_range(s, addr)) { |
| 1660 | return ospi_indac_read(s, size); |
| 1661 | } |
| 1662 | if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DIR_ACC_CTLR_FLD) |
| 1663 | && s->dac_enable) { |
| 1664 | if (ARRAY_FIELD_EX32(s->regs, |
| 1665 | CONFIG_REG, ENB_AHB_ADDR_REMAP_FLD)) { |
| 1666 | addr += s->regs[R_REMAP_ADDR_REG]; |
| 1667 | } |
| 1668 | return ospi_do_dac_read(opaque, addr, size); |
| 1669 | } else { |
| 1670 | qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB rd while DAC disabled\n"); |
| 1671 | } |
| 1672 | } else { |
| 1673 | qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB rd while OSPI disabled\n"); |
| 1674 | } |
| 1675 | |
| 1676 | return 0; |
| 1677 | } |
| 1678 | |
| 1679 | static void ospi_dac_write(void *opaque, hwaddr addr, uint64_t value, |
| 1680 | unsigned int size) |
| 1681 | { |
| 1682 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque); |
| 1683 | |
| 1684 | if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD)) { |
| 1685 | if (ospi_is_indac_active(s) && |
| 1686 | !s->ind_write_disabled && |
| 1687 | is_inside_indac_range(s, addr)) { |
| 1688 | return ospi_indac_write(s, value, size); |
| 1689 | } |
| 1690 | if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DIR_ACC_CTLR_FLD) && |
| 1691 | s->dac_enable) { |
| 1692 | if (ARRAY_FIELD_EX32(s->regs, |
| 1693 | CONFIG_REG, ENB_AHB_ADDR_REMAP_FLD)) { |
| 1694 | addr += s->regs[R_REMAP_ADDR_REG]; |
| 1695 | } |
| 1696 | /* Check if addr is write protected */ |
| 1697 | if (ARRAY_FIELD_EX32(s->regs, WR_PROT_CTRL_REG, ENB_FLD) && |
| 1698 | ospi_is_write_protected(s, addr)) { |
| 1699 | set_irq(s, R_IRQ_STATUS_REG_PROT_WR_ATTEMPT_FLD_MASK); |
| 1700 | ospi_update_irq_line(s); |
| 1701 | qemu_log_mask(LOG_GUEST_ERROR, |
| 1702 | "OSPI writing into write protected area\n"); |
| 1703 | return; |
| 1704 | } |
| 1705 | ospi_do_dac_write(opaque, addr, value, size); |
| 1706 | } else { |
| 1707 | qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB wr while DAC disabled\n"); |
| 1708 | } |
| 1709 | } else { |
| 1710 | qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB wr while OSPI disabled\n"); |
| 1711 | } |
| 1712 | } |
| 1713 | |
| 1714 | static const MemoryRegionOps ospi_dac_ops = { |
| 1715 | .read = ospi_dac_read, |
| 1716 | .write = ospi_dac_write, |
| 1717 | .endianness = DEVICE_LITTLE_ENDIAN, |
| 1718 | .valid = { |
| 1719 | .min_access_size = 4, |
| 1720 | .max_access_size = 4, |
| 1721 | }, |
| 1722 | }; |
| 1723 | |
| 1724 | static void ospi_update_dac_status(void *opaque, int n, int level) |
| 1725 | { |
| 1726 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque); |
| 1727 | |
| 1728 | s->dac_enable = level; |
| 1729 | } |
| 1730 | |
| 1731 | static void xlnx_versal_ospi_realize(DeviceState *dev, Error **errp) |
| 1732 | { |
| 1733 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(dev); |
| 1734 | SysBusDevice *sbd = SYS_BUS_DEVICE(dev); |
| 1735 | |
| 1736 | s->num_cs = 4; |
| 1737 | s->spi = ssi_create_bus(dev, "spi0"); |
| 1738 | s->cs_lines = g_new0(qemu_irq, s->num_cs); |
| 1739 | for (int i = 0; i < s->num_cs; ++i) { |
| 1740 | sysbus_init_irq(sbd, &s->cs_lines[i]); |
| 1741 | } |
| 1742 | |
| 1743 | fifo8_create(&s->rx_fifo, RXFF_SZ); |
| 1744 | fifo8_create(&s->tx_fifo, TXFF_SZ); |
| 1745 | fifo8_create(&s->rx_sram, RXFF_SZ); |
| 1746 | fifo8_create(&s->tx_sram, TXFF_SZ); |
| 1747 | } |
| 1748 | |
| 1749 | static void xlnx_versal_ospi_init(Object *obj) |
| 1750 | { |
| 1751 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(obj); |
| 1752 | SysBusDevice *sbd = SYS_BUS_DEVICE(obj); |
| 1753 | DeviceState *dev = DEVICE(obj); |
| 1754 | RegisterInfoArray *reg_array; |
| 1755 | |
| 1756 | memory_region_init(&s->iomem, obj, TYPE_XILINX_VERSAL_OSPI, |
| 1757 | XILINX_VERSAL_OSPI_R_MAX * 4); |
| 1758 | reg_array = |
| 1759 | register_init_block32(DEVICE(obj), ospi_regs_info, |
| 1760 | ARRAY_SIZE(ospi_regs_info), |
| 1761 | s->regs_info, s->regs, |
| 1762 | &ospi_ops, |
| 1763 | XILINX_VERSAL_OSPI_ERR_DEBUG, |
| 1764 | XILINX_VERSAL_OSPI_R_MAX * 4); |
| 1765 | memory_region_add_subregion(&s->iomem, 0x0, ®_array->mem); |
| 1766 | sysbus_init_mmio(sbd, &s->iomem); |
| 1767 | |
| 1768 | memory_region_init_io(&s->iomem_dac, obj, &ospi_dac_ops, s, |
| 1769 | TYPE_XILINX_VERSAL_OSPI "-dac", 0x20000000); |
| 1770 | sysbus_init_mmio(sbd, &s->iomem_dac); |
| 1771 | /* |
| 1772 | * The OSPI DMA reads flash data through the OSPI linear address space (the |
| 1773 | * iomem_dac region), because of this the reentrancy guard needs to be |
| 1774 | * disabled. |
| 1775 | */ |
| 1776 | s->iomem_dac.disable_reentrancy_guard = true; |
| 1777 | |
| 1778 | sysbus_init_irq(sbd, &s->irq); |
| 1779 | |
| 1780 | object_property_add_link(obj, "dma-src", TYPE_XLNX_CSU_DMA, |
| 1781 | (Object **)&s->dma_src, |
| 1782 | object_property_allow_set_link, |
| 1783 | OBJ_PROP_LINK_STRONG); |
| 1784 | |
| 1785 | qdev_init_gpio_in_named(dev, ospi_update_dac_status, "ospi-mux-sel", 1); |
| 1786 | } |
| 1787 | |
| 1788 | static const VMStateDescription vmstate_ind_op = { |
| 1789 | .name = "OSPIIndOp", |
| 1790 | .version_id = 1, |
| 1791 | .minimum_version_id = 1, |
| 1792 | .fields = (const VMStateField[]) { |
| 1793 | VMSTATE_UINT32(flash_addr, IndOp), |
| 1794 | VMSTATE_UINT32(num_bytes, IndOp), |
| 1795 | VMSTATE_UINT32(done_bytes, IndOp), |
| 1796 | VMSTATE_BOOL(completed, IndOp), |
| 1797 | VMSTATE_END_OF_LIST() |
| 1798 | } |
| 1799 | }; |
| 1800 | |
| 1801 | static const VMStateDescription vmstate_xlnx_versal_ospi = { |
| 1802 | .name = TYPE_XILINX_VERSAL_OSPI, |
| 1803 | .version_id = 1, |
| 1804 | .minimum_version_id = 1, |
| 1805 | .fields = (const VMStateField[]) { |
| 1806 | VMSTATE_FIFO8(rx_fifo, XlnxVersalOspi), |
| 1807 | VMSTATE_FIFO8(tx_fifo, XlnxVersalOspi), |
| 1808 | VMSTATE_FIFO8(rx_sram, XlnxVersalOspi), |
| 1809 | VMSTATE_FIFO8(tx_sram, XlnxVersalOspi), |
| 1810 | VMSTATE_BOOL(ind_write_disabled, XlnxVersalOspi), |
| 1811 | VMSTATE_BOOL(dac_with_indac, XlnxVersalOspi), |
| 1812 | VMSTATE_BOOL(dac_enable, XlnxVersalOspi), |
| 1813 | VMSTATE_BOOL(src_dma_inprog, XlnxVersalOspi), |
| 1814 | VMSTATE_STRUCT_ARRAY(rd_ind_op, XlnxVersalOspi, 2, 1, |
| 1815 | vmstate_ind_op, IndOp), |
| 1816 | VMSTATE_STRUCT_ARRAY(wr_ind_op, XlnxVersalOspi, 2, 1, |
| 1817 | vmstate_ind_op, IndOp), |
| 1818 | VMSTATE_UINT32_ARRAY(regs, XlnxVersalOspi, XILINX_VERSAL_OSPI_R_MAX), |
| 1819 | VMSTATE_UINT8_ARRAY(stig_membank, XlnxVersalOspi, 512), |
| 1820 | VMSTATE_END_OF_LIST(), |
| 1821 | } |
| 1822 | }; |
| 1823 | |
| 1824 | static const Property xlnx_versal_ospi_properties[] = { |
| 1825 | DEFINE_PROP_BOOL("dac-with-indac", XlnxVersalOspi, dac_with_indac, false), |
| 1826 | DEFINE_PROP_BOOL("indac-write-disabled", XlnxVersalOspi, |
| 1827 | ind_write_disabled, false), |
| 1828 | }; |
| 1829 | |
| 1830 | static void xlnx_versal_ospi_class_init(ObjectClass *klass, const void *data) |
| 1831 | { |
| 1832 | DeviceClass *dc = DEVICE_CLASS(klass); |
| 1833 | |
| 1834 | device_class_set_legacy_reset(dc, xlnx_versal_ospi_reset); |
| 1835 | dc->realize = xlnx_versal_ospi_realize; |
| 1836 | dc->vmsd = &vmstate_xlnx_versal_ospi; |
| 1837 | device_class_set_props(dc, xlnx_versal_ospi_properties); |
| 1838 | } |
| 1839 | |
| 1840 | static const TypeInfo xlnx_versal_ospi_info = { |
| 1841 | .name = TYPE_XILINX_VERSAL_OSPI, |
| 1842 | .parent = TYPE_SYS_BUS_DEVICE, |
| 1843 | .instance_size = sizeof(XlnxVersalOspi), |
| 1844 | .class_init = xlnx_versal_ospi_class_init, |
| 1845 | .instance_init = xlnx_versal_ospi_init, |
| 1846 | }; |
| 1847 | |
| 1848 | static void xlnx_versal_ospi_register_types(void) |
| 1849 | { |
| 1850 | type_register_static(&xlnx_versal_ospi_info); |
| 1851 | } |
| 1852 | |
| 1853 | type_init(xlnx_versal_ospi_register_types) |