diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-25 10:26:24 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-25 11:02:19 +0200 |
commit | 64d4fc7788dbf30d408a3433d5b6d850b0ed759c (patch) | |
tree | dc799fc9d83d73b83f54ef3474dfd7a9e01b63c0 /bsps/powerpc/gen5200 | |
parent | bsp/haleakala: Move mmu_405.c to bsps (diff) | |
download | rtems-64d4fc7788dbf30d408a3433d5b6d850b0ed759c.tar.bz2 |
bsp/gen5200: Move source files to bsps
This patch is a part of the BSP source reorganization.
Update #3285.
Diffstat (limited to 'bsps/powerpc/gen5200')
-rw-r--r-- | bsps/powerpc/gen5200/mscan/mscan-base.c | 546 | ||||
-rw-r--r-- | bsps/powerpc/gen5200/mscan/mscan.c | 1262 | ||||
-rw-r--r-- | bsps/powerpc/gen5200/mscan/mscan_int.h | 185 | ||||
-rw-r--r-- | bsps/powerpc/gen5200/nvram/m93cxx.h | 163 | ||||
-rw-r--r-- | bsps/powerpc/gen5200/nvram/nvram.c | 603 | ||||
-rw-r--r-- | bsps/powerpc/gen5200/slicetimer/slicetimer.c | 366 |
6 files changed, 3125 insertions, 0 deletions
diff --git a/bsps/powerpc/gen5200/mscan/mscan-base.c b/bsps/powerpc/gen5200/mscan/mscan-base.c new file mode 100644 index 0000000000..2044bb3917 --- /dev/null +++ b/bsps/powerpc/gen5200/mscan/mscan-base.c @@ -0,0 +1,546 @@ +/** + * @file + * + * @ingroup m + * + * @brief MSCAN support functions code. + */ + +/* + * Copyright (c) 2008 + * Embedded Brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * rtems@embedded-brains.de + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <bsp.h> +#include <bsp/mscan-base.h> + +#define MIN_NO_OF_TQ 7 +#define TSEG_1 1 +#define TSEG_2 2 +#define NO_OF_TABLE_ENTRIES 4 +#define SJW 3 + +#define CAN_MAX_NO_OF_TQ 25 +#define CAN_MAX_NO_OF_TQ_TSEG1 15 +#define CAN_MAX_NO_OF_TQ_TSEG2 7 +#define CAN_MAX_NO_OF_TQ_SJW 2 + +/** + * Time segmant table. + * + * <table> + * <tr> + * <td>Number of time quantas</th> + * <td>Time Segment 1</th> + * <td>Time Segment 2</th> + * <td>Sync: Jump width</th> + * </tr> + * </table> + */ +static uint8_t can_time_segment_table + [CAN_MAX_NO_OF_TQ - MIN_NO_OF_TQ + 1] [NO_OF_TABLE_ENTRIES] = { + {7, 4, 2, 1}, + {8, 5, 2, 1}, + {9, 6, 2, 2}, + {10, 6, 3, 2}, + {11, 7, 3, 2}, + {12, 8, 3, 2}, + {13, 8, 4, 2}, + {14, 9, 4, 2}, + {15, 10, 4, 2}, + {16, 10, 5, 2}, + {17, 11, 5, 2}, + {18, 12, 5, 2}, + {19, 12, 6, 2}, + {20, 13, 6, 2}, + {21, 14, 6, 2}, + {22, 14, 7, 2}, + {23, 15, 7, 2}, + {24, 15, 8, 2}, + {25, 16, 8, 2} +}; + +/** + * @brief Calculates the MSCAN clock prescaler value. + */ +static uint8_t prescaler_calculation( + unsigned can_bit_rate, + unsigned can_clock_frq, + uint8_t *tq_no +) +{ + +/* local variables */ + uint8_t presc_val, + tq_no_dev_min = 0; + uint32_t bit_rate, + bit_rate_dev, + frq_tq, + bit_rate_dev_min = 0xFFFFFFFF; + +/* loop through all values of time quantas */ + for (*tq_no = CAN_MAX_NO_OF_TQ; *tq_no >= MIN_NO_OF_TQ; (*tq_no)--) { + + /* calculate time quanta freq. */ + frq_tq = *tq_no * can_bit_rate; + + /* calculate the optimized prescal. val. */ + presc_val = (can_clock_frq + frq_tq / 2) / frq_tq; + + /* calculate the bitrate */ + bit_rate = can_clock_frq / (*tq_no * presc_val); + + /* calculate the bitrate deviation */ + if (can_bit_rate >= bit_rate) { + /* calculate the bitrate deviation */ + bit_rate_dev = can_bit_rate - bit_rate; + } else { + /* calculate the bitrate deviation */ + bit_rate_dev = bit_rate - can_bit_rate; + } + + /* check the deviation freq. */ + if (bit_rate_dev == 0) { + + /* return if best match (zero deviation) */ + return (uint8_t) (presc_val); + } else { + + /* check for minimum of bit rate deviation */ + if (bit_rate_dev < bit_rate_dev_min) { + + /* recognize the minimum freq. deviation */ + bit_rate_dev_min = bit_rate_dev; + + /* recognize the no. of time quantas */ + tq_no_dev_min = *tq_no; + } + } + } + + /* get the no of tq's */ + *tq_no = tq_no_dev_min; + + /* calculate time quanta freq. */ + frq_tq = *tq_no * can_bit_rate; + + /* return the optimized prescaler value */ + return (uint8_t) ((can_clock_frq + frq_tq / 2) / frq_tq); +} + +/** + * @brief Sets the bit rate for the MSCAN module @a m to @a can_bit_rate + * in [bits/s]. + */ +bool mscan_set_bit_rate( volatile mscan *m, unsigned can_bit_rate) +{ + mscan_context context; + unsigned prescale_val = 0; + uint8_t tq_no, + tseg_1, + tseg_2, + sseg; + + if (can_bit_rate < MSCAN_BIT_RATE_MIN || can_bit_rate > MSCAN_BIT_RATE_MAX) { + return false; + } + + /* Enter initialization mode */ + mscan_initialization_mode_enter( m, &context); + + /* get optimized prescaler value */ + prescale_val = prescaler_calculation(can_bit_rate, IPB_CLOCK, &tq_no); + + /* Check prescaler value */ + if (prescale_val > 64) { + /* Leave initialization mode */ + mscan_initialization_mode_leave( m, &context); + + return false; + } + + /* get time segment length from time segment table */ + tseg_1 = can_time_segment_table[tq_no - MIN_NO_OF_TQ][TSEG_1]; + tseg_2 = can_time_segment_table[tq_no - MIN_NO_OF_TQ][TSEG_2]; + sseg = can_time_segment_table[tq_no - MIN_NO_OF_TQ][SJW]; + + /* Bus Timing Register 0 MSCAN_A/_B ------------------------------ */ + /* [07]:SJW1 1 : Synchronization jump width, Bit1 */ + /* [06]:SJW0 0 : Synchronization jump width, Bit0 */ + /* SJW = 2 -> 3 Tq clock cycles */ + /* [05]:BRP5 0 : Baud Rate Prescaler, Bit 5 */ + /* [04]:BRP4 0 : Baud Rate Prescaler, Bit 4 */ + /* [03]:BRP3 0 : Baud Rate Prescaler, Bit 3 */ + /* [02]:BRP2 1 : Baud Rate Prescaler, Bit 2 */ + /* [01]:BRP1 0 : Baud Rate Prescaler, Bit 1 */ + /* [00]:BRP0 1 : Baud Rate Prescaler, Bit 0 */ + m->btr0 = (BTR0_SJW(sseg - 1) | BTR0_BRP(prescale_val - 1)); + + /* Bus Timing Register 1 MSCAN_A/_B ------------------------------ */ + /* [07]:SAMP 0 : One Sample per bit */ + /* [06]:TSEG22 0 : Time Segment 2, Bit 2 */ + /* [05]:TSEG21 1 : Time Segment 2, Bit 1 */ + /* [04]:TSEG20 0 : Time Segment 2, Bit 0 */ + /* -> PHASE_SEG2 = 3 Tq */ + /* [03]:TSEG13 0 : Time Segment 1, Bit 3 */ + /* [02]:TSEG12 1 : Time Segment 1, Bit 2 */ + /* [01]:TSEG11 1 : Time Segment 1, Bit 1 */ + /* [00]:TSEG10 0 : Time Segment 1, Bit 0 */ + m->btr1 = (BTR1_TSEG2(tseg_2 - 1) | BTR1_TSEG1(tseg_1 - 1)); + + /* Leave initialization mode */ + mscan_initialization_mode_leave( m, &context); + + return true; +} + +/** + * @brief Disables all interrupts for the MSCAN module @a m. + */ +void mscan_interrupts_disable( volatile mscan *m) +{ + m->rier = 0; + m->tier = 0; +} + +/** + * @brief Enter initialization mode for the MSCAN module @a m. + * + * Saves the current MSCAN context in @a context. + */ +void mscan_initialization_mode_enter( volatile mscan *m, mscan_context *context) +{ + /* Save context */ + context->ctl0 = m->ctl0 & CTL0_TIME; + context->rier = m->rier; + context->tier = m->tier; + + /* Request initialization mode */ + m->ctl0 |= CTL0_INITRQ; + + /* Wait for initialization mode acknowledge */ + while ((m->ctl1 & CTL1_INITAK) == 0) { + /* Wait */ + } +} + +/** + * @brief Leave initialization mode for the MSCAN module @a m. + * + * Saves the previous MSCAN context saved in @a context. + */ +void mscan_initialization_mode_leave( volatile mscan *m, const mscan_context *context) +{ + /* Clear initialization mode request */ + m->ctl0 &= ~CTL0_INITRQ; + + /* Wait for clearing of initialization mode acknowledge */ + while ((m->ctl1 & CTL1_INITAK) != 0) { + /* Wait */ + } + + /* Leave sleep mode */ + mscan_sleep_mode_leave( m); + + /* Restore context */ + m->ctl0 |= context->ctl0; + m->rier |= context->rier; + m->tier |= context->tier; +} + +/** + * @brief Enter sleep mode for the MSCAN module @a m. + */ +void mscan_sleep_mode_enter( volatile mscan *m) +{ + /* Request sleep mode */ + m->ctl0 |= CTL0_SLPRQ; +} + +/** + * @brief Leave sleep mode for the MSCAN module @a m. + */ +void mscan_sleep_mode_leave( volatile mscan *m) +{ + /* Clear sleep mode request */ + m->ctl0 &= ~CTL0_SLPRQ; + + /* Wait for clearing of sleep mode acknowledge */ + while ((m->ctl1 & CTL1_SLPAK) != 0) { + /* Wait */ + } +} + +/** + * @brief Enables and initializes the MSCAN module @a m. + * + * The module is set to listen only mode. + */ +bool mscan_enable( volatile mscan *m, unsigned bit_rate) +{ + bool s = true; + + /* Disable the module */ + mscan_disable( m); + + /* Enable module in listen only */ + m->ctl1 = CTL1_CANE | CTL1_LISTEN; + + /* Close acceptance filters */ + m->idac = IDAC_IDAM1 | IDAC_IDAM0; + + /* Clear filter */ + mscan_filter_clear( m); + + /* Set bit rate and leave initialization mode */ + s = mscan_set_bit_rate( m, bit_rate); + + /* Clear all flags */ + m->ctl0 = CTL0_RXFRM; + + /* Disable interrupts */ + mscan_interrupts_disable( m); + + return s; +} + +/** + * @brief Disables the MSCAN module @a m. + * + * The module is set to sleep mode and disabled afterwards. + */ +void mscan_disable( volatile mscan *m) +{ + mscan_context context; + + /* Disable interrupts */ + mscan_interrupts_disable( m); + + /* Enter initialization mode */ + mscan_initialization_mode_enter( m, &context); + + /* Disable module */ + m->ctl1 &= ~CTL1_CANE; +} + +/** + * @brief Sets the filter ID and mask registers of the MSCAN module @a m to + * default values. + */ +void mscan_filter_clear( volatile mscan *m) +{ + mscan_context context; + + mscan_initialization_mode_enter( m, &context); + + /* Setup ID acceptance registers */ + m->idar0 = MSCAN_FILTER_ID_DEFAULT; + m->idar1 = MSCAN_FILTER_ID_DEFAULT; + m->idar2 = MSCAN_FILTER_ID_DEFAULT; + m->idar3 = MSCAN_FILTER_ID_DEFAULT; + m->idar4 = MSCAN_FILTER_ID_DEFAULT; + m->idar5 = MSCAN_FILTER_ID_DEFAULT; + m->idar6 = MSCAN_FILTER_ID_DEFAULT; + m->idar7 = MSCAN_FILTER_ID_DEFAULT; + + /* Setup ID mask registers */ + m->idmr0 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT; + m->idmr1 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT; + m->idmr2 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT; + m->idmr3 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT; + m->idmr4 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT; + m->idmr5 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT; + m->idmr6 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT; + m->idmr7 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT; + + mscan_initialization_mode_leave( m, &context); +} + +/** + * @brief Returns the number of active filters of the MSCAN module @a m. + * + * @see MSCAN_FILTER_NUMBER_MIN, MSCAN_FILTER_NUMBER_2, MSCAN_FILTER_NUMBER_4 + * and MSCAN_FILTER_NUMBER_MAX. + */ +unsigned mscan_filter_number( volatile mscan *m) +{ + uint8_t idam = m->idac & IDAC_IDAM; + + switch (idam) { + case 0: + return MSCAN_FILTER_NUMBER_2; + case IDAC_IDAM0: + return MSCAN_FILTER_NUMBER_4; + case IDAC_IDAM1: + return MSCAN_FILTER_NUMBER_MAX; + default: + return MSCAN_FILTER_NUMBER_MIN; + } +} + +/** + * @brief Sets the number of active filters of the MSCAN module @a m to @a + * number and returns true if @a number is valid. + * + * @see MSCAN_FILTER_NUMBER_MIN, MSCAN_FILTER_NUMBER_2, MSCAN_FILTER_NUMBER_4 + * and MSCAN_FILTER_NUMBER_MAX. + */ +bool mscan_set_filter_number( volatile mscan *m, unsigned number) +{ + mscan_context context; + uint8_t idac = IDAC_IDAM1 | IDAC_IDAM0; + + switch (number) { + case MSCAN_FILTER_NUMBER_MIN: + break; + case MSCAN_FILTER_NUMBER_2: + idac = 0; + break; + case MSCAN_FILTER_NUMBER_4: + idac = IDAC_IDAM0; + break; + case MSCAN_FILTER_NUMBER_MAX: + idac = IDAC_IDAM1; + break; + default: + return false; + } + + mscan_initialization_mode_enter( m, &context); + + m->idac = idac; + + mscan_initialization_mode_leave( m, &context); + + /* Clear filter */ + mscan_filter_clear( m); + + return true; +} + +/** + * @brief Returns the address of the CANIDAR register with index @a i of the + * MSCAN module @a m. + * + * @warning The index @a i is not checked if it is in range. + */ +volatile uint8_t *mscan_id_acceptance_register( volatile mscan *m, unsigned i) +{ + volatile uint8_t *const idar [8] = { + &m->idar0, + &m->idar1, + &m->idar2, + &m->idar3, + &m->idar4, + &m->idar5, + &m->idar6, + &m->idar7 + }; + + return idar [i]; +} + +/** + * @brief Returns the address of the CANIDMR register with index @a i of the + * MSCAN module @a m. + * + * @warning The index @a i is not checked if it is in range. + */ +volatile uint8_t *mscan_id_mask_register( volatile mscan *m, unsigned i) +{ + volatile uint8_t *const idmr [8] = { + &m->idmr0, + &m->idmr1, + &m->idmr2, + &m->idmr3, + &m->idmr4, + &m->idmr5, + &m->idmr6, + &m->idmr7 + }; + + return idmr [i]; +} + +/** + * @brief Sets or gets the filter ID and mask in @a id and @a mask depending on + * @a set of MSCAN module @a m. The filter is selected by the value of @a + * index. + * + * Returns true if the operation was successful. + */ +bool mscan_filter_operation( + volatile mscan *m, + bool set, + unsigned index, + uint32_t *id, + uint32_t *mask +) +{ + unsigned number = mscan_filter_number( m); + unsigned offset = MSCAN_FILTER_NUMBER_MAX / number; + unsigned shift = 24; + + volatile uint8_t *idar = NULL; + volatile uint8_t *idmr = NULL; + + if (!set) { + *id = MSCAN_FILTER_ID_DEFAULT; + *mask = MSCAN_FILTER_MASK_DEFAULT; + } + + if (index < number) { + mscan_context context; + + mscan_initialization_mode_enter( m, &context); + + index *= offset; + offset += index; + while (index < offset) { + idar = mscan_id_acceptance_register( m, index); + idmr = mscan_id_mask_register( m, index); + + if (set) { + *idar = (uint8_t) (*id >> shift); + *idmr = (uint8_t) (*mask >> shift); + } else { + *id = (*id & ~(0xffU << shift)) | (*idar << shift); + *mask = (*mask & ~(0xffU << shift)) | (*idmr << shift); + } + + shift -= 8; + + ++index; + } + + mscan_initialization_mode_leave( m, &context); + } else { + return false; + } + + return true; +} + +/** + * @brief Returns the receiver and transmitter error counter values in @a rec + * and @a tec of MSCAN module @a m. + */ +void mscan_get_error_counters( volatile mscan *m, unsigned *rec, unsigned *tec) +{ + mscan_context context; + + mscan_initialization_mode_enter( m, &context); + + *rec = m->rxerr; + *tec = m->txerr; + + mscan_initialization_mode_leave( m, &context); +} diff --git a/bsps/powerpc/gen5200/mscan/mscan.c b/bsps/powerpc/gen5200/mscan/mscan.c new file mode 100644 index 0000000000..e36b6224cc --- /dev/null +++ b/bsps/powerpc/gen5200/mscan/mscan.c @@ -0,0 +1,1262 @@ +/*===============================================================*\ +| Project: RTEMS generic MPC5200 BSP | ++-----------------------------------------------------------------+ +| Copyright (c) 2005 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.org/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the MSCAN driver | +\*===============================================================*/ + +#include <stdio.h> +#include <stdlib.h> +#include <rtems.h> +#include <rtems/error.h> +#include <rtems/libio.h> +#include <string.h> + +#include <bsp.h> +#include <bsp/fatal.h> +#include <bsp/irq.h> +#include "../mscan/mscan_int.h" + +/* #define MSCAN_LOOPBACK */ + +struct mpc5200_rx_cntrl mpc5200_mscan_rx_cntrl[MPC5200_CAN_NO]; +static struct mscan_channel_info chan_info[MPC5200_CAN_NO]; + +/* + * MPC5x00 MSCAN tx ring buffer function to get a can message buffer from the head of the tx ring buffer + */ +static struct can_message *get_tx_buffer(struct mscan_channel_info *chan) +{ + /* define a temp. mess ptr. */ + struct can_message *tmp_mess_ptr = NULL, + *temp_head_ptr; + + /* set temp. head pointer */ + temp_head_ptr = chan->tx_ring_buf.head_ptr; + + /* check buffer empty condition */ + if (temp_head_ptr != chan->tx_ring_buf.tail_ptr) { + + /* current buffer head. ptr. */ + tmp_mess_ptr = temp_head_ptr; + + /* increment the head pointer */ + temp_head_ptr++; + + /* check for wrap around condition */ + if (temp_head_ptr > chan->tx_ring_buf.buf_ptr + NO_OF_MSCAN_TX_BUFF) { + + /* set head ptr. to the begin of the ring buffer */ + temp_head_ptr = chan->tx_ring_buf.buf_ptr; + + } + + /* end of crtical section restore head ptr. */ + chan->tx_ring_buf.head_ptr = temp_head_ptr; + } + + /* return the current head pointer */ + return tmp_mess_ptr; +} + +/* + * MPC5x00 MSCAN tx ring buffer function to write a can message buffer to the tail of the tx ring buffer + */ +static struct can_message *fill_tx_buffer(struct mscan_channel_info *chan, + struct can_message *mess_ptr) +{ + /* define a temp. mess ptr. to the entry which follows the current tail entry */ + struct can_message *tmp_mess_ptr = chan->tx_ring_buf.tail_ptr + 1; + + /* check for the wrap around condition */ + if (tmp_mess_ptr > chan->tx_ring_buf.buf_ptr + NO_OF_MSCAN_TX_BUFF) { + /* set temp. mess. ptr to the begin of the ring buffer */ + tmp_mess_ptr = chan->tx_ring_buf.buf_ptr; + } + + /* check buffer full condition */ + if (tmp_mess_ptr == chan->tx_ring_buf.head_ptr) { + /* return NULL in case buffer is full */ + return NULL; + } else { + /* copy the can mess. to the tail of the buffer */ + memcpy((void *) chan->tx_ring_buf.tail_ptr, (void *) mess_ptr, + sizeof (struct can_message)); + + /* set new tail equal to temp. mess. ptr. */ + chan->tx_ring_buf.tail_ptr = tmp_mess_ptr; + } + + /* return the actual tail ptr. (next free entry) */ + return chan->tx_ring_buf.tail_ptr; +} + +/* + * MPC5x00 MSCAN interrupt handler + */ +static void mpc5200_mscan_interrupt_handler(rtems_irq_hdl_param handle) +{ + rtems_status_code status; + mscan_handle *mscan_hdl = (mscan_handle *) handle; + struct mscan_channel_info *chan = &chan_info[mscan_hdl->mscan_channel]; + struct can_message rx_mess, + *rx_mess_ptr, + *tx_mess_ptr; + mscan *m = chan->regs; + register uint8_t idx; + + /* + handle tx ring buffer + */ + + /* loop over all 3 tx buffers */ + for (idx = TFLG_TXE0; idx <= TFLG_TXE2; idx = idx << 1) { + + /* check for tx buffer vacation */ + if ((m->tflg) & idx) { + + /* try to get a message */ + tx_mess_ptr = get_tx_buffer(chan); + + /* check for new tx message */ + if (tx_mess_ptr != NULL) { + + /* select the tx buffer */ + m->bsel = idx; + + /* check for toucan interface */ + if ((mscan_hdl->toucan_callback) == NULL) { + + /* set tx id */ + m->txidr0 = SET_IDR0(tx_mess_ptr->mess_id); + m->txidr1 = SET_IDR1(tx_mess_ptr->mess_id); + m->txidr2 = 0; + m->txidr3 = 0; + + } + + /* fill in tx data if TOUCAN is activ an TOUCAN index have a match with the tx buffer or TOUCAN is disabled */ + if (((mscan_hdl->toucan_callback) == NULL) + || (((mscan_hdl->toucan_callback) != NULL) + && ((tx_mess_ptr->toucan_tx_idx) == idx))) { + + /* insert dlc into m register */ + m->txdlr = (uint8_t) ((tx_mess_ptr->mess_len) & 0x000F); + + /* skip data copy in case of RTR */ + if (!(MSCAN_MESS_ID_HAS_RTR(tx_mess_ptr->mess_id))) { + /* copy tx data to MSCAN registers */ + switch (m->txdlr) { + case 8: + m->txdsr7 = tx_mess_ptr->mess_data[7]; + case 7: + m->txdsr6 = tx_mess_ptr->mess_data[6]; + case 6: + m->txdsr5 = tx_mess_ptr->mess_data[5]; + case 5: + m->txdsr4 = tx_mess_ptr->mess_data[4]; + case 4: + m->txdsr3 = tx_mess_ptr->mess_data[3]; + case 3: + m->txdsr2 = tx_mess_ptr->mess_data[2]; + case 2: + m->txdsr1 = tx_mess_ptr->mess_data[1]; + case 1: + m->txdsr0 = tx_mess_ptr->mess_data[0]; + break; + default: + break; + } + } + + /* enable message buffer specific interrupt */ + m->tier |= m->bsel; + + /* start transfer */ + m->tflg = m->bsel; + + /* release counting semaphore of tx ring buffer */ + rtems_semaphore_release((rtems_id) (chan->tx_rb_sid)); + + } else { + + /* refill the tx ring buffer with the message */ + fill_tx_buffer(chan, tx_mess_ptr); + + } + } else { + /* reset interrupt enable bit */ + m->tier &= ~(idx); + } + } + } + + /* + handle rx interrupts + */ + + /* check for rx interrupt source */ + if (m->rier & RIER_RXFIE) { + + /* can messages received ? */ + while (m->rflg & RFLG_RXF) { + + if (mscan_hdl->toucan_callback == NULL) { + + /* select temporary rx buffer */ + rx_mess_ptr = &rx_mess; + + } else { + + /* check the rx fliter-match indicators (16-bit filter mode) */ + /* in case of more than one hit, lower hit has priority */ + idx = (m->idac) & 0x7; + switch (idx) { + + case 0: + case 1: + case 2: + case 3: + rx_mess_ptr = + (struct can_message *) + &(mpc5200_mscan_rx_cntrl[mscan_hdl->mscan_channel]. + can_rx_message[idx]); + break; + + /* this case should never happen */ + default: + /* reset the rx indication flag */ + m->rflg |= RFLG_RXF; + + return; + break; + } + + } + + /* get rx ID */ + rx_mess_ptr->mess_id = GET_IDR0(m->rxidr0) | GET_IDR1(m->rxidr1); + + /* get rx len */ + rx_mess_ptr->mess_len = ((m->rxdlr) & 0x0F); + + /* get time stamp */ + rx_mess_ptr->mess_time_stamp = ((m->rxtimh << 8) | (m->rxtiml)); + + /* skip data copy in case of RTR */ + if (!(MSCAN_MESS_ID_HAS_RTR(rx_mess_ptr->mess_id))) + { + + /* get the data */ + switch (rx_mess_ptr->mess_len) { + case 8: + rx_mess_ptr->mess_data[7] = m->rxdsr7; + case 7: + rx_mess_ptr->mess_data[6] = m->rxdsr6; + case 6: + rx_mess_ptr->mess_data[5] = m->rxdsr5; + case 5: + rx_mess_ptr->mess_data[4] = m->rxdsr4; + case 4: + rx_mess_ptr->mess_data[3] = m->rxdsr3; + case 3: + rx_mess_ptr->mess_data[2] = m->rxdsr2; + case 2: + rx_mess_ptr->mess_data[1] = m->rxdsr1; + case 1: + rx_mess_ptr->mess_data[0] = m->rxdsr0; + case 0: + default: + break; + } + } + + if (mscan_hdl->toucan_callback == NULL) { + + if ((status = + rtems_message_queue_send(chan->rx_qid, (void *) rx_mess_ptr, + sizeof (struct can_message))) != + RTEMS_SUCCESSFUL) { + + chan->int_rx_err++; + + } + + } else { + + mscan_hdl->toucan_callback((int16_t) (((m->idac) & 0x7) + 3)); + + } + + /* reset the rx indication flag */ + m->rflg |= RFLG_RXF; + + } /* end of while(m->rflg & RFLG_RXF) */ + + } + + /* status change detected */ + if (m->rflg & RFLG_CSCIF) { + + m->rflg |= RFLG_CSCIF; + + if (mscan_hdl->toucan_callback != NULL) { + + mscan_hdl->toucan_callback((int16_t) (-1)); + + } + + } + +} + +/** + * @brief Enables some interrupts for the MSCAN module @a m. + * + * Enabled interrupts: + * - Receiver or transmitter enters or leaves bus off state + * - Receiver buffer full + */ +static void mscan_interrupts_enable(mscan *m) +{ + + /* RX Interrupt Enable on MSCAN_A/_B ----------------------------- */ + /* [07]:WUPIE 0 : WakeUp interrupt disabled */ + /* [06]:CSCIE 1 : Status Change interrupt enabled */ + /* [05]:RSTATE1 0 : Recv. Status Change int. ,Bit 1 */ + /* [04]:RSTATE0 1 : Recv. Status Change int. ,Bit 0 */ + /* -> 01 BusOff status changes enabled */ + /* [03]:TSTAT1 0 : Transmit. Status Change int. , Bit 1 */ + /* [02]:TSTAT0 1 : Transmit. Status Change int. , Bit 0 */ + /* -> 01 BusOff status changes enabled */ + /* [01]:OVRIE 0 : Overrun Interrupt is disabled */ + /* [00]:RXFIE 1 : Recv. Full interrupt is enabled */ + m->rier |= (RIER_CSCIE | RIER_RXFIE | RIER_RSTAT(1) | RIER_TSTAT(1)); + + return; + +} + +/* + * Unmask MPC5x00 MSCAN_A interrupts + */ +static void mpc5200_mscan_a_on(const rtems_irq_connect_data * ptr) +{ + mscan *m = (&chan_info[MSCAN_A])->regs; + + mscan_interrupts_enable(m); + + return; + +} + +/* + * Mask MPC5x00 MSCAN_A interrupts + */ +static void mpc5200_mscan_a_off(const rtems_irq_connect_data * ptr) +{ + mscan *m = (&chan_info[MSCAN_A])->regs; + + mscan_interrupts_disable(m); + + return; + +} + +/* + * Get MSCAN_A interrupt mask setting + */ +static int mpc5200_mscan_a_isOn(const rtems_irq_connect_data * ptr) +{ + mscan *m = (&chan_info[MSCAN_A])->regs; + + if ((m->rier & RIER_CSCIE) && (m->rier & RIER_RXFIE)) + return RTEMS_SUCCESSFUL; + else + return RTEMS_UNSATISFIED; + + return RTEMS_SUCCESSFUL; + +} + +/* + * Unmask MPC5x00 MSCAN_B interrupts + */ +static void mpc5200_mscan_b_on(const rtems_irq_connect_data * ptr) +{ + mscan *m = (&chan_info[MSCAN_B])->regs; + + mscan_interrupts_enable(m); + + return; + +} + +/* + * Mask MPC5x00 MSCAN_B interrupts + */ +static void mpc5200_mscan_b_off(const rtems_irq_connect_data * ptr) +{ + mscan *m = (&chan_info[MSCAN_B])->regs; + + mscan_interrupts_disable(m); + + return; + +} + +/* + * Get MSCAN_B interrupt mask setting + */ +static int mpc5200_mscan_b_isOn(const rtems_irq_connect_data * ptr) +{ + mscan *m = (&chan_info[MSCAN_B])->regs; + + if ((m->rier & RIER_CSCIE) && (m->rier & RIER_RXFIE)) + return RTEMS_SUCCESSFUL; + else + return RTEMS_UNSATISFIED; + + return RTEMS_SUCCESSFUL; + +} + +static mscan_handle mscan_a_handle = { + MSCAN_A, + NULL +}; + +static mscan_handle mscan_b_handle = { + MSCAN_B, + NULL +}; + +/* + * MPC5x00 MSCAN_A/_B irq data + */ +static rtems_irq_connect_data mpc5200_mscan_irq_data[MPC5200_CAN_NO] = { + { + BSP_SIU_IRQ_MSCAN1, + (rtems_irq_hdl) mpc5200_mscan_interrupt_handler, + (rtems_irq_hdl_param) & mscan_a_handle, + (rtems_irq_enable) mpc5200_mscan_a_on, + (rtems_irq_disable) mpc5200_mscan_a_off, + (rtems_irq_is_enabled) mpc5200_mscan_a_isOn + }, { + BSP_SIU_IRQ_MSCAN2, + (rtems_irq_hdl) mpc5200_mscan_interrupt_handler, + (rtems_irq_hdl_param) & mscan_b_handle, + (rtems_irq_enable) mpc5200_mscan_b_on, + (rtems_irq_disable) mpc5200_mscan_b_off, + (rtems_irq_is_enabled) mpc5200_mscan_b_isOn + } +}; + +/* + * MPC5x00 MSCAN wait for sync. with CAN bus + */ +void mpc5200_mscan_wait_sync(mscan *m) +{ + + /* Control Register 0 -------------------------------------------- */ + /* [07]:RXFRM 0 : Recv. Frame, Flag Bit (rd.&clear only) */ + /* [06]:RXACT 0 : Recv. Active, Status Bit (rd. only) */ + /* [05]:CSWAI 0 : CAN Stops in Wait Mode */ + /* [04]:SYNCH 0->1 : Synchronized, Status Bit (rd. only) */ + /* [03]:TIME 1 : Generate Timestamps */ + /* [02]:WUPE 0 : WakeUp Disabled */ + /* [01]:SLPRQ 0 : No Sleep Mode Request */ + /* [00]:INITRQ 0 : No init. Mode Request */ + /* wait for MSCAN A_/_B bus synch. */ + +#if 0 /* we don't have a need to wait for sync. */ + while (!((m->ctl0) & CTL0_SYNCH)); +#endif + return; + +} + +/* + * MPC5x00 MSCAN perform settings in init mode + */ +static void mpc5200_mscan_perform_initialization_mode_settings(mscan *m) +{ + mscan_context context; + + /* perform all can bit time settings */ + (void) mscan_set_bit_rate(m, MSCAN_BIT_RATE_DEFAULT); + + /* Enter initialization mode */ + mscan_initialization_mode_enter( m, &context); + + /* Control Register 1 -------------------------------------------- */ + /* [07]:CANE 0 : MSCAN Module is disabled */ + /* [06]:CLKSRC 0 : Clock Source -> IPB_CLOCK (bsp.h) */ + /* [05]:LOOPB 0 : No Loopback */ + /* [04]:LISTEN 0 : Normal Operation */ + /* [03]:res 0 : reserved */ + /* [02]:WUPM 0 : No protect. from spurious WakeUp */ + /* [01]:SLPAK 1->0 : Sleep Mode Acknowledge (rd. only) */ + /* [00]:INITAK 0 : Init. Mode Acknowledge (rd. only) */ + /* Set CLK source, disable loopback & listen-only mode */ +#ifndef MSCAN_LOOPBACK + m->ctl1 &= ~(CTL1_LISTEN | CTL1_LOOPB | CTL1_CLKSRC); +#else + m->ctl1 &= ~(CTL1_LISTEN | CTL1_CLKSRC); + m->ctl1 |= (CTL1_LOOPB); +#endif + + /* IPB clock -> IPB_CLOCK */ + /* bitrate -> CAN_BIT_RATE */ + /* Max. no of Tq -> CAN_MAX_NO_OF_TQ */ + /* Prescaler value -> prescale_val = ROUND_UP(IPB_CLOCK/(CAN_BIT_RATE * CAN_MAX_NO_OF_TQ)) */ + /* SYNC_SEG -> 1 tq */ + /* time segment 1 -> 16 tq (PROP_SEG+PHASE_SEG), CAN_MAX_NO_OF_TQ_TSEG1 = 15 */ + /* time segment 2 -> 8 tq (PHASE_SEG2) , CAN_MAX_NO_OF_TQ_TSEG2 = 7 */ + /* SJW -> 3 (fixed 0...3) , CAN_MAX_NO_OF_TQ_SJW = 2 */ + + /* ID Acceptance Control MSCAN_A/_B ------------------------------ */ + /* [07]:res. 0 : reserved */ + /* [06]:res. 0 : reserved */ + /* [05]:IDAM1 0 : ID acceptance control, Bit1 */ + /* [04]:IDAM0 1 : ID acceptance control, Bit0 */ + /* -> filter 16 bit mode */ + /* [03]:res. 0 : reserved */ + /* [02]:IDHIT2 0 : ID acceptance hit indication, Bit 2 */ + /* [01]:IDHIT1 0 : ID acceptance hit indication, Bit 1 */ + /* [00]:IDHIT0 0 : ID acceptance hit indication, Bit 0 */ + m->idac &= ~(IDAC_IDAM1); + m->idac |= (IDAC_IDAM0); + + /* initialize rx filter masks (16 bit), don't care including rtr */ + m->idmr0 = SET_IDMR0(0x7FF); + m->idmr1 = SET_IDMR1(0x7FF); + m->idmr2 = SET_IDMR2(0x7FF); + m->idmr3 = SET_IDMR3(0x7FF); + m->idmr4 = SET_IDMR4(0x7FF); + m->idmr5 = SET_IDMR5(0x7FF); + m->idmr6 = SET_IDMR6(0x7FF); + m->idmr7 = SET_IDMR7(0x7FF); + + /* Control Register 1 -------------------------------------------- */ + /* [07]:CANE 0->1 : MSCAN Module is enabled */ + /* [06]:CLKSRC 1 : Clock Source -> IPB_CLOCK (bsp.h) */ + /* [05]:LOOPB 0 : No Loopback */ + /* [04]:LISTEN 0 : Normal Operation */ + /* [03]:res 0 : reserved */ + /* [02]:WUPM 0 : No protect. from spurious WakeUp */ + /* [01]:SLPAK 0 : Sleep Mode Acknowledge (rd. only) */ + /* [00]:INITAK 0 : Init. Mode Acknowledge (rd. only) */ + /* enable MSCAN A_/_B */ + m->ctl1 |= (CTL1_CANE); + + /* Leave initialization mode */ + mscan_initialization_mode_leave( m, &context); + + return; + +} + +/* + * MPC5x00 MSCAN perform settings in normal mode + */ +void mpc5200_mscan_perform_normal_mode_settings(mscan + *m) +{ + + /* Control Register 0 -------------------------------------------- */ + /* [07]:RXFRM 0 : Recv. Frame, Flag Bit (rd.&clear only) */ + /* [06]:RXACT 0 : Recv. Active, Status Bit (rd. only) */ + /* [05]:CSWAI 0 : CAN Stops in Wait Mode */ + /* [04]:SYNCH 0 : Synchronized, Status Bit (rd. only) */ + /* [03]:TIME 1 : Generate Timestamps */ + /* [02]:WUPE 0 : WakeUp Disabled */ + /* [01]:SLPRQ 0 : No Sleep Mode Request */ + /* [00]:INITRQ 0 : No init. Mode Request */ + /* Disable wait mode, enable timestamps */ + m->ctl0 &= ~(CTL0_CSWAI); + m->ctl0 |= (CTL0_TIME); + + return; + +} + +rtems_status_code mpc5200_mscan_set_mode(rtems_device_minor_number minor, + uint8_t mode) +{ + struct mscan_channel_info *chan = NULL; + mscan *m = NULL; + + switch (minor) { + + case MSCAN_A: + case MSCAN_B: + chan = &chan_info[minor]; + m = chan->regs; + break; + + default: + return RTEMS_UNSATISFIED; + break; + } + + if (chan->mode == mode) + return RTEMS_SUCCESSFUL; + + switch (mode) { + + case MSCAN_INIT_NORMAL_MODE: + /* perform initialization which has to be done in init mode */ + mpc5200_mscan_perform_initialization_mode_settings(m); + break; + + case MSCAN_NORMAL_MODE: + if ((chan->mode) == MSCAN_INITIALIZED_MODE) { + /* perform initialization which has to be done in init mode */ + mpc5200_mscan_perform_initialization_mode_settings(m); + } + + if ((chan->mode) == MSCAN_SLEEP_MODE) { + + /* exit sleep mode */ + mscan_sleep_mode_leave(m); + } + /* enable ints. */ + mscan_interrupts_enable(m); + /* wait for bus sync. */ + mpc5200_mscan_wait_sync(m); + break; + + case MSCAN_SLEEP_MODE: + /* disable ints. */ + mscan_interrupts_disable(m); + /* knter sleep mode */ + mscan_sleep_mode_enter(m); + break; + + default: + return RTEMS_UNSATISFIED; + break; + + } + + /* set new channel mode */ + chan->mode = mode; + + return RTEMS_SUCCESSFUL; + +} + +/* + * initialization of channel info. + */ +rtems_status_code mscan_channel_initialize(rtems_device_major_number major, + rtems_device_minor_number minor) +{ + rtems_status_code status; + struct mscan_channel_info *chan = &chan_info[minor]; + + /* set registers according to MSCAN channel information */ + switch (minor) { + + case MSCAN_A: + chan->rx_qname = rtems_build_name('C', 'N', 'A', 'Q'); + chan->tx_rb_sname = rtems_build_name('C', 'N', 'A', 'S'); + + /* register RTEMS device names for MSCAN A */ + if ((status = + rtems_io_register_name(MSCAN_A_DEV_NAME, major, + MSCAN_A)) != RTEMS_SUCCESSFUL) + return status; + + /* register RTEMS device names for MSCAN 0 */ + if ((status = + rtems_io_register_name(MSCAN_0_DEV_NAME, major, + MSCAN_A)) != RTEMS_SUCCESSFUL) + return status; + + /* allocate the space for MSCAN A tx ring buffer */ + if (((chan->tx_ring_buf.buf_ptr) = + malloc(sizeof (struct can_message) * (NO_OF_MSCAN_TX_BUFF + 1))) != + NULL) { + chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr = + chan->tx_ring_buf.buf_ptr; + } else { + return RTEMS_UNSATISFIED; + } + break; + + case MSCAN_B: + chan->rx_qname = rtems_build_name('C', 'N', 'B', 'Q'); + chan->tx_rb_sname = rtems_build_name('C', 'N', 'B', 'S'); + + /* register RTEMS device names for MSCAN B */ + if ((status = + rtems_io_register_name(MSCAN_B_DEV_NAME, major, + MSCAN_B)) != RTEMS_SUCCESSFUL) + return status; + + /* register RTEMS device names for MSCAN 1 */ + if ((status = + rtems_io_register_name(MSCAN_1_DEV_NAME, major, + MSCAN_B)) != RTEMS_SUCCESSFUL) + return status; + + /* allocate the space for MSCAN B tx ring buffer */ + if (((chan->tx_ring_buf.buf_ptr) = + malloc(sizeof (struct can_message) * (NO_OF_MSCAN_TX_BUFF + 1))) != + NULL) { + chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr = + chan->tx_ring_buf.buf_ptr; + } else { + return RTEMS_UNSATISFIED; + } + break; + + default: + return RTEMS_UNSATISFIED; + break; + } + + /* create RTEMS rx message queue */ + status = + rtems_message_queue_create(chan->rx_qname, (uint32_t) NO_OF_MSCAN_RX_BUFF, + (uint32_t) + MSCAN_MESSAGE_SIZE(sizeof (struct can_message)), + (rtems_attribute) RTEMS_LOCAL | RTEMS_FIFO, + (rtems_id *) & (chan->rx_qid)); + + /* create counting RTEMS tx ring buffer semaphore */ + status = + rtems_semaphore_create(chan->tx_rb_sname, (uint32_t) (NO_OF_MSCAN_TX_BUFF), + RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY + | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, + (rtems_task_priority) 0, + (rtems_id *) & (chan->tx_rb_sid)); + + /* Set up interrupts */ + if (!BSP_install_rtems_irq_handler(&(mpc5200_mscan_irq_data[minor]))) + rtems_panic("Can't attach MPC5x00 MSCAN interrupt handler %d\n", minor); + + /* basic setup for channel info. struct. */ + chan->regs = (mscan *) &(mpc5200.mscan[minor]); + chan->int_rx_err = 0; + chan->id_extended = FALSE; + chan->mode = MSCAN_INITIALIZED_MODE; + chan->tx_buf_no = NO_OF_MSCAN_TX_BUFF; + + return status; + +} + +/* + * MPC5x00 MSCAN device initialization + */ +rtems_device_driver mscan_initialize(rtems_device_major_number major, + rtems_device_minor_number minor, void *arg) +{ + rtems_status_code status; + + /* Initialization requested via RTEMS */ + if ((status = mscan_channel_initialize(major, MSCAN_A)) != RTEMS_SUCCESSFUL) + bsp_fatal(MPC5200_FATAL_MSCAN_A_INIT); + + if ((status = mscan_channel_initialize(major, MSCAN_B)) != RTEMS_SUCCESSFUL) + bsp_fatal(MPC5200_FATAL_MSCAN_B_INIT); + + if ((status = + mpc5200_mscan_set_mode(MSCAN_A, + MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL) + bsp_fatal(MPC5200_FATAL_MSCAN_A_SET_MODE); + + if ((status = + mpc5200_mscan_set_mode(MSCAN_B, + MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL) + bsp_fatal(MPC5200_FATAL_MSCAN_B_SET_MODE); + + return status; + +} + +/* + * MPC5x00 MSCAN device open + */ +rtems_device_driver mscan_open(rtems_device_major_number major, + rtems_device_minor_number minor, void *arg) +{ + rtems_status_code status = RTEMS_SUCCESSFUL; + struct mscan_channel_info *chan = NULL; + + switch (minor) { + + case MSCAN_A: + case MSCAN_B: + chan = &chan_info[minor]; + break; + + default: + return RTEMS_UNSATISFIED; + break; + } + + /* check mode */ + if ((chan->mode) == MSCAN_SLEEP_MODE) { + + /* if not already set enter init mode */ + status = mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE); + } + + return status; + +} + +/* + * MPC5x00 MSCAN device close + */ +rtems_device_driver mscan_close(rtems_device_major_number major, + rtems_device_minor_number minor, void *arg) +{ + rtems_status_code status; + + switch (minor) { + + case MSCAN_A: + case MSCAN_B: + break; + + default: + return RTEMS_UNSATISFIED; + break; + } + + /* enter deep sleep mode */ + status = mpc5200_mscan_set_mode(minor, MSCAN_SLEEP_MODE); + + return status; + +} + +/* + * MPC5x00 MSCAN device read + */ +rtems_device_driver mscan_read(rtems_device_major_number major, + rtems_device_minor_number minor, void *arg) +{ + rtems_status_code status; + size_t message_size = 0; + rtems_libio_rw_args_t *parms = (rtems_libio_rw_args_t *) arg; + struct mscan_rx_parms *rx_parms = (struct mscan_rx_parms *) (parms->buffer); + struct can_message *rx_mess = (struct can_message *) (rx_parms->rx_mess); + struct mscan_channel_info *chan = NULL; + + switch (minor) { + + case MSCAN_A: + case MSCAN_B: + chan = &chan_info[minor]; + break; + + default: + return RTEMS_UNSATISFIED; + break; + } + + /* end init mode if it is first read */ + if ((chan->mode) == MSCAN_INIT_NORMAL_MODE) { + + /* if not already set enter init mode */ + mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE); + } + + if ((status = + rtems_message_queue_receive(chan->rx_qid, (void *) (rx_mess), + &message_size, + (uint32_t) (rx_parms->rx_flags), + (rtems_interval) (rx_parms->rx_timeout))) + != RTEMS_SUCCESSFUL) { + + parms->bytes_moved = 0; + + } else { + + parms->bytes_moved = sizeof (struct can_message); + + } + + return status; + +} + +/* + * MPC5x00 MSCAN device write + */ +rtems_device_driver mscan_write(rtems_device_major_number major, + rtems_device_minor_number minor, void *arg) +{ + rtems_status_code status; + rtems_libio_rw_args_t *parms = (rtems_libio_rw_args_t *) arg; + struct mscan_tx_parms *tx_parms = (struct mscan_tx_parms *) (parms->buffer); + struct can_message *tx_mess = (struct can_message *) (tx_parms->tx_mess); + struct mscan_channel_info *chan = NULL; + mscan *m = NULL; + + switch (minor) { + case MSCAN_A: + case MSCAN_B: + chan = &chan_info[minor]; + m = chan->regs; + break; + + default: + return RTEMS_UNSATISFIED; + break; + } + + /* end init mode if it is first write */ + if ((chan->mode) == MSCAN_INIT_NORMAL_MODE) { + + /* if not already set enter init mode */ + mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE); + } + + /* preset moved bytes */ + parms->bytes_moved = 0; + + /* obtain counting semaphore of tx ring buffer */ + if ((status = + rtems_semaphore_obtain((rtems_id) (chan->tx_rb_sid), RTEMS_NO_WAIT, + (rtems_interval) 0)) + == RTEMS_SUCCESSFUL) { + + /* append the TOUCAN tx_id to the mess. due to interrupt handling */ + tx_mess->toucan_tx_idx = tx_parms->tx_idx; + + /* fill the tx ring buffer with the message */ + fill_tx_buffer(chan, tx_mess); + + /* enable message buffer specific interrupt */ + m->tier |= (TIER_TXEI0 | TIER_TXEI1 | TIER_TXEI2); + + /* calculate moved bytes */ + parms->bytes_moved = (tx_mess->mess_len) & 0x000F; + + } + + return status; + +} + +/* + * MPC5x00 MSCAN device control + */ +rtems_device_driver mscan_control(rtems_device_major_number major, + rtems_device_minor_number minor, void *arg) +{ + rtems_status_code status; + uint16_t tx_id; + rtems_libio_ioctl_args_t *parms = (rtems_libio_ioctl_args_t *) arg; + struct mscan_ctrl_parms *ctrl_parms = + (struct mscan_ctrl_parms *) (parms->buffer); + struct mscan_channel_info *chan = NULL; + mscan_handle *mscan_hdl = NULL; + mscan *m = NULL; + mscan_context context; + uint8_t tx_buf_count = 0; + + switch (minor) { + + case MSCAN_A: + case MSCAN_B: + chan = &chan_info[minor]; + mscan_hdl = mpc5200_mscan_irq_data[minor].handle; + m = chan->regs; + break; + + default: + return RTEMS_UNSATISFIED; + break; + } + + switch (parms->command) { + + /* TOUCAN callback initialization for MSCAN */ + case TOUCAN_MSCAN_INIT: + mscan_hdl->toucan_callback = ctrl_parms->toucan_cb_fnc; + break; + + /* set rx buffer ID */ + case MSCAN_SET_RX_ID: + + /* enter init mode */ + mscan_initialization_mode_enter(m, &context); + + switch (ctrl_parms->ctrl_reg_no) { + + case RX_BUFFER_0: + m->idar0 = SET_IDR0(ctrl_parms->ctrl_id); + m->idar1 = SET_IDR1(ctrl_parms->ctrl_id); + break; + + case RX_BUFFER_1: + m->idar2 = SET_IDR2(ctrl_parms->ctrl_id); + m->idar3 = SET_IDR3(ctrl_parms->ctrl_id); + break; + + case RX_BUFFER_2: + m->idar4 = SET_IDR4(ctrl_parms->ctrl_id); + m->idar5 = SET_IDR5(ctrl_parms->ctrl_id); + break; + + case RX_BUFFER_3: + m->idar6 = SET_IDR6(ctrl_parms->ctrl_id); + m->idar7 = SET_IDR7(ctrl_parms->ctrl_id); + break; + + default: + break; + + } + + /* exit init mode and perform further initialization which is required in the normal mode */ + mscan_initialization_mode_leave(m, &context); + + /* enable ints. */ + mscan_interrupts_enable(m); + + /* wait for bus sync. */ + mpc5200_mscan_wait_sync(m); + + return RTEMS_SUCCESSFUL; + break; + + /* get rx buffer ID */ + case MSCAN_GET_RX_ID: + + switch (ctrl_parms->ctrl_reg_no) { + + case RX_BUFFER_0: + ctrl_parms->ctrl_id = GET_IDR0(m->idar0) | GET_IDR1(m->idar1); + break; + + case RX_BUFFER_1: + ctrl_parms->ctrl_id = GET_IDR2(m->idar2) | GET_IDR3(m->idar3); + break; + + case RX_BUFFER_2: + ctrl_parms->ctrl_id = GET_IDR4(m->idar4) | GET_IDR5(m->idar5); + break; + + case RX_BUFFER_3: + ctrl_parms->ctrl_id = GET_IDR6(m->idar6) | GET_IDR7(m->idar7); + break; + + default: + break; + + } + + break; + + /* set rx buffer ID mask */ + case MSCAN_SET_RX_ID_MASK: + + /* enter init mode */ + mscan_initialization_mode_enter(m, &context); + + switch (ctrl_parms->ctrl_reg_no) { + + case RX_BUFFER_0: + m->idmr0 = SET_IDMR0(ctrl_parms->ctrl_id_mask); + m->idmr1 = SET_IDMR1(ctrl_parms->ctrl_id_mask); + break; + + case RX_BUFFER_1: + m->idmr2 = SET_IDMR2(ctrl_parms->ctrl_id_mask); + m->idmr3 = SET_IDMR3(ctrl_parms->ctrl_id_mask); + break; + + case RX_BUFFER_2: + m->idmr4 = SET_IDMR4(ctrl_parms->ctrl_id_mask); + m->idmr5 = SET_IDMR5(ctrl_parms->ctrl_id_mask); + break; + + case RX_BUFFER_3: + m->idmr6 = SET_IDMR6(ctrl_parms->ctrl_id_mask); + m->idmr7 = SET_IDMR7(ctrl_parms->ctrl_id_mask); + break; + + default: + break; + + } + + /* exit init mode and perform further initialization which is required in the normal mode */ + mscan_initialization_mode_leave(m, &context); + + /* enable ints. */ + mscan_interrupts_enable(m); + + /* wait for bus sync. */ + mpc5200_mscan_wait_sync(m); + + break; + + /* get rx buffer ID mask */ + case MSCAN_GET_RX_ID_MASK: + + switch (ctrl_parms->ctrl_reg_no) { + + case RX_BUFFER_0: + ctrl_parms->ctrl_id_mask = + (GET_IDMR0(m->idmr0) | GET_IDMR1(m->idmr1)); + break; + + case RX_BUFFER_1: + ctrl_parms->ctrl_id_mask = + (GET_IDMR2(m->idmr2) | GET_IDMR3(m->idmr3)); + break; + + case RX_BUFFER_2: + ctrl_parms->ctrl_id_mask = + (GET_IDMR4(m->idmr4) | GET_IDMR5(m->idmr5)); + break; + + case RX_BUFFER_3: + ctrl_parms->ctrl_id_mask = + (GET_IDMR6(m->idmr6) | GET_IDMR7(m->idmr7)); + break; + + default: + break; + + } + + /* set tx buffer ID */ + case MSCAN_SET_TX_ID: + + /* check for availability of tx buffer */ + if (!((m->tflg) & (uint8_t) (ctrl_parms->ctrl_reg_no))) { + + /* do abort tx buf. request */ + m->tarq = (uint8_t) (ctrl_parms->ctrl_reg_no); + + /* wait for abort tx buf. ack. */ + while ((m->taak) & (uint8_t) (ctrl_parms->ctrl_reg_no)); + + } + + /* select tx buf. */ + m->bsel = (uint8_t) (ctrl_parms->ctrl_reg_no); + + /* set the tx id of selected buf. */ + tx_id = ctrl_parms->ctrl_id; + m->txidr0 = SET_IDR0(tx_id); + m->txidr1 = SET_IDR1(tx_id); + m->txidr2 = 0; + m->txidr3 = 0; + + break; + + /* get tx buffer ID */ + case MSCAN_GET_TX_ID: + + /* select tx buf. */ + m->bsel = (uint8_t) (ctrl_parms->ctrl_reg_no); + + /* get tx id. of selected buf. */ + ctrl_parms->ctrl_id = GET_IDR0(m->txidr0) | GET_IDR1(m->txidr1); + + break; + + /* set can bitrate */ + case MSCAN_SET_BAUDRATE: + /* perform all can bit time settings */ + if (!mscan_set_bit_rate(m, ctrl_parms->ctrl_can_bitrate)) { + return RTEMS_UNSATISFIED; + } + + /* enable ints. */ + mscan_interrupts_enable(m); + + /* wait for bus sync. */ + mpc5200_mscan_wait_sync(m); + + break; + + case SET_TX_BUF_NO: + + /* check for different settings of tx ring buffer */ + if ((tx_buf_count = + chan->tx_buf_no) != (uint8_t) (ctrl_parms->ctrl_tx_buf_no)) { + + /* preset the channel specific no of messages in the tx ring buffer */ + tx_buf_count = chan->tx_buf_no; + + /* try to obtain all of the tx ring buffers */ + while (tx_buf_count > 0) { + + /* obtain semaphore of all tx ring buffers */ + if ((status = + rtems_semaphore_obtain((rtems_id) (chan->tx_rb_sid), RTEMS_WAIT, + (rtems_interval) 10)) + == RTEMS_SUCCESSFUL) { + + tx_buf_count--; + + } + + } + + /* free the former tx ring buffer */ + free((void *) chan->tx_ring_buf.buf_ptr); + + /* allocate the tx ring buffer with new size */ + if (((chan->tx_ring_buf.buf_ptr) = + malloc(sizeof (struct can_message) * + ((uint8_t) (ctrl_parms->ctrl_tx_buf_no) + 1))) != NULL) { + chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr = + chan->tx_ring_buf.buf_ptr; + } else { + return RTEMS_UNSATISFIED; + } + + /* set the new amount of tx buffers */ + chan->tx_buf_no = (uint8_t) (ctrl_parms->ctrl_tx_buf_no); + + /* release the semaphore of all tx ring buffers */ + while (tx_buf_count < chan->tx_buf_no) { + + /* obtain semaphore of all tx ring buffers */ + rtems_semaphore_release((rtems_id) (chan->tx_rb_sid)); + + tx_buf_count++; + + } + + } else { + + return RTEMS_SUCCESSFUL; + + } + break; + + default: + break; + + } + + return RTEMS_SUCCESSFUL; + +} diff --git a/bsps/powerpc/gen5200/mscan/mscan_int.h b/bsps/powerpc/gen5200/mscan/mscan_int.h new file mode 100644 index 0000000000..7bac194f86 --- /dev/null +++ b/bsps/powerpc/gen5200/mscan/mscan_int.h @@ -0,0 +1,185 @@ +/*===============================================================*\ +| Project: RTEMS generic MPC5200 BSP | ++-----------------------------------------------------------------+ +| Partially based on the code references which are named below. | +| Adaptions, modifications, enhancements and any recent parts of | +| the code are: | +| Copyright (c) 2005 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.org/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file has to be included by the m driver | +\*===============================================================*/ +#ifndef __MSCAN_INT_H__ +#define __MSCAN_INT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <bsp/mscan-base.h> + +#include <bsp/mscan.h> + +#define MSCAN_RX_BUFF_NUM 4 +#define MSCAN_TX_BUFF_NUM 3 + +#define MSCAN_NON_INITIALIZED_MODE 0 +#define MSCAN_INITIALIZED_MODE 1 +#define MSCAN_INIT_NORMAL_MODE 2 +#define MSCAN_NORMAL_MODE 4 +#define MSCAN_SLEEP_MODE 8 + +#define MSCAN_RX_BUFF_NOACTIVE (0 << 4) +#define MSCAN_RX_BUFF_EMPTY (1 << 6) +#define MSCAN_RX_BUFF_FULL (1 << 5) +#define MSCAN_RX_BUFF_OVERRUN ((MSCAN_RX_BUFF_EMPTY) | (MSCAN_RX_BUFF_FULL)) +#define MSCAN_RX_BUFF_BUSY (1 << 4) + +#define MSCAN_MBUFF_MASK 0x07 + +#define MSCAN_TX_BUFF0 (1 << 0) +#define MSCAN_TX_BUFF1 (1 << 1) +#define MSCAN_TX_BUFF2 (1 << 2) + +#define MSCAN_IDE (1 << 0) +#define MSCAN_RTR (1 << 1) +#define MSCAN_READ_RXBUFF_0 (1 << 2) +#define MSCAN_READ_RXBUFF_1 (1 << 2) +#define MSCAN_READ_RXBUFF_2 (1 << 2) +#define MSCAN_READ_RXBUFF_3 (1 << 2) + +#define MSCAN_STATE_OK 0 +#define MSCAN_STATE_ERR 1 +#define MSCAN_STATE_WRN 2 +#define MSCAN_STATE_BUSOFF 3 + +#define TX_MBUF_SEL(buf_no) (1 << (buf_no)) +#define TX_DATA_LEN(len) ((len) & 0x0F) + +#define TX_MBUF_EMPTY(val) (1 << (val)) + +#define ID_RTR (1 << 4) + +#define SET_IDR0(u16) ((uint8_t)((u16) >> 3)) +#define SET_IDR1(u16) (MSCAN_MESS_ID_HAS_RTR(u16) ? ((uint8_t)(((u16) & 0x0007) << 5))|((uint8_t)(ID_RTR)) : ((uint8_t)(((u16) & 0x0007) << 5))) + +#define SET_IDR2(u16) SET_IDR0(u16) +#define SET_IDR3(u16) SET_IDR1(u16) + +#define SET_IDR4(u16) SET_IDR0(u16) +#define SET_IDR5(u16) SET_IDR1(u16) + +#define SET_IDR6(u16) SET_IDR0(u16) +#define SET_IDR7(u16) SET_IDR1(u16) + +#define GET_IDR0(u16) ((uint16_t) ((u16) << 3)) +#define GET_IDR1(u16) ((((u16)&(ID_RTR))==(ID_RTR)) ? (uint16_t) ((((u16) >> 5)&0x0007)|MSCAN_MESS_ID_RTR) : (uint16_t)(((u16) >> 5)&0x0007)) + +#define GET_IDR2(u16) GET_IDR0(u16) +#define GET_IDR3(u16) GET_IDR1(u16) + +#define GET_IDR4(u16) GET_IDR0(u16) +#define GET_IDR5(u16) GET_IDR1(u16) + +#define GET_IDR6(u16) GET_IDR0(u16) +#define GET_IDR7(u16) GET_IDR1(u16) + +#define SET_IDMR0(u16) ((uint8_t)((u16) >> 3)) +#define SET_IDMR1(u16) (MSCAN_MESS_ID_HAS_RTR(u16) ? ((uint8_t) (((((u16) & 0x0007) << 5)|((uint8_t)(ID_RTR)))|0x0007)) : ((uint8_t)((((u16) & 0x0007) << 5))|0x0007)) + +#define SET_IDMR2(u16) SET_IDMR0(u16) +#define SET_IDMR3(u16) SET_IDMR1(u16) + +#define SET_IDMR4(u16) SET_IDMR0(u16) +#define SET_IDMR5(u16) SET_IDMR1(u16) + +#define SET_IDMR6(u16) SET_IDMR0(u16) +#define SET_IDMR7(u16) SET_IDMR1(u16) + +#define GET_IDMR0(u16) ((uint16_t)((u16) << 3)) +#define GET_IDMR1(u16) ((((u16)&(ID_RTR))==(ID_RTR)) ? (uint16_t) ((((u16) >> 5)&0x0007)|MSCAN_MESS_ID_RTR) : (uint16_t)(((u16) >> 5)&0x0007)) + +#define GET_IDMR2(u16) GET_IDMR0(u16) +#define GET_IDMR3(u16) GET_IDMR1(u16) + +#define GET_IDMR4(u16) GET_IDMR0(u16) +#define GET_IDMR5(u16) GET_IDMR1(u16) + +#define GET_IDMR6(u16) GET_IDMR0(u16) +#define GET_IDMR7(u16) GET_IDMR1(u16) + +#define NO_OF_MSCAN_RX_BUFF 20 +#define MSCAN_MESSAGE_SIZE(size) (((size)%CPU_ALIGNMENT) ? (((size) + CPU_ALIGNMENT)-((size) + CPU_ALIGNMENT)%CPU_ALIGNMENT) : (size)) + +#define TX_BUFFER_0 0 +#define TX_BUFFER_1 1 +#define TX_BUFFER_2 2 + +#define RX_BUFFER_0 0 +#define RX_BUFFER_1 1 +#define RX_BUFFER_2 2 +#define RX_BUFFER_3 3 + +#define NO_OF_MSCAN_TX_BUFF 20 +#define RING_BUFFER_EMPTY(rbuff) ((((rbuff)->head) == ((rbuff)->tail)) ? TRUE : FALSE) +#define RING_BUFFER_FULL(rbuff) ((((rbuff)->head) == ((rbuff)->tail)) ? TRUE : FALSE) + + +typedef struct _mscan_handle + { + uint8_t mscan_channel; + void (*toucan_callback)(int16_t); + } mscan_handle; + +struct ring_buf + { + struct can_message * volatile buf_ptr; + struct can_message * volatile head_ptr; + struct can_message * volatile tail_ptr; + }; + +struct mpc5200_rx_cntrl + { + struct can_message can_rx_message[MSCAN_RX_BUFF_NUM]; + }; + +struct mscan_channel_info + { + mscan *regs; + uint32_t int_rx_err; + rtems_id rx_qid; + uint32_t rx_qname; + rtems_id tx_rb_sid; + uint32_t tx_rb_sname; + uint8_t id_extended; + uint8_t mode; + uint8_t tx_buf_no; + struct ring_buf tx_ring_buf; + }; + +extern void CanInterrupt_A(int16_t); +extern void CanInterrupt_B(int16_t); + +/*MSCAN driver internal functions */ +void mscan_hardware_initialize(rtems_device_major_number, uint32_t, void *); +void mpc5200_mscan_wait_sync(mscan *); +void mpc5200_mscan_perform_init_mode_settings(mscan *); +void mpc5200_mscan_perform_normal_mode_settings(mscan *); +rtems_status_code mpc5200_mscan_set_mode(rtems_device_minor_number, uint8_t); +rtems_status_code mscan_channel_initialize(rtems_device_major_number, rtems_device_minor_number); + +#ifdef __cplusplus +} +#endif + +#endif /* __MSCAN_H__ */ diff --git a/bsps/powerpc/gen5200/nvram/m93cxx.h b/bsps/powerpc/gen5200/nvram/m93cxx.h new file mode 100644 index 0000000000..a5643dae45 --- /dev/null +++ b/bsps/powerpc/gen5200/nvram/m93cxx.h @@ -0,0 +1,163 @@ +/*===============================================================*\ +| Project: RTEMS generic MPC5200 BSP | ++-----------------------------------------------------------------+ +| Partially based on the code references which are named below. | +| Adaptions, modifications, enhancements and any recent parts of | +| the code are: | +| Copyright (c) 2005 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.org/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains definitions for the M93Cxx EEPROM devices | +\*===============================================================*/ +/***********************************************************************/ +/* */ +/* Module: m93cxx.h */ +/* Date: 07/17/2003 */ +/* Purpose: RTEMS M93C64-based header file */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* Description: M93C46 is a serial microwire EEPROM which contains */ +/* 1Kbit (128 bytes/64 words) of non-volatile memory. */ +/* The device can be configured for byte- or word- */ +/* access. The driver provides a file-like interface */ +/* to this memory. */ +/* */ +/* MPC5x00 PIN settings: */ +/* */ +/* PSC3_6 (output) -> MC93C46 serial data in (D) */ +/* PSC3_7 (input) -> MC93C46 serial data out (Q) */ +/* PSC3_8 (output) -> MC93C46 chip select input (S) */ +/* PSC3_9 (output) -> MC93C46 serial clock (C) */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* Code */ +/* References: none */ +/* Module: */ +/* Project: */ +/* Version */ +/* Date: */ +/* Author: */ +/* Copyright: */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* Partially based on the code references which are named above. */ +/* Adaptions, modifications, enhancements and any recent parts of */ +/* the code are under the right of */ +/* */ +/* IPR Engineering, Dachauer Straße 38, D-80335 München */ +/* Copyright(C) 2003 */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* IPR Engineering makes no representation or warranties with */ +/* respect to the performance of this computer program, and */ +/* specifically disclaims any responsibility for any damages, */ +/* special or consequential, connected with the use of this program. */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* Version history: 1.0 */ +/* */ +/***********************************************************************/ + +#ifndef __M93CXX_H__ +#define __M93CXX_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +static void m93cxx_enable_write(void); +static void m93cxx_disable_write(void); +static void m93cxx_write_byte(uint32_t, uint8_t); +static uint8_t m93cxx_read_byte(uint32_t); +void wait_usec(unsigned long); + +#define M93CXX_MODE_WORD +/*#define M93C46_MODE_BYTE*/ +#define M93C46 +#define M93C46_NVRAM_SIZE 128 + +#define GPIO_PSC3_6 (1 << 12) +#define GPIO_PSC3_7 (1 << 13) +#define GPIO_PSC3_8 (1 << 26) +#define GPIO_PSC3_9 (1 << 26) + +#define START_BIT 0x1 +#define EWDS_OPCODE 0x0 +#define WRAL_OPCODE 0x1 +#define ERAL_OPCODE 0x2 +#define EWEN_OPCODE 0x3 +#define WRITE_OPCODE 0x4 +#define READ_OPCODE 0x8 +#define ERASE_OPCODE 0xC + +#define WAIT(i) wait_usec(i) + +#define ENABLE_CHIP_SELECT mpc5200.gpiosido |= GPIO_PSC3_8 +#define DISABLE_CHIP_SELECT mpc5200.gpiosido &= ~GPIO_PSC3_8 +#define SET_DATA_BIT_HIGH mpc5200.gpiosdo |= GPIO_PSC3_6 +#define SET_DATA_BIT_LOW mpc5200.gpiosdo &= ~GPIO_PSC3_6 + +#ifdef M93CXX_MODE_BYTE +#define GET_DATA_BYTE_SHIFT(val) ((val) |= ((mpc5200.gpiosdi & GPIO_PSC3_7) >> 13)); \ + ((val) <<= 1) +#define SET_DATA_BYTE_SHIFT(val) (((val) & 0x80) ? (mpc5200.gpiosdo |= GPIO_PSC3_6) : (mpc5200.gpiosdo &= ~GPIO_PSC3_6)); \ + ((val) <<= 1) +#else +#define GET_DATA_WORD_SHIFT(val) ((val) |= ((mpc5200.gpiosdi & GPIO_PSC3_7) >> 13)); \ + ((val) <<= 1) +#define SET_DATA_WORD_SHIFT(val) (((val) & 0x8000) ? (mpc5200.gpiosdo |= GPIO_PSC3_6) : (mpc5200.gpiosdo &= ~GPIO_PSC3_6)); \ + ((val) <<= 1) +#endif + +#define MASK_HEAD_SHIFT(head) ((((head) & 0x80000000) >> 31) ? (mpc5200.gpiosdo |= GPIO_PSC3_6) : (mpc5200.gpiosdo &= ~GPIO_PSC3_6)); \ + ((head) <<= 1) +#define DO_CLOCK_CYCLE mpc5200.gpiowdo |= GPIO_PSC3_9; \ + WAIT(1000); \ + mpc5200.gpiowdo &= ~GPIO_PSC3_9 +#define CHECK_WRITE_BUSY while(!(mpc5200.gpiosdi & GPIO_PSC3_7)) + + +#ifdef M93CXX_MODE_BYTE +#ifdef M93C46 +#define M93C46_EWDS ((START_BIT << 31) | (EWDS_OPCODE << 27)) +#define M93C46_WRAL ((START_BIT << 31) | (WRAL_OPCODE << 27)) +#define M93C46_ERAL ((START_BIT << 31) | (ERAL_OPCODE << 27)) +#define M93C46_EWEN ((START_BIT << 31) | (EWEN_OPCODE << 27)) +#define M93C46_READ(addr) ((START_BIT << 31) | (READ_OPCODE << 27) | ((addr) << 22)) +#define M93C46_WRITE(addr) ((START_BIT << 31) | (WRITE_OPCODE << 27) | ((addr) << 22)) +#define M93C46_ERASE(addr) ((START_BIT << 31) | (ERASE_OPCODE << 27) | ((addr) << 22)) +#define M93C46_CLOCK_CYCLES 10 +#endif +#else +#ifdef M93C46 +#define M93C46_EWDS ((START_BIT << 31) | (EWDS_OPCODE << 27)) +#define M93C46_WRAL ((START_BIT << 31) | (WRAL_OPCODE << 27)) +#define M93C46_ERAL ((START_BIT << 31) | (ERAL_OPCODE << 27)) +#define M93C46_EWEN ((START_BIT << 31) | (EWEN_OPCODE << 27)) +#define M93C46_READ(addr) ((START_BIT << 31) | (READ_OPCODE << 27) | ((addr) << 23)) +#define M93C46_WRITE(addr) ((START_BIT << 31) | (WRITE_OPCODE << 27) | ((addr) << 23)) +#define M93C46_ERASE(addr) ((START_BIT << 31) | (ERASE_OPCODE << 27) | ((addr) << 23)) +#define M93C46_CLOCK_CYCLES 9 +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __M93CXX_H__ */ diff --git a/bsps/powerpc/gen5200/nvram/nvram.c b/bsps/powerpc/gen5200/nvram/nvram.c new file mode 100644 index 0000000000..99192ac3c4 --- /dev/null +++ b/bsps/powerpc/gen5200/nvram/nvram.c @@ -0,0 +1,603 @@ +/*===============================================================*\ +| Project: RTEMS generic MPC5200 BSP | ++-----------------------------------------------------------------+ +| Partially based on the code references which are named below. | +| Adaptions, modifications, enhancements and any recent parts of | +| the code are: | +| Copyright (c) 2005 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.org/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the nvram functions | +\*===============================================================*/ +/***********************************************************************/ +/* */ +/* Module: nvram.c */ +/* Date: 07/17/2003 */ +/* Purpose: RTEMS M93C64-based NV memory device driver */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* Description: M93C46 is a serial microwire EEPROM which contains */ +/* 1Kbit (128 bytes/64 words) of non-volatile memory. */ +/* The device can be coigured for byte- or word- */ +/* access. The driver provides a file-like interface */ +/* to this memory. */ +/* */ +/* MPC5x00 PIN settings: */ +/* */ +/* PSC3_6 (output) -> MC93C46 serial data in (D) */ +/* PSC3_7 (input) -> MC93C46 serial data out (Q) */ +/* PSC3_8 (output) -> MC93C46 chip select input (S) */ +/* PSC3_9 (output) -> MC93C46 serial clock (C) */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* Code */ +/* References: DS1307-based Non-Volatile memory device driver */ +/* Module: nvram.c */ +/* Project: RTEMS 4.6.0pre1 / MCF5206Elite BSP */ +/* Version 1.2 */ +/* Date: 11/04/2002 */ +/* Author: Victor V. Vengerov */ +/* Copyright: Copyright (C) 2000 OKTET Ltd.,St.-Petersburg,Russia */ +/* */ +/* The license and distribution terms for this file may be */ +/* found in the file LICENSE in this distribution or at */ +/* http://www.rtems.org/license/LICENSE. */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* Partially based on the code references which are named above. */ +/* Adaptions, modifications, enhancements and any recent parts of */ +/* the code are under the right of */ +/* */ +/* IPR Engineering, Dachauer Straße 38, D-80335 München */ +/* Copyright(C) 2003 */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* IPR Engineering makes no representation or warranties with */ +/* respect to the performance of this computer program, and */ +/* specifically disclaims any responsibility for any damages, */ +/* special or consequential, connected with the use of this program. */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* Version history: 1.0 */ +/* */ +/***********************************************************************/ + +#include <rtems.h> +#include <rtems/libio.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <bsp.h> +#include <bsp/mpc5200.h> +#include <bsp/nvram.h> +#include "m93cxx.h" + +/* + * Simple usec delay function using lower half of HARPO Time Base Register + */ +void wait_usec(unsigned long usec) + { + unsigned long start_count = 0, update_count; + unsigned long delay_count; + + if(TMBASE_CLOCK < 1000000) + delay_count = (TMBASE_CLOCK * usec )/1000000; + else + delay_count = (TMBASE_CLOCK / 1000000) * usec; + + TBL_READ(start_count); + + update_count = start_count; + + while((update_count - start_count) < delay_count) + TBL_READ(update_count); + + } + + +/* + * Enable M93Cxx chip-write + */ +static void m93cxx_enable_write() + { + uint32_t header, i; + + ENABLE_CHIP_SELECT; + + WAIT(1); + + header = M93C46_EWEN; + + for(i = 0; i < M93C46_CLOCK_CYCLES; i++) + { + + MASK_HEAD_SHIFT(header); + + WAIT(1); + + DO_CLOCK_CYCLE; + + WAIT(1); + + } + + DISABLE_CHIP_SELECT; + + return; + + } + + +/* + * Disable M93Cxx chip-write + */ +static void m93cxx_disable_write() + { + uint32_t header, i; + + ENABLE_CHIP_SELECT; + + WAIT(1); + + header = M93C46_EWDS; + + for(i = 0; i < M93C46_CLOCK_CYCLES; i++) + { + + MASK_HEAD_SHIFT(header); + + WAIT(1); + + DO_CLOCK_CYCLE; + + WAIT(1); + + } + + DISABLE_CHIP_SELECT; + + return; + + } + + +/* + * Read one byte from specified offset + */ +static uint8_t m93cxx_read_byte(uint32_t offset) + { + uint8_t byte2read; + uint32_t header, tmp_offset, i; +#ifdef M93CXX_MODE_BYTE + uint8_t byte_recv = 0; +#else + uint32_t word_recv = 0; +#endif + + ENABLE_CHIP_SELECT; + + WAIT(1); + +#ifdef M93CXX_MODE_BYTE + + header = M93C46_READ(offset); + + for(i = 0; i < M93C46_CLOCK_CYCLES; i++) + { + + MASK_HEAD_SHIFT(header); + + WAIT(1); + + DO_CLOCK_CYCLE; + + WAIT(1); + + } + + for(i = 0; i < 8; i++) + { + + WAIT(1); + + DO_CLOCK_CYCLE; + + WAIT(1); + + GET_DATA_BYTE_SHIFT(byte_recv); + + } + + byte_recv >>= 1; + + byte2read = byte_recv; + +#else + tmp_offset = offset/2; + + header = M93C46_READ(tmp_offset); + + for(i = 0; i < M93C46_CLOCK_CYCLES; i++) + { + + MASK_HEAD_SHIFT(header); + + WAIT(1); + + DO_CLOCK_CYCLE; + + WAIT(1); + + } + + for(i = 0; i < 16; i++) + { + + DO_CLOCK_CYCLE; + + WAIT(1); + + GET_DATA_WORD_SHIFT(word_recv); + + WAIT(1); + + } + + word_recv >>= 1; + + if(offset%2) + { + + byte2read = (uint8_t)((word_recv & 0xFF00) >> 8); + +#ifdef NVRAM_DEBUG + printf("\nbyte_read(o) = %x", byte2read); +#endif + + } + else + { + + byte2read = (uint8_t)(word_recv & 0x00FF); + +#ifdef NVRAM_DEBUG + printf("\nbyte_read(e) = %x", byte2read); +#endif + } + +#endif + + WAIT(1); + + DISABLE_CHIP_SELECT; + + return byte2read; + + } + + +/* + * Write one byte to specified offset + */ +void m93cxx_write_byte(uint32_t offset, uint8_t byte2write) + { + uint32_t header, tmp_offset, i; +#ifdef M93CXX_MODE_BYTE + uint8_t byte_send; +#else + uint16_t word_send; +#endif + + ENABLE_CHIP_SELECT; + + WAIT(1); + +#ifdef M93CXX_MODE_BYTE + header = M93C46_WRITE(offset); + + for(i = 0; i < M93C46_CLOCK_CYCLES; i++) + { + + MASK_HEAD_SHIFT(header); + + WAIT(1); + + DO_CLOCK_CYCLE; + + WAIT(1); + + } + + byte_send = byte2write; + + for(i = 0; i < 8; i++) + { + + SET_DATA_BYTE_SHIFT(byte_send); + + WAIT(1); + + DO_CLOCK_CYCLE; + + WAIT(1); + + } + + } +#else + + if(offset%2) + { + + word_send = (uint16_t)m93cxx_read_byte(offset-1); + word_send |= (uint16_t)(m93cxx_read_byte(offset) << 8); + + } + else + { + + word_send = (uint16_t)m93cxx_read_byte(offset); + word_send |= (uint16_t)(m93cxx_read_byte(offset + 1) << 8); + + } + + tmp_offset = offset/2; + + WAIT(1); + + ENABLE_CHIP_SELECT; + + WAIT(1); + + header = M93C46_WRITE(tmp_offset); + + for(i = 0; i < M93C46_CLOCK_CYCLES; i++) + { + + MASK_HEAD_SHIFT(header); + + WAIT(1); + + DO_CLOCK_CYCLE; + + WAIT(1); + + } + + if(offset%2) + { + + word_send = (word_send & 0x00FF) | ((uint16_t)(byte2write << 8)); + +#ifdef NVRAM_DEBUG + printf("\nword_send = %x", word_send); +#endif + + } + else + { + + word_send = (word_send & 0xFF00) | (uint16_t)byte2write; +#ifdef NVRAM_DEBUG + printf("\nword_send = %x", word_send); +#endif + + } + + for(i = 0; i < 16; i++) + { + + SET_DATA_WORD_SHIFT(word_send); + + WAIT(1); + + DO_CLOCK_CYCLE; + + WAIT(1); + + } + + DISABLE_CHIP_SELECT; + + WAIT(1); + + ENABLE_CHIP_SELECT; + + WAIT(1); + + CHECK_WRITE_BUSY; + +#endif + + WAIT(1); + + DISABLE_CHIP_SELECT; + + return; + + } + + +/* nvram_driver_initialize -- + * Non-volatile memory device driver initialization. + */ +rtems_device_driver nvram_driver_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) + { + rtems_status_code sc; + + /* enable PSC3_6/PSC3_7 as general purpose pins */ + mpc5200.gpiosen |= (GPIO_PSC3_6 | GPIO_PSC3_7); + + /* PSC3_6/PSC3_7 has normal CMOS output */ + mpc5200.gpiosod &= ~(GPIO_PSC3_6 | GPIO_PSC3_7); + + /* switch PSC3_6 (MC93C46 serial data in (D)) to low */ + mpc5200.gpiosdo &= ~GPIO_PSC3_6; + + /* PSC3_6 is an output (MC93C46 serial data in (D)) and PSC3_7 (MC93C46 serial data out (Q)) is an input pin */ + mpc5200.gpiosdd |= GPIO_PSC3_6; + mpc5200.gpiosdd &= ~GPIO_PSC3_7; + + /* disable PSC3_8 interrupt capabilities */ + mpc5200.gpiosiie &= ~GPIO_PSC3_8; + + /* enable PSC3_8 as general purpose pin */ + mpc5200.gpiosie |= GPIO_PSC3_8; + + /* PSC3_8 has normal CMOS output */ + mpc5200.gpiosiod &= ~GPIO_PSC3_8; + + /* switch PSC3_8 (MC93C46 chip select input (S)) to low (high activ) */ + mpc5200.gpiosido &= ~GPIO_PSC3_8; + + /* PSC3_8 is an output (MC93C46 chip select input (S)) pin */ + mpc5200.gpiosidd |= GPIO_PSC3_8; + + /* disable PSC3_9 interrupt capabilities */ + mpc5200.gpiowue &= ~GPIO_PSC3_9; + + /* enable PSC3_9 as general purpose pins */ + mpc5200.gpiowe |= GPIO_PSC3_9; + + /* PSC3_9 has normal CMOS output */ + mpc5200.gpiowod &= ~GPIO_PSC3_9; + + /* switch PSC3_9 (MC93C46 serial clock (C)) to low */ + mpc5200.gpiowdo &= ~GPIO_PSC3_9; + + /* PSC3_9 is an output (MC93C46 serial clock (C)) pin */ + mpc5200.gpiowdd |= GPIO_PSC3_9; + + sc = rtems_io_register_name("/dev/nvram", major, 0); + + if(sc != RTEMS_SUCCESSFUL) + { + + errno = EIO; + /*errno = ENODEV;*/ + return RTEMS_UNSATISFIED; + + } + else + return RTEMS_SUCCESSFUL; + + } + + +/* nvram_driver_open -- + * Non-volatile memory device driver open primitive. + */ +rtems_device_driver nvram_driver_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) + { + + return RTEMS_SUCCESSFUL; + + } + + +/* nvram_driver_close -- + * Non-volatile memory device driver close primitive. + */ +rtems_device_driver nvram_driver_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) + { + + return RTEMS_SUCCESSFUL; + + } + + +/* nvram_driver_read -- + * Non-volatile memory device driver read primitive. + */ +rtems_device_driver nvram_driver_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) + { + rtems_libio_rw_args_t *args = arg; + uint32_t count, i; + +#ifdef NVRAM_DEBUG + printf("\nread count = %2x", (int)(args->count)); + printf("\nread offset = %2x", (int)(args->offset)); +#endif + + if((args->offset >= M93C46_NVRAM_SIZE) || (args->offset + args->count > M93C46_NVRAM_SIZE)) + { + + args->bytes_moved = 0; + errno = EINVAL; + return RTEMS_UNSATISFIED; + + } + else + count = args->count; + + for(i = 0; i < count; i++) + { + + (args->buffer)[i] = m93cxx_read_byte((args->offset) + i); + (args->bytes_moved) += 1; + + } + + return RTEMS_SUCCESSFUL; + + } + + +/* nvram_driver_write -- + * Non-volatile memory device driver write primitive. + */ +rtems_device_driver nvram_driver_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) + { + rtems_libio_rw_args_t *args = arg; + uint32_t count, i; + +#ifdef NVRAM_DEBUG + printf("\nwrite count = %2x", (int)(args->count)); + printf("\nwrite offset = %2x", (int)(args->offset)); +#endif + + if((args->offset >= M93C46_NVRAM_SIZE) || (args->offset + args->count > M93C46_NVRAM_SIZE)) + { + + args->bytes_moved = 0; + errno = EINVAL; + return RTEMS_UNSATISFIED; + + } + + count = args->count; + + m93cxx_enable_write(); + + WAIT(1); + + for(i = 0; i < count; i++) + { + + m93cxx_write_byte((args->offset) + i, (args->buffer)[i]); + (args->bytes_moved) += 1; + + } + + WAIT(1); + + m93cxx_disable_write(); + + return RTEMS_SUCCESSFUL; + + } diff --git a/bsps/powerpc/gen5200/slicetimer/slicetimer.c b/bsps/powerpc/gen5200/slicetimer/slicetimer.c new file mode 100644 index 0000000000..adbd70602b --- /dev/null +++ b/bsps/powerpc/gen5200/slicetimer/slicetimer.c @@ -0,0 +1,366 @@ +/*===============================================================*\ +| Project: RTEMS generic MPC5200 BSP | ++-----------------------------------------------------------------+ +| Partially based on the code references which are named below. | +| Adaptions, modifications, enhancements and any recent parts of | +| the code are: | +| Copyright (c) 2005 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.org/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains functions to implement a slice timer | +\*===============================================================*/ +/***********************************************************************/ +/* */ +/* Module: slicetimer.c */ +/* Date: 07/17/2003 */ +/* Purpose: RTEMS MPC5x00 slicetimer driver */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* Description: MPC5x00 slice timer routines for cyclic short time */ +/* trigger */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* Code */ +/* References: Clock driver for PPC403 */ +/* Module: clock.c */ +/* Project: RTEMS 4.6.0pre1 / PPC403 BSP */ +/* Version 1.16 */ +/* Date: 2002/11/01 */ +/* Author(s) / Copyright(s): */ +/* */ +/* Author: Jay Monkman (jmonkman@frasca.com) */ +/* Copyright (C) 1998 by Frasca International, Inc. */ +/* */ +/* Derived from c/src/lib/libcpu/ppc/ppc403/clock/clock.c: */ +/* */ +/* Author: Andrew Bray <andy@i-cubed.co.uk> */ +/* */ +/* COPYRIGHT (c) 1995 by i-cubed ltd. */ +/* */ +/* To anyone who acknowledges that this file is provided "AS IS" */ +/* without any express or implied warranty: */ +/* permission to use, copy, modify, and distribute this file */ +/* for any purpose is hereby granted without fee, provided that */ +/* the above copyright notice and this notice appears in all */ +/* copies, and that the name of i-cubed limited not be used in */ +/* advertising or publicity pertaining to distribution of the */ +/* software without specific, written prior permission. */ +/* i-cubed limited makes no representations about the suitability */ +/* of this software for any purpose. */ +/* */ +/* Derived from c/src/lib/libcpu/hppa1.1/clock/clock.c: */ +/* */ +/* Modifications for deriving timer clock from cpu system clock by */ +/* Thomas Doerfler <td@imd.m.isar.de> */ +/* for these modifications: */ +/* COPYRIGHT (c) 1997 by IMD, Puchheim, Germany. */ +/* */ +/* COPYRIGHT (c) 1989-1999. */ +/* On-Line Applications Research Corporation (OAR). */ +/* */ +/* The license and distribution terms for this file may be */ +/* found in the file LICENSE in this distribution or at */ +/* http://www.rtems.org/license/LICENSE. */ +/* */ +/* Modifications for PPC405GP by Dennis Ehlin */ +/*---------------------------------------------------------------------*/ +/* */ +/* Partially based on the code references which are named above. */ +/* Adaptions, modifications, enhancements and any recent parts of */ +/* the code are under the right of */ +/* */ +/* IPR Engineering, Dachauer Straße 38, D-80335 München */ +/* Copyright(C) 2003 */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* IPR Engineering makes no representation or warranties with */ +/* respect to the performance of this computer program, and */ +/* specifically disclaims any responsibility for any damages, */ +/* special or consequential, connected with the use of this program. */ +/* */ +/*---------------------------------------------------------------------*/ +/* */ +/* Version history: 1.0 */ +/* */ +/***********************************************************************/ + +#include <bsp.h> +#include <rtems/bspIo.h> +#include <bsp/fatal.h> +#include <bsp/irq.h> + +#include <rtems.h> +#include <rtems/clockdrv.h> +#include <rtems/libio.h> + +#include <bsp/irq.h> +#include <bsp/mpc5200.h> +#include <bsp/slicetimer.h> +#include <stdio.h> + +uint32_t value0 = 0; +uint32_t value1 = 0; + +/* + * ISR Handlers + */ +void mpc5200_slt_isr(uint32_t slt_no) + { + uint32_t status; + struct mpc5200_slt *slt = (struct mpc5200_slt *)(&mpc5200.slt[slt_no]); + + status = slt->tsr; + + if(status & SLT_TSR_ST) + { + + slt->tsr |= SLT_TSR_ST; + + /*if(slt_no == SLT0) + slt0_user_defined_handler */ + + /*if(slt_no == SLT1) + slt1_user_defined_handler */ + + } + + } + + +rtems_isr mpc5200_slt0_isr(rtems_irq_hdl_param unused) + { + + mpc5200_slt_isr(SLT0); + + } + + +rtems_isr mpc5200_slt1_isr(rtems_irq_hdl_param unused) + { + + mpc5200_slt_isr(SLT1); + + } + + +/* + * Initialize MPC5x00 slt + */ +void mpc5200_init_slt(uint32_t slt_no) + { + struct mpc5200_slt *slt = (struct mpc5200_slt *)(&mpc5200.slt[slt_no]); + + slt->tsr = SLT_TSR_ST; + slt->cntrl = SLT_CNTRL_RW; + + } + + +/* + * Set MPC5x00 slt counter + */ +void mpc5200_set_slt_count(uint32_t slt_no) + { + struct mpc5200_slt *slt = (struct mpc5200_slt *)(&mpc5200.slt[slt_no]); + + if(slt_no == SLT0) + /* Calculate counter value 24 bit (must be greater than 255) => IPB_Clock=33MHz -> Int. every 7,75us - 508ms */ + if((SLT_TSR_COUNT(SLT0_INT_FREQUENCY) > 0xFF) && (SLT_TSR_COUNT(SLT0_INT_FREQUENCY) < 0x1000000)) + slt->tcr = SLT_TSR_COUNT(SLT0_INT_FREQUENCY); + + if(slt_no == SLT1) + /* Calculate counter value 24 bit (must be greater than 255) => IPB_Clock=33MHz -> Int. every 7,75us - 508ms */ + if((SLT_TSR_COUNT(SLT1_INT_FREQUENCY) > 0xFF) && (SLT_TSR_COUNT(SLT1_INT_FREQUENCY) < 0x1000000)) + slt->tcr = SLT_TSR_COUNT(SLT1_INT_FREQUENCY); + + } + + +/* + * Enable MPC5x00 slt interrupt + */ +void mpc5200_enable_slt_int(uint32_t slt_no) + { + struct mpc5200_slt *slt = (struct mpc5200_slt *)(&mpc5200.slt[slt_no]); + + slt->cntrl |= SLT_CNTRL_TIMEN | SLT_CNTRL_INTEN; + + } + + +/* + * Disable MPC5x00 slt interrupt + */ +void mpc5200_disable_slt_int(uint32_t slt_no) + { + struct mpc5200_slt *slt = (struct mpc5200_slt *)(&mpc5200.slt[slt_no]); + + slt->cntrl &= ~(SLT_CNTRL_TIMEN | SLT_CNTRL_INTEN); + + } + + +/* + * Check MPC5x00 slt status + */ +uint32_t mpc5200_check_slt_status(uint32_t slt_no) + { + struct mpc5200_slt *slt = (struct mpc5200_slt *)(&mpc5200.slt[slt_no]); + + if(((slt->cntrl) & (SLT_CNTRL_TIMEN | SLT_CNTRL_INTEN)) == (SLT_CNTRL_TIMEN | SLT_CNTRL_INTEN)) + return 1; + else + return 0; + + } + +/* + * switch MPC5x00 slt on + */ +static void sltOn(const rtems_irq_connect_data* irq) + { + uint32_t slt_no = 0; + + if((irq->name) == BSP_SIU_IRQ_SL_TIMER0) + slt_no = 0; + + if((irq->name) == BSP_SIU_IRQ_SL_TIMER1) + slt_no = 1; + + mpc5200_set_slt_count((uint32_t)slt_no); + mpc5200_enable_slt_int((uint32_t)slt_no); + + } + +/* + * switch MPC5x00 slt off + */ +static void sltOff(const rtems_irq_connect_data* irq) + { + uint32_t slt_no = 0; + + if((irq->name) == BSP_SIU_IRQ_SL_TIMER0) + slt_no = 0; + + if((irq->name) == BSP_SIU_IRQ_SL_TIMER1) + slt_no = 1; + + mpc5200_disable_slt_int((uint32_t)slt_no); + + } + +/* + * get status of MPC5x00 slt + */ +static int sltIsOn(const rtems_irq_connect_data* irq) + { + uint32_t slt_no = 0; + + if((irq->name) == BSP_SIU_IRQ_SL_TIMER0) + slt_no = 0; + + if((irq->name) == BSP_SIU_IRQ_SL_TIMER1) + slt_no = 1; + + if(mpc5200_check_slt_status(slt_no)) + return 1; + else + return 0; + } + +/* + * MPC5x00 slt0 irq connect data + */ +static rtems_irq_connect_data slt0_IrqData = + { + BSP_SIU_IRQ_SL_TIMER0, + mpc5200_slt0_isr, + (rtems_irq_hdl_param) NULL, + (rtems_irq_enable)sltOn, + (rtems_irq_disable)sltOff, + (rtems_irq_is_enabled)sltIsOn + }; + +/* + * MPC5x00 slt1 irq connect data + */ +static rtems_irq_connect_data slt1_IrqData = + { + BSP_SIU_IRQ_SL_TIMER1, + mpc5200_slt1_isr, + (rtems_irq_hdl_param) NULL, + (rtems_irq_enable)sltOn, + (rtems_irq_disable)sltOff, + (rtems_irq_is_enabled)sltIsOn + }; + +/* + * call MPC5x00 slt install routines + */ +void Install_slt(rtems_device_minor_number slt_no) + { + + mpc5200_init_slt((uint32_t)slt_no); + mpc5200_set_slt_count((uint32_t)slt_no); + + } + +/* + * MPC5x00 slt device driver initialize + */ +rtems_device_driver slt_initialize + ( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *pargp + ) + { + + /* force minor according to definitions in bsp.h */ + if(USE_SLICETIMER_0) + { + + Install_slt(0); + + if(!BSP_install_rtems_irq_handler(&slt0_IrqData)) + { + + printk("Unable to connect PSC Irq handler\n"); + bsp_fatal(MPC5200_FATAL_SLICETIMER_0_IRQ_INSTALL); + + } + + } + + if(USE_SLICETIMER_1) + { + + Install_slt(1); + + if(!BSP_install_rtems_irq_handler(&slt1_IrqData)) + { + + printk("Unable to connect PSC Irq handler\n"); + bsp_fatal(MPC5200_FATAL_SLICETIMER_1_IRQ_INSTALL); + + } + + } + + return RTEMS_SUCCESSFUL; + + } + |