xref: /openbmc/qemu/hw/dma/xlnx_dpdma.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
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