]>
Commit | Line | Data |
---|---|---|
cbb45ff0 FI |
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/sysbus.h" | |
27 | #include "migration/vmstate.h" | |
28 | #include "hw/qdev-properties.h" | |
29 | #include "qemu/bitops.h" | |
30 | #include "qemu/log.h" | |
31 | #include "hw/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)) { | |
9b4b4e51 | 840 | /* Read requested number of bytes, max bytes limited to size of sram */ |
cbb45ff0 FI |
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 *mr_accessor) | |
1573 | { | |
1574 | RegisterInfoArray *reg_array = mr_accessor; | |
1575 | Object *dev; | |
1576 | ||
1577 | dev = reg_array->mem.owner; | |
1578 | assert(dev); | |
1579 | ||
1580 | return XILINX_VERSAL_OSPI(dev); | |
1581 | } | |
1582 | ||
1583 | static void ospi_write(void *opaque, hwaddr addr, uint64_t value, | |
1584 | unsigned int size) | |
1585 | { | |
1586 | XlnxVersalOspi *s = xilinx_ospi_of_mr(opaque); | |
1587 | ||
1588 | register_write_memory(opaque, addr, value, size); | |
1589 | ospi_update_irq_line(s); | |
1590 | } | |
1591 | ||
1592 | static const MemoryRegionOps ospi_ops = { | |
1593 | .read = register_read_memory, | |
1594 | .write = ospi_write, | |
1595 | .endianness = DEVICE_LITTLE_ENDIAN, | |
1596 | .valid = { | |
1597 | .min_access_size = 4, | |
1598 | .max_access_size = 4, | |
1599 | }, | |
1600 | }; | |
1601 | ||
1602 | static uint64_t ospi_indac_read(void *opaque, unsigned int size) | |
1603 | { | |
1604 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque); | |
1605 | uint64_t ret = ospi_rx_sram_read(s, size); | |
1606 | ||
1607 | if (!ospi_ind_op_completed(s->rd_ind_op)) { | |
1608 | ospi_do_ind_read(s); | |
1609 | } | |
1610 | return ret; | |
1611 | } | |
1612 | ||
1613 | static void ospi_indac_write(void *opaque, uint64_t value, unsigned int size) | |
1614 | { | |
1615 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque); | |
1616 | ||
1617 | g_assert(!s->ind_write_disabled); | |
1618 | ||
1619 | if (!ospi_ind_op_completed(s->wr_ind_op)) { | |
1620 | ospi_tx_sram_write(s, value, size); | |
1621 | ospi_do_indirect_write(s); | |
1622 | } else { | |
1623 | qemu_log_mask(LOG_GUEST_ERROR, | |
1624 | "OSPI wr into indac area while no ongoing indac wr\n"); | |
1625 | } | |
1626 | } | |
1627 | ||
1628 | static bool is_inside_indac_range(XlnxVersalOspi *s, hwaddr addr) | |
1629 | { | |
1630 | uint32_t range_start; | |
1631 | uint32_t range_end; | |
1632 | ||
1633 | if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DMA_IF_FLD)) { | |
1634 | return true; | |
1635 | } | |
1636 | ||
1637 | range_start = s->regs[R_IND_AHB_ADDR_TRIGGER_REG]; | |
1638 | range_end = range_start + | |
1639 | (1 << ARRAY_FIELD_EX32(s->regs, | |
1640 | INDIRECT_TRIGGER_ADDR_RANGE_REG, | |
1641 | IND_RANGE_WIDTH_FLD)); | |
1642 | ||
1643 | addr += s->regs[R_IND_AHB_ADDR_TRIGGER_REG] & 0xF0000000; | |
1644 | ||
1645 | return addr >= range_start && addr < range_end; | |
1646 | } | |
1647 | ||
1648 | static bool ospi_is_indac_active(XlnxVersalOspi *s) | |
1649 | { | |
1650 | /* | |
1651 | * When dac and indac cannot be active at the same time, | |
1652 | * return true when dac is disabled. | |
1653 | */ | |
1654 | return s->dac_with_indac || !s->dac_enable; | |
1655 | } | |
1656 | ||
1657 | static uint64_t ospi_dac_read(void *opaque, hwaddr addr, unsigned int size) | |
1658 | { | |
1659 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque); | |
1660 | ||
1661 | if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD)) { | |
1662 | if (ospi_is_indac_active(s) && | |
1663 | is_inside_indac_range(s, addr)) { | |
1664 | return ospi_indac_read(s, size); | |
1665 | } | |
1666 | if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DIR_ACC_CTLR_FLD) | |
1667 | && s->dac_enable) { | |
1668 | if (ARRAY_FIELD_EX32(s->regs, | |
1669 | CONFIG_REG, ENB_AHB_ADDR_REMAP_FLD)) { | |
1670 | addr += s->regs[R_REMAP_ADDR_REG]; | |
1671 | } | |
1672 | return ospi_do_dac_read(opaque, addr, size); | |
1673 | } else { | |
1674 | qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB rd while DAC disabled\n"); | |
1675 | } | |
1676 | } else { | |
1677 | qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB rd while OSPI disabled\n"); | |
1678 | } | |
1679 | ||
1680 | return 0; | |
1681 | } | |
1682 | ||
1683 | static void ospi_dac_write(void *opaque, hwaddr addr, uint64_t value, | |
1684 | unsigned int size) | |
1685 | { | |
1686 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque); | |
1687 | ||
1688 | if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD)) { | |
1689 | if (ospi_is_indac_active(s) && | |
1690 | !s->ind_write_disabled && | |
1691 | is_inside_indac_range(s, addr)) { | |
1692 | return ospi_indac_write(s, value, size); | |
1693 | } | |
1694 | if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DIR_ACC_CTLR_FLD) && | |
1695 | s->dac_enable) { | |
1696 | if (ARRAY_FIELD_EX32(s->regs, | |
1697 | CONFIG_REG, ENB_AHB_ADDR_REMAP_FLD)) { | |
1698 | addr += s->regs[R_REMAP_ADDR_REG]; | |
1699 | } | |
1700 | /* Check if addr is write protected */ | |
1701 | if (ARRAY_FIELD_EX32(s->regs, WR_PROT_CTRL_REG, ENB_FLD) && | |
1702 | ospi_is_write_protected(s, addr)) { | |
1703 | set_irq(s, R_IRQ_STATUS_REG_PROT_WR_ATTEMPT_FLD_MASK); | |
1704 | ospi_update_irq_line(s); | |
1705 | qemu_log_mask(LOG_GUEST_ERROR, | |
1706 | "OSPI writing into write protected area\n"); | |
1707 | return; | |
1708 | } | |
1709 | ospi_do_dac_write(opaque, addr, value, size); | |
1710 | } else { | |
1711 | qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB wr while DAC disabled\n"); | |
1712 | } | |
1713 | } else { | |
1714 | qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB wr while OSPI disabled\n"); | |
1715 | } | |
1716 | } | |
1717 | ||
1718 | static const MemoryRegionOps ospi_dac_ops = { | |
1719 | .read = ospi_dac_read, | |
1720 | .write = ospi_dac_write, | |
1721 | .endianness = DEVICE_LITTLE_ENDIAN, | |
1722 | .valid = { | |
1723 | .min_access_size = 4, | |
1724 | .max_access_size = 4, | |
1725 | }, | |
1726 | }; | |
1727 | ||
1728 | static void ospi_update_dac_status(void *opaque, int n, int level) | |
1729 | { | |
1730 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque); | |
1731 | ||
1732 | s->dac_enable = level; | |
1733 | } | |
1734 | ||
1735 | static void xlnx_versal_ospi_realize(DeviceState *dev, Error **errp) | |
1736 | { | |
1737 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(dev); | |
1738 | SysBusDevice *sbd = SYS_BUS_DEVICE(dev); | |
1739 | ||
1740 | s->num_cs = 4; | |
1741 | s->spi = ssi_create_bus(dev, "spi0"); | |
1742 | s->cs_lines = g_new0(qemu_irq, s->num_cs); | |
1743 | for (int i = 0; i < s->num_cs; ++i) { | |
1744 | sysbus_init_irq(sbd, &s->cs_lines[i]); | |
1745 | } | |
1746 | ||
1747 | fifo8_create(&s->rx_fifo, RXFF_SZ); | |
1748 | fifo8_create(&s->tx_fifo, TXFF_SZ); | |
1749 | fifo8_create(&s->rx_sram, RXFF_SZ); | |
1750 | fifo8_create(&s->tx_sram, TXFF_SZ); | |
1751 | } | |
1752 | ||
1753 | static void xlnx_versal_ospi_init(Object *obj) | |
1754 | { | |
1755 | XlnxVersalOspi *s = XILINX_VERSAL_OSPI(obj); | |
1756 | SysBusDevice *sbd = SYS_BUS_DEVICE(obj); | |
1757 | DeviceState *dev = DEVICE(obj); | |
1758 | RegisterInfoArray *reg_array; | |
1759 | ||
1760 | memory_region_init(&s->iomem, obj, TYPE_XILINX_VERSAL_OSPI, | |
1761 | XILINX_VERSAL_OSPI_R_MAX * 4); | |
1762 | reg_array = | |
1763 | register_init_block32(DEVICE(obj), ospi_regs_info, | |
1764 | ARRAY_SIZE(ospi_regs_info), | |
1765 | s->regs_info, s->regs, | |
1766 | &ospi_ops, | |
1767 | XILINX_VERSAL_OSPI_ERR_DEBUG, | |
1768 | XILINX_VERSAL_OSPI_R_MAX * 4); | |
1769 | memory_region_add_subregion(&s->iomem, 0x0, ®_array->mem); | |
1770 | sysbus_init_mmio(sbd, &s->iomem); | |
1771 | ||
1772 | memory_region_init_io(&s->iomem_dac, obj, &ospi_dac_ops, s, | |
1773 | TYPE_XILINX_VERSAL_OSPI "-dac", 0x20000000); | |
1774 | sysbus_init_mmio(sbd, &s->iomem_dac); | |
1775 | ||
1776 | sysbus_init_irq(sbd, &s->irq); | |
1777 | ||
1778 | object_property_add_link(obj, "dma-src", TYPE_XLNX_CSU_DMA, | |
1779 | (Object **)&s->dma_src, | |
1780 | object_property_allow_set_link, | |
1781 | OBJ_PROP_LINK_STRONG); | |
1782 | ||
1783 | qdev_init_gpio_in_named(dev, ospi_update_dac_status, "ospi-mux-sel", 1); | |
1784 | } | |
1785 | ||
1786 | static const VMStateDescription vmstate_ind_op = { | |
1787 | .name = "OSPIIndOp", | |
1788 | .version_id = 1, | |
1789 | .minimum_version_id = 1, | |
0aa6c7df | 1790 | .fields = (const VMStateField[]) { |
cbb45ff0 FI |
1791 | VMSTATE_UINT32(flash_addr, IndOp), |
1792 | VMSTATE_UINT32(num_bytes, IndOp), | |
1793 | VMSTATE_UINT32(done_bytes, IndOp), | |
1794 | VMSTATE_BOOL(completed, IndOp), | |
1795 | VMSTATE_END_OF_LIST() | |
1796 | } | |
1797 | }; | |
1798 | ||
1799 | static const VMStateDescription vmstate_xlnx_versal_ospi = { | |
1800 | .name = TYPE_XILINX_VERSAL_OSPI, | |
1801 | .version_id = 1, | |
1802 | .minimum_version_id = 1, | |
0aa6c7df | 1803 | .fields = (const VMStateField[]) { |
cbb45ff0 FI |
1804 | VMSTATE_FIFO8(rx_fifo, XlnxVersalOspi), |
1805 | VMSTATE_FIFO8(tx_fifo, XlnxVersalOspi), | |
1806 | VMSTATE_FIFO8(rx_sram, XlnxVersalOspi), | |
1807 | VMSTATE_FIFO8(tx_sram, XlnxVersalOspi), | |
1808 | VMSTATE_BOOL(ind_write_disabled, XlnxVersalOspi), | |
1809 | VMSTATE_BOOL(dac_with_indac, XlnxVersalOspi), | |
1810 | VMSTATE_BOOL(dac_enable, XlnxVersalOspi), | |
1811 | VMSTATE_BOOL(src_dma_inprog, XlnxVersalOspi), | |
1812 | VMSTATE_STRUCT_ARRAY(rd_ind_op, XlnxVersalOspi, 2, 1, | |
1813 | vmstate_ind_op, IndOp), | |
1814 | VMSTATE_STRUCT_ARRAY(wr_ind_op, XlnxVersalOspi, 2, 1, | |
1815 | vmstate_ind_op, IndOp), | |
1816 | VMSTATE_UINT32_ARRAY(regs, XlnxVersalOspi, XILINX_VERSAL_OSPI_R_MAX), | |
1817 | VMSTATE_UINT8_ARRAY(stig_membank, XlnxVersalOspi, 512), | |
1818 | VMSTATE_END_OF_LIST(), | |
1819 | } | |
1820 | }; | |
1821 | ||
1822 | static Property xlnx_versal_ospi_properties[] = { | |
1823 | DEFINE_PROP_BOOL("dac-with-indac", XlnxVersalOspi, dac_with_indac, false), | |
1824 | DEFINE_PROP_BOOL("indac-write-disabled", XlnxVersalOspi, | |
1825 | ind_write_disabled, false), | |
1826 | DEFINE_PROP_END_OF_LIST(), | |
1827 | }; | |
1828 | ||
1829 | static void xlnx_versal_ospi_class_init(ObjectClass *klass, void *data) | |
1830 | { | |
1831 | DeviceClass *dc = DEVICE_CLASS(klass); | |
1832 | ||
1833 | dc->reset = xlnx_versal_ospi_reset; | |
1834 | dc->realize = xlnx_versal_ospi_realize; | |
1835 | dc->vmsd = &vmstate_xlnx_versal_ospi; | |
1836 | device_class_set_props(dc, xlnx_versal_ospi_properties); | |
1837 | } | |
1838 | ||
1839 | static const TypeInfo xlnx_versal_ospi_info = { | |
1840 | .name = TYPE_XILINX_VERSAL_OSPI, | |
1841 | .parent = TYPE_SYS_BUS_DEVICE, | |
1842 | .instance_size = sizeof(XlnxVersalOspi), | |
1843 | .class_init = xlnx_versal_ospi_class_init, | |
1844 | .instance_init = xlnx_versal_ospi_init, | |
1845 | }; | |
1846 | ||
1847 | static void xlnx_versal_ospi_register_types(void) | |
1848 | { | |
1849 | type_register_static(&xlnx_versal_ospi_info); | |
1850 | } | |
1851 | ||
1852 | type_init(xlnx_versal_ospi_register_types) |