summaryrefslogtreecommitdiffstats
path: root/firmware/export/pl080.h
blob: fe0013b59da8fb20974a5bbd00665085428ac0a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2014 Cástor Muñoz
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/
#ifndef _PL080_H
#define _PL080_H

/*
 * ARM PrimeCell PL080 Multiple Master DMA controller
 */
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

/* general defines */
#define DMAC_CH_COUNT               8
#define DMAC_LLI_MAX_COUNT          0xfff
#define DMAC_CH_PRIO(x)             (x)
#define DMAC_CH_BASE(dmac_ba,ch_n)  ((dmac_ba) + 0x100 + ((ch_n) << 5))

/* PL080 controller registers */
#define DMACINTSTS(base)            (*((uint32_t volatile*)((base) + 0x00)))
#define DMACINTTCSTS(base)          (*((uint32_t volatile*)((base) + 0x04)))
#define DMACINTTCCLR(base)          (*((uint32_t volatile*)((base) + 0x08)))
#define DMACINTERRSTS(base)         (*((uint32_t volatile*)((base) + 0x0c)))
#define DMACINTERRCLR(base)         (*((uint32_t volatile*)((base) + 0x10)))
#define DMACRAWINTTCSTS(base)       (*((uint32_t volatile*)((base) + 0x14)))
#define DMACRAWINTERRSTS(base)      (*((uint32_t volatile*)((base) + 0x18)))
#define DMACENABLEDCHANS(base)      (*((uint32_t volatile*)((base) + 0x1c)))
#define DMACSOFTBREQ(base)          (*((uint32_t volatile*)((base) + 0x20)))
#define DMACSOFTSREQ(base)          (*((uint32_t volatile*)((base) + 0x24)))
#define DMACSOFTLBREQ(base)         (*((uint32_t volatile*)((base) + 0x28)))
#define DMACSOFTLSREQ(base)         (*((uint32_t volatile*)((base) + 0x2c)))
#define DMACCONFIG(base)            (*((uint32_t volatile*)((base) + 0x30)))
#define DMACSYNC(base)              (*((uint32_t volatile*)((base) + 0x34)))

/* PL080 controller channel registers */
#define DMACCxSRCADDR(base)         (*((void* volatile*)((base) + 0x00)))
#define DMACCxDESTADDR(base)        (*((void* volatile*)((base) + 0x04)))
#define DMACCxLINK(base)            (*((uint32_t volatile*)((base) + 0x08)))
#define DMACCxCONTROL(base)         (*((uint32_t volatile*)((base) + 0x0c)))
#define DMACCxCONFIG(base)          (*((uint32_t volatile*)((base) + 0x10)))

/* PL080 controller channel LLI */
#define DMACCxLLI(base)             ((struct dmac_lli volatile*)(base))

/* PL080 DMA controller configuration register */
#define DMACCONFIG_E_POS            0       /* DMAC enable */
#define DMACCONFIG_E_MSK            0x1
#define DMACCONFIG_M1_POS           1       /* AHB Master 1 endianness */
#define DMACCONFIG_M1_MSK           0x1
#define DMACCONFIG_M2_POS           2       /* AHB Master 2 endianness */
#define DMACCONFIG_M2_MSK           0x1

#define DMACCONFIG_E_BIT            (1 << DMACCONFIG_E_POS)
#define DMACCONFIG_M1_BIT           (1 << DMACCCONFI_M1_POS)
#define DMACCONFIG_M2_BIT           (1 << DMACCCONFI_M2_POS)

#define DMACCONFIG_M_LITTLE_ENDIAN  0
#define DMACCONFIG_M_BIG_ENDIAN     1

/* PL080 DMA controller channel LLI register */
#define DMACCxLINK_LM_POS           0
#define DMACCxLINK_LM_MSK           0x1
#define DMACCxLINK_NEXTLLI_POS      2
#define DMACCxLINK_NEXTLLI_MSK      0x3fffffff

/* PL080 channel control register */
#define DMACCxCONTROL_I_POS         31      /* terminal count interrupt */
#define DMACCxCONTROL_I_MSK         0x1
#define DMACCxCONTROL_PROT_POS      28      /* protection bits */
#define DMACCxCONTROL_PROT_MSK      0x7
#define DMACCxCONTROL_DI_POS        27      /* destination addr increment */
#define DMACCxCONTROL_DI_MSK        0x1
#define DMACCxCONTROL_SI_POS        26      /* source addr increment */
#define DMACCxCONTROL_SI_MSK        0x1
#define DMACCxCONTROL_D_POS         25      /* destinantion AHB master */
#define DMACCxCONTROL_D_MSK         0x1
#define DMACCxCONTROL_S_POS         24      /* source AHB master */
#define DMACCxCONTROL_S_MSK         0x1
#define DMACCxCONTROL_DWIDTH_POS    21      /* destinantion transfer width */
#define DMACCxCONTROL_DWIDTH_MSK    0x7
#define DMACCxCONTROL_SWIDTH_POS    18      /* source transfer width */
#define DMACCxCONTROL_SWIDTH_MSK    0x7
#define DMACCxCONTROL_DBSIZE_POS    15      /* destinantion burst size */
#define DMACCxCONTROL_DBSIZE_MSK    0x7
#define DMACCxCONTROL_SBSIZE_POS    12      /* source burst size */
#define DMACCxCONTROL_SBSIZE_MSK    0x7
#define DMACCxCONTROL_COUNT_POS     0       /* n SWIDTH size transfers */
#define DMACCxCONTROL_COUNT_MSK     0xfff

#define DMACCxCONTROL_WIDTH_8       0
#define DMACCxCONTROL_WIDTH_16      1
#define DMACCxCONTROL_WIDTH_32      2

#define DMACCxCONTROL_BSIZE_1       0
#define DMACCxCONTROL_BSIZE_4       1
#define DMACCxCONTROL_BSIZE_8       2
#define DMACCxCONTROL_BSIZE_16      3
#define DMACCxCONTROL_BSIZE_32      4
#define DMACCxCONTROL_BSIZE_64      5
#define DMACCxCONTROL_BSIZE_128     6
#define DMACCxCONTROL_BSIZE_256     7

#define DMACCxCONTROL_INC_DISABLE   0
#define DMACCxCONTROL_INC_ENABLE    1

#define DMACCxCONTROL_I_BIT         (1 << DMACCxCONTROL_I_POS)

/* protection bits */
#define DMAC_PROT_PRIV              (1 << 0)
#define DMAC_PROT_BUFF              (1 << 1)
#define DMAC_PROT_CACH              (1 << 2)

/* bus */
#define DMAC_MASTER_AHB1            0
#define DMAC_MASTER_AHB2            1

/* PL080 channel configuration register */
#define DMACCxCONFIG_E_POS          0       /* enable */
#define DMACCxCONFIG_E_MSK          0x1
#define DMACCxCONFIG_SRCPERI_POS    1       /* source peripheral */
#define DMACCxCONFIG_SRCPERI_MSK    0xf
#define DMACCxCONFIG_DESTPERI_POS   6       /* destination peripheral */
#define DMACCxCONFIG_DESTPERI_MSK   0xf
#define DMACCxCONFIG_FLOWCNTRL_POS  11      /* DMA transfer type */
#define DMACCxCONFIG_FLOWCNTRL_MSK  0x7
#define DMACCxCONFIG_IE_POS         14      /* interrupt error mask */
#define DMACCxCONFIG_IE_MSK         0x1
#define DMACCxCONFIG_ITC_POS        15      /* interrupt terminal count mask */
#define DMACCxCONFIG_ITC_MSK        0x1
#define DMACCxCONFIG_L_POS          16      /* lock */
#define DMACCxCONFIG_L_MSK          0x1
#define DMACCxCONFIG_A_POS          17      /* active */
#define DMACCxCONFIG_A_MSK          0x1
#define DMACCxCONFIG_H_POS          18      /* halt */
#define DMACCxCONFIG_H_MSK          0x1

#define DMACCxCONFIG_E_BIT          (1 << DMACCxCONFIG_E_POS)
#define DMACCxCONFIG_IE_BIT         (1 << DMACCxCONFIG_IE_POS)
#define DMACCxCONFIG_ITC_BIT        (1 << DMACCxCONFIG_ITC_POS)
#define DMACCxCONFIG_L_BIT          (1 << DMACCxCONFIG_L_POS)
#define DMACCxCONFIG_A_BIT          (1 << DMACCxCONFIG_A_POS)
#define DMACCxCONFIG_H_BIT          (1 << DMACCxCONFIG_H_POS)

#define DMACCxCONFIG_FLOWCNTRL_MEMMEM_DMA         0
#define DMACCxCONFIG_FLOWCNTRL_MEMPERI_DMA        1
#define DMACCxCONFIG_FLOWCNTRL_PERIMEM_DMA        2
#define DMACCxCONFIG_FLOWCNTRL_PERIPERI_DMA       3
#define DMACCxCONFIG_FLOWCNTRL_PERIPERI_DSTPERI   4
#define DMACCxCONFIG_FLOWCNTRL_MEMPERI_PERI       5
#define DMACCxCONFIG_FLOWCNTRL_PERIMEM_PERI       6
#define DMACCxCONFIG_FLOWCNTRL_PERIPERI_SRCPERI   7

/*
 * types
 */
struct dmac_lli {
    void* srcaddr;
    void* dstaddr;
    uint32_t link;
    uint32_t control;
} __attribute__((aligned(16)));

struct dmac_tsk {
    struct dmac_lli volatile *start_lli;
    struct dmac_lli volatile *end_lli;
    uint32_t size;
    void *cb_data;
};

/* used when src/dst peri is memory */
#define DMAC_PERI_NONE    0x80

struct dmac_ch_cfg {
    uint8_t srcperi;
    uint8_t dstperi;
    uint8_t sbsize;
    uint8_t dbsize;
    uint8_t swidth;
    uint8_t dwidth;
    uint8_t sbus;
    uint8_t dbus;
    uint8_t sinc;
    uint8_t dinc;
    uint8_t prot;
    uint16_t lli_xfer_max_count;
};

struct dmac_ch {
    /** user configurable data **/
    struct dmac *dmac;
    unsigned int prio;
    void (*cb_fn)(void *cb_data);
    /* tsk circular buffer */
    struct dmac_tsk *tskbuf;
    uint32_t tskbuf_mask;
    uint32_t queue_mode;
    /* lli circular buffer */
    struct dmac_lli volatile *llibuf;
    uint32_t llibuf_mask;
    uint32_t llibuf_bus;

    /** private driver data **/
    uint32_t baddr;
    struct dmac_lli volatile *llibuf_top;
    uint32_t tasks_queued;  /* roll-over counter */
    uint32_t tasks_done;    /* roll-over counter */
    uint32_t control;
    struct dmac_ch_cfg *cfg;
};

struct dmac {
    /* user configurable data */
    const uint32_t baddr;
    const uint8_t m1;
    const uint8_t m2;

    /* driver private data */
    struct dmac_ch *ch_l[DMAC_CH_COUNT];
    uint32_t ch_run_status; /* channel running status mask */
};

/* dmac_ch->queue_mode */
enum {
    QUEUE_NORMAL,
    QUEUE_LINK,
};

/*
 * prototypes
 */
void dmac_callback(struct dmac *dmac);

void dmac_open(struct dmac *dmac);

void dmac_ch_init(struct dmac_ch *ch, struct dmac_ch_cfg *cfg);

void dmac_ch_lock_int(struct dmac_ch *ch);
void dmac_ch_unlock_int(struct dmac_ch *ch);

void dmac_ch_queue_2d(struct dmac_ch *ch, void *srcaddr, void *dstaddr,
                size_t size, size_t width, size_t stride, void *cb_data);
#define dmac_ch_queue(ch, srcaddr, dstaddr, size, cb_data) \
                dmac_ch_queue_2d(ch, srcaddr, dstaddr, size, 0, 0, cb_data)

void dmac_ch_stop(struct dmac_ch* ch);

bool dmac_ch_running(struct dmac_ch *ch);

void *dmac_ch_get_info(struct dmac_ch *ch,
                size_t *bytes, size_t *t_bytes);

#endif /* _PL080_H */