From c9b005a9d2ed95bb1ab16fbc0c823c12a5c58b26 Mon Sep 17 00:00:00 2001 From: Thomas Doerfler Date: Sun, 9 Jul 2006 10:05:27 +0000 Subject: applied patches for PR1117/1118/1119/1120 --- c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c | 719 +++++++++++++++++-------- 1 file changed, 498 insertions(+), 221 deletions(-) (limited to 'c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c') diff --git a/c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c b/c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c index 857a160b9b..c107e9e37f 100644 --- a/c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c +++ b/c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c @@ -30,8 +30,107 @@ /* #define MSCAN_LOOPBACK */ +volatile uint32_t tx_int_wr_count = 0; + struct mpc5200_rx_cntrl mpc5200_mscan_rx_cntrl[MPC5200_CAN_NO]; -static struct mscan_channel_info chan_info[MPC5200_CAN_NO]; +volatile static struct mscan_channel_info chan_info[MPC5200_CAN_NO]; + +/* time segmant table */ +uint8_t can_time_segment_table[CAN_MAX_NO_OF_TQ - MIN_NO_OF_TQ + 1][NO_OF_TABLE_ENTRIES] = { + +/* Total no. of time quantas */ /* Time Segment 1*/ /* Time Segment 2 */ /* Sync: Jump width */ +{ 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 }}; + + +/* + * MPC5x00 MSCAN tx ring buffer function to get a can message buffer from the head of the tx ring buffer + */ +volatile static struct can_message * get_tx_buffer(struct mscan_channel_info *chan) + { + /* define a temp. mess ptr. */ + volatile 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 + */ +volatile 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 @@ -41,24 +140,110 @@ 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; + struct can_message rx_mess, *rx_mess_ptr, *tx_mess_ptr; volatile struct mpc5200_mscan *mscan = chan->regs; + register uint8_t idx; /* - handle tx interrupts + handle tx ring buffer */ - /* check and disable tx interrupt for message buffer 0 */ - if(mscan->tier & MSCAN_TX_BUFF0) - mscan->tier &= ~(MSCAN_TX_BUFF0); + /* loop over all 3 tx buffers */ + for(idx = TFLG_TXE0; idx <= TFLG_TXE2; idx=idx<<1) + { + + /* check for tx buffer vacation */ + if((mscan->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 */ + mscan->bsel = idx; + + /* check for toucan interface */ + if((mscan_hdl->toucan_callback) == NULL) + { + + /* set tx id */ + mscan->txidr0 = SET_IDR0(tx_mess_ptr->mess_id); + mscan->txidr1 = SET_IDR1(tx_mess_ptr->mess_id); + mscan->txidr2 = 0; + mscan->txidr3 = 0; + + /* insert dlc into mscan register */ + mscan->txdlr = (uint8_t)((tx_mess_ptr->mess_len) & 0x000F); + } + + /* select one free tx buffer if TOUCAN not registered) */ + if(((mscan_hdl->toucan_callback) == NULL) || (((mscan_hdl->toucan_callback) != NULL) && ((tx_mess_ptr->toucan_tx_id) == idx))) + { + + /* set tx id */ + mscan->txidr0 = SET_IDR0(tx_mess_ptr->mess_id); + mscan->txidr1 = SET_IDR1(tx_mess_ptr->mess_id); + mscan->txidr2 = 0; + mscan->txidr3 = 0; + + /* insert dlc into mscan register */ + mscan->txdlr = (uint8_t)((tx_mess_ptr->mess_len) & 0x000F); + + /* copy tx data to MSCAN registers */ + switch(mscan->txdlr) + { + case 8: + mscan->txdsr7 = tx_mess_ptr->mess_data[7]; + case 7: + mscan->txdsr6 = tx_mess_ptr->mess_data[6]; + case 6: + mscan->txdsr5 = tx_mess_ptr->mess_data[5]; + case 5: + mscan->txdsr4 = tx_mess_ptr->mess_data[4]; + case 4: + mscan->txdsr3 = tx_mess_ptr->mess_data[3]; + case 3: + mscan->txdsr2 = tx_mess_ptr->mess_data[2]; + case 2: + mscan->txdsr1 = tx_mess_ptr->mess_data[1]; + case 1: + mscan->txdsr0 = tx_mess_ptr->mess_data[0]; + break; + default: + break; + } + + /* enable message buffer specific interrupt */ + mscan->tier |= mscan->bsel; + + /* start transfer */ + mscan->tflg = mscan->bsel; + + /* release counting semaphore of tx ring buffer */ + rtems_semaphore_release((rtems_id)(chan->tx_rb_sid)); + + tx_int_wr_count++; - /* check and disable tx interrupt for message buffer 1 */ - if(mscan->tier & MSCAN_TX_BUFF1) - mscan->tier &= ~(MSCAN_TX_BUFF1); + } + else + { - /* check and disable tx interrupt for message buffer 2 */ - if(mscan->tier & MSCAN_TX_BUFF2) - mscan->tier &= ~(MSCAN_TX_BUFF2); + /* refill the tx ring buffer with the message */ + fill_tx_buffer(chan, tx_mess_ptr); + + } + } + else + { + /* reset interrupt enable bit */ + mscan->tier &= ~(idx); + } + } + } /* handle rx interrupts @@ -84,24 +269,17 @@ static void mpc5200_mscan_interrupt_handler(rtems_irq_hdl_param handle) /* check the rx fliter-match indicators (16-bit filter mode) */ /* in case of more than one hit, lower hit has priority */ - switch((mscan->idac) & 0x7) + idx = (mscan->idac) & 0x7; + switch(idx) { case 0: - rx_mess_ptr = (struct can_message *)&(mpc5200_mscan_rx_cntrl[MSCAN_A].can_rx_message[0]); - break; - - case 1: - rx_mess_ptr = (struct can_message *)&(mpc5200_mscan_rx_cntrl[MSCAN_A].can_rx_message[1]); - break; - + case 1: case 2: - rx_mess_ptr = (struct can_message *)&(mpc5200_mscan_rx_cntrl[MSCAN_A].can_rx_message[2]); - break; - - case 3: - rx_mess_ptr = (struct can_message *)&(mpc5200_mscan_rx_cntrl[MSCAN_A].can_rx_message[3]); - break; + 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: @@ -530,34 +708,71 @@ void mpc5200_mscan_wait_sync(volatile struct mpc5200_mscan *mscan) /* [01]:SLPRQ 0 : No Sleep Mode Request */ /* [00]:INITRQ 0 : No init. Mode Request */ /* wait for MSCAN A_/_B bus synch. */ - while(!((mscan->ctl0) & CTL0_SYNCH)); +#if 0 /* we don't have a need to wait for sync. */ + while(!((mscan->ctl0) & CTL0_SYNCH)); +#endif return; } +/* calculate the can clock prescaler value */ +uint8_t prescaler_calculation(uint32_t can_bit_rate, uint32_t can_clock_frq, uint8_t *tq_no) { + +/* local variables */ +uint8_t tq_no_min_dev = 0; +uint32_t frq_tq, frq_dev, frq_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 deviation from requested tq freq. */ + frq_dev = can_clock_frq%frq_tq; + + /* check the deviation freq. */ + if(frq_dev == 0) { + + /* return if best match (zero deviation) */ + return (uint8_t)(can_clock_frq/frq_tq); + } + else + { + + /* check for minimum of freq. deviation */ + if(frq_dev < frq_dev_min) { + + /* recognize the minimum freq. deviation */ + frq_dev_min = frq_dev; + + /* recognize the no. of time quantas */ + tq_no_min_dev = *tq_no; + } + } + } + +/* return the optimized prescaler value */ + *tq_no = tq_no_min_dev; + return (uint8_t)(can_clock_frq/(tq_no_min_dev * can_bit_rate)); +} /* * MPC5x00 MSCAN set up the bit timing */ -void mpc5200_mscan_perform_bit_time_settings(volatile struct mpc5200_mscan *mscan) +void mpc5200_mscan_perform_bit_time_settings(volatile struct mpc5200_mscan *mscan, uint32_t can_bit_rate, uint32_t can_clock_frq) { uint32_t prescale_val = 0; - uint32_t tq_num; - uint32_t sync_seg,tseg1,tseg2; - - if(IPB_CLOCK%(CAN_BIT_RATE * CAN_MAX_NO_OF_TQ)) - prescale_val = (IPB_CLOCK/(CAN_BIT_RATE * (CAN_MAX_NO_OF_TQ*2/3))) + 1; - else - prescale_val = IPB_CLOCK/(CAN_BIT_RATE* (CAN_MAX_NO_OF_TQ*2/3)); - - tq_num = ((IPB_CLOCK/prescale_val)+CAN_BIT_RATE/2)/CAN_BIT_RATE; - /* - * XXX: make this table controlled according to MPC5200UM/Rev.3,Table 19-34 - */ - sync_seg = 2; - tseg2 = (tq_num-sync_seg)/6; - tseg1 = tq_num - sync_seg - tseg2; + uint8_t tq_no, tseg_1, tseg_2, sseg; + + /* get optimized prescaler value */ + prescale_val = prescaler_calculation(can_bit_rate, can_clock_frq, &tq_no); + + /* 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 */ @@ -569,7 +784,7 @@ void mpc5200_mscan_perform_bit_time_settings(volatile struct mpc5200_mscan *msca /* [02]:BRP2 1 : Baud Rate Prescaler, Bit 2 */ /* [01]:BRP1 0 : Baud Rate Prescaler, Bit 1 */ /* [00]:BRP0 1 : Baud Rate Prescaler, Bit 0 */ - mscan->btr0 |= (BTR0_SJW(sync_seg-1) | BTR0_BRP(prescale_val - 1)); + mscan->btr0 = (BTR0_SJW(sseg-1) | BTR0_BRP(prescale_val-1)); /* Bus Timing Register 1 MSCAN_A/_B ------------------------------*/ /* [07]:SAMP 0 : One Sample per bit */ @@ -581,8 +796,7 @@ void mpc5200_mscan_perform_bit_time_settings(volatile struct mpc5200_mscan *msca /* [02]:TSEG12 1 : Time Segment 1, Bit 2 */ /* [01]:TSEG11 1 : Time Segment 1, Bit 1 */ /* [00]:TSEG10 0 : Time Segment 1, Bit 0 */ - mscan->btr1 &= ~(BTR1_SAMP); - mscan->btr1 |= (BTR1_TSEG_22_20(tseg2-1) | BTR1_TSEG_13_10(tseg1-1)); + mscan->btr1 = (BTR1_TSEG_22_20(tseg_2-1) | BTR1_TSEG_13_10(tseg_1-1)); return; @@ -594,7 +808,10 @@ void mpc5200_mscan_perform_bit_time_settings(volatile struct mpc5200_mscan *msca */ void mpc5200_mscan_perform_init_mode_settings(volatile struct mpc5200_mscan *mscan) { - mpc5200_mscan_perform_bit_time_settings(mscan); + + /* perform all can bit time settings */ + mpc5200_mscan_perform_bit_time_settings(mscan,CAN_BIT_RATE,IPB_CLOCK); + /* Control Register 1 --------------------------------------------*/ /* [07]:CANE 0 : MSCAN Module is disabled */ /* [06]:CLKSRC 0 : Clock Source -> IPB_CLOCK (bsp.h) */ @@ -634,25 +851,15 @@ void mpc5200_mscan_perform_init_mode_settings(volatile struct mpc5200_mscan *msc mscan->idac &= ~(IDAC_IDAM1); mscan->idac |= (IDAC_IDAM0); - /* initialize rx filter masks: only accept exact matches */ - mscan->idmr0 = 0x00; - mscan->idmr1 = 0x00; - mscan->idmr2 = 0x00; - mscan->idmr3 = 0x00; - mscan->idmr4 = 0x00; - mscan->idmr5 = 0x00; - mscan->idmr6 = 0x00; - mscan->idmr7 = 0x00; - - /* initialize rx filters: set to illegal values, so no matches occure */ - mscan->idar0 = 0xff; - mscan->idar1 = 0xff; - mscan->idar2 = 0xff; - mscan->idar3 = 0xff; - mscan->idar4 = 0xff; - mscan->idar5 = 0xff; - mscan->idar6 = 0xff; - mscan->idar7 = 0xff; + /* initialize rx filter masks (16 bit) */ + mscan->idmr0 = SET_IDMR0(0x07FF); + mscan->idmr1 = SET_IDMR1(0x07FF); + mscan->idmr2 = SET_IDMR2(0x07FF); + mscan->idmr3 = SET_IDMR3(0x07FF); + mscan->idmr4 = SET_IDMR4(0x07FF); + mscan->idmr5 = SET_IDMR5(0x07FF); + mscan->idmr6 = SET_IDMR6(0x07FF); + mscan->idmr7 = SET_IDMR7(0x07FF); /* Control Register 1 --------------------------------------------*/ /* [07]:CANE 0->1 : MSCAN Module is enabled */ @@ -719,36 +926,44 @@ rtems_status_code mpc5200_mscan_set_mode(rtems_device_minor_number minor, uint8_ switch(mode) { + case MSCAN_INIT_NORMAL_MODE: + /* if not already set enter init mode */ + mpc5200_mscan_enter_init_mode(mscan); + /* perform initialization which has to be done in init mode */ + mpc5200_mscan_perform_init_mode_settings(mscan); + break; + case MSCAN_NORMAL_MODE: /* if not already set enter init mode */ mpc5200_mscan_enter_init_mode(mscan); if((chan->mode) == MSCAN_INITIALIZED_MODE) + { + /* perform initialization which has to be done in init mode */ mpc5200_mscan_perform_init_mode_settings(mscan); - else + } + + if((chan->mode) == MSCAN_SLEEP_MODE) + { + /* exit sleep mode */ mpc5200_mscan_exit_sleep_mode(mscan); + } - /* exit init mode */ + /* exit init mode */ mpc5200_mscan_exit_init_mode(mscan); /* enable ints. */ mpc5200_mscan_int_enable(mscan); /* wait for bus sync. */ mpc5200_mscan_wait_sync(mscan); - return RTEMS_SUCCESSFUL; break; case MSCAN_SLEEP_MODE: - /* enable ints. */ + /* disable ints. */ mpc5200_mscan_int_disable(mscan); - /* if not already set enter init mode */ - mpc5200_mscan_enter_init_mode(mscan); /* exit sleep mode */ mpc5200_mscan_enter_sleep_mode(mscan); - /* exit init mode */ - mpc5200_mscan_exit_init_mode(mscan); - return RTEMS_SUCCESSFUL; break; default: @@ -773,26 +988,55 @@ rtems_status_code mscan_channel_initialize(rtems_device_major_number major, rtem 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) + 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: @@ -800,27 +1044,30 @@ rtems_status_code mscan_channel_initialize(rtems_device_major_number major, rtem break; } - /* create RTEMS rx message queue for MSCAN A */ - if((status = rtems_message_queue_create(chan->rx_qname, - (uint32_t) NO_OF_MSCAN_A_RX_BUFF, - (uint32_t) MSCAN_MESSAGE_SIZE(sizeof(struct can_message)), - (rtems_attribute) RTEMS_LOCAL | RTEMS_FIFO, - (rtems_id *)&(chan->rx_qid))) - != RTEMS_SUCCESSFUL) - { - return status; - - } - - /* Set up interrupts MSCAN A */ + /* 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 = (struct mpc5200_mscan *)&(mpc5200.mscan[minor]); - chan->int_rx_err = 0; - chan->id_extended = FALSE; - chan->mode = MSCAN_INITIALIZED_MODE; + chan->regs = (struct mpc5200_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; @@ -844,10 +1091,10 @@ rtems_device_driver mscan_initialize(rtems_device_major_number major, if((status = mscan_channel_initialize(major,MSCAN_B)) != RTEMS_SUCCESSFUL) rtems_fatal_error_occurred(status); - if((status = mpc5200_mscan_set_mode(MSCAN_A, MSCAN_NORMAL_MODE)) != RTEMS_SUCCESSFUL) + if((status = mpc5200_mscan_set_mode(MSCAN_A, MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL) rtems_fatal_error_occurred(status); - if((status = mpc5200_mscan_set_mode(MSCAN_B, MSCAN_NORMAL_MODE)) != RTEMS_SUCCESSFUL) + if((status = mpc5200_mscan_set_mode(MSCAN_B, MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL) rtems_fatal_error_occurred(status); return status; @@ -863,7 +1110,7 @@ rtems_device_driver mscan_open( rtems_device_major_number major, void * arg ) { - rtems_status_code status; + rtems_status_code status = RTEMS_SUCCESSFUL; struct mscan_channel_info *chan = NULL; switch(minor) @@ -879,8 +1126,14 @@ rtems_device_driver mscan_open( rtems_device_major_number major, break; } - /* if not already set enter init mode */ - status = mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE); + + /* 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; @@ -947,6 +1200,15 @@ rtems_device_driver mscan_read( rtems_device_major_number major, 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), (uint32_t *)&message_size, @@ -978,16 +1240,16 @@ rtems_device_driver mscan_write( rtems_device_major_number major, void * arg ) { - 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_handle *mscan_hdl = NULL; - volatile struct mpc5200_mscan *mscan = NULL; + 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_handle *mscan_hdl = NULL; + volatile struct mpc5200_mscan *mscan = NULL; switch(minor) { - case MSCAN_A: case MSCAN_B: chan = &chan_info[minor]; @@ -1000,118 +1262,39 @@ rtems_device_driver mscan_write( rtems_device_major_number major, break; } - /* select one free tx buffer (TOUCAN not registered) */ - if((mscan_hdl->toucan_callback) == NULL) - { - - if(mscan->tflg & MSCAN_TX_BUFF2) - mscan->bsel = MSCAN_TX_BUFF2; - - if(mscan->tflg & MSCAN_TX_BUFF1) - mscan->bsel = MSCAN_TX_BUFF1; - - if(mscan->tflg & MSCAN_TX_BUFF0) - mscan->bsel = MSCAN_TX_BUFF0; - } - else + /* end init mode if it is first write */ + if((chan->mode) == MSCAN_INIT_NORMAL_MODE) { - /* select a specific, preconfigured tx buffer (TOUCAN registered) */ - switch(tx_parms->tx_id) - { - - case 0: - if(mscan->tflg & MSCAN_TX_BUFF0) - mscan->bsel = MSCAN_TX_BUFF0; - break; - - case 1: - if(mscan->tflg & MSCAN_TX_BUFF1) - mscan->bsel = MSCAN_TX_BUFF1; - break; - - case 2: - if(mscan->tflg & MSCAN_TX_BUFF2) - mscan->bsel = MSCAN_TX_BUFF2; - break; - - default: - break; - - } - + /* if not already set enter init mode */ + mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE); } - /* if no tx buffer is available, teminate the write request */ - if(!(mscan->bsel)) - { - - parms->bytes_moved = 0; - return RTEMS_UNSATISFIED; - - } + /* preset moved bytes */ + parms->bytes_moved = 0; - /* prepare tx id and dlc (TOUCAN not initialized) */ - if((mscan_hdl->toucan_callback) == NULL) + /* 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) { - /* check for tx length */ - if((tx_mess->mess_len) & 0x000F) - { + /* append the TOUCAN tx_id to the mess. due to interrupt handling */ + tx_mess->toucan_tx_id = tx_parms->tx_id; - /* set tx id */ - mscan->txidr0 = SET_IDR0(tx_mess->mess_id); - mscan->txidr1 = SET_IDR1(tx_mess->mess_id); - mscan->txidr2 = 0; - mscan->txidr3 = 0; + /* fill the tx ring buffer with the message */ + fill_tx_buffer(chan, tx_mess); - /* insert dlc into mscan register */ - mscan->txdlr = (uint8_t)((tx_mess->mess_len) & 0x000F); - - } - else - { + /* enable message buffer specific interrupt */ + mscan->tier |= (TIER_TXEI0 | TIER_TXEI1 | TIER_TXEI2); - parms->bytes_moved = 0; - return RTEMS_UNSATISFIED; - - } - - } - - /* copy tx data to MSCAN registers */ - switch(mscan->txdlr) - { - - case 8: - mscan->txdsr7 = tx_mess->mess_data[7]; - case 7: - mscan->txdsr6 = tx_mess->mess_data[6]; - case 6: - mscan->txdsr5 = tx_mess->mess_data[5]; - case 5: - mscan->txdsr4 = tx_mess->mess_data[4]; - case 4: - mscan->txdsr3 = tx_mess->mess_data[3]; - case 3: - mscan->txdsr2 = tx_mess->mess_data[2]; - case 2: - mscan->txdsr1 = tx_mess->mess_data[1]; - case 1: - mscan->txdsr0 = tx_mess->mess_data[0]; - break; - default: - break; + /* calculate moved bytes */ + parms->bytes_moved = (tx_mess->mess_len) & 0x000F; } - /* enable message buffer specific interrupt */ - mscan->tier |= mscan->bsel; - - /* start transfer */ - mscan->tflg = mscan->bsel; - - return RTEMS_SUCCESSFUL; + return status; } @@ -1124,12 +1307,14 @@ rtems_device_driver mscan_control( rtems_device_major_number major, 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; - volatile struct mpc5200_mscan *mscan = NULL; + 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; + volatile struct mpc5200_mscan *mscan = NULL; + uint8_t tx_buf_count = 0; switch(minor) { @@ -1239,23 +1424,23 @@ rtems_device_driver mscan_control( rtems_device_major_number major, { case RX_BUFFER_0: - mscan->idmr0 = SET_IDR0(ctrl_parms->ctrl_id_mask); - mscan->idmr1 = SET_IDR1(ctrl_parms->ctrl_id_mask); + mscan->idmr0 = SET_IDMR0(ctrl_parms->ctrl_id_mask); + mscan->idmr1 = SET_IDMR1(ctrl_parms->ctrl_id_mask); break; case RX_BUFFER_1: - mscan->idmr2 = SET_IDR2(ctrl_parms->ctrl_id_mask); - mscan->idmr3 = SET_IDR3(ctrl_parms->ctrl_id_mask); + mscan->idmr2 = SET_IDMR2(ctrl_parms->ctrl_id_mask); + mscan->idmr3 = SET_IDMR3(ctrl_parms->ctrl_id_mask); break; case RX_BUFFER_2: - mscan->idmr4 = SET_IDR4(ctrl_parms->ctrl_id_mask); - mscan->idmr5 = SET_IDR5(ctrl_parms->ctrl_id_mask); + mscan->idmr4 = SET_IDMR4(ctrl_parms->ctrl_id_mask); + mscan->idmr5 = SET_IDMR5(ctrl_parms->ctrl_id_mask); break; case RX_BUFFER_3: - mscan->idmr6 = SET_IDR6(ctrl_parms->ctrl_id_mask); - mscan->idmr7 = SET_IDR7(ctrl_parms->ctrl_id_mask); + mscan->idmr6 = SET_IDMR6(ctrl_parms->ctrl_id_mask); + mscan->idmr7 = SET_IDMR7(ctrl_parms->ctrl_id_mask); break; default: @@ -1281,19 +1466,19 @@ rtems_device_driver mscan_control( rtems_device_major_number major, { case RX_BUFFER_0: - ctrl_parms->ctrl_id_mask = GET_IDR0(mscan->idmr0) | GET_IDR1(mscan->idmr1); + ctrl_parms->ctrl_id_mask = GET_IDMR0(mscan->idmr0) | GET_IDMR1(mscan->idmr1); break; case RX_BUFFER_1: - ctrl_parms->ctrl_id_mask = GET_IDR2(mscan->idmr2) | GET_IDR3(mscan->idmr3); + ctrl_parms->ctrl_id_mask = GET_IDMR2(mscan->idmr2) | GET_IDMR3(mscan->idmr3); break; case RX_BUFFER_2: - ctrl_parms->ctrl_id_mask = GET_IDR4(mscan->idmr4) | GET_IDR5(mscan->idmr5); + ctrl_parms->ctrl_id_mask = GET_IDMR4(mscan->idmr4) | GET_IDMR5(mscan->idmr5); break; case RX_BUFFER_3: - ctrl_parms->ctrl_id_mask = GET_IDR6(mscan->idmr6) | GET_IDR7(mscan->idmr7); + ctrl_parms->ctrl_id_mask = GET_IDMR6(mscan->idmr6) | GET_IDMR7(mscan->idmr7); break; default: @@ -1339,6 +1524,98 @@ rtems_device_driver mscan_control( rtems_device_major_number major, break; + /* set can bitrate */ + case MSCAN_SET_BAUDRATE: + + /* check bitrate settings */ + if(((ctrl_parms->ctrl_can_bitrate) >= CAN_BIT_RATE_MIN) && ((ctrl_parms->ctrl_can_bitrate) <= CAN_BIT_RATE_MAX)) { + + /* enter init mode */ + mpc5200_mscan_enter_init_mode(mscan); + + /* perform all can bit time settings */ + mpc5200_mscan_perform_bit_time_settings(mscan,(uint32_t)(ctrl_parms->ctrl_can_bitrate),IPB_CLOCK); + + /* exit init mode and perform further initialization which is required in the normal mode */ + mpc5200_mscan_exit_init_mode(mscan); + + /* enable ints. */ + mpc5200_mscan_int_enable(mscan); + + /* wait for bus sync. */ + mpc5200_mscan_wait_sync(mscan); + + return RTEMS_SUCCESSFUL; + } + else { + + return RTEMS_UNSATISFIED; + } + + 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; -- cgit v1.2.3