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