Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:06

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  *  non-FD specific function for GRCAN driver
0005  *
0006  *  COPYRIGHT (c) 2007-2019.
0007  *  Cobham Gaisler AB.
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  * 1. Redistributions of source code must retain the above copyright
0013  *    notice, this list of conditions and the following disclaimer.
0014  * 2. Redistributions in binary form must reproduce the above copyright
0015  *    notice, this list of conditions and the following disclaimer in the
0016  *    documentation and/or other materials provided with the distribution.
0017  *
0018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0028  * POSSIBILITY OF SUCH DAMAGE.
0029  */
0030 
0031 #include <bsp.h>
0032 #include <stdlib.h>
0033 #include <stdio.h>
0034 #include <string.h>
0035 #include <assert.h>
0036 #include <ctype.h>
0037 #include <rtems/bspIo.h>
0038 
0039 #include <grlib/grcan.h>
0040 #include <grlib/canbtrs.h>
0041 #include <drvmgr/drvmgr.h>
0042 #include <grlib/ambapp_bus.h>
0043 #include <grlib/ambapp.h>
0044 
0045 #include <grlib/grlib_impl.h>
0046 #include "grcan_internal.h"
0047 
0048 /* Uncomment for debug output */
0049 /****************** DEBUG Definitions ********************/
0050 #define DBG_TX 2
0051 #define DBG_RX 4
0052 #define DBG_STATE 8
0053 
0054 #define DEBUG_FLAGS (DBG_STATE | DBG_RX | DBG_TX )
0055 /*
0056 #define DEBUG
0057 #define DEBUGFUNCS
0058 */
0059 #include <grlib/debug_defs.h>
0060 
0061 static int grcan_hw_read_try(
0062     struct grcan_priv *pDev,
0063     struct grcan_regs *regs,
0064     CANMsg * buffer,
0065     int max
0066 )
0067 {
0068     int i, j;
0069     CANMsg *dest;
0070     struct grcan_msg *source, tmp;
0071     unsigned int wp, rp, size, rxmax, addr;
0072     int trunk_msg_cnt;
0073 
0074     FUNCDBG();
0075 
0076     wp = READ_REG(&regs->rx0wr);
0077     rp = READ_REG(&regs->rx0rd);
0078 
0079     /*
0080      * Due to hardware wrap around simplification write pointer will
0081      * never reach the read pointer, at least a gap of 8 bytes.
0082      * The only time they are equal is when the read pointer has
0083      * reached the write pointer (empty buffer)
0084      *
0085      */
0086     if (wp != rp) {
0087         /* Not empty, we have received chars...
0088          * Read as much as possible from DMA buffer
0089          */
0090         size = READ_REG(&regs->rx0size);
0091 
0092         /* Get number of bytes available in RX buffer */
0093         trunk_msg_cnt = grcan_hw_rxavail(rp, wp, size);
0094 
0095         /* truncate size if user space buffer hasn't room for
0096          * all received chars.
0097          */
0098         if (trunk_msg_cnt > max)
0099             trunk_msg_cnt = max;
0100 
0101         /* Read until i is 0 */
0102         i = trunk_msg_cnt;
0103 
0104         addr = (unsigned int)pDev->rx;
0105         source = (struct grcan_msg *)(addr + rp);
0106         dest = buffer;
0107         rxmax = addr + (size - GRCAN_MSG_SIZE);
0108 
0109         /* Read as many can messages as possible */
0110         while (i > 0) {
0111             /* Read CAN message from DMA buffer */
0112             tmp.head[0] = READ_DMA_WORD(&source->head[0]);
0113             tmp.head[1] = READ_DMA_WORD(&source->head[1]);
0114             if (tmp.head[1] & 0x4) {
0115                 DBGC(DBG_RX, "overrun\n");
0116             }
0117             if (tmp.head[1] & 0x2) {
0118                 DBGC(DBG_RX, "bus-off mode\n");
0119             }
0120             if (tmp.head[1] & 0x1) {
0121                 DBGC(DBG_RX, "error-passive mode\n");
0122             }
0123             /* Convert one grcan CAN message to one "software" CAN message */
0124             dest->extended = tmp.head[0] >> 31;
0125             dest->rtr = (tmp.head[0] >> 30) & 0x1;
0126             if (dest->extended) {
0127                 dest->id = tmp.head[0] & 0x3fffffff;
0128             } else {
0129                 dest->id = (tmp.head[0] >> 18) & 0xfff;
0130             }
0131             dest->len = tmp.head[1] >> 28;
0132             for (j = 0; j < dest->len; j++)
0133                 dest->data[j] = READ_DMA_BYTE(&source->data[j]);
0134 
0135             /* wrap around if neccessary */
0136             source =
0137                 ((unsigned int)source >= rxmax) ?
0138                 (struct grcan_msg *)addr : source + 1;
0139             dest++; /* straight user buffer */
0140             i--;
0141         }
0142         {
0143             /* A bus off interrupt may have occured after checking pDev->started */
0144             SPIN_IRQFLAGS(oldLevel);
0145 
0146             SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
0147             if (pDev->started == STATE_STARTED) {
0148                 regs->rx0rd = (unsigned int) source - addr;
0149                 regs->rx0ctrl = GRCAN_RXCTRL_ENABLE;
0150             } else {
0151                 DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
0152                 trunk_msg_cnt = state2err[pDev->started];
0153             }
0154             SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
0155         }
0156         return trunk_msg_cnt;
0157     }
0158     return 0;
0159 }
0160 
0161 static int grcan_hw_write_try(
0162     struct grcan_priv *pDev,
0163     struct grcan_regs *regs,
0164     CANMsg * buffer,
0165     int count
0166 )
0167 {
0168     unsigned int rp, wp, size, txmax, addr;
0169     int ret;
0170     struct grcan_msg *dest;
0171     CANMsg *source;
0172     int space_left;
0173     unsigned int tmp;
0174     int i;
0175 
0176     DBGC(DBG_TX, "\n");
0177     /*FUNCDBG(); */
0178 
0179     rp = READ_REG(&regs->tx0rd);
0180     wp = READ_REG(&regs->tx0wr);
0181     size = READ_REG(&regs->tx0size);
0182 
0183     space_left = grcan_hw_txspace(rp, wp, size);
0184 
0185     /* is circular fifo full? */
0186     if (space_left < 1)
0187         return 0;
0188 
0189     /* Truncate size */
0190     if (space_left > count)
0191         space_left = count;
0192     ret = space_left;
0193 
0194     addr = (unsigned int)pDev->tx;
0195 
0196     dest = (struct grcan_msg *)(addr + wp);
0197     source = (CANMsg *) buffer;
0198     txmax = addr + (size - GRCAN_MSG_SIZE);
0199 
0200     while (space_left > 0) {
0201         /* Convert and write CAN message to DMA buffer */
0202         if (source->extended) {
0203             tmp = (1 << 31) | (source->id & 0x3fffffff);
0204         } else {
0205             tmp = (source->id & 0xfff) << 18;
0206         }
0207         if (source->rtr)
0208             tmp |= (1 << 30);
0209         dest->head[0] = tmp;
0210         dest->head[1] = source->len << 28;
0211         for (i = 0; i < source->len; i++)
0212             dest->data[i] = source->data[i];
0213         source++;   /* straight user buffer */
0214         dest =
0215             ((unsigned int)dest >= txmax) ?
0216             (struct grcan_msg *)addr : dest + 1;
0217         space_left--;
0218     }
0219 
0220     {
0221         /* A bus off interrupt may have occured after checking pDev->started */
0222         SPIN_IRQFLAGS(oldLevel);
0223 
0224         SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
0225         if (pDev->started == STATE_STARTED) {
0226             regs->tx0wr = (unsigned int) dest - addr;
0227             regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
0228         } else {
0229             DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
0230             ret = state2err[pDev->started];
0231         }
0232         SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
0233     }
0234     return ret;
0235 }
0236 
0237 
0238 int grcan_read(void *d, CANMsg *msg, size_t ucount)
0239 {
0240     struct grcan_priv *pDev = d;
0241     CANMsg *dest;
0242     unsigned int count, left;
0243     int nread;
0244     int req_cnt;
0245 
0246     FUNCDBG();
0247 
0248     dest = msg;
0249     req_cnt = ucount;
0250 
0251     if ( (!dest) || (req_cnt<1) )
0252         return GRCAN_RET_INVARG;
0253 
0254     if (pDev->started != STATE_STARTED) {
0255         return GRCAN_RET_NOTSTARTED;
0256     }
0257 
0258     DBGC(DBG_RX, "grcan_read [%p]: buf: %p len: %u\n", d, msg, (unsigned int) ucount);
0259 
0260     nread = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt);
0261     if (nread < 0) {
0262         return nread;
0263     }
0264     count = nread;
0265     if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
0266         if ( count > 0 ) {
0267             /* Successfully received messages (at least one) */
0268             return count;
0269         }
0270 
0271         /* nothing read, shall we block? */
0272         if ( !pDev->rxblock ) {
0273             /* non-blocking mode */
0274             return GRCAN_RET_TIMEOUT;
0275         }
0276     }
0277 
0278     while (count == 0 || (pDev->rxcomplete && (count!=req_cnt))) {
0279         if (!pDev->rxcomplete) {
0280             left = 1; /* return as soon as there is one message available */
0281         } else {
0282             left = req_cnt - count;     /* return as soon as all data are available */
0283 
0284             /* never wait for more than the half the maximum size of the receive buffer
0285              * Why? We need some time to copy buffer before to catch up with hw,
0286              * otherwise we would have to copy everything when the data has been
0287              * received.
0288              */
0289             if (left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2)){
0290                 left = (pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2;
0291             }
0292         }
0293 
0294         nread = grcan_wait_rxdata(pDev, left);
0295         if (nread) {
0296             /* The wait has been aborted, probably due to
0297              * the device driver has been closed by another
0298              * thread or a bus-off. Return error code.
0299              */
0300             return nread;
0301         }
0302 
0303         /* Try read bytes from circular buffer */
0304         nread = grcan_hw_read_try(
0305                 pDev,
0306                 pDev->regs,
0307                 dest+count,
0308                 req_cnt-count);
0309 
0310         if (nread < 0) {
0311             /* The read was aborted by bus-off. */
0312             return nread;
0313         }
0314         count += nread;
0315     }
0316     /* no need to unmask IRQ as IRQ Handler do that for us. */
0317     return count;
0318 }
0319 
0320 int grcan_write(void *d, CANMsg *msg, size_t ucount)
0321 {
0322     struct grcan_priv *pDev = d;
0323     CANMsg *source;
0324     unsigned int count, left;
0325     int nwritten;
0326     int req_cnt;
0327 
0328     DBGC(DBG_TX,"\n");
0329 
0330     if ((pDev->started != STATE_STARTED) || pDev->config.silent || pDev->flushing)
0331         return GRCAN_RET_NOTSTARTED;
0332 
0333     req_cnt = ucount;
0334     source = (CANMsg *) msg;
0335 
0336     /* check proper length and buffer pointer */
0337     if (( req_cnt < 1) || (source == NULL) ){
0338         return GRCAN_RET_INVARG;
0339     }
0340 
0341     nwritten = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt);
0342     if (nwritten < 0) {
0343         return nwritten;
0344     }
0345     count = nwritten;
0346     if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
0347         if ( count > 0 ) {
0348             /* Successfully transmitted chars (at least one char) */
0349             return count;
0350         }
0351 
0352         /* nothing written, shall we block? */
0353         if ( !pDev->txblock ) {
0354             /* non-blocking mode */
0355             return GRCAN_RET_TIMEOUT;
0356         }
0357     }
0358 
0359     /* if in txcomplete mode we need to transmit all chars */
0360     while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){
0361         /*** block until room to fit all or as much of transmit buffer as possible
0362          * IRQ comes. Set up a valid IRQ point so that an IRQ is received 
0363          * when we can put a chunk of data into transmit fifo
0364          */
0365         if ( !pDev->txcomplete ){
0366             left = 1; /* wait for anything to fit buffer */
0367         }else{
0368             left = req_cnt - count; /* wait for all data to fit in buffer */
0369 
0370             /* never wait for more than the half the maximum size of the transmit
0371              * buffer 
0372              * Why? We need some time to fill buffer before hw catches up.
0373              */
0374             if ( left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2) ){
0375                 left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2;
0376             }
0377         }
0378 
0379         nwritten = grcan_wait_txspace(pDev,left);
0380         /* Wait until more room in transmit buffer */
0381         if ( nwritten ) {
0382             /* The wait has been aborted, probably due to 
0383              * the device driver has been closed by another
0384              * thread. To avoid deadlock we return directly
0385              * with error status.
0386              */
0387             return nwritten;
0388         }
0389 
0390         /* Try read bytes from circular buffer */
0391         nwritten = grcan_hw_write_try(
0392             pDev,
0393             pDev->regs,
0394             source+count,
0395             req_cnt-count);
0396 
0397         if (nwritten < 0) {
0398             /* Write was aborted by bus-off. */
0399             return nwritten;
0400         }
0401         count += nwritten;
0402     }
0403     /* no need to unmask IRQ as IRQ Handler do that for us. */
0404 
0405     return count;
0406 }
0407 
0408 
0409 int grcan_set_speed(void *d, unsigned int speed)
0410 {
0411     struct grcan_priv *pDev = d;
0412     struct grcan_timing timing;
0413     int ret;
0414 
0415     FUNCDBG();
0416 
0417     /* cannot change speed during run mode */
0418     if ((pDev->started == STATE_STARTED) || pDev->fd_capable)
0419         return -1;
0420 
0421     /* get speed rate from argument */
0422     ret = grlib_canbtrs_calc_timing(
0423         speed, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
0424         &grcan_btrs_ranges, (struct grlib_canbtrs_timing *)&timing);
0425     if (ret)
0426         return -2;
0427 
0428     /* save timing/speed */
0429     pDev->config.timing = timing;
0430     pDev->config_changed = 1;
0431 
0432     return 0;
0433 }
0434 
0435 int grcan_set_btrs(void *d, const struct grcan_timing *timing)
0436 {
0437     struct grcan_priv *pDev = d;
0438 
0439     FUNCDBG();
0440 
0441     /* Set BTR registers manually
0442      * Read GRCAN/HurriCANe Manual.
0443      */
0444     if ((pDev->started == STATE_STARTED) || pDev->fd_capable)
0445         return -1;
0446 
0447     if ( !timing )
0448         return -2;
0449 
0450     pDev->config.timing = *timing;
0451     pDev->config_changed = 1;
0452 
0453     return 0;
0454 }