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

4.104.11
Last change on this file since 602aee20 was 602aee20, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on Oct 10, 2008 at 3:50:15 PM

shared/include/utility.h: Removed file.

shared/include/powerpc-utility.h: Use constraint "b" for address
base registers in inline assembler statements.
Update for status-checks.h changes.

  • Property mode set to 100644
File size: 8.1 KB
Line 
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 <bsp/irq.h>
26
27#include <string.h>
28
29#define RTEMS_STATUS_CHECKS_USE_PRINTK
30
31#include <rtems/status-checks.h>
32
33#define MPC55XX_EDMA_CHANNEL_NUMBER 64
34#define MPC55XX_EDMA_INVALID_CHANNEL UINT8_MAX
35#define MPC55XX_EDMA_IS_CHANNEL_INVALID( i) ((i) < 0 || (i) >= MPC55XX_EDMA_CHANNEL_NUMBER)
36
37#define MPC55XX_EDMA_IRQ_PRIORITY MPC55XX_INTC_MIN_PRIORITY
38
39typedef struct {
40        uint8_t channel;
41        rtems_id transfer_update;
42        uint32_t *error_status;
43} mpc55xx_edma_channel_entry;
44
45static mpc55xx_edma_channel_entry mpc55xx_edma_channel_table [MPC55XX_EDMA_CHANNEL_NUMBER];
46
47static uint32_t mpc55xx_edma_channel_occupation_low = 0;
48
49static uint32_t mpc55xx_edma_channel_occupation_high = 0;
50
51static rtems_id mpc55xx_edma_channel_occupation_mutex = RTEMS_ID_NONE;
52
53static uint8_t mpc55xx_edma_irq_error_low_channel = 0;
54
55static uint8_t mpc55xx_edma_irq_error_high_channel = 32;
56
57static void mpc55xx_edma_irq_handler( rtems_vector_number vector, void *data)
58{
59        rtems_status_code sc = RTEMS_SUCCESSFUL;
60        mpc55xx_edma_channel_entry *e = (mpc55xx_edma_channel_entry *) data;
61#ifdef DEBUG
62        uint32_t citer = EDMA.TCD [e->channel].CITERE_LINK ? EDMA.TCD [e->channel].CITER & EDMA_TCD_BITER_LINKED_MASK : EDMA.TCD [e->channel].CITER;
63        RTEMS_DEBUG_PRINT( "Channel %i (CITER = %i)\n", e->channel, citer);
64#endif /* DEBUG */
65        EDMA.CIRQR.R = e->channel;
66        sc = rtems_semaphore_release( e->transfer_update);
67        RTEMS_SYSLOG_WARNING_SC( sc, "Transfer update semaphore release");
68}
69
70static void mpc55xx_edma_irq_update_error_table( uint8_t *link_table, uint8_t *error_table, int channel)
71{
72        int i = 0;
73        error_table [channel] = 1;
74        for (i = 0; i < MPC55XX_EDMA_CHANNEL_NUMBER; ++i) {
75                if (channel == link_table [i] && error_table [i] == 0) {
76                        mpc55xx_edma_irq_update_error_table( link_table, error_table, i);
77                }
78        }
79}
80
81static void mpc55xx_edma_irq_error_handler( rtems_vector_number vector, void *data)
82{
83        rtems_status_code sc = RTEMS_SUCCESSFUL;
84        uint8_t channel_start = *((uint8_t *) data);
85        uint8_t channel_end = (uint8_t) (channel_start + 32);
86        int i = 0;
87        uint32_t mask = 0x1;
88        uint32_t error_register = 0;
89        uint8_t channel_link_table [MPC55XX_EDMA_CHANNEL_NUMBER];
90        uint8_t channel_error_table [MPC55XX_EDMA_CHANNEL_NUMBER];
91
92        /* Error register */
93        if (channel_start < 32) {
94                error_register = EDMA.ERL.R;
95        } else if (channel_start < 64) {
96                error_register = EDMA.ERH.R;
97        }
98        RTEMS_DEBUG_PRINT( "Error register %s: 0x%08x\n", channel_start < 32 ? "low" : "high", error_register);
99
100        /* Fill channel link table */
101        for (i = 0; i < MPC55XX_EDMA_CHANNEL_NUMBER; ++i) {
102                if (EDMA.TCD [i].BITERE_LINK && EDMA.TCD [i].CITER != EDMA.TCD [i].BITER) {
103                        channel_link_table [i] = (uint8_t) EDMA_TCD_BITER_LINK( i);
104                } else if (EDMA.TCD [i].MAJORE_LINK && EDMA.TCD [i].CITER == EDMA.TCD [i].BITER) {
105                        channel_link_table [i] = EDMA.TCD [i].MAJORLINKCH;
106                } else {
107                        channel_link_table [i] = MPC55XX_EDMA_INVALID_CHANNEL;
108                }
109                channel_error_table [i] = 0;
110        }
111
112        /* Search for channels with errors */
113        for (i = channel_start; i < channel_end; ++i) {
114                if ((error_register & mask) != 0) {
115                        mpc55xx_edma_irq_update_error_table( channel_link_table, channel_error_table, i);
116                }
117                mask <<= 1;
118        }
119
120        /* Process the channels related to errors */
121        error_register = EDMA.ESR.R;
122        for (i = 0; i < MPC55XX_EDMA_CHANNEL_NUMBER; ++i) {
123                if (channel_error_table [i]) {
124                        mpc55xx_edma_channel_entry *e = &mpc55xx_edma_channel_table [i];
125                        if (e->error_status != NULL) {
126                                *e->error_status = error_register;
127                        }
128                        sc = mpc55xx_edma_enable_hardware_requests( i, false);
129                        RTEMS_SYSLOG_ERROR_SC( sc, "Disable hardware requests");
130                        sc = rtems_semaphore_release( e->transfer_update);
131                        RTEMS_SYSLOG_WARNING_SC( sc, "Transfer update semaphore release");
132                }
133        }
134
135        /* Clear the error interrupt requests */
136        for (i = 0; i < MPC55XX_EDMA_CHANNEL_NUMBER; ++i) {
137                if (channel_error_table [i]) {
138                        EDMA.CER.R = (uint8_t) i;
139                }
140        }
141}
142
143rtems_status_code mpc55xx_edma_enable_hardware_requests( int channel, bool enable)
144{
145        if (MPC55XX_EDMA_IS_CHANNEL_INVALID( channel)) {
146                return RTEMS_INVALID_NUMBER;
147        }
148        if (enable) {
149                EDMA.SERQR.R = (uint8_t) channel;
150        } else {
151                EDMA.CERQR.R = (uint8_t) channel;
152        }
153        return RTEMS_SUCCESSFUL;
154}
155
156rtems_status_code mpc55xx_edma_enable_error_interrupts( int channel, bool enable)
157{
158        if (MPC55XX_EDMA_IS_CHANNEL_INVALID( channel)) {
159                return RTEMS_INVALID_NUMBER;
160        }
161        if (enable) {
162                EDMA.SEEIR.R = channel;
163        } else {
164                EDMA.CEEIR.R = channel;
165        }
166        return RTEMS_SUCCESSFUL;
167}
168
169rtems_status_code mpc55xx_edma_init()
170{
171        rtems_status_code sc = RTEMS_SUCCESSFUL;
172        int i = 0;
173
174        /* Channel occupation mutex */
175        sc = rtems_semaphore_create (
176                rtems_build_name ( 'D', 'M', 'A', 'O'),
177                1,
178                RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
179                RTEMS_NO_PRIORITY,
180                &mpc55xx_edma_channel_occupation_mutex
181        );
182        RTEMS_CHECK_SC( sc, "Create channel occupation mutex");
183
184        /* Arbitration mode: round robin */
185        EDMA.CR.B.ERCA = 1;
186        EDMA.CR.B.ERGA = 1;
187
188        /* Clear TCDs */
189        memset( &EDMA.TCD [0], 0, sizeof( EDMA.TCD));
190
191        /* Channel table */
192        for (i = 0; i < MPC55XX_EDMA_CHANNEL_NUMBER; ++i) {
193                mpc55xx_edma_channel_table [i].channel = i;
194                mpc55xx_edma_channel_table [i].transfer_update = RTEMS_ID_NONE;
195                mpc55xx_edma_channel_table [i].error_status = NULL;
196        }
197
198        /* Error interrupt handler */
199        sc = mpc55xx_interrupt_handler_install(
200                MPC55XX_IRQ_EDMA_ERROR_LOW,
201                MPC55XX_EDMA_IRQ_PRIORITY,
202                "eDMA Error (Low)",
203                RTEMS_INTERRUPT_UNIQUE,
204                mpc55xx_edma_irq_error_handler,
205                &mpc55xx_edma_irq_error_low_channel
206        );
207        RTEMS_CHECK_SC( sc, "Install low error interrupt handler");
208        sc = mpc55xx_interrupt_handler_install(
209                MPC55XX_IRQ_EDMA_ERROR_HIGH,
210                MPC55XX_EDMA_IRQ_PRIORITY,
211                "eDMA Error (High)",
212                RTEMS_INTERRUPT_UNIQUE,
213                mpc55xx_edma_irq_error_handler,
214                &mpc55xx_edma_irq_error_high_channel
215        );
216        RTEMS_CHECK_SC( sc, "Install high error interrupt handler");
217
218        return RTEMS_SUCCESSFUL;
219}
220
221rtems_status_code mpc55xx_edma_obtain_channel( int channel, uint32_t *error_status, rtems_id transfer_update)
222{
223        rtems_status_code sc = RTEMS_SUCCESSFUL;
224        int channel_occupied = 1;
225
226        if (MPC55XX_EDMA_IS_CHANNEL_INVALID( channel)) {
227                return RTEMS_INVALID_NUMBER;
228        }
229
230        /* Check occupation */
231        sc = rtems_semaphore_obtain( mpc55xx_edma_channel_occupation_mutex, RTEMS_WAIT, 0);
232        RTEMS_CHECK_SC( sc, "Obtain channel occupation mutex");
233        if (channel < 32) {
234                channel_occupied = mpc55xx_edma_channel_occupation_low & (0x1 << channel);
235                if (!channel_occupied) {
236                        mpc55xx_edma_channel_occupation_low |= 0x1 << channel;
237                }
238        } else if (channel < 64) {
239                channel_occupied = mpc55xx_edma_channel_occupation_high & (0x1 << (channel - 32));
240                if (!channel_occupied) {
241                        mpc55xx_edma_channel_occupation_high |= 0x1 << (channel - 32);
242                }
243        }
244        if (channel_occupied) {
245                sc = rtems_semaphore_release( mpc55xx_edma_channel_occupation_mutex);
246                RTEMS_SYSLOG_WARNING_SC( sc, "Release occupation mutex");
247                return RTEMS_RESOURCE_IN_USE;
248        } else {
249                sc = rtems_semaphore_release( mpc55xx_edma_channel_occupation_mutex);
250                RTEMS_CHECK_SC( sc, "Release channel occupation mutex");
251        }
252
253        /* Channel data */
254        mpc55xx_edma_channel_table [channel].transfer_update = transfer_update;
255        mpc55xx_edma_channel_table [channel].error_status = error_status;
256
257        /* Interrupt handler */
258        sc = mpc55xx_interrupt_handler_install(
259                MPC55XX_IRQ_EDMA_GET_REQUEST( channel),
260                MPC55XX_EDMA_IRQ_PRIORITY,
261                "eDMA Channel",
262                RTEMS_INTERRUPT_SHARED,
263                mpc55xx_edma_irq_handler,
264                &mpc55xx_edma_channel_table [channel]
265        );
266        RTEMS_CHECK_SC( sc, "Install channel interrupt handler");
267
268        /* Enable error interrupts */
269        sc = mpc55xx_edma_enable_error_interrupts( channel, true);
270        RTEMS_CHECK_SC( sc, "Enable error interrupts");
271
272        return RTEMS_SUCCESSFUL;
273}
274
275rtems_status_code mpc55xx_edma_release_channel( int channel)
276{
277        // TODO
278        return RTEMS_NOT_IMPLEMENTED;
279}
Note: See TracBrowser for help on using the repository browser.