1d3c6369aSKONRAD Frederic /*
2d3c6369aSKONRAD Frederic * xlnx_dpdma.c
3d3c6369aSKONRAD Frederic *
4d3c6369aSKONRAD Frederic * Copyright (C) 2015 : GreenSocs Ltd
5d3c6369aSKONRAD Frederic * http://www.greensocs.com/ , email: info@greensocs.com
6d3c6369aSKONRAD Frederic *
7d3c6369aSKONRAD Frederic * Developed by :
8d3c6369aSKONRAD Frederic * Frederic Konrad <fred.konrad@greensocs.com>
9d3c6369aSKONRAD Frederic *
10d3c6369aSKONRAD Frederic * This program is free software; you can redistribute it and/or modify
11d3c6369aSKONRAD Frederic * it under the terms of the GNU General Public License as published by
12d3c6369aSKONRAD Frederic * the Free Software Foundation, either version 2 of the License, or
13d3c6369aSKONRAD Frederic * (at your option) any later version.
14d3c6369aSKONRAD Frederic *
15d3c6369aSKONRAD Frederic * This program is distributed in the hope that it will be useful,
16d3c6369aSKONRAD Frederic * but WITHOUT ANY WARRANTY; without even the implied warranty of
17d3c6369aSKONRAD Frederic * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18d3c6369aSKONRAD Frederic * GNU General Public License for more details.
19d3c6369aSKONRAD Frederic *
20d3c6369aSKONRAD Frederic * You should have received a copy of the GNU General Public License along
21d3c6369aSKONRAD Frederic * with this program; if not, see <http://www.gnu.org/licenses/>.
22d3c6369aSKONRAD Frederic *
23d3c6369aSKONRAD Frederic */
24d3c6369aSKONRAD Frederic
25d3c6369aSKONRAD Frederic #include "qemu/osdep.h"
26415b7327SMarc-André Lureau #include "qemu/cutils.h"
27d3c6369aSKONRAD Frederic #include "qemu/log.h"
280b8fa32fSMarkus Armbruster #include "qemu/module.h"
29d3c6369aSKONRAD Frederic #include "hw/dma/xlnx_dpdma.h"
3064552b6bSMarkus Armbruster #include "hw/irq.h"
31d6454270SMarkus Armbruster #include "migration/vmstate.h"
32d3c6369aSKONRAD Frederic
33d3c6369aSKONRAD Frederic #ifndef DEBUG_DPDMA
34d3c6369aSKONRAD Frederic #define DEBUG_DPDMA 0
35d3c6369aSKONRAD Frederic #endif
36d3c6369aSKONRAD Frederic
37d3c6369aSKONRAD Frederic #define DPRINTF(fmt, ...) do { \
38d3c6369aSKONRAD Frederic if (DEBUG_DPDMA) { \
39d3c6369aSKONRAD Frederic qemu_log("xlnx_dpdma: " fmt , ## __VA_ARGS__); \
40d3c6369aSKONRAD Frederic } \
412562755eSEric Blake } while (0)
42d3c6369aSKONRAD Frederic
43d3c6369aSKONRAD Frederic /*
44d3c6369aSKONRAD Frederic * Registers offset for DPDMA.
45d3c6369aSKONRAD Frederic */
46d3c6369aSKONRAD Frederic #define DPDMA_ERR_CTRL (0x0000)
47d3c6369aSKONRAD Frederic #define DPDMA_ISR (0x0004 >> 2)
48d3c6369aSKONRAD Frederic #define DPDMA_IMR (0x0008 >> 2)
49d3c6369aSKONRAD Frederic #define DPDMA_IEN (0x000C >> 2)
50d3c6369aSKONRAD Frederic #define DPDMA_IDS (0x0010 >> 2)
51d3c6369aSKONRAD Frederic #define DPDMA_EISR (0x0014 >> 2)
52d3c6369aSKONRAD Frederic #define DPDMA_EIMR (0x0018 >> 2)
53d3c6369aSKONRAD Frederic #define DPDMA_EIEN (0x001C >> 2)
54d3c6369aSKONRAD Frederic #define DPDMA_EIDS (0x0020 >> 2)
55d3c6369aSKONRAD Frederic #define DPDMA_CNTL (0x0100 >> 2)
56d3c6369aSKONRAD Frederic
57d3c6369aSKONRAD Frederic #define DPDMA_GBL (0x0104 >> 2)
58d3c6369aSKONRAD Frederic #define DPDMA_GBL_TRG_CH(n) (1 << n)
59d3c6369aSKONRAD Frederic #define DPDMA_GBL_RTRG_CH(n) (1 << 6 << n)
60d3c6369aSKONRAD Frederic
61d3c6369aSKONRAD Frederic #define DPDMA_ALC0_CNTL (0x0108 >> 2)
62d3c6369aSKONRAD Frederic #define DPDMA_ALC0_STATUS (0x010C >> 2)
63d3c6369aSKONRAD Frederic #define DPDMA_ALC0_MAX (0x0110 >> 2)
64d3c6369aSKONRAD Frederic #define DPDMA_ALC0_MIN (0x0114 >> 2)
65d3c6369aSKONRAD Frederic #define DPDMA_ALC0_ACC (0x0118 >> 2)
66d3c6369aSKONRAD Frederic #define DPDMA_ALC0_ACC_TRAN (0x011C >> 2)
67d3c6369aSKONRAD Frederic #define DPDMA_ALC1_CNTL (0x0120 >> 2)
68d3c6369aSKONRAD Frederic #define DPDMA_ALC1_STATUS (0x0124 >> 2)
69d3c6369aSKONRAD Frederic #define DPDMA_ALC1_MAX (0x0128 >> 2)
70d3c6369aSKONRAD Frederic #define DPDMA_ALC1_MIN (0x012C >> 2)
71d3c6369aSKONRAD Frederic #define DPDMA_ALC1_ACC (0x0130 >> 2)
72d3c6369aSKONRAD Frederic #define DPDMA_ALC1_ACC_TRAN (0x0134 >> 2)
73d3c6369aSKONRAD Frederic
74d3c6369aSKONRAD Frederic #define DPDMA_DSCR_STRT_ADDRE_CH(n) ((0x0200 + n * 0x100) >> 2)
75d3c6369aSKONRAD Frederic #define DPDMA_DSCR_STRT_ADDR_CH(n) ((0x0204 + n * 0x100) >> 2)
76d3c6369aSKONRAD Frederic #define DPDMA_DSCR_NEXT_ADDRE_CH(n) ((0x0208 + n * 0x100) >> 2)
77d3c6369aSKONRAD Frederic #define DPDMA_DSCR_NEXT_ADDR_CH(n) ((0x020C + n * 0x100) >> 2)
78d3c6369aSKONRAD Frederic #define DPDMA_PYLD_CUR_ADDRE_CH(n) ((0x0210 + n * 0x100) >> 2)
79d3c6369aSKONRAD Frederic #define DPDMA_PYLD_CUR_ADDR_CH(n) ((0x0214 + n * 0x100) >> 2)
80d3c6369aSKONRAD Frederic
81d3c6369aSKONRAD Frederic #define DPDMA_CNTL_CH(n) ((0x0218 + n * 0x100) >> 2)
82d3c6369aSKONRAD Frederic #define DPDMA_CNTL_CH_EN (1)
83d3c6369aSKONRAD Frederic #define DPDMA_CNTL_CH_PAUSED (1 << 1)
84d3c6369aSKONRAD Frederic
85d3c6369aSKONRAD Frederic #define DPDMA_STATUS_CH(n) ((0x021C + n * 0x100) >> 2)
86d3c6369aSKONRAD Frederic #define DPDMA_STATUS_BURST_TYPE (1 << 4)
87d3c6369aSKONRAD Frederic #define DPDMA_STATUS_MODE (1 << 5)
88d3c6369aSKONRAD Frederic #define DPDMA_STATUS_EN_CRC (1 << 6)
89d3c6369aSKONRAD Frederic #define DPDMA_STATUS_LAST_DSCR (1 << 7)
90d3c6369aSKONRAD Frederic #define DPDMA_STATUS_LDSCR_FRAME (1 << 8)
91d3c6369aSKONRAD Frederic #define DPDMA_STATUS_IGNR_DONE (1 << 9)
92d3c6369aSKONRAD Frederic #define DPDMA_STATUS_DSCR_DONE (1 << 10)
93d3c6369aSKONRAD Frederic #define DPDMA_STATUS_EN_DSCR_UP (1 << 11)
94d3c6369aSKONRAD Frederic #define DPDMA_STATUS_EN_DSCR_INTR (1 << 12)
95d3c6369aSKONRAD Frederic #define DPDMA_STATUS_PREAMBLE_OFF (13)
96d3c6369aSKONRAD Frederic
97d3c6369aSKONRAD Frederic #define DPDMA_VDO_CH(n) ((0x0220 + n * 0x100) >> 2)
98d3c6369aSKONRAD Frederic #define DPDMA_PYLD_SZ_CH(n) ((0x0224 + n * 0x100) >> 2)
99d3c6369aSKONRAD Frederic #define DPDMA_DSCR_ID_CH(n) ((0x0228 + n * 0x100) >> 2)
100d3c6369aSKONRAD Frederic
101d3c6369aSKONRAD Frederic /*
102d3c6369aSKONRAD Frederic * Descriptor control field.
103d3c6369aSKONRAD Frederic */
104d3c6369aSKONRAD Frederic #define CONTROL_PREAMBLE_VALUE 0xA5
105d3c6369aSKONRAD Frederic
106d3c6369aSKONRAD Frederic #define DSCR_CTRL_PREAMBLE 0xFF
107d3c6369aSKONRAD Frederic #define DSCR_CTRL_EN_DSCR_DONE_INTR (1 << 8)
108d3c6369aSKONRAD Frederic #define DSCR_CTRL_EN_DSCR_UPDATE (1 << 9)
109d3c6369aSKONRAD Frederic #define DSCR_CTRL_IGNORE_DONE (1 << 10)
110d3c6369aSKONRAD Frederic #define DSCR_CTRL_AXI_BURST_TYPE (1 << 11)
111d3c6369aSKONRAD Frederic #define DSCR_CTRL_AXCACHE (0x0F << 12)
112d3c6369aSKONRAD Frederic #define DSCR_CTRL_AXPROT (0x2 << 16)
113d3c6369aSKONRAD Frederic #define DSCR_CTRL_DESCRIPTOR_MODE (1 << 18)
114d3c6369aSKONRAD Frederic #define DSCR_CTRL_LAST_DESCRIPTOR (1 << 19)
115d3c6369aSKONRAD Frederic #define DSCR_CTRL_ENABLE_CRC (1 << 20)
116d3c6369aSKONRAD Frederic #define DSCR_CTRL_LAST_DESCRIPTOR_OF_FRAME (1 << 21)
117d3c6369aSKONRAD Frederic
118d3c6369aSKONRAD Frederic /*
119d3c6369aSKONRAD Frederic * Descriptor timestamp field.
120d3c6369aSKONRAD Frederic */
121d3c6369aSKONRAD Frederic #define STATUS_DONE (1 << 31)
122d3c6369aSKONRAD Frederic
123d3c6369aSKONRAD Frederic #define DPDMA_FRAG_MAX_SZ (4096)
124d3c6369aSKONRAD Frederic
125d3c6369aSKONRAD Frederic enum DPDMABurstType {
126d3c6369aSKONRAD Frederic DPDMA_INCR = 0,
127d3c6369aSKONRAD Frederic DPDMA_FIXED = 1
128d3c6369aSKONRAD Frederic };
129d3c6369aSKONRAD Frederic
130d3c6369aSKONRAD Frederic enum DPDMAMode {
131d3c6369aSKONRAD Frederic DPDMA_CONTIGOUS = 0,
132d3c6369aSKONRAD Frederic DPDMA_FRAGMENTED = 1
133d3c6369aSKONRAD Frederic };
134d3c6369aSKONRAD Frederic
135d3c6369aSKONRAD Frederic struct DPDMADescriptor {
136d3c6369aSKONRAD Frederic uint32_t control;
137d3c6369aSKONRAD Frederic uint32_t descriptor_id;
138d3c6369aSKONRAD Frederic /* transfer size in byte. */
139d3c6369aSKONRAD Frederic uint32_t xfer_size;
140d3c6369aSKONRAD Frederic uint32_t line_size_stride;
141d3c6369aSKONRAD Frederic uint32_t timestamp_lsb;
142d3c6369aSKONRAD Frederic uint32_t timestamp_msb;
143d3c6369aSKONRAD Frederic /* contains extension for both descriptor and source. */
144d3c6369aSKONRAD Frederic uint32_t address_extension;
145d3c6369aSKONRAD Frederic uint32_t next_descriptor;
146d3c6369aSKONRAD Frederic uint32_t source_address;
147d3c6369aSKONRAD Frederic uint32_t address_extension_23;
148d3c6369aSKONRAD Frederic uint32_t address_extension_45;
149d3c6369aSKONRAD Frederic uint32_t source_address2;
150d3c6369aSKONRAD Frederic uint32_t source_address3;
151d3c6369aSKONRAD Frederic uint32_t source_address4;
152d3c6369aSKONRAD Frederic uint32_t source_address5;
153d3c6369aSKONRAD Frederic uint32_t crc;
154d3c6369aSKONRAD Frederic };
155d3c6369aSKONRAD Frederic
156d3c6369aSKONRAD Frederic typedef enum DPDMABurstType DPDMABurstType;
157d3c6369aSKONRAD Frederic typedef enum DPDMAMode DPDMAMode;
158d3c6369aSKONRAD Frederic typedef struct DPDMADescriptor DPDMADescriptor;
159d3c6369aSKONRAD Frederic
xlnx_dpdma_desc_is_last(DPDMADescriptor * desc)160d3c6369aSKONRAD Frederic static bool xlnx_dpdma_desc_is_last(DPDMADescriptor *desc)
161d3c6369aSKONRAD Frederic {
162d3c6369aSKONRAD Frederic return ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR) != 0);
163d3c6369aSKONRAD Frederic }
164d3c6369aSKONRAD Frederic
xlnx_dpdma_desc_is_last_of_frame(DPDMADescriptor * desc)165d3c6369aSKONRAD Frederic static bool xlnx_dpdma_desc_is_last_of_frame(DPDMADescriptor *desc)
166d3c6369aSKONRAD Frederic {
167d3c6369aSKONRAD Frederic return ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR_OF_FRAME) != 0);
168d3c6369aSKONRAD Frederic }
169d3c6369aSKONRAD Frederic
xlnx_dpdma_desc_get_source_address(DPDMADescriptor * desc,uint8_t frag)170d3c6369aSKONRAD Frederic static uint64_t xlnx_dpdma_desc_get_source_address(DPDMADescriptor *desc,
171d3c6369aSKONRAD Frederic uint8_t frag)
172d3c6369aSKONRAD Frederic {
173d3c6369aSKONRAD Frederic uint64_t addr = 0;
174d3c6369aSKONRAD Frederic assert(frag < 5);
175d3c6369aSKONRAD Frederic
176d3c6369aSKONRAD Frederic switch (frag) {
177d3c6369aSKONRAD Frederic case 0:
1784b00855fSAlexandra Diupina addr = (uint64_t)desc->source_address
1794b00855fSAlexandra Diupina + (extract64(desc->address_extension, 16, 16) << 32);
180d3c6369aSKONRAD Frederic break;
181d3c6369aSKONRAD Frederic case 1:
1824b00855fSAlexandra Diupina addr = (uint64_t)desc->source_address2
1834b00855fSAlexandra Diupina + (extract64(desc->address_extension_23, 0, 16) << 32);
184d3c6369aSKONRAD Frederic break;
185d3c6369aSKONRAD Frederic case 2:
1864b00855fSAlexandra Diupina addr = (uint64_t)desc->source_address3
1874b00855fSAlexandra Diupina + (extract64(desc->address_extension_23, 16, 16) << 32);
188d3c6369aSKONRAD Frederic break;
189d3c6369aSKONRAD Frederic case 3:
1904b00855fSAlexandra Diupina addr = (uint64_t)desc->source_address4
1914b00855fSAlexandra Diupina + (extract64(desc->address_extension_45, 0, 16) << 32);
192d3c6369aSKONRAD Frederic break;
193d3c6369aSKONRAD Frederic case 4:
1944b00855fSAlexandra Diupina addr = (uint64_t)desc->source_address5
1954b00855fSAlexandra Diupina + (extract64(desc->address_extension_45, 16, 16) << 32);
196d3c6369aSKONRAD Frederic break;
197d3c6369aSKONRAD Frederic default:
198d3c6369aSKONRAD Frederic addr = 0;
199d3c6369aSKONRAD Frederic break;
200d3c6369aSKONRAD Frederic }
201d3c6369aSKONRAD Frederic
202d3c6369aSKONRAD Frederic return addr;
203d3c6369aSKONRAD Frederic }
204d3c6369aSKONRAD Frederic
xlnx_dpdma_desc_get_transfer_size(DPDMADescriptor * desc)205d3c6369aSKONRAD Frederic static uint32_t xlnx_dpdma_desc_get_transfer_size(DPDMADescriptor *desc)
206d3c6369aSKONRAD Frederic {
207d3c6369aSKONRAD Frederic return desc->xfer_size;
208d3c6369aSKONRAD Frederic }
209d3c6369aSKONRAD Frederic
xlnx_dpdma_desc_get_line_size(DPDMADescriptor * desc)210d3c6369aSKONRAD Frederic static uint32_t xlnx_dpdma_desc_get_line_size(DPDMADescriptor *desc)
211d3c6369aSKONRAD Frederic {
212d3c6369aSKONRAD Frederic return extract32(desc->line_size_stride, 0, 18);
213d3c6369aSKONRAD Frederic }
214d3c6369aSKONRAD Frederic
xlnx_dpdma_desc_get_line_stride(DPDMADescriptor * desc)215d3c6369aSKONRAD Frederic static uint32_t xlnx_dpdma_desc_get_line_stride(DPDMADescriptor *desc)
216d3c6369aSKONRAD Frederic {
217d3c6369aSKONRAD Frederic return extract32(desc->line_size_stride, 18, 14) * 16;
218d3c6369aSKONRAD Frederic }
219d3c6369aSKONRAD Frederic
xlnx_dpdma_desc_crc_enabled(DPDMADescriptor * desc)220d3c6369aSKONRAD Frederic static inline bool xlnx_dpdma_desc_crc_enabled(DPDMADescriptor *desc)
221d3c6369aSKONRAD Frederic {
222d3c6369aSKONRAD Frederic return (desc->control & DSCR_CTRL_ENABLE_CRC) != 0;
223d3c6369aSKONRAD Frederic }
224d3c6369aSKONRAD Frederic
xlnx_dpdma_desc_check_crc(DPDMADescriptor * desc)225d3c6369aSKONRAD Frederic static inline bool xlnx_dpdma_desc_check_crc(DPDMADescriptor *desc)
226d3c6369aSKONRAD Frederic {
227d3c6369aSKONRAD Frederic uint32_t *p = (uint32_t *)desc;
228d3c6369aSKONRAD Frederic uint32_t crc = 0;
229d3c6369aSKONRAD Frederic uint8_t i;
230d3c6369aSKONRAD Frederic
231d3c6369aSKONRAD Frederic /*
232d3c6369aSKONRAD Frederic * CRC is calculated on the whole descriptor except the last 32bits word
233d3c6369aSKONRAD Frederic * using 32bits addition.
234d3c6369aSKONRAD Frederic */
235d3c6369aSKONRAD Frederic for (i = 0; i < 15; i++) {
236d3c6369aSKONRAD Frederic crc += p[i];
237d3c6369aSKONRAD Frederic }
238d3c6369aSKONRAD Frederic
239d3c6369aSKONRAD Frederic return crc == desc->crc;
240d3c6369aSKONRAD Frederic }
241d3c6369aSKONRAD Frederic
xlnx_dpdma_desc_completion_interrupt(DPDMADescriptor * desc)242d3c6369aSKONRAD Frederic static inline bool xlnx_dpdma_desc_completion_interrupt(DPDMADescriptor *desc)
243d3c6369aSKONRAD Frederic {
244d3c6369aSKONRAD Frederic return (desc->control & DSCR_CTRL_EN_DSCR_DONE_INTR) != 0;
245d3c6369aSKONRAD Frederic }
246d3c6369aSKONRAD Frederic
xlnx_dpdma_desc_is_valid(DPDMADescriptor * desc)247d3c6369aSKONRAD Frederic static inline bool xlnx_dpdma_desc_is_valid(DPDMADescriptor *desc)
248d3c6369aSKONRAD Frederic {
249d3c6369aSKONRAD Frederic return (desc->control & DSCR_CTRL_PREAMBLE) == CONTROL_PREAMBLE_VALUE;
250d3c6369aSKONRAD Frederic }
251d3c6369aSKONRAD Frederic
xlnx_dpdma_desc_is_contiguous(DPDMADescriptor * desc)252d3c6369aSKONRAD Frederic static inline bool xlnx_dpdma_desc_is_contiguous(DPDMADescriptor *desc)
253d3c6369aSKONRAD Frederic {
254d3c6369aSKONRAD Frederic return (desc->control & DSCR_CTRL_DESCRIPTOR_MODE) == 0;
255d3c6369aSKONRAD Frederic }
256d3c6369aSKONRAD Frederic
xlnx_dpdma_desc_update_enabled(DPDMADescriptor * desc)257d3c6369aSKONRAD Frederic static inline bool xlnx_dpdma_desc_update_enabled(DPDMADescriptor *desc)
258d3c6369aSKONRAD Frederic {
259d3c6369aSKONRAD Frederic return (desc->control & DSCR_CTRL_EN_DSCR_UPDATE) != 0;
260d3c6369aSKONRAD Frederic }
261d3c6369aSKONRAD Frederic
xlnx_dpdma_desc_set_done(DPDMADescriptor * desc)262d3c6369aSKONRAD Frederic static inline void xlnx_dpdma_desc_set_done(DPDMADescriptor *desc)
263d3c6369aSKONRAD Frederic {
264d3c6369aSKONRAD Frederic desc->timestamp_msb |= STATUS_DONE;
265d3c6369aSKONRAD Frederic }
266d3c6369aSKONRAD Frederic
xlnx_dpdma_desc_is_already_done(DPDMADescriptor * desc)267d3c6369aSKONRAD Frederic static inline bool xlnx_dpdma_desc_is_already_done(DPDMADescriptor *desc)
268d3c6369aSKONRAD Frederic {
269d3c6369aSKONRAD Frederic return (desc->timestamp_msb & STATUS_DONE) != 0;
270d3c6369aSKONRAD Frederic }
271d3c6369aSKONRAD Frederic
xlnx_dpdma_desc_ignore_done_bit(DPDMADescriptor * desc)272d3c6369aSKONRAD Frederic static inline bool xlnx_dpdma_desc_ignore_done_bit(DPDMADescriptor *desc)
273d3c6369aSKONRAD Frederic {
274d3c6369aSKONRAD Frederic return (desc->control & DSCR_CTRL_IGNORE_DONE) != 0;
275d3c6369aSKONRAD Frederic }
276d3c6369aSKONRAD Frederic
277d3c6369aSKONRAD Frederic static const VMStateDescription vmstate_xlnx_dpdma = {
278d3c6369aSKONRAD Frederic .name = TYPE_XLNX_DPDMA,
279d3c6369aSKONRAD Frederic .version_id = 1,
28063e6b564SRichard Henderson .fields = (const VMStateField[]) {
281d3c6369aSKONRAD Frederic VMSTATE_UINT32_ARRAY(registers, XlnxDPDMAState,
282d3c6369aSKONRAD Frederic XLNX_DPDMA_REG_ARRAY_SIZE),
283d3c6369aSKONRAD Frederic VMSTATE_BOOL_ARRAY(operation_finished, XlnxDPDMAState, 6),
284d3c6369aSKONRAD Frederic VMSTATE_END_OF_LIST()
285d3c6369aSKONRAD Frederic }
286d3c6369aSKONRAD Frederic };
287d3c6369aSKONRAD Frederic
xlnx_dpdma_update_irq(XlnxDPDMAState * s)288d3c6369aSKONRAD Frederic static void xlnx_dpdma_update_irq(XlnxDPDMAState *s)
289d3c6369aSKONRAD Frederic {
290d3c6369aSKONRAD Frederic bool flags;
291d3c6369aSKONRAD Frederic
292d3c6369aSKONRAD Frederic flags = ((s->registers[DPDMA_ISR] & (~s->registers[DPDMA_IMR]))
293d3c6369aSKONRAD Frederic || (s->registers[DPDMA_EISR] & (~s->registers[DPDMA_EIMR])));
294d3c6369aSKONRAD Frederic qemu_set_irq(s->irq, flags);
295d3c6369aSKONRAD Frederic }
296d3c6369aSKONRAD Frederic
xlnx_dpdma_descriptor_start_address(XlnxDPDMAState * s,uint8_t channel)297d3c6369aSKONRAD Frederic static uint64_t xlnx_dpdma_descriptor_start_address(XlnxDPDMAState *s,
298d3c6369aSKONRAD Frederic uint8_t channel)
299d3c6369aSKONRAD Frederic {
300d3c6369aSKONRAD Frederic return (s->registers[DPDMA_DSCR_STRT_ADDRE_CH(channel)] << 16)
301d3c6369aSKONRAD Frederic + s->registers[DPDMA_DSCR_STRT_ADDR_CH(channel)];
302d3c6369aSKONRAD Frederic }
303d3c6369aSKONRAD Frederic
xlnx_dpdma_descriptor_next_address(XlnxDPDMAState * s,uint8_t channel)304d3c6369aSKONRAD Frederic static uint64_t xlnx_dpdma_descriptor_next_address(XlnxDPDMAState *s,
305d3c6369aSKONRAD Frederic uint8_t channel)
306d3c6369aSKONRAD Frederic {
307d3c6369aSKONRAD Frederic return ((uint64_t)s->registers[DPDMA_DSCR_NEXT_ADDRE_CH(channel)] << 32)
308d3c6369aSKONRAD Frederic + s->registers[DPDMA_DSCR_NEXT_ADDR_CH(channel)];
309d3c6369aSKONRAD Frederic }
310d3c6369aSKONRAD Frederic
xlnx_dpdma_is_channel_enabled(XlnxDPDMAState * s,uint8_t channel)311d3c6369aSKONRAD Frederic static bool xlnx_dpdma_is_channel_enabled(XlnxDPDMAState *s,
312d3c6369aSKONRAD Frederic uint8_t channel)
313d3c6369aSKONRAD Frederic {
314d3c6369aSKONRAD Frederic return (s->registers[DPDMA_CNTL_CH(channel)] & DPDMA_CNTL_CH_EN) != 0;
315d3c6369aSKONRAD Frederic }
316d3c6369aSKONRAD Frederic
xlnx_dpdma_is_channel_paused(XlnxDPDMAState * s,uint8_t channel)317d3c6369aSKONRAD Frederic static bool xlnx_dpdma_is_channel_paused(XlnxDPDMAState *s,
318d3c6369aSKONRAD Frederic uint8_t channel)
319d3c6369aSKONRAD Frederic {
320d3c6369aSKONRAD Frederic return (s->registers[DPDMA_CNTL_CH(channel)] & DPDMA_CNTL_CH_PAUSED) != 0;
321d3c6369aSKONRAD Frederic }
322d3c6369aSKONRAD Frederic
xlnx_dpdma_is_channel_retriggered(XlnxDPDMAState * s,uint8_t channel)323d3c6369aSKONRAD Frederic static inline bool xlnx_dpdma_is_channel_retriggered(XlnxDPDMAState *s,
324d3c6369aSKONRAD Frederic uint8_t channel)
325d3c6369aSKONRAD Frederic {
326d3c6369aSKONRAD Frederic /* Clear the retriggered bit after reading it. */
327d3c6369aSKONRAD Frederic bool channel_is_retriggered = s->registers[DPDMA_GBL]
328d3c6369aSKONRAD Frederic & DPDMA_GBL_RTRG_CH(channel);
329d3c6369aSKONRAD Frederic s->registers[DPDMA_GBL] &= ~DPDMA_GBL_RTRG_CH(channel);
330d3c6369aSKONRAD Frederic return channel_is_retriggered;
331d3c6369aSKONRAD Frederic }
332d3c6369aSKONRAD Frederic
xlnx_dpdma_is_channel_triggered(XlnxDPDMAState * s,uint8_t channel)333d3c6369aSKONRAD Frederic static inline bool xlnx_dpdma_is_channel_triggered(XlnxDPDMAState *s,
334d3c6369aSKONRAD Frederic uint8_t channel)
335d3c6369aSKONRAD Frederic {
336d3c6369aSKONRAD Frederic return s->registers[DPDMA_GBL] & DPDMA_GBL_TRG_CH(channel);
337d3c6369aSKONRAD Frederic }
338d3c6369aSKONRAD Frederic
xlnx_dpdma_update_desc_info(XlnxDPDMAState * s,uint8_t channel,DPDMADescriptor * desc)339d3c6369aSKONRAD Frederic static void xlnx_dpdma_update_desc_info(XlnxDPDMAState *s, uint8_t channel,
340d3c6369aSKONRAD Frederic DPDMADescriptor *desc)
341d3c6369aSKONRAD Frederic {
342d3c6369aSKONRAD Frederic s->registers[DPDMA_DSCR_NEXT_ADDRE_CH(channel)] =
343d3c6369aSKONRAD Frederic extract32(desc->address_extension, 0, 16);
344d3c6369aSKONRAD Frederic s->registers[DPDMA_DSCR_NEXT_ADDR_CH(channel)] = desc->next_descriptor;
345d3c6369aSKONRAD Frederic s->registers[DPDMA_PYLD_CUR_ADDRE_CH(channel)] =
346d3c6369aSKONRAD Frederic extract32(desc->address_extension, 16, 16);
347d3c6369aSKONRAD Frederic s->registers[DPDMA_PYLD_CUR_ADDR_CH(channel)] = desc->source_address;
348d3c6369aSKONRAD Frederic s->registers[DPDMA_VDO_CH(channel)] =
349d3c6369aSKONRAD Frederic extract32(desc->line_size_stride, 18, 14)
350d3c6369aSKONRAD Frederic + (extract32(desc->line_size_stride, 0, 18)
351d3c6369aSKONRAD Frederic << 14);
352d3c6369aSKONRAD Frederic s->registers[DPDMA_PYLD_SZ_CH(channel)] = desc->xfer_size;
353d3c6369aSKONRAD Frederic s->registers[DPDMA_DSCR_ID_CH(channel)] = desc->descriptor_id;
354d3c6369aSKONRAD Frederic
355d3c6369aSKONRAD Frederic /* Compute the status register with the descriptor information. */
356d3c6369aSKONRAD Frederic s->registers[DPDMA_STATUS_CH(channel)] =
357d3c6369aSKONRAD Frederic extract32(desc->control, 0, 8) << 13;
358d3c6369aSKONRAD Frederic if ((desc->control & DSCR_CTRL_EN_DSCR_DONE_INTR) != 0) {
359d3c6369aSKONRAD Frederic s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_EN_DSCR_INTR;
360d3c6369aSKONRAD Frederic }
361d3c6369aSKONRAD Frederic if ((desc->control & DSCR_CTRL_EN_DSCR_UPDATE) != 0) {
362d3c6369aSKONRAD Frederic s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_EN_DSCR_UP;
363d3c6369aSKONRAD Frederic }
364d3c6369aSKONRAD Frederic if ((desc->timestamp_msb & STATUS_DONE) != 0) {
365d3c6369aSKONRAD Frederic s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_DSCR_DONE;
366d3c6369aSKONRAD Frederic }
367d3c6369aSKONRAD Frederic if ((desc->control & DSCR_CTRL_IGNORE_DONE) != 0) {
368d3c6369aSKONRAD Frederic s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_IGNR_DONE;
369d3c6369aSKONRAD Frederic }
370d3c6369aSKONRAD Frederic if ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR_OF_FRAME) != 0) {
371d3c6369aSKONRAD Frederic s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_LDSCR_FRAME;
372d3c6369aSKONRAD Frederic }
373d3c6369aSKONRAD Frederic if ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR) != 0) {
374d3c6369aSKONRAD Frederic s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_LAST_DSCR;
375d3c6369aSKONRAD Frederic }
376d3c6369aSKONRAD Frederic if ((desc->control & DSCR_CTRL_ENABLE_CRC) != 0) {
377d3c6369aSKONRAD Frederic s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_EN_CRC;
378d3c6369aSKONRAD Frederic }
379d3c6369aSKONRAD Frederic if ((desc->control & DSCR_CTRL_DESCRIPTOR_MODE) != 0) {
380d3c6369aSKONRAD Frederic s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_MODE;
381d3c6369aSKONRAD Frederic }
382d3c6369aSKONRAD Frederic if ((desc->control & DSCR_CTRL_AXI_BURST_TYPE) != 0) {
383d3c6369aSKONRAD Frederic s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_BURST_TYPE;
384d3c6369aSKONRAD Frederic }
385d3c6369aSKONRAD Frederic }
386d3c6369aSKONRAD Frederic
xlnx_dpdma_dump_descriptor(DPDMADescriptor * desc)387d3c6369aSKONRAD Frederic static void xlnx_dpdma_dump_descriptor(DPDMADescriptor *desc)
388d3c6369aSKONRAD Frederic {
389d3c6369aSKONRAD Frederic if (DEBUG_DPDMA) {
390d3c6369aSKONRAD Frederic qemu_log("DUMP DESCRIPTOR:\n");
391b42581f5SPhilippe Mathieu-Daudé qemu_hexdump(stdout, "", desc, sizeof(DPDMADescriptor));
392d3c6369aSKONRAD Frederic }
393d3c6369aSKONRAD Frederic }
394d3c6369aSKONRAD Frederic
xlnx_dpdma_read(void * opaque,hwaddr offset,unsigned size)395d3c6369aSKONRAD Frederic static uint64_t xlnx_dpdma_read(void *opaque, hwaddr offset,
396d3c6369aSKONRAD Frederic unsigned size)
397d3c6369aSKONRAD Frederic {
398d3c6369aSKONRAD Frederic XlnxDPDMAState *s = XLNX_DPDMA(opaque);
399d3c6369aSKONRAD Frederic
400d3c6369aSKONRAD Frederic DPRINTF("read @%" HWADDR_PRIx "\n", offset);
401d3c6369aSKONRAD Frederic offset = offset >> 2;
402d3c6369aSKONRAD Frederic
403d3c6369aSKONRAD Frederic switch (offset) {
404d3c6369aSKONRAD Frederic /*
405d3c6369aSKONRAD Frederic * Trying to read a write only register.
406d3c6369aSKONRAD Frederic */
407d3c6369aSKONRAD Frederic case DPDMA_GBL:
408d3c6369aSKONRAD Frederic return 0;
409d3c6369aSKONRAD Frederic default:
410d3c6369aSKONRAD Frederic assert(offset <= (0xFFC >> 2));
411d3c6369aSKONRAD Frederic return s->registers[offset];
412d3c6369aSKONRAD Frederic }
413d3c6369aSKONRAD Frederic return 0;
414d3c6369aSKONRAD Frederic }
415d3c6369aSKONRAD Frederic
xlnx_dpdma_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)416d3c6369aSKONRAD Frederic static void xlnx_dpdma_write(void *opaque, hwaddr offset,
417d3c6369aSKONRAD Frederic uint64_t value, unsigned size)
418d3c6369aSKONRAD Frederic {
419d3c6369aSKONRAD Frederic XlnxDPDMAState *s = XLNX_DPDMA(opaque);
420d3c6369aSKONRAD Frederic
421d3c6369aSKONRAD Frederic DPRINTF("write @%" HWADDR_PRIx " = %" PRIx64 "\n", offset, value);
422d3c6369aSKONRAD Frederic offset = offset >> 2;
423d3c6369aSKONRAD Frederic
424d3c6369aSKONRAD Frederic switch (offset) {
425d3c6369aSKONRAD Frederic case DPDMA_ISR:
426d3c6369aSKONRAD Frederic s->registers[DPDMA_ISR] &= ~value;
427d3c6369aSKONRAD Frederic xlnx_dpdma_update_irq(s);
428d3c6369aSKONRAD Frederic break;
429d3c6369aSKONRAD Frederic case DPDMA_IEN:
430d3c6369aSKONRAD Frederic s->registers[DPDMA_IMR] &= ~value;
431d3c6369aSKONRAD Frederic break;
432d3c6369aSKONRAD Frederic case DPDMA_IDS:
433d3c6369aSKONRAD Frederic s->registers[DPDMA_IMR] |= value;
434d3c6369aSKONRAD Frederic break;
435d3c6369aSKONRAD Frederic case DPDMA_EISR:
436d3c6369aSKONRAD Frederic s->registers[DPDMA_EISR] &= ~value;
437d3c6369aSKONRAD Frederic xlnx_dpdma_update_irq(s);
438d3c6369aSKONRAD Frederic break;
439d3c6369aSKONRAD Frederic case DPDMA_EIEN:
440d3c6369aSKONRAD Frederic s->registers[DPDMA_EIMR] &= ~value;
441d3c6369aSKONRAD Frederic break;
442d3c6369aSKONRAD Frederic case DPDMA_EIDS:
443d3c6369aSKONRAD Frederic s->registers[DPDMA_EIMR] |= value;
444d3c6369aSKONRAD Frederic break;
445d3c6369aSKONRAD Frederic case DPDMA_IMR:
446d3c6369aSKONRAD Frederic case DPDMA_EIMR:
447d3c6369aSKONRAD Frederic case DPDMA_DSCR_NEXT_ADDRE_CH(0):
448d3c6369aSKONRAD Frederic case DPDMA_DSCR_NEXT_ADDRE_CH(1):
449d3c6369aSKONRAD Frederic case DPDMA_DSCR_NEXT_ADDRE_CH(2):
450d3c6369aSKONRAD Frederic case DPDMA_DSCR_NEXT_ADDRE_CH(3):
451d3c6369aSKONRAD Frederic case DPDMA_DSCR_NEXT_ADDRE_CH(4):
452d3c6369aSKONRAD Frederic case DPDMA_DSCR_NEXT_ADDRE_CH(5):
453d3c6369aSKONRAD Frederic case DPDMA_DSCR_NEXT_ADDR_CH(0):
454d3c6369aSKONRAD Frederic case DPDMA_DSCR_NEXT_ADDR_CH(1):
455d3c6369aSKONRAD Frederic case DPDMA_DSCR_NEXT_ADDR_CH(2):
456d3c6369aSKONRAD Frederic case DPDMA_DSCR_NEXT_ADDR_CH(3):
457d3c6369aSKONRAD Frederic case DPDMA_DSCR_NEXT_ADDR_CH(4):
458d3c6369aSKONRAD Frederic case DPDMA_DSCR_NEXT_ADDR_CH(5):
459d3c6369aSKONRAD Frederic case DPDMA_PYLD_CUR_ADDRE_CH(0):
460d3c6369aSKONRAD Frederic case DPDMA_PYLD_CUR_ADDRE_CH(1):
461d3c6369aSKONRAD Frederic case DPDMA_PYLD_CUR_ADDRE_CH(2):
462d3c6369aSKONRAD Frederic case DPDMA_PYLD_CUR_ADDRE_CH(3):
463d3c6369aSKONRAD Frederic case DPDMA_PYLD_CUR_ADDRE_CH(4):
464d3c6369aSKONRAD Frederic case DPDMA_PYLD_CUR_ADDRE_CH(5):
465d3c6369aSKONRAD Frederic case DPDMA_PYLD_CUR_ADDR_CH(0):
466d3c6369aSKONRAD Frederic case DPDMA_PYLD_CUR_ADDR_CH(1):
467d3c6369aSKONRAD Frederic case DPDMA_PYLD_CUR_ADDR_CH(2):
468d3c6369aSKONRAD Frederic case DPDMA_PYLD_CUR_ADDR_CH(3):
469d3c6369aSKONRAD Frederic case DPDMA_PYLD_CUR_ADDR_CH(4):
470d3c6369aSKONRAD Frederic case DPDMA_PYLD_CUR_ADDR_CH(5):
471d3c6369aSKONRAD Frederic case DPDMA_STATUS_CH(0):
472d3c6369aSKONRAD Frederic case DPDMA_STATUS_CH(1):
473d3c6369aSKONRAD Frederic case DPDMA_STATUS_CH(2):
474d3c6369aSKONRAD Frederic case DPDMA_STATUS_CH(3):
475d3c6369aSKONRAD Frederic case DPDMA_STATUS_CH(4):
476d3c6369aSKONRAD Frederic case DPDMA_STATUS_CH(5):
477d3c6369aSKONRAD Frederic case DPDMA_VDO_CH(0):
478d3c6369aSKONRAD Frederic case DPDMA_VDO_CH(1):
479d3c6369aSKONRAD Frederic case DPDMA_VDO_CH(2):
480d3c6369aSKONRAD Frederic case DPDMA_VDO_CH(3):
481d3c6369aSKONRAD Frederic case DPDMA_VDO_CH(4):
482d3c6369aSKONRAD Frederic case DPDMA_VDO_CH(5):
483d3c6369aSKONRAD Frederic case DPDMA_PYLD_SZ_CH(0):
484d3c6369aSKONRAD Frederic case DPDMA_PYLD_SZ_CH(1):
485d3c6369aSKONRAD Frederic case DPDMA_PYLD_SZ_CH(2):
486d3c6369aSKONRAD Frederic case DPDMA_PYLD_SZ_CH(3):
487d3c6369aSKONRAD Frederic case DPDMA_PYLD_SZ_CH(4):
488d3c6369aSKONRAD Frederic case DPDMA_PYLD_SZ_CH(5):
489d3c6369aSKONRAD Frederic case DPDMA_DSCR_ID_CH(0):
490d3c6369aSKONRAD Frederic case DPDMA_DSCR_ID_CH(1):
491d3c6369aSKONRAD Frederic case DPDMA_DSCR_ID_CH(2):
492d3c6369aSKONRAD Frederic case DPDMA_DSCR_ID_CH(3):
493d3c6369aSKONRAD Frederic case DPDMA_DSCR_ID_CH(4):
494d3c6369aSKONRAD Frederic case DPDMA_DSCR_ID_CH(5):
495d3c6369aSKONRAD Frederic /*
496d3c6369aSKONRAD Frederic * Trying to write to a read only register..
497d3c6369aSKONRAD Frederic */
498d3c6369aSKONRAD Frederic break;
499d3c6369aSKONRAD Frederic case DPDMA_GBL:
500d3c6369aSKONRAD Frederic /*
501d3c6369aSKONRAD Frederic * This is a write only register so it's read as zero in the read
502d3c6369aSKONRAD Frederic * callback.
503d3c6369aSKONRAD Frederic * We store the value anyway so we can know if the channel is
504d3c6369aSKONRAD Frederic * enabled.
505d3c6369aSKONRAD Frederic */
506d3c6369aSKONRAD Frederic s->registers[offset] |= value & 0x00000FFF;
507d3c6369aSKONRAD Frederic break;
508d3c6369aSKONRAD Frederic case DPDMA_DSCR_STRT_ADDRE_CH(0):
509d3c6369aSKONRAD Frederic case DPDMA_DSCR_STRT_ADDRE_CH(1):
510d3c6369aSKONRAD Frederic case DPDMA_DSCR_STRT_ADDRE_CH(2):
511d3c6369aSKONRAD Frederic case DPDMA_DSCR_STRT_ADDRE_CH(3):
512d3c6369aSKONRAD Frederic case DPDMA_DSCR_STRT_ADDRE_CH(4):
513d3c6369aSKONRAD Frederic case DPDMA_DSCR_STRT_ADDRE_CH(5):
514d3c6369aSKONRAD Frederic value &= 0x0000FFFF;
515d3c6369aSKONRAD Frederic s->registers[offset] = value;
516d3c6369aSKONRAD Frederic break;
517d3c6369aSKONRAD Frederic case DPDMA_CNTL_CH(0):
518d3c6369aSKONRAD Frederic s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(0);
519d3c6369aSKONRAD Frederic value &= 0x3FFFFFFF;
520d3c6369aSKONRAD Frederic s->registers[offset] = value;
521d3c6369aSKONRAD Frederic break;
522d3c6369aSKONRAD Frederic case DPDMA_CNTL_CH(1):
523d3c6369aSKONRAD Frederic s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(1);
524d3c6369aSKONRAD Frederic value &= 0x3FFFFFFF;
525d3c6369aSKONRAD Frederic s->registers[offset] = value;
526d3c6369aSKONRAD Frederic break;
527d3c6369aSKONRAD Frederic case DPDMA_CNTL_CH(2):
528d3c6369aSKONRAD Frederic s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(2);
529d3c6369aSKONRAD Frederic value &= 0x3FFFFFFF;
530d3c6369aSKONRAD Frederic s->registers[offset] = value;
531d3c6369aSKONRAD Frederic break;
532d3c6369aSKONRAD Frederic case DPDMA_CNTL_CH(3):
533d3c6369aSKONRAD Frederic s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(3);
534d3c6369aSKONRAD Frederic value &= 0x3FFFFFFF;
535d3c6369aSKONRAD Frederic s->registers[offset] = value;
536d3c6369aSKONRAD Frederic break;
537d3c6369aSKONRAD Frederic case DPDMA_CNTL_CH(4):
538d3c6369aSKONRAD Frederic s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(4);
539d3c6369aSKONRAD Frederic value &= 0x3FFFFFFF;
540d3c6369aSKONRAD Frederic s->registers[offset] = value;
541d3c6369aSKONRAD Frederic break;
542d3c6369aSKONRAD Frederic case DPDMA_CNTL_CH(5):
543d3c6369aSKONRAD Frederic s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(5);
544d3c6369aSKONRAD Frederic value &= 0x3FFFFFFF;
545d3c6369aSKONRAD Frederic s->registers[offset] = value;
546d3c6369aSKONRAD Frederic break;
547d3c6369aSKONRAD Frederic default:
548d3c6369aSKONRAD Frederic assert(offset <= (0xFFC >> 2));
549d3c6369aSKONRAD Frederic s->registers[offset] = value;
550d3c6369aSKONRAD Frederic break;
551d3c6369aSKONRAD Frederic }
552d3c6369aSKONRAD Frederic }
553d3c6369aSKONRAD Frederic
554d3c6369aSKONRAD Frederic static const MemoryRegionOps dma_ops = {
555d3c6369aSKONRAD Frederic .read = xlnx_dpdma_read,
556d3c6369aSKONRAD Frederic .write = xlnx_dpdma_write,
557d3c6369aSKONRAD Frederic .endianness = DEVICE_NATIVE_ENDIAN,
558d3c6369aSKONRAD Frederic .valid = {
559d3c6369aSKONRAD Frederic .min_access_size = 4,
560d3c6369aSKONRAD Frederic .max_access_size = 4,
561d3c6369aSKONRAD Frederic },
562d3c6369aSKONRAD Frederic .impl = {
563d3c6369aSKONRAD Frederic .min_access_size = 4,
564d3c6369aSKONRAD Frederic .max_access_size = 4,
565d3c6369aSKONRAD Frederic },
566d3c6369aSKONRAD Frederic };
567d3c6369aSKONRAD Frederic
xlnx_dpdma_init(Object * obj)568d3c6369aSKONRAD Frederic static void xlnx_dpdma_init(Object *obj)
569d3c6369aSKONRAD Frederic {
570d3c6369aSKONRAD Frederic SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
571d3c6369aSKONRAD Frederic XlnxDPDMAState *s = XLNX_DPDMA(obj);
572d3c6369aSKONRAD Frederic
573d3c6369aSKONRAD Frederic memory_region_init_io(&s->iomem, obj, &dma_ops, s,
574d3c6369aSKONRAD Frederic TYPE_XLNX_DPDMA, 0x1000);
575d3c6369aSKONRAD Frederic sysbus_init_mmio(sbd, &s->iomem);
576d3c6369aSKONRAD Frederic sysbus_init_irq(sbd, &s->irq);
577d3c6369aSKONRAD Frederic }
578d3c6369aSKONRAD Frederic
xlnx_dpdma_reset(DeviceState * dev)579d3c6369aSKONRAD Frederic static void xlnx_dpdma_reset(DeviceState *dev)
580d3c6369aSKONRAD Frederic {
581d3c6369aSKONRAD Frederic XlnxDPDMAState *s = XLNX_DPDMA(dev);
582d3c6369aSKONRAD Frederic size_t i;
583d3c6369aSKONRAD Frederic
584d3c6369aSKONRAD Frederic memset(s->registers, 0, sizeof(s->registers));
585d3c6369aSKONRAD Frederic s->registers[DPDMA_IMR] = 0x07FFFFFF;
586d3c6369aSKONRAD Frederic s->registers[DPDMA_EIMR] = 0xFFFFFFFF;
587d3c6369aSKONRAD Frederic s->registers[DPDMA_ALC0_MIN] = 0x0000FFFF;
588d3c6369aSKONRAD Frederic s->registers[DPDMA_ALC1_MIN] = 0x0000FFFF;
589d3c6369aSKONRAD Frederic
590d3c6369aSKONRAD Frederic for (i = 0; i < 6; i++) {
591d3c6369aSKONRAD Frederic s->data[i] = NULL;
592d3c6369aSKONRAD Frederic s->operation_finished[i] = true;
593d3c6369aSKONRAD Frederic }
594d3c6369aSKONRAD Frederic }
595d3c6369aSKONRAD Frederic
xlnx_dpdma_class_init(ObjectClass * oc,void * data)596d3c6369aSKONRAD Frederic static void xlnx_dpdma_class_init(ObjectClass *oc, void *data)
597d3c6369aSKONRAD Frederic {
598d3c6369aSKONRAD Frederic DeviceClass *dc = DEVICE_CLASS(oc);
599d3c6369aSKONRAD Frederic
600d3c6369aSKONRAD Frederic dc->vmsd = &vmstate_xlnx_dpdma;
601*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, xlnx_dpdma_reset);
602d3c6369aSKONRAD Frederic }
603d3c6369aSKONRAD Frederic
604d3c6369aSKONRAD Frederic static const TypeInfo xlnx_dpdma_info = {
605d3c6369aSKONRAD Frederic .name = TYPE_XLNX_DPDMA,
606d3c6369aSKONRAD Frederic .parent = TYPE_SYS_BUS_DEVICE,
607d3c6369aSKONRAD Frederic .instance_size = sizeof(XlnxDPDMAState),
608d3c6369aSKONRAD Frederic .instance_init = xlnx_dpdma_init,
609d3c6369aSKONRAD Frederic .class_init = xlnx_dpdma_class_init,
610d3c6369aSKONRAD Frederic };
611d3c6369aSKONRAD Frederic
xlnx_dpdma_register_types(void)612d3c6369aSKONRAD Frederic static void xlnx_dpdma_register_types(void)
613d3c6369aSKONRAD Frederic {
614d3c6369aSKONRAD Frederic type_register_static(&xlnx_dpdma_info);
615d3c6369aSKONRAD Frederic }
616d3c6369aSKONRAD Frederic
xlnx_dpdma_read_descriptor(XlnxDPDMAState * s,uint64_t desc_addr,DPDMADescriptor * desc)617fdf02976SAlexandra Diupina static MemTxResult xlnx_dpdma_read_descriptor(XlnxDPDMAState *s,
618fdf02976SAlexandra Diupina uint64_t desc_addr,
619fdf02976SAlexandra Diupina DPDMADescriptor *desc)
620fdf02976SAlexandra Diupina {
621fdf02976SAlexandra Diupina MemTxResult res = dma_memory_read(&address_space_memory, desc_addr,
622a7d8244bSPeter Maydell desc, sizeof(DPDMADescriptor),
623fdf02976SAlexandra Diupina MEMTXATTRS_UNSPECIFIED);
624fdf02976SAlexandra Diupina if (res) {
625fdf02976SAlexandra Diupina return res;
626fdf02976SAlexandra Diupina }
627fdf02976SAlexandra Diupina
628fdf02976SAlexandra Diupina /* Convert from LE into host endianness. */
629fdf02976SAlexandra Diupina desc->control = le32_to_cpu(desc->control);
630fdf02976SAlexandra Diupina desc->descriptor_id = le32_to_cpu(desc->descriptor_id);
631fdf02976SAlexandra Diupina desc->xfer_size = le32_to_cpu(desc->xfer_size);
632fdf02976SAlexandra Diupina desc->line_size_stride = le32_to_cpu(desc->line_size_stride);
633fdf02976SAlexandra Diupina desc->timestamp_lsb = le32_to_cpu(desc->timestamp_lsb);
634fdf02976SAlexandra Diupina desc->timestamp_msb = le32_to_cpu(desc->timestamp_msb);
635fdf02976SAlexandra Diupina desc->address_extension = le32_to_cpu(desc->address_extension);
636fdf02976SAlexandra Diupina desc->next_descriptor = le32_to_cpu(desc->next_descriptor);
637fdf02976SAlexandra Diupina desc->source_address = le32_to_cpu(desc->source_address);
638fdf02976SAlexandra Diupina desc->address_extension_23 = le32_to_cpu(desc->address_extension_23);
639fdf02976SAlexandra Diupina desc->address_extension_45 = le32_to_cpu(desc->address_extension_45);
640fdf02976SAlexandra Diupina desc->source_address2 = le32_to_cpu(desc->source_address2);
641fdf02976SAlexandra Diupina desc->source_address3 = le32_to_cpu(desc->source_address3);
642fdf02976SAlexandra Diupina desc->source_address4 = le32_to_cpu(desc->source_address4);
643fdf02976SAlexandra Diupina desc->source_address5 = le32_to_cpu(desc->source_address5);
644fdf02976SAlexandra Diupina desc->crc = le32_to_cpu(desc->crc);
645fdf02976SAlexandra Diupina
646fdf02976SAlexandra Diupina return res;
647fdf02976SAlexandra Diupina }
648fdf02976SAlexandra Diupina
xlnx_dpdma_write_descriptor(uint64_t desc_addr,DPDMADescriptor * desc)649fdf02976SAlexandra Diupina static MemTxResult xlnx_dpdma_write_descriptor(uint64_t desc_addr,
650fdf02976SAlexandra Diupina DPDMADescriptor *desc)
651fdf02976SAlexandra Diupina {
652fdf02976SAlexandra Diupina DPDMADescriptor tmp_desc = *desc;
653fdf02976SAlexandra Diupina
654fdf02976SAlexandra Diupina /* Convert from host endianness into LE. */
655fdf02976SAlexandra Diupina tmp_desc.control = cpu_to_le32(tmp_desc.control);
656fdf02976SAlexandra Diupina tmp_desc.descriptor_id = cpu_to_le32(tmp_desc.descriptor_id);
657fdf02976SAlexandra Diupina tmp_desc.xfer_size = cpu_to_le32(tmp_desc.xfer_size);
658fdf02976SAlexandra Diupina tmp_desc.line_size_stride = cpu_to_le32(tmp_desc.line_size_stride);
659fdf02976SAlexandra Diupina tmp_desc.timestamp_lsb = cpu_to_le32(tmp_desc.timestamp_lsb);
660fdf02976SAlexandra Diupina tmp_desc.timestamp_msb = cpu_to_le32(tmp_desc.timestamp_msb);
661fdf02976SAlexandra Diupina tmp_desc.address_extension = cpu_to_le32(tmp_desc.address_extension);
662fdf02976SAlexandra Diupina tmp_desc.next_descriptor = cpu_to_le32(tmp_desc.next_descriptor);
663fdf02976SAlexandra Diupina tmp_desc.source_address = cpu_to_le32(tmp_desc.source_address);
664fdf02976SAlexandra Diupina tmp_desc.address_extension_23 = cpu_to_le32(tmp_desc.address_extension_23);
665fdf02976SAlexandra Diupina tmp_desc.address_extension_45 = cpu_to_le32(tmp_desc.address_extension_45);
666fdf02976SAlexandra Diupina tmp_desc.source_address2 = cpu_to_le32(tmp_desc.source_address2);
667fdf02976SAlexandra Diupina tmp_desc.source_address3 = cpu_to_le32(tmp_desc.source_address3);
668fdf02976SAlexandra Diupina tmp_desc.source_address4 = cpu_to_le32(tmp_desc.source_address4);
669fdf02976SAlexandra Diupina tmp_desc.source_address5 = cpu_to_le32(tmp_desc.source_address5);
670fdf02976SAlexandra Diupina tmp_desc.crc = cpu_to_le32(tmp_desc.crc);
671fdf02976SAlexandra Diupina
672fdf02976SAlexandra Diupina return dma_memory_write(&address_space_memory, desc_addr, &tmp_desc,
673fdf02976SAlexandra Diupina sizeof(DPDMADescriptor), MEMTXATTRS_UNSPECIFIED);
674fdf02976SAlexandra Diupina }
675fdf02976SAlexandra Diupina
xlnx_dpdma_start_operation(XlnxDPDMAState * s,uint8_t channel,bool one_desc)676d3c6369aSKONRAD Frederic size_t xlnx_dpdma_start_operation(XlnxDPDMAState *s, uint8_t channel,
677d3c6369aSKONRAD Frederic bool one_desc)
678d3c6369aSKONRAD Frederic {
679d3c6369aSKONRAD Frederic uint64_t desc_addr;
680d3c6369aSKONRAD Frederic uint64_t source_addr[6];
681d3c6369aSKONRAD Frederic DPDMADescriptor desc;
682d3c6369aSKONRAD Frederic bool done = false;
683d3c6369aSKONRAD Frederic size_t ptr = 0;
684d3c6369aSKONRAD Frederic
685d3c6369aSKONRAD Frederic assert(channel <= 5);
686d3c6369aSKONRAD Frederic
687d3c6369aSKONRAD Frederic DPRINTF("start dpdma channel 0x%" PRIX8 "\n", channel);
688d3c6369aSKONRAD Frederic
689d3c6369aSKONRAD Frederic if (!xlnx_dpdma_is_channel_triggered(s, channel)) {
690d3c6369aSKONRAD Frederic DPRINTF("Channel isn't triggered..\n");
691d3c6369aSKONRAD Frederic return 0;
692d3c6369aSKONRAD Frederic }
693d3c6369aSKONRAD Frederic
694d3c6369aSKONRAD Frederic if (!xlnx_dpdma_is_channel_enabled(s, channel)) {
695d3c6369aSKONRAD Frederic DPRINTF("Channel isn't enabled..\n");
696d3c6369aSKONRAD Frederic return 0;
697d3c6369aSKONRAD Frederic }
698d3c6369aSKONRAD Frederic
699d3c6369aSKONRAD Frederic if (xlnx_dpdma_is_channel_paused(s, channel)) {
700d3c6369aSKONRAD Frederic DPRINTF("Channel is paused..\n");
701d3c6369aSKONRAD Frederic return 0;
702d3c6369aSKONRAD Frederic }
703d3c6369aSKONRAD Frederic
704d3c6369aSKONRAD Frederic do {
705d3c6369aSKONRAD Frederic if ((s->operation_finished[channel])
706d3c6369aSKONRAD Frederic || xlnx_dpdma_is_channel_retriggered(s, channel)) {
707d3c6369aSKONRAD Frederic desc_addr = xlnx_dpdma_descriptor_start_address(s, channel);
708d3c6369aSKONRAD Frederic s->operation_finished[channel] = false;
709d3c6369aSKONRAD Frederic } else {
710d3c6369aSKONRAD Frederic desc_addr = xlnx_dpdma_descriptor_next_address(s, channel);
711d3c6369aSKONRAD Frederic }
712d3c6369aSKONRAD Frederic
713fdf02976SAlexandra Diupina if (xlnx_dpdma_read_descriptor(s, desc_addr, &desc)) {
714d3c6369aSKONRAD Frederic s->registers[DPDMA_EISR] |= ((1 << 1) << channel);
715d3c6369aSKONRAD Frederic xlnx_dpdma_update_irq(s);
716d3c6369aSKONRAD Frederic s->operation_finished[channel] = true;
717d3c6369aSKONRAD Frederic DPRINTF("Can't get the descriptor.\n");
718d3c6369aSKONRAD Frederic break;
719d3c6369aSKONRAD Frederic }
720d3c6369aSKONRAD Frederic
721d3c6369aSKONRAD Frederic xlnx_dpdma_update_desc_info(s, channel, &desc);
722d3c6369aSKONRAD Frederic
723d3c6369aSKONRAD Frederic #ifdef DEBUG_DPDMA
724d3c6369aSKONRAD Frederic xlnx_dpdma_dump_descriptor(&desc);
725d3c6369aSKONRAD Frederic #endif
726d3c6369aSKONRAD Frederic
727d3c6369aSKONRAD Frederic DPRINTF("location of the descriptor: %" PRIx64 "\n", desc_addr);
728d3c6369aSKONRAD Frederic if (!xlnx_dpdma_desc_is_valid(&desc)) {
729d3c6369aSKONRAD Frederic s->registers[DPDMA_EISR] |= ((1 << 7) << channel);
730d3c6369aSKONRAD Frederic xlnx_dpdma_update_irq(s);
731d3c6369aSKONRAD Frederic s->operation_finished[channel] = true;
732d3c6369aSKONRAD Frederic DPRINTF("Invalid descriptor..\n");
733d3c6369aSKONRAD Frederic break;
734d3c6369aSKONRAD Frederic }
735d3c6369aSKONRAD Frederic
736d3c6369aSKONRAD Frederic if (xlnx_dpdma_desc_crc_enabled(&desc)
737d3c6369aSKONRAD Frederic && !xlnx_dpdma_desc_check_crc(&desc)) {
738d3c6369aSKONRAD Frederic s->registers[DPDMA_EISR] |= ((1 << 13) << channel);
739d3c6369aSKONRAD Frederic xlnx_dpdma_update_irq(s);
740d3c6369aSKONRAD Frederic s->operation_finished[channel] = true;
741d3c6369aSKONRAD Frederic DPRINTF("Bad CRC for descriptor..\n");
742d3c6369aSKONRAD Frederic break;
743d3c6369aSKONRAD Frederic }
744d3c6369aSKONRAD Frederic
745d3c6369aSKONRAD Frederic if (xlnx_dpdma_desc_is_already_done(&desc)
746d3c6369aSKONRAD Frederic && !xlnx_dpdma_desc_ignore_done_bit(&desc)) {
747d3c6369aSKONRAD Frederic /* We are trying to process an already processed descriptor. */
748d3c6369aSKONRAD Frederic s->registers[DPDMA_EISR] |= ((1 << 25) << channel);
749d3c6369aSKONRAD Frederic xlnx_dpdma_update_irq(s);
750d3c6369aSKONRAD Frederic s->operation_finished[channel] = true;
751d3c6369aSKONRAD Frederic DPRINTF("Already processed descriptor..\n");
752d3c6369aSKONRAD Frederic break;
753d3c6369aSKONRAD Frederic }
754d3c6369aSKONRAD Frederic
755d3c6369aSKONRAD Frederic done = xlnx_dpdma_desc_is_last(&desc)
756d3c6369aSKONRAD Frederic || xlnx_dpdma_desc_is_last_of_frame(&desc);
757d3c6369aSKONRAD Frederic
758d3c6369aSKONRAD Frederic s->operation_finished[channel] = done;
759d3c6369aSKONRAD Frederic if (s->data[channel]) {
760d3c6369aSKONRAD Frederic int64_t transfer_len = xlnx_dpdma_desc_get_transfer_size(&desc);
761d3c6369aSKONRAD Frederic uint32_t line_size = xlnx_dpdma_desc_get_line_size(&desc);
762d3c6369aSKONRAD Frederic uint32_t line_stride = xlnx_dpdma_desc_get_line_stride(&desc);
763d3c6369aSKONRAD Frederic if (xlnx_dpdma_desc_is_contiguous(&desc)) {
764d3c6369aSKONRAD Frederic source_addr[0] = xlnx_dpdma_desc_get_source_address(&desc, 0);
765d3c6369aSKONRAD Frederic while (transfer_len != 0) {
766d3c6369aSKONRAD Frederic if (dma_memory_read(&address_space_memory,
767d3c6369aSKONRAD Frederic source_addr[0],
768d3c6369aSKONRAD Frederic &s->data[channel][ptr],
769ba06fe8aSPhilippe Mathieu-Daudé line_size,
770ba06fe8aSPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED)) {
771d3c6369aSKONRAD Frederic s->registers[DPDMA_ISR] |= ((1 << 12) << channel);
772d3c6369aSKONRAD Frederic xlnx_dpdma_update_irq(s);
773d3c6369aSKONRAD Frederic DPRINTF("Can't get data.\n");
774d3c6369aSKONRAD Frederic break;
775d3c6369aSKONRAD Frederic }
776d3c6369aSKONRAD Frederic ptr += line_size;
777d3c6369aSKONRAD Frederic transfer_len -= line_size;
778d3c6369aSKONRAD Frederic source_addr[0] += line_stride;
779d3c6369aSKONRAD Frederic }
780d3c6369aSKONRAD Frederic } else {
781d3c6369aSKONRAD Frederic DPRINTF("Source address:\n");
782d3c6369aSKONRAD Frederic int frag;
783d3c6369aSKONRAD Frederic for (frag = 0; frag < 5; frag++) {
784d3c6369aSKONRAD Frederic source_addr[frag] =
785d3c6369aSKONRAD Frederic xlnx_dpdma_desc_get_source_address(&desc, frag);
786d3c6369aSKONRAD Frederic DPRINTF("Fragment %u: %" PRIx64 "\n", frag + 1,
787d3c6369aSKONRAD Frederic source_addr[frag]);
788d3c6369aSKONRAD Frederic }
789d3c6369aSKONRAD Frederic
790d3c6369aSKONRAD Frederic frag = 0;
791d3c6369aSKONRAD Frederic while ((transfer_len < 0) && (frag < 5)) {
792d3c6369aSKONRAD Frederic size_t fragment_len = DPDMA_FRAG_MAX_SZ
793d3c6369aSKONRAD Frederic - (source_addr[frag] % DPDMA_FRAG_MAX_SZ);
794d3c6369aSKONRAD Frederic
795d3c6369aSKONRAD Frederic if (dma_memory_read(&address_space_memory,
796d3c6369aSKONRAD Frederic source_addr[frag],
797d3c6369aSKONRAD Frederic &(s->data[channel][ptr]),
798ba06fe8aSPhilippe Mathieu-Daudé fragment_len,
799ba06fe8aSPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED)) {
800d3c6369aSKONRAD Frederic s->registers[DPDMA_ISR] |= ((1 << 12) << channel);
801d3c6369aSKONRAD Frederic xlnx_dpdma_update_irq(s);
802d3c6369aSKONRAD Frederic DPRINTF("Can't get data.\n");
803d3c6369aSKONRAD Frederic break;
804d3c6369aSKONRAD Frederic }
805d3c6369aSKONRAD Frederic ptr += fragment_len;
806d3c6369aSKONRAD Frederic transfer_len -= fragment_len;
807d3c6369aSKONRAD Frederic frag += 1;
808d3c6369aSKONRAD Frederic }
809d3c6369aSKONRAD Frederic }
810d3c6369aSKONRAD Frederic }
811d3c6369aSKONRAD Frederic
812d3c6369aSKONRAD Frederic if (xlnx_dpdma_desc_update_enabled(&desc)) {
813d3c6369aSKONRAD Frederic /* The descriptor need to be updated when it's completed. */
814d3c6369aSKONRAD Frederic DPRINTF("update the descriptor with the done flag set.\n");
815d3c6369aSKONRAD Frederic xlnx_dpdma_desc_set_done(&desc);
816fdf02976SAlexandra Diupina if (xlnx_dpdma_write_descriptor(desc_addr, &desc)) {
817fdf02976SAlexandra Diupina DPRINTF("Can't write the descriptor.\n");
818fdf02976SAlexandra Diupina /* TODO: check hardware behaviour for memory write failure */
819fdf02976SAlexandra Diupina }
820d3c6369aSKONRAD Frederic }
821d3c6369aSKONRAD Frederic
822d3c6369aSKONRAD Frederic if (xlnx_dpdma_desc_completion_interrupt(&desc)) {
823d3c6369aSKONRAD Frederic DPRINTF("completion interrupt enabled!\n");
824d3c6369aSKONRAD Frederic s->registers[DPDMA_ISR] |= (1 << channel);
825d3c6369aSKONRAD Frederic xlnx_dpdma_update_irq(s);
826d3c6369aSKONRAD Frederic }
827d3c6369aSKONRAD Frederic
828d3c6369aSKONRAD Frederic } while (!done && !one_desc);
829d3c6369aSKONRAD Frederic
830d3c6369aSKONRAD Frederic return ptr;
831d3c6369aSKONRAD Frederic }
832d3c6369aSKONRAD Frederic
xlnx_dpdma_set_host_data_location(XlnxDPDMAState * s,uint8_t channel,void * p)833d3c6369aSKONRAD Frederic void xlnx_dpdma_set_host_data_location(XlnxDPDMAState *s, uint8_t channel,
834d3c6369aSKONRAD Frederic void *p)
835d3c6369aSKONRAD Frederic {
836d3c6369aSKONRAD Frederic if (!s) {
837d3c6369aSKONRAD Frederic qemu_log_mask(LOG_UNIMP, "DPDMA client not attached to valid DPDMA"
838d3c6369aSKONRAD Frederic " instance\n");
839d3c6369aSKONRAD Frederic return;
840d3c6369aSKONRAD Frederic }
841d3c6369aSKONRAD Frederic
842d3c6369aSKONRAD Frederic assert(channel <= 5);
843d3c6369aSKONRAD Frederic s->data[channel] = p;
844d3c6369aSKONRAD Frederic }
845d3c6369aSKONRAD Frederic
xlnx_dpdma_trigger_vsync_irq(XlnxDPDMAState * s)846d3c6369aSKONRAD Frederic void xlnx_dpdma_trigger_vsync_irq(XlnxDPDMAState *s)
847d3c6369aSKONRAD Frederic {
848d3c6369aSKONRAD Frederic s->registers[DPDMA_ISR] |= (1 << 27);
849d3c6369aSKONRAD Frederic xlnx_dpdma_update_irq(s);
850d3c6369aSKONRAD Frederic }
851d3c6369aSKONRAD Frederic
852d3c6369aSKONRAD Frederic type_init(xlnx_dpdma_register_types)
853