source: rtems/bsps/powerpc/mpc55xxevb/start/edma.c @ 762fa62

5
Last change on this file since 762fa62 was dc1ea01, checked in by Sebastian Huber <sebastian.huber@…>, on 03/22/18 at 05:27:31

bsps/mpc55xx: Move libcpu content to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 8.0 KB
RevLine 
[574fb67]1/**
2 * @file
3 *
4 * @ingroup mpc55xx
5 *
6 * @brief Enhanced Direct Memory Access (eDMA).
7 */
8
9/*
[db21e1d]10 * Copyright (c) 2008-2013 embedded brains GmbH.  All rights reserved.
[574fb67]11 *
[a762dc2]12 *  embedded brains GmbH
[db21e1d]13 *  Dornierstr. 4
[a762dc2]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
[c499856]20 * http://www.rtems.org/license/LICENSE.
[574fb67]21 */
22
23#include <mpc55xx/edma.h>
24#include <mpc55xx/mpc55xx.h>
25
[97fa2f1b]26#include <assert.h>
[574fb67]27
[30158371]28#include <bsp.h>
[33cb8bf]29#include <bsp/fatal.h>
[d374492]30#include <bsp/irq.h>
31
[97fa2f1b]32#define EDMA_CHANNELS_PER_GROUP 32U
[574fb67]33
[97fa2f1b]34#define EDMA_GROUP_COUNT ((EDMA_CHANNEL_COUNT + 31U) / 32U)
[574fb67]35
[97fa2f1b]36#define EDMA_GROUP_INDEX(channel) ((channel) / EDMA_CHANNELS_PER_GROUP)
[574fb67]37
[97fa2f1b]38#define EDMA_GROUP_BIT(channel) (1U << ((channel) % EDMA_CHANNELS_PER_GROUP))
[574fb67]39
[97fa2f1b]40#define EDMA_MODULE_INDEX(channel) ((channel) / EDMA_CHANNELS_PER_MODULE)
41
42static uint32_t edma_channel_occupation [EDMA_GROUP_COUNT];
[574fb67]43
[97fa2f1b]44static RTEMS_CHAIN_DEFINE_EMPTY(edma_channel_chain);
[d374492]45
[db21e1d]46static unsigned edma_channel_index_of_tcd(volatile struct tcd_t *edma_tcd)
[97fa2f1b]47{
[db21e1d]48  volatile struct EDMA_tag *edma = mpc55xx_edma_by_tcd(edma_tcd);
49  unsigned channel = edma_tcd - &edma->TCD[0];
50
[97fa2f1b]51#if EDMA_MODULE_COUNT == 1
[db21e1d]52  return channel;
[97fa2f1b]53#elif EDMA_MODULE_COUNT == 2
[db21e1d]54  return channel + (&EDMA_A == edma ? 0 : EDMA_CHANNELS_PER_MODULE);
[97fa2f1b]55#else
56  #error "unsupported module count"
57#endif
[574fb67]58}
59
[2d43f2d]60static volatile struct EDMA_tag *edma_get_regs_by_module(unsigned module)
[574fb67]61{
[97fa2f1b]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
[574fb67]69}
70
[97fa2f1b]71static uint32_t edma_bit_array_set(unsigned channel, uint32_t *bit_array)
[574fb67]72{
[97fa2f1b]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;
[574fb67]80}
81
[97fa2f1b]82static uint32_t edma_bit_array_clear(unsigned channel, uint32_t *bit_array)
[574fb67]83{
[97fa2f1b]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;
[574fb67]91}
92
[97fa2f1b]93static void edma_interrupt_handler(void *arg)
[574fb67]94{
[db21e1d]95  edma_channel_context *ctx = arg;
[97fa2f1b]96
[db21e1d]97  mpc55xx_edma_clear_interrupts(ctx->edma_tcd);
[97fa2f1b]98
[db21e1d]99  (*ctx->done)(ctx, 0);
[574fb67]100}
101
[97fa2f1b]102static void edma_interrupt_error_handler(void *arg)
[574fb67]103{
[97fa2f1b]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)) {
[db21e1d]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);
[97fa2f1b]141
142    if ((error_channels [group_index] & group_bit) != 0) {
[db21e1d]143      unsigned module_index = EDMA_MODULE_INDEX(channel_index);
[97fa2f1b]144
[db21e1d]145      (*ctx->done)(ctx, error_status [module_index]);
[97fa2f1b]146    }
147
148    node = rtems_chain_next(node);
149  }
[574fb67]150}
151
[97fa2f1b]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
[2d43f2d]167    /* Disable requests */
168    edma->CERQR.B.CERQ = 0x40;
169
[97fa2f1b]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) {
[2d43f2d]174      volatile struct tcd_t *tcd = &edma->TCD [channel];
[97fa2f1b]175      edma->CPR [channel].R = 0x80U | (channel & 0xfU);
[2d43f2d]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;
[97fa2f1b]186    }
187
[2d43f2d]188    /* Clear interrupt requests */
189    edma->CIRQR.B.CINT = 0x40;
190    edma->CER.B.CERR = 0x40;
[97fa2f1b]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) {
[33cb8bf]203      bsp_fatal(MPC55XX_FATAL_EDMA_IRQ_INSTALL);
[97fa2f1b]204    }
205  }
206}
[d374492]207
[db21e1d]208rtems_status_code mpc55xx_edma_obtain_channel_by_tcd(
209  volatile struct tcd_t *edma_tcd
[97fa2f1b]210)
211{
212  rtems_status_code sc = RTEMS_SUCCESSFUL;
[db21e1d]213  unsigned channel_index = edma_channel_index_of_tcd(edma_tcd);
[97fa2f1b]214  rtems_interrupt_level level;
[db21e1d]215  uint32_t channel_occupation;
[97fa2f1b]216
217  rtems_interrupt_disable(level);
218  channel_occupation = edma_bit_array_set(
[db21e1d]219    channel_index,
[97fa2f1b]220    &edma_channel_occupation [0]
221  );
222  rtems_interrupt_enable(level);
223
[db21e1d]224  if ((channel_occupation & EDMA_GROUP_BIT(channel_index)) != 0) {
225    sc = RTEMS_RESOURCE_IN_USE;
[97fa2f1b]226  }
227
[db21e1d]228  return sc;
[97fa2f1b]229}
230
[db21e1d]231void mpc55xx_edma_release_channel_by_tcd(volatile struct tcd_t *edma_tcd)
[97fa2f1b]232{
[db21e1d]233  unsigned channel_index = edma_channel_index_of_tcd(edma_tcd);
[97fa2f1b]234  rtems_interrupt_level level;
235
236  rtems_interrupt_disable(level);
[db21e1d]237  edma_bit_array_clear(channel_index, &edma_channel_occupation [0]);
[97fa2f1b]238  rtems_interrupt_enable(level);
239
[db21e1d]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);
[ae88aa7]279  rtems_chain_extract(&ctx->node);
[97fa2f1b]280
281  sc = rtems_interrupt_handler_remove(
[db21e1d]282    MPC55XX_IRQ_EDMA(channel_index),
[97fa2f1b]283    edma_interrupt_handler,
[db21e1d]284    ctx
[97fa2f1b]285  );
286  if (sc != RTEMS_SUCCESSFUL) {
[33cb8bf]287    bsp_fatal(MPC55XX_FATAL_EDMA_IRQ_REMOVE);
[97fa2f1b]288  }
[db21e1d]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}
[97fa2f1b]308
[db21e1d]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  }
[574fb67]329}
Note: See TracBrowser for help on using the repository browser.