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

4.115
Last change on this file since 95b18d0 was 95b18d0, checked in by Joel Sherrill <joel.sherrill@…>, on 11/30/10 at 17:13:28

2010-11-30 Joel Sherrill <joel.sherrilL@…>

  • mpc55xx/edma/edma.c: Use rtems_chain_first() and do not directly access the structure.
  • Property mode set to 100644
File size: 7.6 KB
RevLine 
[574fb67]1/**
2 * @file
3 *
4 * @ingroup mpc55xx
5 *
6 * @brief Enhanced Direct Memory Access (eDMA).
7 */
8
9/*
10 * Copyright (c) 2008
11 * Embedded Brains GmbH
12 * Obere Lagerstr. 30
13 * D-82178 Puchheim
14 * Germany
15 * rtems@embedded-brains.de
16 *
17 * The license and distribution terms for this file may be found in the file
18 * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE.
19 */
20
21#include <mpc55xx/regs.h>
22#include <mpc55xx/edma.h>
23#include <mpc55xx/mpc55xx.h>
24
25#include <string.h>
26
[d374492]27#include <bsp/irq.h>
28
[574fb67]29#define RTEMS_STATUS_CHECKS_USE_PRINTK
30
31#include <rtems/status-checks.h>
32
[88919d0]33#if   ((MPC55XX_CHIP_TYPE >= 5510) && (MPC55XX_CHIP_TYPE <= 5517))
[29313369]34#define MPC55XX_EDMA_CHANNEL_COUNT 16U
[88919d0]35#else /* ((MPC55XX_CHIP_TYPE >= 5510) && (MPC55XX_CHIP_TYPE <= 5517)) */
[29313369]36#define MPC55XX_EDMA_CHANNEL_COUNT 64U
[88919d0]37#endif /* ((MPC55XX_CHIP_TYPE >= 5510) && (MPC55XX_CHIP_TYPE <= 5517)) */
[574fb67]38
[29313369]39#define MPC55XX_EDMA_INVALID_CHANNEL MPC55XX_EDMA_CHANNEL_COUNT
[574fb67]40
[29313369]41#define MPC55XX_EDMA_IS_CHANNEL_INVALID( i) ((unsigned) (i) >= MPC55XX_EDMA_CHANNEL_COUNT)
[574fb67]42
[29313369]43#define MPC55XX_EDMA_IS_CHANNEL_VALID( i) ((unsigned) (i) < MPC55XX_EDMA_CHANNEL_COUNT)
[574fb67]44
[d374492]45#define MPC55XX_EDMA_IRQ_PRIORITY MPC55XX_INTC_DEFAULT_PRIORITY
[574fb67]46
[d374492]47#define MPC55XX_EDMA_CHANNEL_FLAG( channel) ((uint64_t) 1 << (channel))
[574fb67]48
[d374492]49static uint64_t mpc55xx_edma_channel_occupation = 0;
[574fb67]50
[d374492]51static rtems_chain_control mpc55xx_edma_channel_chain;
[574fb67]52
[60e5832]53static void mpc55xx_edma_interrupt_handler( void *arg)
[574fb67]54{
[d374492]55        mpc55xx_edma_channel_entry *e = (mpc55xx_edma_channel_entry *) arg;
56
[574fb67]57#ifdef DEBUG
58        uint32_t citer = EDMA.TCD [e->channel].CITERE_LINK ? EDMA.TCD [e->channel].CITER & EDMA_TCD_BITER_LINKED_MASK : EDMA.TCD [e->channel].CITER;
[d374492]59        RTEMS_DEBUG_PRINT( "channel %i (CITER = %i)\n", e->channel, citer);
[574fb67]60#endif /* DEBUG */
61
[d374492]62        /* Clear interrupt */
63        EDMA.CIRQR.R = (uint8_t) e->channel;
64
65        /* Notify user */
66        e->done( e, 0);
[574fb67]67}
68
[60e5832]69static void mpc55xx_edma_interrupt_error_handler( void *arg)
[574fb67]70{
[d374492]71        rtems_chain_control *chain = &mpc55xx_edma_channel_chain;
[95b18d0]72        rtems_chain_node *node = rtems_chain_first( chain );
[d374492]73        unsigned i = 0;
74        uint64_t error_status = EDMA.ESR.R;
75        uint64_t error_channels = ((uint64_t) EDMA.ERH.R << 32) | EDMA.ERL.R;
76        uint64_t error_channels_update = 0;
77
78        RTEMS_DEBUG_PRINT( "error channels: %08x %08x\n", (unsigned) (error_channels >> 32), (unsigned) error_channels);
79
80        /* Mark all channels that are linked to a channel with errors */
81        do {
82                error_channels_update = 0;
83
[29313369]84                for (i = 0; i < MPC55XX_EDMA_CHANNEL_COUNT; ++i) {
[d374492]85                        uint64_t channel_flags = 0;
86                        unsigned minor_link = i;
87                        unsigned major_link = i;
88
89                        /* Check if we have linked channels */
90                        if (EDMA.TCD [i].BMF.B.BITERE_LINK) {
91                                minor_link = EDMA_TCD_BITER_LINK( i);
92                        }
93                        if (EDMA.TCD [i].BMF.B.MAJORE_LINK) {
94                                major_link = EDMA.TCD [i].BMF.B.MAJORLINKCH;
95                        }
[574fb67]96
[d374492]97                        /* Set flags related to this channel */
98                        channel_flags = MPC55XX_EDMA_CHANNEL_FLAG( i) | MPC55XX_EDMA_CHANNEL_FLAG( minor_link) | MPC55XX_EDMA_CHANNEL_FLAG( major_link);
99
100                        /* Any errors in these channels? */
[b450e0c]101                        if ( error_channels & channel_flags ) {
[d374492]102                                /* Get new error channels */
103                                uint64_t update = (error_channels & channel_flags) ^ channel_flags;
[574fb67]104
[d374492]105                                /* Update error channels */
[b450e0c]106                                error_channels |= channel_flags;
[d374492]107
108                                /* Contribute to the update of this round */
[b450e0c]109                                error_channels_update |=  update;
[d374492]110                        }
[574fb67]111                }
[d374492]112        } while (error_channels_update != 0);
113
114        RTEMS_DEBUG_PRINT( "error channels (all): %08x %08x\n", (unsigned) (error_channels >> 32), (unsigned) error_channels);
[574fb67]115
116        /* Process the channels related to errors */
[d374492]117        while (!rtems_chain_is_tail( chain, node)) {
118                mpc55xx_edma_channel_entry *e = (mpc55xx_edma_channel_entry *) node;
119
[b450e0c]120                if ( error_channels & MPC55XX_EDMA_CHANNEL_FLAG( e->channel)) {
[d374492]121                        mpc55xx_edma_enable_hardware_requests( e->channel, false);
122
123                        /* Notify user */
124                        e->done( e, error_status);
[574fb67]125                }
[d374492]126
127                node = node->next;
[574fb67]128        }
129
130        /* Clear the error interrupt requests */
[29313369]131        for (i = 0; i < MPC55XX_EDMA_CHANNEL_COUNT; ++i) {
[b450e0c]132                if ( error_channels & MPC55XX_EDMA_CHANNEL_FLAG( i)) {
[1dab788]133                        EDMA.CER.R = (uint8_t) i;
[574fb67]134                }
135        }
136}
137
[d374492]138void mpc55xx_edma_enable_hardware_requests( unsigned channel, bool enable)
[574fb67]139{
[d374492]140        if (MPC55XX_EDMA_IS_CHANNEL_VALID( channel)) {
141                if (enable) {
142                        EDMA.SERQR.R = (uint8_t) channel;
143                } else {
144                        EDMA.CERQR.R = (uint8_t) channel;
145                }
[574fb67]146        } else {
[d374492]147                RTEMS_SYSLOG_ERROR( "invalid channel number\n");
[574fb67]148        }
149}
150
[d374492]151void mpc55xx_edma_enable_error_interrupts( unsigned channel, bool enable)
[574fb67]152{
[d374492]153        if (MPC55XX_EDMA_IS_CHANNEL_VALID( channel)) {
154                if (enable) {
155                        EDMA.SEEIR.R = (uint8_t) channel;
156                } else {
157                        EDMA.CEEIR.R = (uint8_t) channel;
158                }
[574fb67]159        } else {
[d374492]160                RTEMS_SYSLOG_ERROR( "invalid channel number\n");
[574fb67]161        }
162}
163
[2f5435a4]164rtems_status_code mpc55xx_edma_init(void)
[574fb67]165{
166        rtems_status_code sc = RTEMS_SUCCESSFUL;
[d374492]167
168        /* Initialize channel chain */
169        rtems_chain_initialize_empty( &mpc55xx_edma_channel_chain);
[574fb67]170
171        /* Arbitration mode: round robin */
172        EDMA.CR.B.ERCA = 1;
173        EDMA.CR.B.ERGA = 1;
174
175        /* Clear TCDs */
[29313369]176        memset( (void *)&EDMA.TCD [0], 0,
177                MPC55XX_EDMA_CHANNEL_COUNT * sizeof( EDMA.TCD[0]));
[574fb67]178
[d374492]179        /* Error interrupt handlers */
[574fb67]180        sc = mpc55xx_interrupt_handler_install(
181                MPC55XX_IRQ_EDMA_ERROR_LOW,
182                "eDMA Error (Low)",
183                RTEMS_INTERRUPT_UNIQUE,
[d374492]184                MPC55XX_EDMA_IRQ_PRIORITY,
185                mpc55xx_edma_interrupt_error_handler,
186                NULL
[574fb67]187        );
[d374492]188        RTEMS_CHECK_SC( sc, "install low error interrupt handler");
[29313369]189
190#if defined(MPC55XX_IRQ_EDMA_ERROR_HIGH)
[574fb67]191        sc = mpc55xx_interrupt_handler_install(
192                MPC55XX_IRQ_EDMA_ERROR_HIGH,
193                "eDMA Error (High)",
194                RTEMS_INTERRUPT_UNIQUE,
[d374492]195                MPC55XX_EDMA_IRQ_PRIORITY,
196                mpc55xx_edma_interrupt_error_handler,
197                NULL
[574fb67]198        );
[d374492]199        RTEMS_CHECK_SC( sc, "install high error interrupt handler");
[29313369]200#endif /* defined(MPC55XX_IRQ_EDMA_ERROR_HIGH) */
[574fb67]201
202        return RTEMS_SUCCESSFUL;
203}
204
[d374492]205rtems_status_code mpc55xx_edma_obtain_channel( mpc55xx_edma_channel_entry *e)
[574fb67]206{
207        rtems_status_code sc = RTEMS_SUCCESSFUL;
[d374492]208        rtems_interrupt_level level;
209        uint64_t channel_occupation = 0;
[574fb67]210
[d374492]211        if (MPC55XX_EDMA_IS_CHANNEL_INVALID( e->channel)) {
[574fb67]212                return RTEMS_INVALID_NUMBER;
213        }
214
[d374492]215        /* Test and set channel occupation flag */
216        rtems_interrupt_disable( level);
217        channel_occupation = mpc55xx_edma_channel_occupation;
[b450e0c]218        if ( (channel_occupation & MPC55XX_EDMA_CHANNEL_FLAG( e->channel)) == 0 ) {
219                mpc55xx_edma_channel_occupation = channel_occupation | MPC55XX_EDMA_CHANNEL_FLAG( e->channel);
[574fb67]220        }
[d374492]221        rtems_interrupt_enable( level);
222
223        /* Check channel occupation flag */
[b450e0c]224        if ( channel_occupation & MPC55XX_EDMA_CHANNEL_FLAG( e->channel)) {
[574fb67]225                return RTEMS_RESOURCE_IN_USE;
226        }
227
228        /* Interrupt handler */
229        sc = mpc55xx_interrupt_handler_install(
[d374492]230                MPC55XX_IRQ_EDMA_GET_REQUEST( e->channel),
[574fb67]231                "eDMA Channel",
232                RTEMS_INTERRUPT_SHARED,
[d374492]233                MPC55XX_EDMA_IRQ_PRIORITY,
234                mpc55xx_edma_interrupt_handler,
235                e
[574fb67]236        );
[d374492]237        RTEMS_CHECK_SC( sc, "install channel interrupt handler");
[574fb67]238
239        /* Enable error interrupts */
[d374492]240        mpc55xx_edma_enable_error_interrupts( e->channel, true);
241
242        /* Prepend channel entry to channel list */
243        rtems_chain_prepend( &mpc55xx_edma_channel_chain, &e->node);
[574fb67]244
245        return RTEMS_SUCCESSFUL;
246}
247
[d374492]248rtems_status_code mpc55xx_edma_release_channel( mpc55xx_edma_channel_entry *e)
[574fb67]249{
[d374492]250        rtems_status_code sc = RTEMS_SUCCESSFUL;
251        rtems_interrupt_level level;
252
253        /* Clear channel occupation flag */
254        rtems_interrupt_disable( level);
[b450e0c]255        mpc55xx_edma_channel_occupation &= ~MPC55XX_EDMA_CHANNEL_FLAG( e->channel);
[d374492]256        rtems_interrupt_enable( level);
257
258        /* Disable hardware requests */
259        mpc55xx_edma_enable_hardware_requests( e->channel, false);
260
261        /* Disable error interrupts */
262        mpc55xx_edma_enable_error_interrupts( e->channel, false);
263
264        /* Extract channel entry from channel chain */
265        rtems_chain_extract( &e->node);
266
267        /* Remove interrupt handler */
268        sc = rtems_interrupt_handler_remove(
269                MPC55XX_IRQ_EDMA_GET_REQUEST( e->channel),
270                mpc55xx_edma_interrupt_handler,
271                e
272        );
273        RTEMS_CHECK_SC( sc, "remove channel interrupt handler");
274
275        /* Notify user */
276        e->done( e, 0);
277
278        return RTEMS_SUCCESSFUL;
[574fb67]279}
Note: See TracBrowser for help on using the repository browser.