source: rtems/c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c @ c9b005a9

4.104.114.84.95
Last change on this file since c9b005a9 was c9b005a9, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on Jul 9, 2006 at 10:05:27 AM

applied patches for PR1117/1118/1119/1120

  • Property mode set to 100644
File size: 49.7 KB
Line 
1/*===============================================================*\
2| Project: RTEMS generic MPC5200 BSP                              |
3+-----------------------------------------------------------------+
4|                    Copyright (c) 2005                           |
5|                    Embedded Brains GmbH                         |
6|                    Obere Lagerstr. 30                           |
7|                    D-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.com/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#include <bsp.h>
27#include "../irq/irq.h"
28#include "../include/mpc5200.h"
29#include "mscan.h"
30
31/* #define MSCAN_LOOPBACK */
32
33volatile uint32_t tx_int_wr_count = 0;
34
35struct mpc5200_rx_cntrl mpc5200_mscan_rx_cntrl[MPC5200_CAN_NO];
36volatile static struct mscan_channel_info chan_info[MPC5200_CAN_NO];
37
38/* time segmant table  */
39uint8_t can_time_segment_table[CAN_MAX_NO_OF_TQ - MIN_NO_OF_TQ + 1][NO_OF_TABLE_ENTRIES] = {
40
41/* Total no. of time quantas */   /* Time Segment 1*/    /* Time Segment 2 */     /* Sync: Jump width */
42{         7,                                4,                     2,                       1          },
43{         8,                                5,                     2,                       1          },
44{         9,                                6,                     2,                       2          },
45{        10,                                6,                     3,                       2          },
46{        11,                                7,                     3,                       2          },
47{        12,                                8,                     3,                       2          },
48{        13,                                8,                     4,                       2          },
49{        14,                                9,                     4,                       2          },
50{        15,                               10,                     4,                       2          },
51{        16,                               10,                     5,                       2          },
52{        17,                               11,                     5,                       2          },
53{        18,                               12,                     5,                       2          },
54{        19,                               12,                     6,                       2          },
55{        20,                               13,                     6,                       2          },
56{        21,                               14,                     6,                       2          },
57{        22,                               14,                     7,                       2          },
58{        23,                               15,                     7,                       2          },
59{        24,                               15,                     8,                       2          },
60{        25,                               16,                     8,                       2          }};
61
62
63/*
64 * MPC5x00 MSCAN tx ring buffer function to get a can message buffer from the head of the tx ring buffer
65 */
66volatile static struct can_message * get_tx_buffer(struct mscan_channel_info *chan)
67  {
68  /* define a temp. mess ptr. */
69  volatile struct can_message * tmp_mess_ptr = NULL, *temp_head_ptr;
70
71  /* set temp. head pointer */
72  temp_head_ptr = chan->tx_ring_buf.head_ptr;
73
74  /* check buffer empty condition */
75  if(temp_head_ptr != chan->tx_ring_buf.tail_ptr)
76    {
77
78    /* current buffer head. ptr. */
79    tmp_mess_ptr = temp_head_ptr;
80
81    /* increment the head pointer */
82    temp_head_ptr++;
83
84    /* check for wrap around condition */
85    if(temp_head_ptr > chan->tx_ring_buf.buf_ptr + NO_OF_MSCAN_TX_BUFF)
86      {
87
88      /* set head ptr. to the begin of the ring buffer */
89      temp_head_ptr = chan->tx_ring_buf.buf_ptr;
90
91      }
92
93    /* end of crtical section restore head ptr. */
94    chan->tx_ring_buf.head_ptr = temp_head_ptr;
95    }
96
97  /* return the current head pointer */
98  return tmp_mess_ptr;
99  }
100
101/*
102 * MPC5x00 MSCAN tx ring buffer function to write a can message buffer to the tail of the tx ring buffer
103 */
104volatile static struct can_message * fill_tx_buffer(struct mscan_channel_info *chan, struct can_message * mess_ptr)
105  {
106  /* define a temp. mess ptr. to the entry which follows the current tail entry */
107  struct can_message * tmp_mess_ptr = chan->tx_ring_buf.tail_ptr + 1;
108
109  /* check for the wrap around condition */
110  if(tmp_mess_ptr >  chan->tx_ring_buf.buf_ptr + NO_OF_MSCAN_TX_BUFF)
111    {
112        /* set temp. mess. ptr to the begin of the ring buffer */
113        tmp_mess_ptr = chan->tx_ring_buf.buf_ptr;
114    }
115
116  /* check buffer full condition */
117  if(tmp_mess_ptr == chan->tx_ring_buf.head_ptr)
118    {
119        /* return NULL in case buffer is full */
120        return NULL;
121    }
122  else
123    {
124        /* copy the can mess. to the tail of the buffer */
125    memcpy((void *)chan->tx_ring_buf.tail_ptr, (void *)mess_ptr, sizeof(struct can_message));
126
127    /* set new tail equal to temp. mess. ptr. */
128    chan->tx_ring_buf.tail_ptr = tmp_mess_ptr;
129    }
130
131  /* return the actual tail ptr. (next free entry) */
132  return chan->tx_ring_buf.tail_ptr;
133  }
134
135/*
136 * MPC5x00 MSCAN interrupt handler
137 */
138static void mpc5200_mscan_interrupt_handler(rtems_irq_hdl_param handle)
139  {
140  rtems_status_code status;
141  mscan_handle *mscan_hdl = (mscan_handle *)handle;
142  struct mscan_channel_info *chan = &chan_info[mscan_hdl->mscan_channel];
143  struct can_message rx_mess, *rx_mess_ptr, *tx_mess_ptr;
144  volatile struct mpc5200_mscan *mscan = chan->regs;
145  register uint8_t idx;
146
147  /*
148   handle tx ring buffer
149   */
150
151  /* loop over all 3 tx buffers */
152  for(idx = TFLG_TXE0; idx <= TFLG_TXE2; idx=idx<<1)
153    {
154
155    /* check for tx buffer vacation */
156    if((mscan->tflg) & idx)
157      {
158
159      /* try to get a message */
160      tx_mess_ptr = get_tx_buffer(chan);
161
162      /* check for new tx message */
163      if(tx_mess_ptr != NULL)
164        {
165
166        /* select the tx buffer */
167        mscan->bsel  = idx;
168
169        /* check for toucan interface */
170        if((mscan_hdl->toucan_callback) == NULL)
171          {
172
173          /* set tx id */
174                  mscan->txidr0 = SET_IDR0(tx_mess_ptr->mess_id);
175                  mscan->txidr1 = SET_IDR1(tx_mess_ptr->mess_id);
176                  mscan->txidr2 = 0;
177          mscan->txidr3 = 0;
178
179          /* insert dlc into mscan register */
180                  mscan->txdlr = (uint8_t)((tx_mess_ptr->mess_len) & 0x000F);
181              }
182
183        /* select one free tx buffer if TOUCAN not registered) */
184        if(((mscan_hdl->toucan_callback) == NULL) || (((mscan_hdl->toucan_callback) != NULL) && ((tx_mess_ptr->toucan_tx_id) == idx)))
185          {
186
187          /* set tx id */
188                  mscan->txidr0 = SET_IDR0(tx_mess_ptr->mess_id);
189                  mscan->txidr1 = SET_IDR1(tx_mess_ptr->mess_id);
190                  mscan->txidr2 = 0;
191          mscan->txidr3 = 0;
192
193          /* insert dlc into mscan register */
194                  mscan->txdlr = (uint8_t)((tx_mess_ptr->mess_len) & 0x000F);
195
196          /* copy tx data to MSCAN registers */
197          switch(mscan->txdlr)
198            {
199            case 8:
200              mscan->txdsr7 = tx_mess_ptr->mess_data[7];
201            case 7:
202              mscan->txdsr6 = tx_mess_ptr->mess_data[6];
203            case 6:
204              mscan->txdsr5 = tx_mess_ptr->mess_data[5];
205            case 5:
206              mscan->txdsr4 = tx_mess_ptr->mess_data[4];
207            case 4:
208              mscan->txdsr3 = tx_mess_ptr->mess_data[3];
209            case 3:
210              mscan->txdsr2 = tx_mess_ptr->mess_data[2];
211            case 2:
212              mscan->txdsr1 = tx_mess_ptr->mess_data[1];
213            case 1:
214              mscan->txdsr0 = tx_mess_ptr->mess_data[0];
215              break;
216            default:
217              break;
218            }
219
220          /* enable message buffer specific interrupt */
221              mscan->tier |= mscan->bsel;
222
223              /* start transfer */
224          mscan->tflg = mscan->bsel;
225
226          /* release counting semaphore of tx ring buffer */
227                  rtems_semaphore_release((rtems_id)(chan->tx_rb_sid));
228
229                  tx_int_wr_count++;
230
231          }
232        else
233          {
234
235          /* refill the tx ring buffer with the message */
236          fill_tx_buffer(chan, tx_mess_ptr);
237
238              }
239            }
240          else
241            {
242                /* reset interrupt enable bit */
243            mscan->tier &= ~(idx);
244            }
245      }
246    }
247
248  /*
249   handle rx interrupts
250   */
251
252  /* check for rx interrupt source */
253  if(mscan->rier & RIER_RXFIE)
254    {
255
256    /* can messages received ? */
257    while(mscan->rflg & RFLG_RXF)
258      {
259
260      if(mscan_hdl->toucan_callback == NULL)
261        {
262
263        /* select temporary rx buffer */
264        rx_mess_ptr = &rx_mess;
265
266        }
267      else
268        {
269
270        /* check the rx fliter-match indicators (16-bit filter mode) */
271        /* in case of more than one hit, lower hit has priority */
272          idx = (mscan->idac) & 0x7;
273          switch(idx)
274          {
275
276          case 0:
277          case 1:
278          case 2:
279          case 3:
280            rx_mess_ptr =
281              (struct can_message *)&(mpc5200_mscan_rx_cntrl[mscan_hdl->mscan_channel].can_rx_message[idx]);
282            break;
283
284          /* this case should never happen */
285                  default:
286            /* reset the rx indication flag */
287            mscan->rflg |= RFLG_RXF;
288
289            return;
290            break;
291              }
292
293        }
294
295      /* get rx ID */
296      rx_mess_ptr->mess_id = GET_IDR0(mscan->rxidr0) | GET_IDR1(mscan->rxidr1);
297
298      /* get rx len */
299      rx_mess_ptr->mess_len = ((mscan->rxdlr) & 0x0F);
300
301      /* get time stamp */
302      rx_mess_ptr->mess_time_stamp = ((mscan->rxtimh << 8) | (mscan->rxtiml));
303
304      /* get the data */
305          switch(rx_mess_ptr->mess_len)
306            {
307
308            case 8:
309              rx_mess_ptr->mess_data[7] = mscan->rxdsr7;
310            case 7:
311              rx_mess_ptr->mess_data[6] = mscan->rxdsr6;
312            case 6:
313              rx_mess_ptr->mess_data[5] = mscan->rxdsr5;
314            case 5:
315              rx_mess_ptr->mess_data[4] = mscan->rxdsr4;
316            case 4:
317              rx_mess_ptr->mess_data[3] = mscan->rxdsr3;
318            case 3:
319              rx_mess_ptr->mess_data[2] = mscan->rxdsr2;
320            case 2:
321              rx_mess_ptr->mess_data[1] = mscan->rxdsr1;
322            case 1:
323              rx_mess_ptr->mess_data[0] = mscan->rxdsr0;
324            case 0:
325            default:
326              break;
327
328            }
329
330      if(mscan_hdl->toucan_callback == NULL)
331        {
332
333        if((status = rtems_message_queue_send(chan->rx_qid, (void *)rx_mess_ptr, sizeof(struct can_message))) != RTEMS_SUCCESSFUL)
334                  {
335
336                  chan->int_rx_err++;
337
338          }
339
340            }
341      else
342        {
343
344        mscan_hdl->toucan_callback((int16_t)(((mscan->idac) & 0x7) + 3));
345
346            }
347
348      /* reset the rx indication flag */
349      mscan->rflg |= RFLG_RXF;
350
351      } /* end of while(mscan->rflg & RFLG_RXF) */
352
353    }
354
355    /* status change detected */
356    if(mscan->rflg & RFLG_CSCIF)
357      {
358
359      mscan->rflg |= RFLG_CSCIF;
360
361      if(mscan_hdl->toucan_callback != NULL)
362        {
363
364        mscan_hdl->toucan_callback((int16_t)(-1));
365
366        }
367
368      }
369
370  }
371
372
373/*
374 * Disable MSCAN ints.
375 */
376void mpc5200_mscan_int_disable(volatile struct mpc5200_mscan *mscan)
377  {
378
379  /* RX Interrupt Enable on MSCAN_A/_B -----------------------------*/
380  /*    [07]:WUPIE         0 : WakeUp interrupt disabled            */
381  /*    [06]:CSCIE         0 : Status Change interrupt disabled     */
382  /*    [05]:RSTATE1       0 : Recv. Status Change int. ,Bit 1      */
383  /*    [04]:RSTATE0       0 : Recv. Status Change int. ,Bit 0      */
384  /*                           -> 00 rx status change int. disabled */
385  /*    [03]:TSTAT1        0 : Transmit. Status Change int. , Bit 1 */
386  /*    [02]:TSTAT0        0 : Transmit. Status Change int. , Bit 0 */
387  /*                           -> 00 tx status change int. disabled */
388  /*    [01]:OVRIE         0 : Overrun Interrupt is disabled        */
389  /*    [00]:RXFIE         0 : Recv. Full interrupt is disabled     */
390  mscan->rier &= ~(RIER_CSCIE | RIER_RXFIE);
391
392  /* TX Interrupt Enable on MSCAN_A/_B -----------------------------*/
393  /*    [07]:res.          0 : reserved                             */
394  /*    [06]:res.          0 : reserved                             */
395  /*    [05]:res.          0 : reserved                             */
396  /*    [04]:res.          0 : reserved                             */
397  /*    [03]:res.          0 : reserved                             */
398  /*    [02]:TSEG12        0 : TX2message buffer int. is disabled   */
399  /*    [01]:TSEG11        0 : TX1 message buffer int. is disabled  */
400  /*    [00]:TSEG10        0 : TX0 message buffer int. is disabled  */
401  mscan->tier &= ~(TIER_TXEI2 | TIER_TXEI1 | TIER_TXEI0);
402
403  return;
404
405  }
406
407
408/*
409 * Enable MSCAN ints.
410 */
411void mpc5200_mscan_int_enable(volatile struct mpc5200_mscan *mscan)
412  {
413
414  /* RX Interrupt Enable on MSCAN_A/_B -----------------------------*/
415  /*    [07]:WUPIE         0 : WakeUp interrupt disabled            */
416  /*    [06]:CSCIE         1 : Status Change interrupt enabled      */
417  /*    [05]:RSTATE1       0 : Recv. Status Change int. ,Bit 1      */
418  /*    [04]:RSTATE0       1 : Recv. Status Change int. ,Bit 0      */
419  /*                           -> 01 BusOff status changes enabled  */
420  /*    [03]:TSTAT1        0 : Transmit. Status Change int. , Bit 1 */
421  /*    [02]:TSTAT0        1 : Transmit. Status Change int. , Bit 0 */
422  /*                           -> 01 BusOff status changes enabled  */
423  /*    [01]:OVRIE         0 : Overrun Interrupt is disabled        */
424  /*    [00]:RXFIE         1 : Recv. Full interrupt is enabled      */
425  mscan->rier |= (RIER_CSCIE  | RIER_RXFIE | RIER_RSTAT(1) | RIER_TSTAT(1));
426
427  return;
428
429  }
430
431/*
432 * Unmask MPC5x00 MSCAN_A interrupts
433 */
434void mpc5200_mscan_a_on(const rtems_irq_connect_data* ptr)
435  {
436  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_A])->regs;
437
438  mpc5200_mscan_int_enable(mscan);
439
440  return;
441
442  }
443
444
445/*
446 * Mask MPC5x00 MSCAN_A interrupts
447 */
448void mpc5200_mscan_a_off(const rtems_irq_connect_data* ptr)
449  {
450  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_A])->regs;
451
452  mpc5200_mscan_int_disable(mscan);
453
454  return;
455
456  }
457
458
459/*
460 *  Get MSCAN_A interrupt mask setting
461 */
462int mpc5200_mscan_a_isOn(const rtems_irq_connect_data* ptr)
463  {
464  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_A])->regs;
465
466  if((mscan->rier & RIER_CSCIE) && (mscan->rier & RIER_RXFIE))
467    return RTEMS_SUCCESSFUL;
468  else
469    return RTEMS_UNSATISFIED;
470
471  return RTEMS_SUCCESSFUL;
472
473  }
474
475
476/*
477 * Unmask MPC5x00 MSCAN_B interrupts
478 */
479void mpc5200_mscan_b_on(const rtems_irq_connect_data* ptr)
480  {
481  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_B])->regs;
482
483  mpc5200_mscan_int_enable(mscan);
484
485  return;
486
487  }
488
489
490/*
491 * Mask MPC5x00 MSCAN_B interrupts
492 */
493void mpc5200_mscan_b_off(const rtems_irq_connect_data* ptr)
494  {
495  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_B])->regs;
496
497  mpc5200_mscan_int_disable(mscan);
498
499  return;
500
501  }
502
503
504/*
505 *  Get MSCAN_B interrupt mask setting
506 */
507int mpc5200_mscan_b_isOn(const rtems_irq_connect_data* ptr)
508  {
509  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_B])->regs;
510
511  if((mscan->rier & RIER_CSCIE) && (mscan->rier & RIER_RXFIE))
512    return RTEMS_SUCCESSFUL;
513  else
514    return RTEMS_UNSATISFIED;
515
516  return RTEMS_SUCCESSFUL;
517
518  }
519
520static mscan_handle mscan_a_handle =
521  {
522  MSCAN_A,
523  NULL
524  };
525
526
527static mscan_handle mscan_b_handle =
528  {
529  MSCAN_B,
530  NULL
531  };
532
533/*
534 * MPC5x00 MSCAN_A/_B irq data
535 */
536static rtems_irq_connect_data mpc5200_mscan_irq_data[MPC5200_CAN_NO] =
537  {{
538  BSP_SIU_IRQ_MSCAN1,
539  (rtems_irq_hdl) mpc5200_mscan_interrupt_handler,
540  (rtems_irq_hdl_param) &mscan_a_handle,
541  (rtems_irq_enable) mpc5200_mscan_a_on,
542  (rtems_irq_disable) mpc5200_mscan_a_off,
543  (rtems_irq_is_enabled) mpc5200_mscan_a_isOn
544  },
545  {
546  BSP_SIU_IRQ_MSCAN2,
547  (rtems_irq_hdl) mpc5200_mscan_interrupt_handler,
548  (rtems_irq_hdl_param) &mscan_b_handle,
549  (rtems_irq_enable) mpc5200_mscan_b_on,
550  (rtems_irq_disable) mpc5200_mscan_b_off,
551  (rtems_irq_is_enabled) mpc5200_mscan_b_isOn
552  }};
553
554
555/*
556 * Enter MSCAN sleep mode
557 */
558void mpc5200_mscan_enter_sleep_mode(volatile struct mpc5200_mscan *mscan)
559  {
560
561  /* Control Register 0 --------------------------------------------*/
562  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
563  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
564  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
565  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
566  /*    [03]:TIME        1 : Generate Timestamps                    */
567  /*    [02]:WUPE        1 : WakeUp Enabled                         */
568  /*    [01]:SLPRQ    0->1 : Sleep Mode Request                     */
569  /*    [00]:INITRQ      0 : No init. Mode Request                  */
570  /* select sleep mode */
571  mscan->ctl0 |= (CTL0_SLPRQ);
572
573  /* Control Register 1 --------------------------------------------*/
574  /*    [07]:CANE        0 : MSCAN Module is disabled               */
575  /*    [06]:CLKSRC      1 : Clock Source -> IPB-Clock (33 MHz)     */
576  /*    [05]:LOOPB       0 : No Loopback                            */
577  /*    [04]:LISTEN      0 : Normal Operation                       */
578  /*    [03]:res         0 : reserved                               */
579  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
580  /*    [01]:SLPAK    0->1 : Sleep Mode Acknowledge (rd. only)      */
581  /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
582  /* wait for sleep mode acknowledge */
583  while(!(mscan->ctl1 & CTL1_SLPAK));
584
585  return;
586
587  }
588
589
590/*
591 * Exit MSCAN sleep mode
592 */
593void mpc5200_mscan_exit_sleep_mode(volatile struct mpc5200_mscan *mscan)
594  {
595
596  /* Control Register 0 --------------------------------------------*/
597  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
598  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
599  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
600  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
601  /*    [03]:TIME        1 : Generate Timestamps                    */
602  /*    [02]:WUPE        1 : WakeUp Enabled                         */
603  /*    [01]:SLPRQ    0->1 : Sleep Mode Request                     */
604  /*    [00]:INITRQ      0 : No init. Mode Request                  */
605  /* select sleep mode */
606  mscan->ctl0 &= ~(CTL0_SLPRQ);
607
608  /* Control Register 1 --------------------------------------------*/
609  /*    [07]:CANE        0 : MSCAN Module is disabled               */
610  /*    [06]:CLKSRC      1 : Clock Source -> IPB-Clock (33 MHz)     */
611  /*    [05]:LOOPB       0 : No Loopback                            */
612  /*    [04]:LISTEN      0 : Normal Operation                       */
613  /*    [03]:res         0 : reserved                               */
614  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
615  /*    [01]:SLPAK    0->1 : Sleep Mode Acknowledge (rd. only)      */
616  /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
617  /* wait for sleep mode acknowledge */
618  while((mscan->ctl1 & CTL1_SLPAK));
619
620  return;
621
622  }
623
624
625/*
626 * Enter MSCAN init mode and disconnect from bus
627 */
628void mpc5200_mscan_enter_init_mode(volatile struct mpc5200_mscan *mscan)
629  {
630
631  /* Control Register 0 --------------------------------------------*/
632  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
633  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
634  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
635  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
636  /*    [03]:TIME        1 : Generate Timestamps                    */
637  /*    [02]:WUPE        0 : WakeUp disabled                        */
638  /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
639  /*    [00]:INITRQ   0->1 : Init. Mode Request                     */
640  /* select init mode */
641  mscan->ctl0 |= (CTL0_INITRQ);
642
643  /* Control Register 1 --------------------------------------------*/
644  /*    [07]:CANE        0 : MSCAN Module is disabled               */
645  /*    [06]:CLKSRC      1 : Clock Source -> IPB-Clock (33 MHz)     */
646  /*    [05]:LOOPB       0 : No Loopback                            */
647  /*    [04]:LISTEN      0 : Normal Operation                       */
648  /*    [03]:res         0 : reserved                               */
649  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
650  /*    [01]:SLPAK       0 : Sleep Mode Acknowledge (rd. only)      */
651  /*    [00]:INITAK   0->1 : Init. Mode Acknowledge (rd. only)      */
652  /* wait for init mode acknowledge */
653  while(!(mscan->ctl1 & CTL1_INITAK));
654
655  return;
656
657  }
658
659
660/*
661 * Exit MSCAN init mode
662 */
663void mpc5200_mscan_exit_init_mode(volatile struct mpc5200_mscan *mscan)
664  {
665
666  /* Control Register 0 --------------------------------------------*/
667  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
668  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
669  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
670  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
671  /*    [03]:TIME        1 : Generate Timestamps                    */
672  /*    [02]:WUPE        0 : WakeUp Disabled                        */
673  /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
674  /*    [00]:INITRQ   1->0 : Init. Mode Request                     */
675  /* select normal mode */
676  mscan->ctl0 &= ~(CTL0_INITRQ);
677
678  /* Control Register 1 --------------------------------------------*/
679  /*    [07]:CANE        0 : MSCAN Module is disabled               */
680  /*    [06]:CLKSRC      1 : Clock Source -> IPB-Clock (33 MHz)     */
681  /*    [05]:LOOPB       0 : No Loopback                            */
682  /*    [04]:LISTEN      0 : Normal Operation                       */
683  /*    [03]:res         0 : reserved                               */
684  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
685  /*    [01]:SLPAK       0 : Sleep Mode Acknowledge (rd. only)      */
686  /*    [00]:INITAK   1->0 : Init. Mode Acknowledge (rd. only)      */
687  /* wait for normal mode acknowledge */
688  while(mscan->ctl1 & CTL1_INITAK);
689
690  return;
691
692  }
693
694
695/*
696 * MPC5x00 MSCAN wait for sync. with CAN bus
697 */
698void mpc5200_mscan_wait_sync(volatile struct mpc5200_mscan *mscan)
699  {
700
701  /* Control Register 0 --------------------------------------------*/
702  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
703  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
704  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
705  /*    [04]:SYNCH    0->1 : Synchronized, Status Bit (rd. only)    */
706  /*    [03]:TIME        1 : Generate Timestamps                    */
707  /*    [02]:WUPE        0 : WakeUp Disabled                        */
708  /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
709  /*    [00]:INITRQ      0 : No init. Mode Request                  */
710  /* wait for MSCAN A_/_B bus synch. */
711
712#if 0 /* we don't have a need to wait for sync. */
713  while(!((mscan->ctl0) & CTL0_SYNCH));
714#endif
715  return;
716
717  }
718
719/* calculate the can clock prescaler value */
720uint8_t prescaler_calculation(uint32_t can_bit_rate, uint32_t can_clock_frq, uint8_t *tq_no) {
721
722/* local variables */
723uint8_t tq_no_min_dev = 0;
724uint32_t frq_tq, frq_dev, frq_dev_min = 0xFFFFFFFF;
725
726/* loop through all values of time quantas */
727for(*tq_no = CAN_MAX_NO_OF_TQ; *tq_no >= MIN_NO_OF_TQ; (*tq_no)--) {
728
729  /* calculate time quanta freq. */
730  frq_tq = *tq_no * can_bit_rate;
731
732  /* calculate the deviation from requested tq freq. */
733  frq_dev = can_clock_frq%frq_tq;
734
735  /* check the deviation freq. */
736  if(frq_dev == 0) {
737
738    /* return if best match (zero deviation) */
739   return (uint8_t)(can_clock_frq/frq_tq);
740    }
741  else
742    {
743
744    /* check for minimum of freq. deviation */
745    if(frq_dev < frq_dev_min) {
746
747      /* recognize the minimum freq. deviation */
748      frq_dev_min = frq_dev;
749
750      /* recognize the no. of time quantas */
751      tq_no_min_dev = *tq_no;
752          }
753        }
754  }
755
756/* return the optimized prescaler value */
757 *tq_no = tq_no_min_dev;
758 return (uint8_t)(can_clock_frq/(tq_no_min_dev * can_bit_rate));
759}
760
761/*
762 * MPC5x00 MSCAN set up the bit timing
763 */
764void mpc5200_mscan_perform_bit_time_settings(volatile struct mpc5200_mscan *mscan, uint32_t can_bit_rate, uint32_t can_clock_frq)
765{
766  uint32_t prescale_val = 0;
767  uint8_t tq_no, tseg_1, tseg_2, sseg;
768
769  /* get optimized prescaler value */
770  prescale_val = prescaler_calculation(can_bit_rate, can_clock_frq, &tq_no);
771
772  /* get time segment length from time segment table */
773  tseg_1 = can_time_segment_table[tq_no - MIN_NO_OF_TQ][TSEG_1];
774  tseg_2 = can_time_segment_table[tq_no - MIN_NO_OF_TQ][TSEG_2];
775  sseg    = can_time_segment_table[tq_no - MIN_NO_OF_TQ][SJW];
776
777  /* Bus Timing Register 0 MSCAN_A/_B ------------------------------*/
778  /*    [07]:SJW1        1 : Synchronization jump width, Bit1       */
779  /*    [06]:SJW0        0 : Synchronization jump width, Bit0       */
780  /*                         SJW = 2 -> 3 Tq clock cycles           */
781  /*    [05]:BRP5        0 : Baud Rate Prescaler, Bit 5             */
782  /*    [04]:BRP4        0 : Baud Rate Prescaler, Bit 4             */
783  /*    [03]:BRP3        0 : Baud Rate Prescaler, Bit 3             */
784  /*    [02]:BRP2        1 : Baud Rate Prescaler, Bit 2             */
785  /*    [01]:BRP1        0 : Baud Rate Prescaler, Bit 1             */
786  /*    [00]:BRP0        1 : Baud Rate Prescaler, Bit 0             */
787  mscan->btr0 = (BTR0_SJW(sseg-1) | BTR0_BRP(prescale_val-1));
788
789  /* Bus Timing Register 1 MSCAN_A/_B ------------------------------*/
790  /*    [07]:SAMP        0 : One Sample per bit                     */
791  /*    [06]:TSEG22      0 : Time Segment 2, Bit 2                  */
792  /*    [05]:TSEG21      1 : Time Segment 2, Bit 1                  */
793  /*    [04]:TSEG20      0 : Time Segment 2, Bit 0                  */
794  /*                         -> PHASE_SEG2 = 3 Tq                   */
795  /*    [03]:TSEG13      0 : Time Segment 1, Bit 3                  */
796  /*    [02]:TSEG12      1 : Time Segment 1, Bit 2                  */
797  /*    [01]:TSEG11      1 : Time Segment 1, Bit 1                  */
798  /*    [00]:TSEG10      0 : Time Segment 1, Bit 0                  */
799  mscan->btr1 =  (BTR1_TSEG_22_20(tseg_2-1) | BTR1_TSEG_13_10(tseg_1-1));
800
801  return;
802
803  }
804
805
806/*
807 * MPC5x00 MSCAN perform settings in init mode
808 */
809void mpc5200_mscan_perform_init_mode_settings(volatile struct mpc5200_mscan *mscan)
810  {
811
812  /* perform all can bit time settings */
813  mpc5200_mscan_perform_bit_time_settings(mscan,CAN_BIT_RATE,IPB_CLOCK);
814
815  /* Control Register 1 --------------------------------------------*/
816  /*    [07]:CANE        0 : MSCAN Module is disabled               */
817  /*    [06]:CLKSRC      0 : Clock Source -> IPB_CLOCK (bsp.h)      */
818  /*    [05]:LOOPB       0 : No Loopback                            */
819  /*    [04]:LISTEN      0 : Normal Operation                       */
820  /*    [03]:res         0 : reserved                               */
821  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
822  /*    [01]:SLPAK    1->0 : Sleep Mode Acknowledge (rd. only)      */
823  /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
824  /* Set CLK source, disable loopback & listen-only mode */
825#ifndef MSCAN_LOOPBACK
826  mscan->ctl1 &= ~(CTL1_LISTEN | CTL1_LOOPB | CTL1_CLKSRC);
827#else
828  mscan->ctl1 &= ~(CTL1_LISTEN | CTL1_CLKSRC);
829  mscan->ctl1 |=  (CTL1_LOOPB);
830#endif
831
832  /* IPB clock                  -> IPB_CLOCK (bsp.h)                                                    */
833  /* bitrate                    -> CAN_BIT_RATE (mscan.h)                                               */
834  /* Max. no of Tq              -> CAN_MAX_NO_OF_TQ (mscan.h)                                           */
835  /* Prescaler value            -> prescale_val = ROUND_UP(IPB_CLOCK/(CAN_BIT_RATE * CAN_MAX_NO_OF_TQ)) */
836  /* SYNC_SEG                   ->  1 tq                                                                */
837  /* time segment 1             -> 16 tq (PROP_SEG+PHASE_SEG), CAN_MAX_NO_OF_TQ_TSEG1 = 15 (mscan.h)    */
838  /* time segment 2             ->  8 tq (PHASE_SEG2)        , CAN_MAX_NO_OF_TQ_TSEG2 =  7 (mscan.h)    */
839  /* SJW                        ->  3 (fixed 0...3)          , CAN_MAX_NO_OF_TQ_SJW   =  2 (mscan.h)    */
840
841  /* ID Acceptance Control MSCAN_A/_B ------------------------------*/
842  /*    [07]:res.        0 : reserved                               */
843  /*    [06]:res.        0 : reserved                               */
844  /*    [05]:IDAM1       0 : ID acceptance control, Bit1            */
845  /*    [04]:IDAM0       1 : ID acceptance control, Bit0            */
846  /*                         -> filter 16 bit mode                  */
847  /*    [03]:res.        0 : reserved                               */
848  /*    [02]:IDHIT2      0 : ID acceptance hit indication, Bit 2    */
849  /*    [01]:IDHIT1      0 : ID acceptance hit indication, Bit 1    */
850  /*    [00]:IDHIT0      0 : ID acceptance hit indication, Bit 0    */
851  mscan->idac &= ~(IDAC_IDAM1);
852  mscan->idac |=  (IDAC_IDAM0);
853
854  /* initialize rx filter masks (16 bit) */
855  mscan->idmr0  = SET_IDMR0(0x07FF);
856  mscan->idmr1  = SET_IDMR1(0x07FF);
857  mscan->idmr2  = SET_IDMR2(0x07FF);
858  mscan->idmr3  = SET_IDMR3(0x07FF);
859  mscan->idmr4  = SET_IDMR4(0x07FF);
860  mscan->idmr5  = SET_IDMR5(0x07FF);
861  mscan->idmr6  = SET_IDMR6(0x07FF);
862  mscan->idmr7  = SET_IDMR7(0x07FF);
863
864  /* Control Register 1 --------------------------------------------*/
865  /*    [07]:CANE     0->1 : MSCAN Module is enabled                */
866  /*    [06]:CLKSRC      1 : Clock Source -> IPB_CLOCK (bsp.h)      */
867  /*    [05]:LOOPB       0 : No Loopback                            */
868  /*    [04]:LISTEN      0 : Normal Operation                       */
869  /*    [03]:res         0 : reserved                               */
870  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
871  /*    [01]:SLPAK       0 : Sleep Mode Acknowledge (rd. only)      */
872  /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
873  /* enable MSCAN A_/_B */
874  mscan->ctl1 |= (CTL1_CANE);
875
876  return;
877
878  }
879
880
881/*
882 * MPC5x00 MSCAN perform settings in normal mode
883 */
884void mpc5200_mscan_perform_normal_mode_settings(volatile struct mpc5200_mscan *mscan)
885  {
886
887  /* Control Register 0 --------------------------------------------*/
888  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
889  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
890  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
891  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
892  /*    [03]:TIME        1 : Generate Timestamps                    */
893  /*    [02]:WUPE        0 : WakeUp Disabled                        */
894  /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
895  /*    [00]:INITRQ      0 : No init. Mode Request                  */
896  /* Disable wait mode, enable timestamps */
897  mscan->ctl0 &= ~(CTL0_CSWAI);
898  mscan->ctl0 |=  (CTL0_TIME);
899
900  return;
901
902  }
903
904rtems_status_code mpc5200_mscan_set_mode(rtems_device_minor_number minor, uint8_t mode)
905  {
906  struct mscan_channel_info *chan = NULL;
907  volatile struct mpc5200_mscan *mscan     = NULL;
908
909  switch(minor)
910    {
911
912    case MSCAN_A:
913    case MSCAN_B:
914      chan  = &chan_info[minor];
915      mscan = chan->regs;
916      break;
917
918    default:
919      return RTEMS_UNSATISFIED;
920      break;
921    }
922
923  if(chan->mode == mode)
924    return RTEMS_SUCCESSFUL;
925
926  switch(mode)
927    {
928
929    case MSCAN_INIT_NORMAL_MODE:
930      /* if not already set enter init mode */
931          mpc5200_mscan_enter_init_mode(mscan);
932          /* perform initialization which has to be done in init mode */
933      mpc5200_mscan_perform_init_mode_settings(mscan);
934      break;
935
936    case MSCAN_NORMAL_MODE:
937      /* if not already set enter init mode */
938      mpc5200_mscan_enter_init_mode(mscan);
939
940      if((chan->mode) == MSCAN_INITIALIZED_MODE)
941        {
942
943        /* perform initialization which has to be done in init mode */
944        mpc5200_mscan_perform_init_mode_settings(mscan);
945            }
946
947      if((chan->mode) == MSCAN_SLEEP_MODE)
948        {
949
950        /* exit sleep mode */
951            mpc5200_mscan_exit_sleep_mode(mscan);
952            }
953
954      /* exit init mode */
955      mpc5200_mscan_exit_init_mode(mscan);
956      /* enable ints. */
957      mpc5200_mscan_int_enable(mscan);
958      /* wait for bus sync. */
959      mpc5200_mscan_wait_sync(mscan);
960      break;
961
962    case MSCAN_SLEEP_MODE:
963      /* disable ints. */
964      mpc5200_mscan_int_disable(mscan);
965      /* exit sleep mode */
966          mpc5200_mscan_enter_sleep_mode(mscan);
967      break;
968
969    default:
970      return RTEMS_UNSATISFIED;
971      break;
972
973    }
974
975  /* set new channel mode */
976  chan->mode = mode;
977
978  return RTEMS_SUCCESSFUL;
979
980  }
981
982
983/*
984 * initialization of channel info.
985 */
986rtems_status_code mscan_channel_initialize(rtems_device_major_number major, rtems_device_minor_number minor)
987  {
988  rtems_status_code status;
989  struct mscan_channel_info *chan = &chan_info[minor];
990
991
992  /* set registers according to MSCAN channel information */
993  switch(minor)
994    {
995
996    case MSCAN_A:
997      chan->rx_qname = rtems_build_name ('C', 'N', 'A', 'Q');
998      chan->tx_rb_sname = rtems_build_name ('C', 'N', 'A', 'S');
999
1000      /* register RTEMS device names for MSCAN A */
1001      if((status = rtems_io_register_name (MSCAN_A_DEV_NAME, major, MSCAN_A)) != RTEMS_SUCCESSFUL)
1002            return status;
1003
1004      /* register RTEMS device names for MSCAN 0 */
1005      if((status = rtems_io_register_name (MSCAN_0_DEV_NAME, major, MSCAN_A)) != RTEMS_SUCCESSFUL)
1006            return status;
1007
1008          /* allocate the space for MSCAN A tx ring buffer */
1009          if(((chan->tx_ring_buf.buf_ptr) = malloc(sizeof(struct can_message)*(NO_OF_MSCAN_TX_BUFF+1))) != NULL)
1010            {
1011        chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr = chan->tx_ring_buf.buf_ptr;
1012            }
1013          else
1014            {
1015                return RTEMS_UNSATISFIED;
1016            }
1017      break;
1018
1019    case MSCAN_B:
1020          chan->rx_qname = rtems_build_name ('C', 'N', 'B', 'Q');
1021      chan->tx_rb_sname = rtems_build_name ('C', 'N', 'B', 'S');
1022
1023          /* register RTEMS device names for MSCAN B */
1024          if((status = rtems_io_register_name (MSCAN_B_DEV_NAME, major, MSCAN_B)) != RTEMS_SUCCESSFUL)
1025            return status;
1026
1027      /* register RTEMS device names for MSCAN 1 */
1028          if((status = rtems_io_register_name (MSCAN_1_DEV_NAME, major, MSCAN_B)) != RTEMS_SUCCESSFUL)
1029            return status;
1030
1031      /* allocate the space for MSCAN B tx ring buffer */
1032          if(((chan->tx_ring_buf.buf_ptr) = malloc(sizeof(struct can_message)*(NO_OF_MSCAN_TX_BUFF+1))) != NULL)
1033            {
1034                chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr = chan->tx_ring_buf.buf_ptr;
1035            }
1036          else
1037            {
1038                return RTEMS_UNSATISFIED;
1039            }
1040      break;
1041
1042    default:
1043      return RTEMS_UNSATISFIED;
1044      break;
1045    }
1046
1047  /* create RTEMS rx message queue */
1048  status = rtems_message_queue_create(chan->rx_qname,
1049                                             (uint32_t) NO_OF_MSCAN_RX_BUFF,
1050                                             (uint32_t) MSCAN_MESSAGE_SIZE(sizeof(struct can_message)),
1051                                             (rtems_attribute) RTEMS_LOCAL | RTEMS_FIFO,
1052                                             (rtems_id *)&(chan->rx_qid));
1053
1054  /* create counting RTEMS tx ring buffer semaphore */
1055  status = rtems_semaphore_create(chan->tx_rb_sname,
1056                                 (uint32_t)(NO_OF_MSCAN_TX_BUFF),
1057                                  RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
1058                                 (rtems_task_priority)0,
1059                                 (rtems_id *)&(chan->tx_rb_sid));
1060
1061  /* Set up interrupts */
1062  if(!BSP_install_rtems_irq_handler(&(mpc5200_mscan_irq_data[minor])))
1063    rtems_panic("Can't attach MPC5x00 MSCAN interrupt handler %d\n", minor);
1064
1065  /* basic setup for channel info. struct. */
1066  chan->regs           = (struct mpc5200_mscan *)&(mpc5200.mscan[minor]);
1067  chan->int_rx_err     = 0;
1068  chan->id_extended    = FALSE;
1069  chan->mode           = MSCAN_INITIALIZED_MODE;
1070  chan->tx_buf_no      = NO_OF_MSCAN_TX_BUFF;
1071
1072  return status;
1073
1074  }
1075
1076
1077/*
1078 * MPC5x00 MSCAN device initialization
1079 */
1080rtems_device_driver mscan_initialize(rtems_device_major_number major,
1081                                     rtems_device_minor_number minor,
1082                                     void *arg
1083                                    )
1084  {
1085  rtems_status_code status;
1086
1087  /* Initialization requested via RTEMS */
1088  if((status = mscan_channel_initialize(major,MSCAN_A)) != RTEMS_SUCCESSFUL)
1089    rtems_fatal_error_occurred(status);
1090
1091  if((status = mscan_channel_initialize(major,MSCAN_B)) != RTEMS_SUCCESSFUL)
1092    rtems_fatal_error_occurred(status);
1093
1094  if((status = mpc5200_mscan_set_mode(MSCAN_A, MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL)
1095    rtems_fatal_error_occurred(status);
1096
1097  if((status = mpc5200_mscan_set_mode(MSCAN_B, MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL)
1098    rtems_fatal_error_occurred(status);
1099
1100  return status;
1101
1102  }
1103
1104
1105/*
1106 * MPC5x00 MSCAN device open
1107 */
1108rtems_device_driver mscan_open( rtems_device_major_number major,
1109                                 rtems_device_minor_number minor,
1110                                 void * arg
1111                               )
1112  {
1113  rtems_status_code status = RTEMS_SUCCESSFUL;
1114  struct mscan_channel_info *chan = NULL;
1115
1116  switch(minor)
1117    {
1118
1119    case MSCAN_A:
1120    case MSCAN_B:
1121      chan = &chan_info[minor];
1122      break;
1123
1124    default:
1125      return RTEMS_UNSATISFIED;
1126      break;
1127    }
1128
1129
1130  /* check mode */
1131  if((chan->mode) == MSCAN_SLEEP_MODE)
1132    {
1133
1134    /* if not already set enter init mode */
1135    status = mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
1136    }
1137
1138  return status;
1139
1140  }
1141
1142
1143/*
1144 * MPC5x00 MSCAN device close
1145 */
1146rtems_device_driver mscan_close( rtems_device_major_number major,
1147                                  rtems_device_minor_number minor,
1148                                  void * arg
1149                                )
1150  {
1151  rtems_status_code status;
1152  struct mscan_channel_info *chan = NULL;
1153
1154  switch(minor)
1155    {
1156
1157    case MSCAN_A:
1158    case MSCAN_B:
1159          chan = &chan_info[minor];
1160      break;
1161
1162    default:
1163      return RTEMS_UNSATISFIED;
1164      break;
1165    }
1166
1167  /* enter deep sleep mode */
1168  status = mpc5200_mscan_set_mode(minor, MSCAN_SLEEP_MODE);
1169
1170  return status;
1171
1172  }
1173
1174
1175/*
1176 * MPC5x00 MSCAN device read
1177 */
1178rtems_device_driver mscan_read( rtems_device_major_number major,
1179                                 rtems_device_minor_number minor,
1180                                 void * arg
1181                               )
1182  {
1183  rtems_status_code status;
1184  uint32_t          message_size = 0;
1185  rtems_libio_rw_args_t     *parms       = (rtems_libio_rw_args_t *)arg;
1186  struct mscan_rx_parms     *rx_parms    = (struct mscan_rx_parms *)(parms->buffer);
1187  struct can_message        *rx_mess     = (struct can_message *)(rx_parms->rx_mess);
1188  struct mscan_channel_info *chan        = NULL;
1189
1190  switch(minor)
1191    {
1192
1193    case MSCAN_A:
1194    case MSCAN_B:
1195          chan = &chan_info[minor];
1196      break;
1197
1198    default:
1199      return RTEMS_UNSATISFIED;
1200      break;
1201    }
1202
1203
1204  /* end init mode if it is first read */
1205  if((chan->mode) == MSCAN_INIT_NORMAL_MODE)
1206    {
1207
1208    /* if not already set enter init mode */
1209    mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
1210    }
1211
1212  if((status = rtems_message_queue_receive(chan->rx_qid,
1213                                          (void *)(rx_mess),
1214                                          (uint32_t *)&message_size,
1215                                          (uint32_t)(rx_parms->rx_flags),
1216                                          (rtems_interval)(rx_parms->rx_timeout)))
1217                                          != RTEMS_SUCCESSFUL)
1218    {
1219
1220    parms->bytes_moved = 0;
1221
1222    }
1223  else
1224    {
1225
1226    parms->bytes_moved = sizeof(struct can_message);
1227
1228    }
1229
1230  return status;
1231
1232  }
1233
1234
1235/*
1236 * MPC5x00 MSCAN device write
1237 */
1238rtems_device_driver mscan_write( rtems_device_major_number major,
1239                                 rtems_device_minor_number minor,
1240                                 void * arg
1241                                )
1242  {
1243  rtems_status_code status;
1244  rtems_libio_rw_args_t         *parms       = (rtems_libio_rw_args_t *)arg;
1245  struct mscan_tx_parms         *tx_parms    = (struct mscan_tx_parms *)(parms->buffer);
1246  struct can_message            *tx_mess     = (struct can_message *)(tx_parms->tx_mess);
1247  struct mscan_channel_info     *chan        = NULL;
1248  mscan_handle                  *mscan_hdl   = NULL;
1249  volatile struct mpc5200_mscan *mscan       = NULL;
1250
1251  switch(minor)
1252    {
1253    case MSCAN_A:
1254    case MSCAN_B:
1255          chan      = &chan_info[minor];
1256      mscan_hdl = mpc5200_mscan_irq_data[minor].handle;
1257      mscan     = chan->regs;
1258      break;
1259
1260    default:
1261      return RTEMS_UNSATISFIED;
1262      break;
1263    }
1264
1265  /* end init mode if it is first write */
1266  if((chan->mode) == MSCAN_INIT_NORMAL_MODE)
1267    {
1268
1269    /* if not already set enter init mode */
1270    mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
1271    }
1272
1273  /* preset moved bytes */
1274  parms->bytes_moved = 0;
1275
1276  /* obtain counting semaphore of tx ring buffer */
1277  if((status = rtems_semaphore_obtain((rtems_id)(chan->tx_rb_sid),
1278                                       RTEMS_NO_WAIT,
1279                                          (rtems_interval)0))
1280                                        == RTEMS_SUCCESSFUL)
1281    {
1282
1283    /* append the TOUCAN tx_id to the mess. due to interrupt handling */
1284        tx_mess->toucan_tx_id = tx_parms->tx_id;
1285
1286    /* fill the tx ring buffer with the message */
1287    fill_tx_buffer(chan, tx_mess);
1288
1289    /* enable message buffer specific interrupt */
1290    mscan->tier |= (TIER_TXEI0 | TIER_TXEI1 | TIER_TXEI2);
1291
1292    /* calculate moved bytes */
1293    parms->bytes_moved = (tx_mess->mess_len) & 0x000F;
1294
1295    }
1296
1297  return status;
1298
1299  }
1300
1301
1302/*
1303 * MPC5x00 MSCAN device control
1304 */
1305rtems_device_driver mscan_control( rtems_device_major_number major,
1306                                    rtems_device_minor_number minor,
1307                                    void * arg
1308                                  )
1309  {
1310  rtems_status_code status;
1311  uint16_t tx_id;
1312  rtems_libio_ioctl_args_t      *parms       = (rtems_libio_ioctl_args_t *)arg;
1313  struct mscan_ctrl_parms       *ctrl_parms  = (struct mscan_ctrl_parms *)(parms->buffer);
1314  struct mscan_channel_info     *chan        = NULL;
1315  mscan_handle                  *mscan_hdl   = NULL;
1316  volatile struct mpc5200_mscan *mscan       = NULL;
1317  uint8_t                       tx_buf_count = 0;
1318
1319  switch(minor)
1320    {
1321
1322    case MSCAN_A:
1323    case MSCAN_B:
1324          chan = &chan_info[minor];
1325      mscan_hdl  = mpc5200_mscan_irq_data[minor].handle;
1326      mscan = chan->regs;
1327      break;
1328
1329    default:
1330      return RTEMS_UNSATISFIED;
1331      break;
1332    }
1333
1334  switch(parms->command)
1335    {
1336
1337      /* TOUCAN callback initialization for MSCAN */
1338    case TOUCAN_MSCAN_INIT:
1339      mscan_hdl->toucan_callback = ctrl_parms->toucan_cb_fnc;
1340      break;
1341
1342    /* set rx buffer ID */
1343    case MSCAN_SET_RX_ID:
1344
1345      /* enter init mode */
1346      mpc5200_mscan_enter_init_mode(mscan);
1347
1348      switch(ctrl_parms->ctrl_reg_no)
1349        {
1350
1351        case RX_BUFFER_0:
1352          mscan->idar0  = SET_IDR0(ctrl_parms->ctrl_id);
1353          mscan->idar1  = SET_IDR1(ctrl_parms->ctrl_id);
1354          break;
1355
1356        case RX_BUFFER_1:
1357          mscan->idar2  = SET_IDR2(ctrl_parms->ctrl_id);
1358          mscan->idar3  = SET_IDR3(ctrl_parms->ctrl_id);
1359          break;
1360
1361        case RX_BUFFER_2:
1362          mscan->idar4  = SET_IDR4(ctrl_parms->ctrl_id);
1363          mscan->idar5  = SET_IDR5(ctrl_parms->ctrl_id);
1364          break;
1365
1366        case RX_BUFFER_3:
1367          mscan->idar6  = SET_IDR6(ctrl_parms->ctrl_id);
1368          mscan->idar7  = SET_IDR7(ctrl_parms->ctrl_id);
1369          break;
1370
1371        default:
1372        break;
1373
1374        }
1375
1376      /* exit init mode and perform further initialization which is required in the normal mode */
1377      mpc5200_mscan_exit_init_mode(mscan);
1378
1379      /* enable ints. */
1380      mpc5200_mscan_int_enable(mscan);
1381
1382      /* wait for bus sync. */
1383      mpc5200_mscan_wait_sync(mscan);
1384
1385      return RTEMS_SUCCESSFUL;
1386      break;
1387
1388    /* get rx buffer ID */
1389    case MSCAN_GET_RX_ID:
1390
1391      switch(ctrl_parms->ctrl_reg_no)
1392            {
1393
1394        case RX_BUFFER_0:
1395          ctrl_parms->ctrl_id = GET_IDR0(mscan->idar0) | GET_IDR1(mscan->idar1);
1396          break;
1397
1398        case RX_BUFFER_1:
1399          ctrl_parms->ctrl_id = GET_IDR2(mscan->idar2) | GET_IDR3(mscan->idar3);
1400          break;
1401
1402        case RX_BUFFER_2:
1403          ctrl_parms->ctrl_id = GET_IDR4(mscan->idar4) | GET_IDR5(mscan->idar5);
1404          break;
1405
1406        case RX_BUFFER_3:
1407          ctrl_parms->ctrl_id = GET_IDR6(mscan->idar6) | GET_IDR7(mscan->idar7);
1408          break;
1409
1410        default:
1411        break;
1412
1413        }
1414
1415      break;
1416
1417    /* set rx buffer ID mask */
1418    case MSCAN_SET_RX_ID_MASK:
1419
1420      /* enter init mode */
1421      mpc5200_mscan_enter_init_mode(mscan);
1422
1423      switch(ctrl_parms->ctrl_reg_no)
1424        {
1425
1426        case RX_BUFFER_0:
1427          mscan->idmr0  = SET_IDMR0(ctrl_parms->ctrl_id_mask);
1428          mscan->idmr1  = SET_IDMR1(ctrl_parms->ctrl_id_mask);
1429          break;
1430
1431        case RX_BUFFER_1:
1432          mscan->idmr2  = SET_IDMR2(ctrl_parms->ctrl_id_mask);
1433          mscan->idmr3  = SET_IDMR3(ctrl_parms->ctrl_id_mask);
1434          break;
1435
1436        case RX_BUFFER_2:
1437          mscan->idmr4  = SET_IDMR4(ctrl_parms->ctrl_id_mask);
1438          mscan->idmr5  = SET_IDMR5(ctrl_parms->ctrl_id_mask);
1439          break;
1440
1441        case RX_BUFFER_3:
1442          mscan->idmr6  = SET_IDMR6(ctrl_parms->ctrl_id_mask);
1443          mscan->idmr7  = SET_IDMR7(ctrl_parms->ctrl_id_mask);
1444          break;
1445
1446        default:
1447        break;
1448
1449        }
1450
1451      /* exit init mode and perform further initialization which is required in the normal mode */
1452      mpc5200_mscan_exit_init_mode(mscan);
1453
1454      /* enable ints. */
1455      mpc5200_mscan_int_enable(mscan);
1456
1457      /* wait for bus sync. */
1458      mpc5200_mscan_wait_sync(mscan);
1459
1460      break;
1461
1462    /* get rx buffer ID mask */
1463    case MSCAN_GET_RX_ID_MASK:
1464
1465      switch(ctrl_parms->ctrl_reg_no)
1466        {
1467
1468        case RX_BUFFER_0:
1469          ctrl_parms->ctrl_id_mask = GET_IDMR0(mscan->idmr0) | GET_IDMR1(mscan->idmr1);
1470          break;
1471
1472        case RX_BUFFER_1:
1473          ctrl_parms->ctrl_id_mask = GET_IDMR2(mscan->idmr2) | GET_IDMR3(mscan->idmr3);
1474          break;
1475
1476        case RX_BUFFER_2:
1477          ctrl_parms->ctrl_id_mask = GET_IDMR4(mscan->idmr4) | GET_IDMR5(mscan->idmr5);
1478          break;
1479
1480        case RX_BUFFER_3:
1481          ctrl_parms->ctrl_id_mask = GET_IDMR6(mscan->idmr6) | GET_IDMR7(mscan->idmr7);
1482          break;
1483
1484        default:
1485        break;
1486
1487        }
1488
1489    /* set tx buffer ID */
1490    case MSCAN_SET_TX_ID:
1491
1492      /* check for availability of tx buffer */
1493      if(!((mscan->tflg) & (uint8_t)(ctrl_parms->ctrl_reg_no)))
1494        {
1495
1496        /* do abort tx buf. request */
1497        mscan->tarq = (uint8_t)(ctrl_parms->ctrl_reg_no);
1498
1499        /* wait for abort tx buf. ack. */
1500        while((mscan->taak) & (uint8_t)(ctrl_parms->ctrl_reg_no));
1501
1502        }
1503
1504      /* select tx buf. */
1505      mscan->bsel   = (uint8_t)(ctrl_parms->ctrl_reg_no);
1506
1507      /* set the tx id of selected buf. */
1508      tx_id = ctrl_parms->ctrl_id;
1509      mscan->txidr0 = SET_IDR0(tx_id);
1510      mscan->txidr1 = SET_IDR1(tx_id);
1511      mscan->txidr2 = 0;
1512      mscan->txidr3 = 0;
1513
1514      break;
1515
1516    /* get tx buffer ID */
1517    case MSCAN_GET_TX_ID:
1518
1519      /* select tx buf. */
1520      mscan->bsel   = (uint8_t)(ctrl_parms->ctrl_reg_no);
1521
1522      /* get tx id. of selected buf. */
1523      ctrl_parms->ctrl_id = GET_IDR0(mscan->txidr0) | GET_IDR1(mscan->txidr1);
1524
1525      break;
1526
1527    /* set can bitrate */
1528    case MSCAN_SET_BAUDRATE:
1529
1530      /* check bitrate settings */
1531      if(((ctrl_parms->ctrl_can_bitrate) >= CAN_BIT_RATE_MIN) && ((ctrl_parms->ctrl_can_bitrate) <= CAN_BIT_RATE_MAX)) {
1532
1533        /* enter init mode */
1534        mpc5200_mscan_enter_init_mode(mscan);
1535
1536        /* perform all can bit time settings */
1537        mpc5200_mscan_perform_bit_time_settings(mscan,(uint32_t)(ctrl_parms->ctrl_can_bitrate),IPB_CLOCK);
1538
1539        /* exit init mode and perform further initialization which is required in the normal mode */
1540        mpc5200_mscan_exit_init_mode(mscan);
1541
1542        /* enable ints. */
1543        mpc5200_mscan_int_enable(mscan);
1544
1545        /* wait for bus sync. */
1546        mpc5200_mscan_wait_sync(mscan);
1547
1548            return RTEMS_SUCCESSFUL;
1549            }
1550          else {
1551
1552             return RTEMS_UNSATISFIED;
1553             }
1554
1555      break;
1556
1557    case SET_TX_BUF_NO:
1558
1559      /* check for different settings of tx ring buffer */
1560      if((tx_buf_count = chan->tx_buf_no) != (uint8_t)(ctrl_parms->ctrl_tx_buf_no))
1561        {
1562
1563        /* preset the channel specific no of messages in the tx ring buffer */
1564        tx_buf_count = chan->tx_buf_no;
1565
1566        /* try to obtain all of the tx ring buffers */
1567        while(tx_buf_count > 0)
1568          {
1569
1570          /* obtain semaphore of all tx ring buffers */
1571                  if((status = rtems_semaphore_obtain((rtems_id)(chan->tx_rb_sid),
1572                                                           RTEMS_WAIT,
1573                                                          (rtems_interval)10))
1574                                                == RTEMS_SUCCESSFUL)
1575                {
1576
1577                    tx_buf_count--;
1578
1579                }
1580
1581          }
1582
1583        /* free the former tx ring buffer */
1584        free((void *)chan->tx_ring_buf.buf_ptr);
1585
1586        /* allocate the tx ring buffer with new size */
1587            if(((chan->tx_ring_buf.buf_ptr) = malloc(sizeof(struct can_message)*((uint8_t)(ctrl_parms->ctrl_tx_buf_no)+1))) != NULL)
1588              {
1589                  chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr = chan->tx_ring_buf.buf_ptr;
1590              }
1591            else
1592              {
1593                  return RTEMS_UNSATISFIED;
1594              }
1595
1596        /* set the new amount of tx buffers */
1597        chan->tx_buf_no =  (uint8_t)(ctrl_parms->ctrl_tx_buf_no);
1598
1599        /* release the semaphore of all tx ring buffers */
1600        while(tx_buf_count < chan->tx_buf_no)
1601                  {
1602
1603                  /* obtain semaphore of all tx ring buffers */
1604              rtems_semaphore_release((rtems_id)(chan->tx_rb_sid));
1605
1606                  tx_buf_count++;
1607
1608                  }
1609
1610            }
1611          else
1612            {
1613
1614        return RTEMS_SUCCESSFUL;
1615
1616            }
1617      break;
1618
1619    default:
1620      break;
1621
1622    }
1623
1624  return RTEMS_SUCCESSFUL;
1625
1626  }
1627
Note: See TracBrowser for help on using the repository browser.