aboutsummaryrefslogtreecommitdiff
path: root/include/kern/dma/dma_manager.h
blob: 055bbb213d03fb3112f65d7f440fb70ff88bdf27 (plain) (blame)
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
271
272
273
274
#ifndef PERI_DMA_H_
#define PERI_DMA_H_

#include "arch/stm32l4xxx/peripherals/dma.h" /* Access to the DMA registers. */
#include "arch/stm32l4xxx/peripherals/irq.h"
#include "kern/common.h"

#define DMA_ERROR_CHANNEL_IN_USE 1

#define CAT2(x, y) x##y
#define CAT1(v, c) CAT2(v, c)
#define DMA_RESERVED(dma) CAT1(dma##_PERIPH_RESERVED, __COUNTER__)

#define ALTERNATE0 0x0000
#define ALTERNATE1 0x0100
#define ALTERNATE2 0x0200
#define ALTERNATE3 0x0300

#define DMA_N_CHANNELS 7
typedef enum {
  DMA1_PERIPH_ADC1 = 0,
  DMA1_PERIPH_ADC2 = 1,
  DMA1_PERIPH_ADC3 = 2,
  DMA1_PERIPH_DFSDM1_FLT0 = 3,
  DMA1_PERIPH_DFSDM1_FLT1 = 4,
  DMA1_PERIPH_DFSDM1_FLT2 = 5,
  DMA1_PERIPH_DFSDM1_FLT3 = 6,

  DMA_RESERVED(DMA1) = 7,
  DMA1_PERIPH_SPI1_RX = 8,
  DMA1_PERIPH_SPI1_TX = 9,
  DMA1_PERIPH_SPI2_RX = 10,
  DMA1_PERIPH_SPI2_TX = 11,
  DMA1_PERIPH_SAI2_A = 12,
  DMA1_PERIPH_SAI2_B = 13,

  DMA_RESERVED(DMA1) = 14,
  DMA1_PERIPH_USART3_TX = 15,
  DMA1_PERIPH_USART3_RX = 16,
  DMA1_PERIPH_USART1_TX = 17,
  DMA1_PERIPH_USART1_RX = 18,
  DMA1_PERIPH_USART2_RX = 19,
  DMA1_PERIPH_USART2_TX = 20,

  DMA_RESERVED(DMA1) = 21,
  DMA1_PERIPH_I2C3_TX = 22,
  DMA1_PERIPH_I2C3_RX = 23,
  DMA1_PERIPH_I2C2_TX = 24,
  DMA1_PERIPH_I2C2_RX = 25,
  DMA1_PERIPH_I2C1_TX = 26,
  DMA1_PERIPH_I2C1_RX = 27,

  DMA1_PERIPH_TIM2_CH3 = 28,
  DMA1_PERIPH_TIM2_UP = 29,
  DMA1_PERIPH_TIM16_CH1_1 = 30 | ALTERNATE0,
  DMA1_PERIPH_TIM16_UP_1 = 30 | ALTERNATE1, /* Same as TIM16_CH1. */
  DMA_RESERVED(DMA1) = 31,
  DMA1_PERIPH_TIM2_CH1 = 32,
  DMA1_PERIPH_TIM16_CH1_2 = 33,
  DMA1_PERIPH_TIM16_UP_2 = 33 | ALTERNATE1, /* Same as TIM16_CH1. */
  DMA1_PERIPH_TIM2_CH2 = 34,
  DMA1_PERIPH_TIM2_CH4 = 34 | ALTERNATE1, /* Same as TIM2_CH2. */

  DMA1_PERIPH_TIM17_CH1_1 = 35,
  DMA1_PERIPH_TIM17_UP_1 = 35 | ALTERNATE1, /* Same as TIM17_CH1 */
  DMA1_PERIPH_TIM3_CH3 = 36,
  DMA1_PERIPH_TIM3_CH4 = 37,
  DMA1_PERIPH_TIM3_UP = 37 | ALTERNATE1, /* Same as TIM3_CH4 */
  DMA1_PERIPH_TIM7_UP = 38,
  DMA1_PERIPH_DAC_CH2 = 38 | ALTERNATE1, /* Same as TIM7_UP */
  DMA1_PERIPH_QUADSPI = 39,
  DMA1_PERIPH_TIM3_CH1 = 40,
  DMA1_PERIPH_TIM3_TRIG = 40 | ALTERNATE1, /* Same as TIM3_CH1 */
  DMA1_PERIPH_TIM17_CH1_2 = 41,
  DMA1_PERIPH_TIM17_UP_2 = 41 | ALTERNATE1, /* Same as TIM17_CH1 */

  DMA1_PERIPH_TIM4_CH1 = 42,
  DMA_RESERVED(DMA1) = 43,
  DMA1_PERIPH_TIM6_UP = 44,
  DMA1_PERIPH_DAC_CH1 = 44 | ALTERNATE1, /* Same as TIM6_UP */
  DMA1_PERIPH_TIM4_CH2 = 45,
  DMA1_PERIPH_TIM4_CH3 = 46,
  DMA_RESERVED(DMA1) = 47,
  DMA1_PERIPH_TIM4_UP = 48,

  DMA_DMA1_PERIHP_RESERVED5 = 49,
  DMA1_PERIPH_TIM1_CH1 = 50,
  DMA1_PERIPH_TIM1_CH2 = 51,
  DMA1_PERIPH_TIM1_CH4 = 52,
  DMA1_PERIPH_TIM1_TRIG = 52 | ALTERNATE1, /* Same as TIM1_TRIG */
  DMA1_PERIPH_TIM1_COM = 52 | ALTERNATE2,  /* Same as TIM1_TRIG */
  DMA1_PERIPH_TIM15_CH1 = 53,
  DMA1_PERIPH_TIM15_UP = 53 | ALTERNATE1,   /* Same as TIM15_CH1 */
  DMA1_PERIPH_TIM15_TRIG = 53 | ALTERNATE2, /* Same as TIM15_CH1 */
  DMA1_PERIPH_TIM15_COM = 53 | ALTERNATE3,  /* Same as TIM15_CH1 */
  DMA1_PERIPH_TIM1_UP = 54,
  DMA1_PERIPH_TIM1_CH3 = 55,

  DMA2_DMA1_SWITCH__ = 56,

  DMA2_PERIPH_I2C4_RX = 56,
  DMA2_PERIPH_I2C4_TX = 57,
  DMA2_PERIPH_ADC1 = 58,
  DMA2_PERIPH_ADC2 = 59,
  DMA2_PERIPH_ADC3 = 60,
  DMA2_PERIPH_DCMI_1 = 61,
  DMA_RESERVED(DMA2) = 62,

  DMA2_PERIPH_SAI1_A_1 = 63,
  DMA2_PERIPH_SAI1_B_1 = 64,
  DMA2_PERIPH_SAI2_A = 65,
  DMA2_PERIPH_SAI2_B = 66,
  DMA_RESERVED(DMA2) = 67,
  DMA2_PERIPH_SAI1_A_2 = 68,
  DMA2_PERIPH_SAI1_B_2 = 69,

  DMA2_PERIPH_UART5_TX = 70,
  DMA2_PERIPH_UART5_RX = 71,
  DMA2_PERIPH_UART4_TX = 72,
  DMA_RESERVED(DMA2) = 73,
  DMA2_PERIPH_UART4_RX = 74,
  DMA2_PERIPH_USART1_TX = 75,
  DMA2_PERIPH_USART1_RX = 76,

  DMA2_PERIPH_SPI3_RX = 77,
  DMA2_PERIPH_SPI3_TX = 78,
  DMA_RESERVED(DMA2) = 79,
  DMA2_PERIPH_TIM6_UP = 80,
  DMA2_PERIPH_DAC_CH1 = 80 | ALTERNATE1, /* Same as TIM6_UP */
  DMA2_PERIPH_TIM7_UP = 81,
  DMA2_PERIPH_DAC_CH2 = 81 | ALTERNATE1, /* Same as TIM7_UP */
  DMA_RESERVED(DMA2) = 82,
  DMA2_PERIPH_QUADSPI = 83,

  DMA2_PERIPH_SWPMI1_RX = 84,
  DMA2_PERIPH_SWPMI1_TX = 85,
  DMA2_PERIPH_SPI1_RX = 86,
  DMA2_PERIPH_SPI1_TX = 87,
  DMA2_PERIPH_DCMI_2 = 88,
  DMA2_PERIPH_LPUART1_TX = 89,
  DMA2_PERIPH_LPUART1_RX = 90,

  DMA2_PERIPH_TIM5_CH4 = 91,
  DMA2_PERIPH_TIM5_TRIG = 91 | ALTERNATE1, /* Same as TIM5_CH4 */
  DMA2_PERIPH_TIM5_CH3 = 92,
  DMA2_PERIPH_TIM5_UP = 92 | ALTERNATE1, /* Same as TIM5_CH3 */
  DMA_RESERVED(DMA2) = 93,
  DMA2_PERIPH_TIM5_CH2 = 94,
  DMA2_PERIPH_TIM5_CH1 = 95,
  DMA2_PERIPH_I2C1_RX = 96,
  DMA2_PERIPH_I2C1_TX = 97,

  DMA2_PERIPH_AES_IN_1 = 98,
  DMA2_PERIPH_AES_OUT_1 = 99,
  DMA2_PERIPH_AES_OUT_2 = 100,
  DMA_RESERVED(DMA2) = 101,
  DMA2_PERIPH_AES_IN_2 = 102,
  DMA_RESERVED(DMA2) = 103,
  DMA2_PERIPH_HASH_IN = 104,

  DMA2_PERIPH_TIM8_CH3 = 105,
  DMA2_PERIPH_TIM8_UP = 105 | ALTERNATE1, /* Same as TIM8_CH3 */
  DMA2_PERIPH_TIM8_CH4 = 106,
  DMA2_PERIPH_TIM8_TRIG = 106 | ALTERNATE1, /* Same as TIM8_CH4 */
  DMA2_PERIPH_TIM8_COM = 106 | ALTERNATE2,  /* Same as TIM8_CH4 */
  DMA_RESERVED(DMA2) = 107,
  DMA2_PERIPH_SDMMC1_1 = 108,
  DMA2_PERIPH_SDMMC1_2 = 109,
  DMA2_PERIPH_TIM8_CH1 = 110,
  DMA2_PERIPH_TIM8_CH2 = 111,

  DMA_PERIPH_SENTINEL,
} dma_peripheral_t;

/* Defines a DMA channel. */
typedef struct {
  uint8_t dma;  /* 0 = DMA1, 1 = DMA2 */
  uint8_t chan; /* 0 - 6 */
} dma_channel_t;

/*
 * Defines a DMA channel allocated for memory-to-peripheral transfers.  This
 * structure is only nominally different from dma_channel_t in order to provide
 * rudimentary type-checking.
 */
typedef struct {
  dma_channel_t c_;
} dma_mem2p_channel_t;

/*
 * Defines a DMA channel allocated for peripheral-to-memory transfers.  This
 * structure is only nominally different from dma_channel_t in order to provide
 * rudimentary type-checking.
 */
typedef struct {
  dma_channel_t c_;
} dma_p2mem_channel_t;

/* Defines a DMA channel allocated for mem2mem transfers.
 * This structure is only nominally different from dma_channel_t
 * in order to provide rudimentary type-checking.
 */
typedef struct {
  dma_channel_t c_;
} dma_mem2mem_channel_t;

#define DMA_CHAN_ERROR ((dma_channel_t){.dma = 0xff, .chan = 0xff})

typedef struct {
  bool transfer_complete_interrupt_enable;
  bool half_transfer_interrupt_enable;
  bool transfer_error_interrupt_enable;

  bool circular_mode;
  bool peripheral_increment;
  bool memory_increment;

  dma_size_t peripheral_block_size;
  dma_size_t memory_block_size;

  dma_priority_level_t priority;
} dma_opts_t;

#define DEFAULT_DMA_OPTS                        \
  ((dma_opts_t){                                \
      .memory_increment = 1,                    \
      .peripheral_increment = 0,                \
      .transfer_complete_interrupt_enable = 0,  \
      .half_transfer_interrupt_enable = 0,      \
      .transfer_error_interrupt_enable = 0,     \
      .circular_mode = 0,                       \
      .peripheral_block_size = DMA_SIZE_8_BITS, \
      .memory_block_size = DMA_SIZE_8_BITS,     \
      .priority = DMA_PRIORITY_LEVEL_MEDIUM})

dma_p2mem_channel_t select_dma_channel_p2mem(
    dma_peripheral_t peripheral, dma_opts_t* opts_in, int* error);

dma_mem2p_channel_t select_dma_channel_mem2p(
    dma_peripheral_t peripheral, dma_opts_t* opts_in, int* error);

/* Returns a dma channel used for memory-to-memory transfers.
 *
 * channel - the channel this dma should use. The channel should
 * be on the range [0-13]. The channels [0-6] refer to the 7 channels
 * on DMA1, where channels [7-13] refer to the 7 channels on DMA2.
 *
 * If `channel` is -1, then the highest unused dma channel is selected.
 */
dma_mem2mem_channel_t select_dma_channel_mem2mem(
    int channel, dma_opts_t* opts, int* error_out);

void dma_mem2p_initiate_transfer(
    dma_mem2p_channel_t chan, const void* from_loc, uint16_t nblocks);

void dma_p2mem_initiate_transfer(
    dma_p2mem_channel_t chan, void* to_loc, uint16_t nblocks);

void dma_mem2mem_initiate_transfer(
    dma_mem2mem_channel_t chan,
    void* to_loc,
    const void* from_loc,
    uint16_t nblocks);

void release_dma_channel(dma_channel_t chan);

interrupt_t dma_channel_get_interrupt(dma_channel_t chan);

void dma_chan_set_callback(
    dma_channel_t chan, void (*callback)(void*), void* arg);

void dma_channel_interrupt_enable(dma_channel_t chan, bool enabled);

#endif