source: rtems/c/src/lib/libcpu/powerpc/mpc55xx/edma/edma.c @ c499856

4.115
Last change on this file since c499856 was c499856, checked in by Chris Johns <chrisj@…>, on Mar 20, 2014 at 9:10:47 PM

Change all references of rtems.com to rtems.org.

  • Property mode set to 100644
File size: 8.0 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup mpc55xx
5 *
6 * @brief Enhanced Direct Memory Access (eDMA).
7 */
8
9/*
10 * Copyright (c) 2008-2013 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Dornierstr. 4
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23#include <mpc55xx/edma.h>
24#include <mpc55xx/mpc55xx.h>
25
26#include <assert.h>
27
28#include <bsp.h>
29#include <bsp/fatal.h>
30#include <bsp/irq.h>
31
32#define EDMA_CHANNELS_PER_GROUP 32U
33
34#define EDMA_GROUP_COUNT ((EDMA_CHANNEL_COUNT + 31U) / 32U)
35
36#define EDMA_GROUP_INDEX(channel) ((channel) / EDMA_CHANNELS_PER_GROUP)
37
38#define EDMA_GROUP_BIT(channel) (1U << ((channel) % EDMA_CHANNELS_PER_GROUP))
39
40#define EDMA_MODULE_INDEX(channel) ((channel) / EDMA_CHANNELS_PER_MODULE)
41
42static uint32_t edma_channel_occupation [EDMA_GROUP_COUNT];
43
44static RTEMS_CHAIN_DEFINE_EMPTY(edma_channel_chain);
45
46static unsigned edma_channel_index_of_tcd(volatile struct tcd_t *edma_tcd)
47{
48  volatile struct EDMA_tag *edma = mpc55xx_edma_by_tcd(edma_tcd);
49  unsigned channel = edma_tcd - &edma->TCD[0];
50
51#if EDMA_MODULE_COUNT == 1
52  return channel;
53#elif EDMA_MODULE_COUNT == 2
54  return channel + (&EDMA_A == edma ? 0 : EDMA_CHANNELS_PER_MODULE);
55#else
56  #error "unsupported module count"
57#endif
58}
59
60static volatile struct EDMA_tag *edma_get_regs_by_module(unsigned module)
61{
62#if EDMA_MODULE_COUNT == 1
63  return &EDMA;
64#elif EDMA_MODULE_COUNT == 2
65  return module == 0 ? &EDMA_A : &EDMA_B;
66#else
67  #error "unsupported module count"
68#endif
69}
70
71static uint32_t edma_bit_array_set(unsigned channel, uint32_t *bit_array)
72{
73  unsigned array = channel / 32;
74  uint32_t bit = 1U << (channel % 32);
75  uint32_t previous = bit_array [array];
76
77  bit_array [array] = previous | bit;
78
79  return previous;
80}
81
82static uint32_t edma_bit_array_clear(unsigned channel, uint32_t *bit_array)
83{
84  unsigned array = channel / 32;
85  uint32_t bit = 1U << (channel % 32);
86  uint32_t previous = bit_array [array];
87
88  bit_array [array] = previous & ~bit;
89
90  return previous;
91}
92
93static void edma_interrupt_handler(void *arg)
94{
95  edma_channel_context *ctx = arg;
96
97  mpc55xx_edma_clear_interrupts(ctx->edma_tcd);
98
99  (*ctx->done)(ctx, 0);
100}
101
102static void edma_interrupt_error_handler(void *arg)
103{
104  rtems_chain_control *chain = &edma_channel_chain;
105  rtems_chain_node *node = rtems_chain_first(chain);
106  uint32_t error_channels [] = {
107#if EDMA_GROUP_COUNT >= 1
108    EDMA.ERL.R
109#endif
110#if EDMA_GROUP_COUNT >= 2
111    , EDMA.ERH.R
112#endif
113#if EDMA_GROUP_COUNT >= 3
114    , EDMA_B.ERL.R
115#endif
116  };
117  uint32_t error_status [] = {
118#if EDMA_GROUP_COUNT >= 1
119    EDMA.ESR.R
120#endif
121#if EDMA_GROUP_COUNT >= 3
122    , EDMA_B.ESR.R
123#endif
124  };
125
126#if EDMA_GROUP_COUNT >= 1
127  EDMA.ERL.R = error_channels [0];
128#endif
129#if EDMA_GROUP_COUNT >= 2
130  EDMA.ERH.R = error_channels [1];
131#endif
132#if EDMA_GROUP_COUNT >= 3
133  EDMA_B.ERL.R = error_channels [2];
134#endif
135
136  while (!rtems_chain_is_tail(chain, node)) {
137    edma_channel_context *ctx = (edma_channel_context *) node;
138    unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd);
139    unsigned group_index = EDMA_GROUP_INDEX(channel_index);
140    unsigned group_bit = EDMA_GROUP_BIT(channel_index);
141
142    if ((error_channels [group_index] & group_bit) != 0) {
143      unsigned module_index = EDMA_MODULE_INDEX(channel_index);
144
145      (*ctx->done)(ctx, error_status [module_index]);
146    }
147
148    node = rtems_chain_next(node);
149  }
150}
151
152void mpc55xx_edma_init(void)
153{
154  rtems_status_code sc = RTEMS_SUCCESSFUL;
155  unsigned channel_remaining = EDMA_CHANNEL_COUNT;
156  unsigned module = 0;
157  unsigned group = 0;
158
159  for (module = 0; module < EDMA_MODULE_COUNT; ++module) {
160    volatile struct EDMA_tag *edma = edma_get_regs_by_module(module);
161    unsigned channel_count = channel_remaining < EDMA_CHANNELS_PER_MODULE ?
162      channel_remaining : EDMA_CHANNELS_PER_MODULE;
163    unsigned channel = 0;
164
165    channel_remaining -= channel_count;
166
167    /* Disable requests */
168    edma->CERQR.B.CERQ = 0x40;
169
170    /* Arbitration mode: group round robin, channel fixed */
171    edma->CR.B.ERGA = 1;
172    edma->CR.B.ERCA = 0;
173    for (channel = 0; channel < channel_count; ++channel) {
174      volatile struct tcd_t *tcd = &edma->TCD [channel];
175      edma->CPR [channel].R = 0x80U | (channel & 0xfU);
176
177      /* Initialize TCD, stop channel first */
178      tcd->BMF.R = 0;
179      tcd->SADDR = 0;
180      tcd->SDF.R = 0;
181      tcd->NBYTES = 0;
182      tcd->SLAST = 0;
183      tcd->DADDR = 0;
184      tcd->CDF.R = 0;
185      tcd->DLAST_SGA = 0;
186    }
187
188    /* Clear interrupt requests */
189    edma->CIRQR.B.CINT = 0x40;
190    edma->CER.B.CERR = 0x40;
191  }
192
193  for (group = 0; group < EDMA_GROUP_COUNT; ++group) {
194    sc = mpc55xx_interrupt_handler_install(
195      MPC55XX_IRQ_EDMA_ERROR(group),
196      "eDMA Error",
197      RTEMS_INTERRUPT_UNIQUE,
198      MPC55XX_INTC_DEFAULT_PRIORITY,
199      edma_interrupt_error_handler,
200      NULL
201    );
202    if (sc != RTEMS_SUCCESSFUL) {
203      bsp_fatal(MPC55XX_FATAL_EDMA_IRQ_INSTALL);
204    }
205  }
206}
207
208rtems_status_code mpc55xx_edma_obtain_channel_by_tcd(
209  volatile struct tcd_t *edma_tcd
210)
211{
212  rtems_status_code sc = RTEMS_SUCCESSFUL;
213  unsigned channel_index = edma_channel_index_of_tcd(edma_tcd);
214  rtems_interrupt_level level;
215  uint32_t channel_occupation;
216
217  rtems_interrupt_disable(level);
218  channel_occupation = edma_bit_array_set(
219    channel_index,
220    &edma_channel_occupation [0]
221  );
222  rtems_interrupt_enable(level);
223
224  if ((channel_occupation & EDMA_GROUP_BIT(channel_index)) != 0) {
225    sc = RTEMS_RESOURCE_IN_USE;
226  }
227
228  return sc;
229}
230
231void mpc55xx_edma_release_channel_by_tcd(volatile struct tcd_t *edma_tcd)
232{
233  unsigned channel_index = edma_channel_index_of_tcd(edma_tcd);
234  rtems_interrupt_level level;
235
236  rtems_interrupt_disable(level);
237  edma_bit_array_clear(channel_index, &edma_channel_occupation [0]);
238  rtems_interrupt_enable(level);
239
240  mpc55xx_edma_disable_hardware_requests(edma_tcd);
241  mpc55xx_edma_disable_error_interrupts(edma_tcd);
242}
243
244rtems_status_code mpc55xx_edma_obtain_channel(
245  edma_channel_context *ctx,
246  unsigned irq_priority
247)
248{
249  rtems_status_code sc = mpc55xx_edma_obtain_channel_by_tcd(ctx->edma_tcd);
250  if (sc == RTEMS_SUCCESSFUL) {
251    unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd);
252
253    sc = mpc55xx_interrupt_handler_install(
254      MPC55XX_IRQ_EDMA(channel_index),
255      "eDMA Channel",
256      RTEMS_INTERRUPT_SHARED,
257      irq_priority,
258      edma_interrupt_handler,
259      ctx
260    );
261    if (sc == RTEMS_SUCCESSFUL) {
262      rtems_chain_prepend(&edma_channel_chain, &ctx->node);
263      mpc55xx_edma_enable_error_interrupts(ctx->edma_tcd);
264    } else {
265      mpc55xx_edma_release_channel_by_tcd(ctx->edma_tcd);
266      sc = RTEMS_IO_ERROR;
267    }
268  }
269
270  return sc;
271}
272
273void mpc55xx_edma_release_channel(edma_channel_context *ctx)
274{
275  rtems_status_code sc = RTEMS_SUCCESSFUL;
276  unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd);
277
278  mpc55xx_edma_release_channel_by_tcd(ctx->edma_tcd);
279  rtems_chain_extract(&ctx->node);
280
281  sc = rtems_interrupt_handler_remove(
282    MPC55XX_IRQ_EDMA(channel_index),
283    edma_interrupt_handler,
284    ctx
285  );
286  if (sc != RTEMS_SUCCESSFUL) {
287    bsp_fatal(MPC55XX_FATAL_EDMA_IRQ_REMOVE);
288  }
289}
290
291void mpc55xx_edma_copy(
292  volatile struct tcd_t *edma_tcd,
293  const struct tcd_t *source_tcd
294)
295{
296  /* Clear DONE flag */
297  edma_tcd->BMF.R = 0;
298
299  edma_tcd->SADDR = source_tcd->SADDR;
300  edma_tcd->SDF.R = source_tcd->SDF.R;
301  edma_tcd->NBYTES = source_tcd->NBYTES;
302  edma_tcd->SLAST = source_tcd->SLAST;
303  edma_tcd->DADDR = source_tcd->DADDR;
304  edma_tcd->CDF.R = source_tcd->CDF.R;
305  edma_tcd->DLAST_SGA = source_tcd->DLAST_SGA;
306  edma_tcd->BMF.R = source_tcd->BMF.R;
307}
308
309void mpc55xx_edma_copy_and_enable_hardware_requests(
310  volatile struct tcd_t *edma_tcd,
311  const struct tcd_t *source_tcd
312)
313{
314  mpc55xx_edma_copy(edma_tcd, source_tcd);
315  mpc55xx_edma_enable_hardware_requests(edma_tcd);
316}
317
318void mpc55xx_edma_sg_link(
319  volatile struct tcd_t *edma_tcd,
320  const struct tcd_t *source_tcd
321)
322{
323  edma_tcd->DLAST_SGA = (int32_t) source_tcd;
324  edma_tcd->BMF.B.E_SG = 1;
325
326  if (!edma_tcd->BMF.B.E_SG) {
327    mpc55xx_edma_copy(edma_tcd, source_tcd);
328  }
329}
Note: See TracBrowser for help on using the repository browser.