source: rtems/bsps/powerpc/gen5200/mscan/mscan.c @ e560ee85

Last change on this file since e560ee85 was e560ee85, checked in by Joel Sherrill <joel@…>, on 03/01/22 at 21:38:55

bsps/powerpc/: Scripted embedded brains header file clean up

Updates #4625.

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