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

4.115
Last change on this file since 1215fd4 was 1215fd4, checked in by Sebastian Huber <sebastian.huber@…>, on 08/26/13 at 13:14:33

sapi: SMP support for chains

Add ISR lock to chain control for proper SMP protection. Replace
rtems_chain_extract() with rtems_chain_explicit_extract() and
rtems_chain_insert() with rtems_chain_explicit_insert() on SMP
configurations. Use rtems_chain_explicit_extract() and
rtems_chain_explicit_insert() to provide SMP support.

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