source: rtems/bsps/powerpc/gen5200/mscan/mscan.c @ 3fb2a815

Last change on this file since 3fb2a815 was 3fb2a815, checked in by Christian Mauderer <christian.mauderer@…>, on 03/03/22 at 08:17:22

bsps/powerpc/gen5200: Manual file header clean up

Updates #4625.

  • Property mode set to 100644
File size: 34.1 KB
Line 
1/*
2 * RTEMS generic MPC5200 BSP
3 *
4 * This file contains the MSCAN driver.
5 */
6
7/*
8 * Copyright (c) 2005 embedded brains GmbH. All rights reserved.
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <rtems.h>
18#include <rtems/error.h>
19#include <rtems/libio.h>
20#include <string.h>
21
22#include <bsp.h>
23#include <bsp/fatal.h>
24#include <bsp/irq.h>
25#include "../mscan/mscan_int.h"
26
27/* #define MSCAN_LOOPBACK */
28
29struct mpc5200_rx_cntrl mpc5200_mscan_rx_cntrl[MPC5200_CAN_NO];
30static struct mscan_channel_info chan_info[MPC5200_CAN_NO];
31
32/*
33 * MPC5x00 MSCAN tx ring buffer function to get a can message buffer from the head of the tx ring buffer
34 */
35static struct can_message *get_tx_buffer(struct mscan_channel_info *chan)
36{
37  /* define a temp. mess ptr. */
38  struct can_message *tmp_mess_ptr = NULL,
39    *temp_head_ptr;
40
41  /* set temp. head pointer */
42  temp_head_ptr = chan->tx_ring_buf.head_ptr;
43
44  /* check buffer empty condition */
45  if (temp_head_ptr != chan->tx_ring_buf.tail_ptr) {
46
47    /* current buffer head. ptr. */
48    tmp_mess_ptr = temp_head_ptr;
49
50    /* increment the head pointer */
51    temp_head_ptr++;
52
53    /* check for wrap around condition */
54    if (temp_head_ptr > chan->tx_ring_buf.buf_ptr + NO_OF_MSCAN_TX_BUFF) {
55
56      /* set head ptr. to the begin of the ring buffer */
57      temp_head_ptr = chan->tx_ring_buf.buf_ptr;
58
59    }
60
61    /* end of crtical section restore head ptr. */
62    chan->tx_ring_buf.head_ptr = temp_head_ptr;
63  }
64
65  /* return the current head pointer */
66  return tmp_mess_ptr;
67}
68
69/*
70 * MPC5x00 MSCAN tx ring buffer function to write a can message buffer to the tail of the tx ring buffer
71 */
72static struct can_message *fill_tx_buffer(struct mscan_channel_info *chan,
73                                          struct can_message *mess_ptr)
74{
75  /* define a temp. mess ptr. to the entry which follows the current tail entry */
76  struct can_message *tmp_mess_ptr = chan->tx_ring_buf.tail_ptr + 1;
77
78  /* check for the wrap around condition */
79  if (tmp_mess_ptr > chan->tx_ring_buf.buf_ptr + NO_OF_MSCAN_TX_BUFF) {
80    /* set temp. mess. ptr to the begin of the ring buffer */
81    tmp_mess_ptr = chan->tx_ring_buf.buf_ptr;
82  }
83
84  /* check buffer full condition */
85  if (tmp_mess_ptr == chan->tx_ring_buf.head_ptr) {
86    /* return NULL in case buffer is full */
87    return NULL;
88  } else {
89    /* copy the can mess. to the tail of the buffer */
90    memcpy((void *) chan->tx_ring_buf.tail_ptr, (void *) mess_ptr,
91           sizeof (struct can_message));
92
93    /* set new tail equal to temp. mess. ptr. */
94    chan->tx_ring_buf.tail_ptr = tmp_mess_ptr;
95  }
96
97  /* return the actual tail ptr. (next free entry) */
98  return chan->tx_ring_buf.tail_ptr;
99}
100
101/*
102 * MPC5x00 MSCAN interrupt handler
103 */
104static void mpc5200_mscan_interrupt_handler(rtems_irq_hdl_param handle)
105{
106  rtems_status_code status;
107  mscan_handle *mscan_hdl = (mscan_handle *) handle;
108  struct mscan_channel_info *chan = &chan_info[mscan_hdl->mscan_channel];
109  struct can_message rx_mess,
110   *rx_mess_ptr,
111   *tx_mess_ptr;
112  mscan *m = chan->regs;
113  register uint8_t idx;
114
115  /*
116     handle tx ring buffer
117   */
118
119  /* loop over all 3 tx buffers */
120  for (idx = TFLG_TXE0; idx <= TFLG_TXE2; idx = idx << 1) {
121
122    /* check for tx buffer vacation */
123    if ((m->tflg) & idx) {
124
125      /* try to get a message */
126      tx_mess_ptr = get_tx_buffer(chan);
127
128      /* check for new tx message */
129      if (tx_mess_ptr != NULL) {
130
131        /* select the tx buffer */
132        m->bsel = idx;
133
134        /* check for toucan interface */
135        if ((mscan_hdl->toucan_callback) == NULL) {
136
137          /* set tx id */
138          m->txidr0 = SET_IDR0(tx_mess_ptr->mess_id);
139          m->txidr1 = SET_IDR1(tx_mess_ptr->mess_id);
140          m->txidr2 = 0;
141          m->txidr3 = 0;
142
143        }
144
145        /* fill in tx data if TOUCAN is activ an TOUCAN index have a match with the tx buffer or TOUCAN is disabled */
146        if (((mscan_hdl->toucan_callback) == NULL)
147            || (((mscan_hdl->toucan_callback) != NULL)
148                && ((tx_mess_ptr->toucan_tx_idx) == idx))) {
149
150          /* insert dlc into m register */
151          m->txdlr = (uint8_t) ((tx_mess_ptr->mess_len) & 0x000F);
152
153          /* skip data copy in case of RTR */
154          if (!(MSCAN_MESS_ID_HAS_RTR(tx_mess_ptr->mess_id))) {
155            /* copy tx data to MSCAN registers */
156            switch (m->txdlr) {
157              case 8:
158                m->txdsr7 = tx_mess_ptr->mess_data[7];
159              case 7:
160                m->txdsr6 = tx_mess_ptr->mess_data[6];
161              case 6:
162                m->txdsr5 = tx_mess_ptr->mess_data[5];
163              case 5:
164                m->txdsr4 = tx_mess_ptr->mess_data[4];
165              case 4:
166                m->txdsr3 = tx_mess_ptr->mess_data[3];
167              case 3:
168                m->txdsr2 = tx_mess_ptr->mess_data[2];
169              case 2:
170                m->txdsr1 = tx_mess_ptr->mess_data[1];
171              case 1:
172                m->txdsr0 = tx_mess_ptr->mess_data[0];
173                break;
174              default:
175                break;
176            }
177          }
178
179          /* enable message buffer specific interrupt */
180          m->tier |= m->bsel;
181
182          /* start transfer */
183          m->tflg = m->bsel;
184
185          /* release counting semaphore of tx ring buffer */
186          rtems_semaphore_release((rtems_id) (chan->tx_rb_sid));
187
188        } else {
189
190          /* refill the tx ring buffer with the message */
191          fill_tx_buffer(chan, tx_mess_ptr);
192
193        }
194      } else {
195        /* reset interrupt enable bit */
196        m->tier &= ~(idx);
197      }
198    }
199  }
200
201  /*
202     handle rx interrupts
203   */
204
205  /* check for rx interrupt source */
206  if (m->rier & RIER_RXFIE) {
207
208    /* can messages received ? */
209    while (m->rflg & RFLG_RXF) {
210
211      if (mscan_hdl->toucan_callback == NULL) {
212
213        /* select temporary rx buffer */
214        rx_mess_ptr = &rx_mess;
215
216      } else {
217
218        /* check the rx fliter-match indicators (16-bit filter mode) */
219        /* in case of more than one hit, lower hit has priority */
220        idx = (m->idac) & 0x7;
221        switch (idx) {
222
223          case 0:
224          case 1:
225          case 2:
226          case 3:
227            rx_mess_ptr =
228              (struct can_message *)
229              &(mpc5200_mscan_rx_cntrl[mscan_hdl->mscan_channel].
230                can_rx_message[idx]);
231            break;
232
233            /* this case should never happen */
234          default:
235            /* reset the rx indication flag */
236            m->rflg |= RFLG_RXF;
237
238            return;
239            break;
240        }
241
242      }
243
244      /* get rx ID */
245      rx_mess_ptr->mess_id = GET_IDR0(m->rxidr0) | GET_IDR1(m->rxidr1);
246
247      /* get rx len */
248      rx_mess_ptr->mess_len = ((m->rxdlr) & 0x0F);
249
250      /* get time stamp */
251      rx_mess_ptr->mess_time_stamp = ((m->rxtimh << 8) | (m->rxtiml));
252
253      /* skip data copy in case of RTR */
254      if (!(MSCAN_MESS_ID_HAS_RTR(rx_mess_ptr->mess_id)))
255      {
256
257        /* get the data */
258        switch (rx_mess_ptr->mess_len) {
259          case 8:
260            rx_mess_ptr->mess_data[7] = m->rxdsr7;
261          case 7:
262            rx_mess_ptr->mess_data[6] = m->rxdsr6;
263          case 6:
264            rx_mess_ptr->mess_data[5] = m->rxdsr5;
265          case 5:
266            rx_mess_ptr->mess_data[4] = m->rxdsr4;
267          case 4:
268            rx_mess_ptr->mess_data[3] = m->rxdsr3;
269          case 3:
270            rx_mess_ptr->mess_data[2] = m->rxdsr2;
271          case 2:
272            rx_mess_ptr->mess_data[1] = m->rxdsr1;
273          case 1:
274            rx_mess_ptr->mess_data[0] = m->rxdsr0;
275          case 0:
276          default:
277            break;
278        }
279      }
280
281      if (mscan_hdl->toucan_callback == NULL) {
282
283        if ((status =
284             rtems_message_queue_send(chan->rx_qid, (void *) rx_mess_ptr,
285                                      sizeof (struct can_message))) !=
286            RTEMS_SUCCESSFUL) {
287
288          chan->int_rx_err++;
289
290        }
291
292      } else {
293
294        mscan_hdl->toucan_callback((int16_t) (((m->idac) & 0x7) + 3));
295
296      }
297
298      /* reset the rx indication flag */
299      m->rflg |= RFLG_RXF;
300
301    }                           /* end of while(m->rflg & RFLG_RXF) */
302
303  }
304
305  /* status change detected */
306  if (m->rflg & RFLG_CSCIF) {
307
308    m->rflg |= RFLG_CSCIF;
309
310    if (mscan_hdl->toucan_callback != NULL) {
311
312      mscan_hdl->toucan_callback((int16_t) (-1));
313
314    }
315
316  }
317
318}
319
320/**
321 * @brief Enables some interrupts for the MSCAN module @a m.
322 *
323 * Enabled interrupts:
324 *  - Receiver or transmitter enters or leaves bus off state
325 *  - Receiver buffer full
326 */
327static void mscan_interrupts_enable(mscan *m)
328{
329
330  /* RX Interrupt Enable on MSCAN_A/_B ----------------------------- */
331  /*    [07]:WUPIE         0 : WakeUp interrupt disabled            */
332  /*    [06]:CSCIE         1 : Status Change interrupt enabled      */
333  /*    [05]:RSTATE1       0 : Recv. Status Change int. ,Bit 1      */
334  /*    [04]:RSTATE0       1 : Recv. Status Change int. ,Bit 0      */
335  /*                           -> 01 BusOff status changes enabled  */
336  /*    [03]:TSTAT1        0 : Transmit. Status Change int. , Bit 1 */
337  /*    [02]:TSTAT0        1 : Transmit. Status Change int. , Bit 0 */
338  /*                           -> 01 BusOff status changes enabled  */
339  /*    [01]:OVRIE         0 : Overrun Interrupt is disabled        */
340  /*    [00]:RXFIE         1 : Recv. Full interrupt is enabled      */
341  m->rier |= (RIER_CSCIE | RIER_RXFIE | RIER_RSTAT(1) | RIER_TSTAT(1));
342
343  return;
344
345}
346
347/*
348 * Unmask MPC5x00 MSCAN_A interrupts
349 */
350static void mpc5200_mscan_a_on(const rtems_irq_connect_data * ptr)
351{
352  mscan *m = (&chan_info[MSCAN_A])->regs;
353
354  mscan_interrupts_enable(m);
355
356  return;
357
358}
359
360/*
361 * Mask MPC5x00 MSCAN_A interrupts
362 */
363static void mpc5200_mscan_a_off(const rtems_irq_connect_data * ptr)
364{
365  mscan *m = (&chan_info[MSCAN_A])->regs;
366
367  mscan_interrupts_disable(m);
368
369  return;
370
371}
372
373/*
374 *  Get MSCAN_A interrupt mask setting
375 */
376static int mpc5200_mscan_a_isOn(const rtems_irq_connect_data * ptr)
377{
378  mscan *m = (&chan_info[MSCAN_A])->regs;
379
380  if ((m->rier & RIER_CSCIE) && (m->rier & RIER_RXFIE))
381    return RTEMS_SUCCESSFUL;
382  else
383    return RTEMS_UNSATISFIED;
384
385  return RTEMS_SUCCESSFUL;
386
387}
388
389/*
390 * Unmask MPC5x00 MSCAN_B interrupts
391 */
392static void mpc5200_mscan_b_on(const rtems_irq_connect_data * ptr)
393{
394  mscan *m = (&chan_info[MSCAN_B])->regs;
395
396  mscan_interrupts_enable(m);
397
398  return;
399
400}
401
402/*
403 * Mask MPC5x00 MSCAN_B interrupts
404 */
405static void mpc5200_mscan_b_off(const rtems_irq_connect_data * ptr)
406{
407  mscan *m = (&chan_info[MSCAN_B])->regs;
408
409  mscan_interrupts_disable(m);
410
411  return;
412
413}
414
415/*
416 *  Get MSCAN_B interrupt mask setting
417 */
418static int mpc5200_mscan_b_isOn(const rtems_irq_connect_data * ptr)
419{
420  mscan *m = (&chan_info[MSCAN_B])->regs;
421
422  if ((m->rier & RIER_CSCIE) && (m->rier & RIER_RXFIE))
423    return RTEMS_SUCCESSFUL;
424  else
425    return RTEMS_UNSATISFIED;
426
427  return RTEMS_SUCCESSFUL;
428
429}
430
431static mscan_handle mscan_a_handle = {
432  MSCAN_A,
433  NULL
434};
435
436static mscan_handle mscan_b_handle = {
437  MSCAN_B,
438  NULL
439};
440
441/*
442 * MPC5x00 MSCAN_A/_B irq data
443 */
444static rtems_irq_connect_data mpc5200_mscan_irq_data[MPC5200_CAN_NO] = {
445  {
446    BSP_SIU_IRQ_MSCAN1,
447    (rtems_irq_hdl) mpc5200_mscan_interrupt_handler,
448    (rtems_irq_hdl_param) & mscan_a_handle,
449    (rtems_irq_enable) mpc5200_mscan_a_on,
450    (rtems_irq_disable) mpc5200_mscan_a_off,
451    (rtems_irq_is_enabled) mpc5200_mscan_a_isOn
452  }, {
453    BSP_SIU_IRQ_MSCAN2,
454    (rtems_irq_hdl) mpc5200_mscan_interrupt_handler,
455    (rtems_irq_hdl_param) & mscan_b_handle,
456    (rtems_irq_enable) mpc5200_mscan_b_on,
457    (rtems_irq_disable) mpc5200_mscan_b_off,
458    (rtems_irq_is_enabled) mpc5200_mscan_b_isOn
459  }
460};
461
462/*
463 * MPC5x00 MSCAN wait for sync. with CAN bus
464 */
465void mpc5200_mscan_wait_sync(mscan *m)
466{
467
468  /* Control Register 0 -------------------------------------------- */
469  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
470  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
471  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
472  /*    [04]:SYNCH    0->1 : Synchronized, Status Bit (rd. only)    */
473  /*    [03]:TIME        1 : Generate Timestamps                    */
474  /*    [02]:WUPE        0 : WakeUp Disabled                        */
475  /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
476  /*    [00]:INITRQ      0 : No init. Mode Request                  */
477  /* wait for MSCAN A_/_B bus synch. */
478
479#if 0                           /* we don't have a need to wait for sync. */
480  while (!((m->ctl0) & CTL0_SYNCH));
481#endif
482  return;
483
484}
485
486/*
487 * MPC5x00 MSCAN perform settings in init mode
488 */
489static void mpc5200_mscan_perform_initialization_mode_settings(mscan *m)
490{
491  mscan_context context;
492
493  /* perform all can bit time settings */
494  (void) mscan_set_bit_rate(m, MSCAN_BIT_RATE_DEFAULT);
495
496  /* Enter initialization mode */
497  mscan_initialization_mode_enter( m, &context);
498
499  /* Control Register 1 -------------------------------------------- */
500  /*    [07]:CANE        0 : MSCAN Module is disabled               */
501  /*    [06]:CLKSRC      0 : Clock Source -> IPB_CLOCK (bsp.h)      */
502  /*    [05]:LOOPB       0 : No Loopback                            */
503  /*    [04]:LISTEN      0 : Normal Operation                       */
504  /*    [03]:res         0 : reserved                               */
505  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
506  /*    [01]:SLPAK    1->0 : Sleep Mode Acknowledge (rd. only)      */
507  /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
508  /* Set CLK source, disable loopback & listen-only mode */
509#ifndef MSCAN_LOOPBACK
510  m->ctl1 &= ~(CTL1_LISTEN | CTL1_LOOPB | CTL1_CLKSRC);
511#else
512  m->ctl1 &= ~(CTL1_LISTEN | CTL1_CLKSRC);
513  m->ctl1 |= (CTL1_LOOPB);
514#endif
515
516  /* IPB clock       -> IPB_CLOCK                                                            */
517  /* bitrate         -> CAN_BIT_RATE                                                         */
518  /* Max. no of Tq   -> CAN_MAX_NO_OF_TQ                                                     */
519  /* Prescaler value -> prescale_val = ROUND_UP(IPB_CLOCK/(CAN_BIT_RATE * CAN_MAX_NO_OF_TQ)) */
520  /* SYNC_SEG        ->  1 tq                                                                */
521  /* time segment 1  -> 16 tq (PROP_SEG+PHASE_SEG), CAN_MAX_NO_OF_TQ_TSEG1 = 15              */
522  /* time segment 2  ->  8 tq (PHASE_SEG2)        , CAN_MAX_NO_OF_TQ_TSEG2 =  7              */
523  /* SJW             ->  3 (fixed 0...3)          , CAN_MAX_NO_OF_TQ_SJW   =  2              */
524
525  /* ID Acceptance Control MSCAN_A/_B ------------------------------ */
526  /*    [07]:res.        0 : reserved                               */
527  /*    [06]:res.        0 : reserved                               */
528  /*    [05]:IDAM1       0 : ID acceptance control, Bit1            */
529  /*    [04]:IDAM0       1 : ID acceptance control, Bit0            */
530  /*                         -> filter 16 bit mode                  */
531  /*    [03]:res.        0 : reserved                               */
532  /*    [02]:IDHIT2      0 : ID acceptance hit indication, Bit 2    */
533  /*    [01]:IDHIT1      0 : ID acceptance hit indication, Bit 1    */
534  /*    [00]:IDHIT0      0 : ID acceptance hit indication, Bit 0    */
535  m->idac &= ~(IDAC_IDAM1);
536  m->idac |= (IDAC_IDAM0);
537
538  /* initialize rx filter masks (16 bit), don't care including rtr */
539  m->idmr0 = SET_IDMR0(0x7FF);
540  m->idmr1 = SET_IDMR1(0x7FF);
541  m->idmr2 = SET_IDMR2(0x7FF);
542  m->idmr3 = SET_IDMR3(0x7FF);
543  m->idmr4 = SET_IDMR4(0x7FF);
544  m->idmr5 = SET_IDMR5(0x7FF);
545  m->idmr6 = SET_IDMR6(0x7FF);
546  m->idmr7 = SET_IDMR7(0x7FF);
547
548  /* Control Register 1 -------------------------------------------- */
549  /*    [07]:CANE     0->1 : MSCAN Module is enabled                */
550  /*    [06]:CLKSRC      1 : Clock Source -> IPB_CLOCK (bsp.h)      */
551  /*    [05]:LOOPB       0 : No Loopback                            */
552  /*    [04]:LISTEN      0 : Normal Operation                       */
553  /*    [03]:res         0 : reserved                               */
554  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
555  /*    [01]:SLPAK       0 : Sleep Mode Acknowledge (rd. only)      */
556  /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
557  /* enable MSCAN A_/_B */
558  m->ctl1 |= (CTL1_CANE);
559
560  /* Leave initialization mode */
561  mscan_initialization_mode_leave( m, &context);
562
563  return;
564
565}
566
567/*
568 * MPC5x00 MSCAN perform settings in normal mode
569 */
570void mpc5200_mscan_perform_normal_mode_settings(mscan
571                                                *m)
572{
573
574  /* Control Register 0 -------------------------------------------- */
575  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
576  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
577  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
578  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
579  /*    [03]:TIME        1 : Generate Timestamps                    */
580  /*    [02]:WUPE        0 : WakeUp Disabled                        */
581  /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
582  /*    [00]:INITRQ      0 : No init. Mode Request                  */
583  /* Disable wait mode, enable timestamps */
584  m->ctl0 &= ~(CTL0_CSWAI);
585  m->ctl0 |= (CTL0_TIME);
586
587  return;
588
589}
590
591rtems_status_code mpc5200_mscan_set_mode(rtems_device_minor_number minor,
592                                         uint8_t mode)
593{
594  struct mscan_channel_info *chan = NULL;
595  mscan *m = NULL;
596
597  switch (minor) {
598
599    case MSCAN_A:
600    case MSCAN_B:
601      chan = &chan_info[minor];
602      m = chan->regs;
603      break;
604
605    default:
606      return RTEMS_UNSATISFIED;
607      break;
608  }
609
610  if (chan->mode == mode)
611    return RTEMS_SUCCESSFUL;
612
613  switch (mode) {
614
615    case MSCAN_INIT_NORMAL_MODE:
616      /* perform initialization which has to be done in init mode */
617      mpc5200_mscan_perform_initialization_mode_settings(m);
618      break;
619
620    case MSCAN_NORMAL_MODE:
621      if ((chan->mode) == MSCAN_INITIALIZED_MODE) {
622        /* perform initialization which has to be done in init mode */
623        mpc5200_mscan_perform_initialization_mode_settings(m);
624      }
625
626      if ((chan->mode) == MSCAN_SLEEP_MODE) {
627
628        /* exit sleep mode */
629        mscan_sleep_mode_leave(m);
630      }
631      /* enable ints. */
632      mscan_interrupts_enable(m);
633      /* wait for bus sync. */
634      mpc5200_mscan_wait_sync(m);
635      break;
636
637    case MSCAN_SLEEP_MODE:
638      /* disable ints. */
639      mscan_interrupts_disable(m);
640      /* knter sleep mode */
641      mscan_sleep_mode_enter(m);
642      break;
643
644    default:
645      return RTEMS_UNSATISFIED;
646      break;
647
648  }
649
650  /* set new channel mode */
651  chan->mode = mode;
652
653  return RTEMS_SUCCESSFUL;
654
655}
656
657/*
658 * initialization of channel info.
659 */
660rtems_status_code mscan_channel_initialize(rtems_device_major_number major,
661                                           rtems_device_minor_number minor)
662{
663  rtems_status_code status;
664  struct mscan_channel_info *chan = &chan_info[minor];
665
666  /* set registers according to MSCAN channel information */
667  switch (minor) {
668
669    case MSCAN_A:
670      chan->rx_qname = rtems_build_name('C', 'N', 'A', 'Q');
671      chan->tx_rb_sname = rtems_build_name('C', 'N', 'A', 'S');
672
673      /* register RTEMS device names for MSCAN A */
674      if ((status =
675           rtems_io_register_name(MSCAN_A_DEV_NAME, major,
676                                  MSCAN_A)) != RTEMS_SUCCESSFUL)
677        return status;
678
679      /* register RTEMS device names for MSCAN 0 */
680      if ((status =
681           rtems_io_register_name(MSCAN_0_DEV_NAME, major,
682                                  MSCAN_A)) != RTEMS_SUCCESSFUL)
683        return status;
684
685      /* allocate the space for MSCAN A tx ring buffer */
686      if (((chan->tx_ring_buf.buf_ptr) =
687           malloc(sizeof (struct can_message) * (NO_OF_MSCAN_TX_BUFF + 1))) !=
688          NULL) {
689        chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr =
690          chan->tx_ring_buf.buf_ptr;
691      } else {
692        return RTEMS_UNSATISFIED;
693      }
694      break;
695
696    case MSCAN_B:
697      chan->rx_qname = rtems_build_name('C', 'N', 'B', 'Q');
698      chan->tx_rb_sname = rtems_build_name('C', 'N', 'B', 'S');
699
700      /* register RTEMS device names for MSCAN B */
701      if ((status =
702           rtems_io_register_name(MSCAN_B_DEV_NAME, major,
703                                  MSCAN_B)) != RTEMS_SUCCESSFUL)
704        return status;
705
706      /* register RTEMS device names for MSCAN 1 */
707      if ((status =
708           rtems_io_register_name(MSCAN_1_DEV_NAME, major,
709                                  MSCAN_B)) != RTEMS_SUCCESSFUL)
710        return status;
711
712      /* allocate the space for MSCAN B tx ring buffer */
713      if (((chan->tx_ring_buf.buf_ptr) =
714           malloc(sizeof (struct can_message) * (NO_OF_MSCAN_TX_BUFF + 1))) !=
715          NULL) {
716        chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr =
717          chan->tx_ring_buf.buf_ptr;
718      } else {
719        return RTEMS_UNSATISFIED;
720      }
721      break;
722
723    default:
724      return RTEMS_UNSATISFIED;
725      break;
726  }
727
728  /* create RTEMS rx message queue */
729  status =
730    rtems_message_queue_create(chan->rx_qname, (uint32_t) NO_OF_MSCAN_RX_BUFF,
731                               (uint32_t)
732                               MSCAN_MESSAGE_SIZE(sizeof (struct can_message)),
733                               (rtems_attribute) RTEMS_LOCAL | RTEMS_FIFO,
734                               (rtems_id *) & (chan->rx_qid));
735
736  /* create counting RTEMS tx ring buffer semaphore */
737  status =
738    rtems_semaphore_create(chan->tx_rb_sname, (uint32_t) (NO_OF_MSCAN_TX_BUFF),
739                           RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY
740                           | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
741                           (rtems_task_priority) 0,
742                           (rtems_id *) & (chan->tx_rb_sid));
743
744  /* Set up interrupts */
745  if (!BSP_install_rtems_irq_handler(&(mpc5200_mscan_irq_data[minor])))
746    rtems_panic("Can't attach MPC5x00 MSCAN interrupt handler %ld\n", minor);
747
748  /* basic setup for channel info. struct. */
749  chan->regs = (mscan *) &(mpc5200.mscan[minor]);
750  chan->int_rx_err = 0;
751  chan->id_extended = FALSE;
752  chan->mode = MSCAN_INITIALIZED_MODE;
753  chan->tx_buf_no = NO_OF_MSCAN_TX_BUFF;
754
755  return status;
756
757}
758
759/*
760 * MPC5x00 MSCAN device initialization
761 */
762rtems_device_driver mscan_initialize(rtems_device_major_number major,
763                                     rtems_device_minor_number minor, void *arg)
764{
765  rtems_status_code status;
766
767  /* Initialization requested via RTEMS */
768  if ((status = mscan_channel_initialize(major, MSCAN_A)) != RTEMS_SUCCESSFUL)
769    bsp_fatal(MPC5200_FATAL_MSCAN_A_INIT);
770
771  if ((status = mscan_channel_initialize(major, MSCAN_B)) != RTEMS_SUCCESSFUL)
772    bsp_fatal(MPC5200_FATAL_MSCAN_B_INIT);
773
774  if ((status =
775       mpc5200_mscan_set_mode(MSCAN_A,
776                              MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL)
777    bsp_fatal(MPC5200_FATAL_MSCAN_A_SET_MODE);
778
779  if ((status =
780       mpc5200_mscan_set_mode(MSCAN_B,
781                              MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL)
782    bsp_fatal(MPC5200_FATAL_MSCAN_B_SET_MODE);
783
784  return status;
785
786}
787
788/*
789 * MPC5x00 MSCAN device open
790 */
791rtems_device_driver mscan_open(rtems_device_major_number major,
792                               rtems_device_minor_number minor, void *arg)
793{
794  rtems_status_code status = RTEMS_SUCCESSFUL;
795  struct mscan_channel_info *chan = NULL;
796
797  switch (minor) {
798
799    case MSCAN_A:
800    case MSCAN_B:
801      chan = &chan_info[minor];
802      break;
803
804    default:
805      return RTEMS_UNSATISFIED;
806      break;
807  }
808
809  /* check mode */
810  if ((chan->mode) == MSCAN_SLEEP_MODE) {
811
812    /* if not already set enter init mode */
813    status = mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
814  }
815
816  return status;
817
818}
819
820/*
821 * MPC5x00 MSCAN device close
822 */
823rtems_device_driver mscan_close(rtems_device_major_number major,
824                                rtems_device_minor_number minor, void *arg)
825{
826  rtems_status_code status;
827
828  switch (minor) {
829
830    case MSCAN_A:
831    case MSCAN_B:
832      break;
833
834    default:
835      return RTEMS_UNSATISFIED;
836      break;
837  }
838
839  /* enter deep sleep mode */
840  status = mpc5200_mscan_set_mode(minor, MSCAN_SLEEP_MODE);
841
842  return status;
843
844}
845
846/*
847 * MPC5x00 MSCAN device read
848 */
849rtems_device_driver mscan_read(rtems_device_major_number major,
850                               rtems_device_minor_number minor, void *arg)
851{
852  rtems_status_code status;
853  size_t message_size = 0;
854  rtems_libio_rw_args_t *parms = (rtems_libio_rw_args_t *) arg;
855  struct mscan_rx_parms *rx_parms = (struct mscan_rx_parms *) (parms->buffer);
856  struct can_message *rx_mess = (struct can_message *) (rx_parms->rx_mess);
857  struct mscan_channel_info *chan = NULL;
858
859  switch (minor) {
860
861    case MSCAN_A:
862    case MSCAN_B:
863      chan = &chan_info[minor];
864      break;
865
866    default:
867      return RTEMS_UNSATISFIED;
868      break;
869  }
870
871  /* end init mode if it is first read */
872  if ((chan->mode) == MSCAN_INIT_NORMAL_MODE) {
873
874    /* if not already set enter init mode */
875    mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
876  }
877
878  if ((status =
879       rtems_message_queue_receive(chan->rx_qid, (void *) (rx_mess),
880                                   &message_size,
881                                   (uint32_t) (rx_parms->rx_flags),
882                                   (rtems_interval) (rx_parms->rx_timeout)))
883      != RTEMS_SUCCESSFUL) {
884
885    parms->bytes_moved = 0;
886
887  } else {
888
889    parms->bytes_moved = sizeof (struct can_message);
890
891  }
892
893  return status;
894
895}
896
897/*
898 * MPC5x00 MSCAN device write
899 */
900rtems_device_driver mscan_write(rtems_device_major_number major,
901                                rtems_device_minor_number minor, void *arg)
902{
903  rtems_status_code status;
904  rtems_libio_rw_args_t *parms = (rtems_libio_rw_args_t *) arg;
905  struct mscan_tx_parms *tx_parms = (struct mscan_tx_parms *) (parms->buffer);
906  struct can_message *tx_mess = (struct can_message *) (tx_parms->tx_mess);
907  struct mscan_channel_info *chan = NULL;
908  mscan *m = NULL;
909
910  switch (minor) {
911    case MSCAN_A:
912    case MSCAN_B:
913      chan = &chan_info[minor];
914      m = chan->regs;
915      break;
916
917    default:
918      return RTEMS_UNSATISFIED;
919      break;
920  }
921
922  /* end init mode if it is first write */
923  if ((chan->mode) == MSCAN_INIT_NORMAL_MODE) {
924
925    /* if not already set enter init mode */
926    mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
927  }
928
929  /* preset moved bytes */
930  parms->bytes_moved = 0;
931
932  /* obtain counting semaphore of tx ring buffer */
933  if ((status =
934       rtems_semaphore_obtain((rtems_id) (chan->tx_rb_sid), RTEMS_NO_WAIT,
935                              (rtems_interval) 0))
936      == RTEMS_SUCCESSFUL) {
937
938    /* append the TOUCAN tx_id to the mess. due to interrupt handling */
939    tx_mess->toucan_tx_idx = tx_parms->tx_idx;
940
941    /* fill the tx ring buffer with the message */
942    fill_tx_buffer(chan, tx_mess);
943
944    /* enable message buffer specific interrupt */
945    m->tier |= (TIER_TXEI0 | TIER_TXEI1 | TIER_TXEI2);
946
947    /* calculate moved bytes */
948    parms->bytes_moved = (tx_mess->mess_len) & 0x000F;
949
950  }
951
952  return status;
953
954}
955
956/*
957 * MPC5x00 MSCAN device control
958 */
959rtems_device_driver mscan_control(rtems_device_major_number major,
960                                  rtems_device_minor_number minor, void *arg)
961{
962  rtems_status_code status;
963  uint16_t tx_id;
964  rtems_libio_ioctl_args_t *parms = (rtems_libio_ioctl_args_t *) arg;
965  struct mscan_ctrl_parms *ctrl_parms =
966    (struct mscan_ctrl_parms *) (parms->buffer);
967  struct mscan_channel_info *chan = NULL;
968  mscan_handle *mscan_hdl = NULL;
969  mscan *m = NULL;
970  mscan_context context;
971  uint8_t tx_buf_count = 0;
972
973  switch (minor) {
974
975    case MSCAN_A:
976    case MSCAN_B:
977      chan = &chan_info[minor];
978      mscan_hdl = mpc5200_mscan_irq_data[minor].handle;
979      m = chan->regs;
980      break;
981
982    default:
983      return RTEMS_UNSATISFIED;
984      break;
985  }
986
987  switch (parms->command) {
988
989      /* TOUCAN callback initialization for MSCAN */
990    case TOUCAN_MSCAN_INIT:
991      mscan_hdl->toucan_callback = ctrl_parms->toucan_cb_fnc;
992      break;
993
994      /* set rx buffer ID */
995    case MSCAN_SET_RX_ID:
996
997      /* enter init mode */
998      mscan_initialization_mode_enter(m, &context);
999
1000      switch (ctrl_parms->ctrl_reg_no) {
1001
1002        case RX_BUFFER_0:
1003          m->idar0 = SET_IDR0(ctrl_parms->ctrl_id);
1004          m->idar1 = SET_IDR1(ctrl_parms->ctrl_id);
1005          break;
1006
1007        case RX_BUFFER_1:
1008          m->idar2 = SET_IDR2(ctrl_parms->ctrl_id);
1009          m->idar3 = SET_IDR3(ctrl_parms->ctrl_id);
1010          break;
1011
1012        case RX_BUFFER_2:
1013          m->idar4 = SET_IDR4(ctrl_parms->ctrl_id);
1014          m->idar5 = SET_IDR5(ctrl_parms->ctrl_id);
1015          break;
1016
1017        case RX_BUFFER_3:
1018          m->idar6 = SET_IDR6(ctrl_parms->ctrl_id);
1019          m->idar7 = SET_IDR7(ctrl_parms->ctrl_id);
1020          break;
1021
1022        default:
1023          break;
1024
1025      }
1026
1027      /* exit init mode and perform further initialization which is required in the normal mode */
1028      mscan_initialization_mode_leave(m, &context);
1029
1030      /* enable ints. */
1031      mscan_interrupts_enable(m);
1032
1033      /* wait for bus sync. */
1034      mpc5200_mscan_wait_sync(m);
1035
1036      return RTEMS_SUCCESSFUL;
1037      break;
1038
1039      /* get rx buffer ID */
1040    case MSCAN_GET_RX_ID:
1041
1042      switch (ctrl_parms->ctrl_reg_no) {
1043
1044        case RX_BUFFER_0:
1045          ctrl_parms->ctrl_id = GET_IDR0(m->idar0) | GET_IDR1(m->idar1);
1046          break;
1047
1048        case RX_BUFFER_1:
1049          ctrl_parms->ctrl_id = GET_IDR2(m->idar2) | GET_IDR3(m->idar3);
1050          break;
1051
1052        case RX_BUFFER_2:
1053          ctrl_parms->ctrl_id = GET_IDR4(m->idar4) | GET_IDR5(m->idar5);
1054          break;
1055
1056        case RX_BUFFER_3:
1057          ctrl_parms->ctrl_id = GET_IDR6(m->idar6) | GET_IDR7(m->idar7);
1058          break;
1059
1060        default:
1061          break;
1062
1063      }
1064
1065      break;
1066
1067      /* set rx buffer ID mask */
1068    case MSCAN_SET_RX_ID_MASK:
1069
1070      /* enter init mode */
1071      mscan_initialization_mode_enter(m, &context);
1072
1073      switch (ctrl_parms->ctrl_reg_no) {
1074
1075        case RX_BUFFER_0:
1076          m->idmr0 = SET_IDMR0(ctrl_parms->ctrl_id_mask);
1077          m->idmr1 = SET_IDMR1(ctrl_parms->ctrl_id_mask);
1078          break;
1079
1080        case RX_BUFFER_1:
1081          m->idmr2 = SET_IDMR2(ctrl_parms->ctrl_id_mask);
1082          m->idmr3 = SET_IDMR3(ctrl_parms->ctrl_id_mask);
1083          break;
1084
1085        case RX_BUFFER_2:
1086          m->idmr4 = SET_IDMR4(ctrl_parms->ctrl_id_mask);
1087          m->idmr5 = SET_IDMR5(ctrl_parms->ctrl_id_mask);
1088          break;
1089
1090        case RX_BUFFER_3:
1091          m->idmr6 = SET_IDMR6(ctrl_parms->ctrl_id_mask);
1092          m->idmr7 = SET_IDMR7(ctrl_parms->ctrl_id_mask);
1093          break;
1094
1095        default:
1096          break;
1097
1098      }
1099
1100      /* exit init mode and perform further initialization which is required in the normal mode */
1101      mscan_initialization_mode_leave(m, &context);
1102
1103      /* enable ints. */
1104      mscan_interrupts_enable(m);
1105
1106      /* wait for bus sync. */
1107      mpc5200_mscan_wait_sync(m);
1108
1109      break;
1110
1111      /* get rx buffer ID mask */
1112    case MSCAN_GET_RX_ID_MASK:
1113
1114      switch (ctrl_parms->ctrl_reg_no) {
1115
1116        case RX_BUFFER_0:
1117          ctrl_parms->ctrl_id_mask =
1118            (GET_IDMR0(m->idmr0) | GET_IDMR1(m->idmr1));
1119          break;
1120
1121        case RX_BUFFER_1:
1122          ctrl_parms->ctrl_id_mask =
1123            (GET_IDMR2(m->idmr2) | GET_IDMR3(m->idmr3));
1124          break;
1125
1126        case RX_BUFFER_2:
1127          ctrl_parms->ctrl_id_mask =
1128            (GET_IDMR4(m->idmr4) | GET_IDMR5(m->idmr5));
1129          break;
1130
1131        case RX_BUFFER_3:
1132          ctrl_parms->ctrl_id_mask =
1133            (GET_IDMR6(m->idmr6) | GET_IDMR7(m->idmr7));
1134          break;
1135
1136        default:
1137          break;
1138
1139      }
1140
1141      /* set tx buffer ID */
1142    case MSCAN_SET_TX_ID:
1143
1144      /* check for availability of tx buffer */
1145      if (!((m->tflg) & (uint8_t) (ctrl_parms->ctrl_reg_no))) {
1146
1147        /* do abort tx buf. request */
1148        m->tarq = (uint8_t) (ctrl_parms->ctrl_reg_no);
1149
1150        /* wait for abort tx buf. ack. */
1151        while ((m->taak) & (uint8_t) (ctrl_parms->ctrl_reg_no));
1152
1153      }
1154
1155      /* select tx buf. */
1156      m->bsel = (uint8_t) (ctrl_parms->ctrl_reg_no);
1157
1158      /* set the tx id of selected buf. */
1159      tx_id = ctrl_parms->ctrl_id;
1160      m->txidr0 = SET_IDR0(tx_id);
1161      m->txidr1 = SET_IDR1(tx_id);
1162      m->txidr2 = 0;
1163      m->txidr3 = 0;
1164
1165      break;
1166
1167      /* get tx buffer ID */
1168    case MSCAN_GET_TX_ID:
1169
1170      /* select tx buf. */
1171      m->bsel = (uint8_t) (ctrl_parms->ctrl_reg_no);
1172
1173      /* get tx id. of selected buf. */
1174      ctrl_parms->ctrl_id = GET_IDR0(m->txidr0) | GET_IDR1(m->txidr1);
1175
1176      break;
1177
1178      /* set can bitrate */
1179    case MSCAN_SET_BAUDRATE:
1180      /* perform all can bit time settings */
1181      if (!mscan_set_bit_rate(m, ctrl_parms->ctrl_can_bitrate)) {
1182        return RTEMS_UNSATISFIED;
1183      }
1184
1185      /* enable ints. */
1186      mscan_interrupts_enable(m);
1187
1188      /* wait for bus sync. */
1189      mpc5200_mscan_wait_sync(m);
1190
1191      break;
1192
1193    case SET_TX_BUF_NO:
1194
1195      /* check for different settings of tx ring buffer */
1196      if ((tx_buf_count =
1197           chan->tx_buf_no) != (uint8_t) (ctrl_parms->ctrl_tx_buf_no)) {
1198
1199        /* preset the channel specific no of messages in the tx ring buffer */
1200        tx_buf_count = chan->tx_buf_no;
1201
1202        /* try to obtain all of the tx ring buffers */
1203        while (tx_buf_count > 0) {
1204
1205          /* obtain semaphore of all tx ring buffers */
1206          if ((status =
1207               rtems_semaphore_obtain((rtems_id) (chan->tx_rb_sid), RTEMS_WAIT,
1208                                      (rtems_interval) 10))
1209              == RTEMS_SUCCESSFUL) {
1210
1211            tx_buf_count--;
1212
1213          }
1214
1215        }
1216
1217        /* free the former tx ring buffer */
1218        free((void *) chan->tx_ring_buf.buf_ptr);
1219
1220        /* allocate the tx ring buffer with new size */
1221        if (((chan->tx_ring_buf.buf_ptr) =
1222             malloc(sizeof (struct can_message) *
1223                    ((uint8_t) (ctrl_parms->ctrl_tx_buf_no) + 1))) != NULL) {
1224          chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr =
1225            chan->tx_ring_buf.buf_ptr;
1226        } else {
1227          return RTEMS_UNSATISFIED;
1228        }
1229
1230        /* set the new amount of tx buffers */
1231        chan->tx_buf_no = (uint8_t) (ctrl_parms->ctrl_tx_buf_no);
1232
1233        /* release the semaphore of all tx ring buffers */
1234        while (tx_buf_count < chan->tx_buf_no) {
1235
1236          /* obtain semaphore of all tx ring buffers */
1237          rtems_semaphore_release((rtems_id) (chan->tx_rb_sid));
1238
1239          tx_buf_count++;
1240
1241        }
1242
1243      } else {
1244
1245        return RTEMS_SUCCESSFUL;
1246
1247      }
1248      break;
1249
1250    default:
1251      break;
1252
1253  }
1254
1255  return RTEMS_SUCCESSFUL;
1256
1257}
Note: See TracBrowser for help on using the repository browser.