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  *  FD extenstions to the 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 /*********************************************************/
0062 
0063 struct grcanfd_bd0 {
0064     uint32_t head[2];
0065     uint64_t data0; /* variable size, from 1 to 8 dwords */
0066 };
0067 
0068 struct grcanfd_bd1 {
0069     unsigned long long data[2];
0070 };
0071 
0072 static uint8_t dlc2len[16] = {
0073     0, 1, 2, 3,
0074     4, 5, 6, 7,
0075     8, 12, 16, 20,
0076     24, 32, 48, 64
0077 };
0078 
0079 static uint8_t len2fddlc[14] = {
0080  /* 12,13 */    0x9,
0081  /* 16,17 */    0xA,
0082  /* 20,21 */    0xB,
0083  /* 24,25 */    0xC,
0084  /* 28,29 */    -1,
0085  /* 32,33 */    0xD,
0086  /* 36,37 */    -1,
0087  /* 40,41 */    -1,
0088  /* 44,45 */    -1,
0089  /* 48,49 */    0xE,
0090  /* 52,53 */    -1,
0091  /* 56,57 */    -1,
0092  /* 60,61 */    -1,
0093  /* 64,65 */    0xF,
0094 };
0095 
0096 /* Convert length in bytes to descriptor length field */
0097 static inline uint8_t grcan_len2dlc(int len)
0098 {
0099     if (len <= 8)
0100         return len;
0101     if (len > 64)
0102         return -1;
0103     if (len & 0x3)
0104         return -1;
0105     return len2fddlc[(len - 12) >> 2];
0106 }
0107 
0108 static inline int grcan_numbds(int len)
0109 {
0110     return 1 + ((len + 7) >> 4);
0111 }
0112 
0113 static int grcan_hw_read_try_fd(
0114     struct grcan_priv *pDev,
0115     struct grcan_regs *regs,
0116     CANFDMsg * buffer,
0117     int max)
0118 {
0119     int j;
0120     CANFDMsg *dest;
0121     struct grcanfd_bd0 *source, tmp, *rxmax;
0122     unsigned int wp, rp, size, addr;
0123     int bds_hw_avail, bds_tot, bds, ret, dlc;
0124     uint64_t *dp;
0125     SPIN_IRQFLAGS(oldLevel);
0126 
0127     FUNCDBG();
0128 
0129     wp = READ_REG(&regs->rx0wr);
0130     rp = READ_REG(&regs->rx0rd);
0131 
0132     /*
0133      * Due to hardware wrap around simplification write pointer will
0134      * never reach the read pointer, at least a gap of 8 bytes.
0135      * The only time they are equal is when the read pointer has
0136      * reached the write pointer (empty buffer)
0137      *
0138      */
0139     if (wp != rp) {
0140         /* Not empty, we have received chars...
0141          * Read as much as possible from DMA buffer
0142          */
0143         size = READ_REG(&regs->rx0size);
0144 
0145         /* Get number of bytes available in RX buffer */
0146         bds_hw_avail = grcan_hw_rxavail(rp, wp, size);
0147 
0148         addr = (unsigned int)pDev->rx;
0149         source = (struct grcanfd_bd0 *)(addr + rp);
0150         dest = buffer;
0151         rxmax = (struct grcanfd_bd0 *)(addr + size);
0152         ret = bds_tot = 0;
0153 
0154         /* Read as many can messages as possible */
0155         while ((ret < max) && (bds_tot < bds_hw_avail)) {
0156             /* Read CAN message from DMA buffer */
0157             *(uint64_t *)&tmp = READ_DMA_DOUBLE(source);
0158             if (tmp.head[1] & 0x4) {
0159                 DBGC(DBG_RX, "overrun\n");
0160             }
0161             if (tmp.head[1] & 0x2) {
0162                 DBGC(DBG_RX, "bus-off mode\n");
0163             }
0164             if (tmp.head[1] & 0x1) {
0165                 DBGC(DBG_RX, "error-passive mode\n");
0166             }
0167             /* Convert one grcan CAN message to one "software" CAN message */
0168             dest->extended = tmp.head[0] >> 31;
0169             dest->rtr = (tmp.head[0] >> 30) & 0x1;
0170             if (dest->extended) {
0171                 dest->id = tmp.head[0] & 0x3fffffff;
0172             } else {
0173                 dest->id = (tmp.head[0] >> 18) & 0xfff;
0174             }
0175             dest->fdopts = (tmp.head[1] >> 25) & GRCAN_FDMASK;
0176             dlc = tmp.head[1] >> 28;
0177             if (dest->fdopts & GRCAN_FDOPT_FDFRM) {
0178                 dest->len = dlc2len[dlc];
0179             } else {
0180                 dest->len = dlc;
0181                 if (dlc > 8)
0182                     dest->len = 8;
0183             }
0184 
0185             dp = (uint64_t *)&source->data0;
0186             for (j = 0; j < ((dest->len + 7) / 8); j++) {
0187                 dest->data.dwords[j] = READ_DMA_DOUBLE(dp);
0188                 if (++dp >= (uint64_t *)rxmax)
0189                     dp = (uint64_t *)addr; /* wrap around */
0190             }
0191 
0192             /* wrap around if neccessary */
0193             bds = grcan_numbds(dest->len);
0194             source += bds;
0195             if (source >= rxmax) {
0196                 source = (struct grcanfd_bd0 *)
0197                      ((void *)source - size);
0198             }
0199             dest++; /* straight user buffer */
0200             ret++;
0201             bds_tot += bds;
0202         }
0203 
0204         /* A bus off interrupt may have occured after checking pDev->started */
0205         SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
0206         if (pDev->started == STATE_STARTED) {
0207             regs->rx0rd = (unsigned int) source - addr;
0208             regs->rx0ctrl = GRCAN_RXCTRL_ENABLE;
0209         } else {
0210             DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
0211             ret = state2err[pDev->started];
0212         }
0213         SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
0214 
0215         return ret;
0216     }
0217     return 0;
0218 }
0219 
0220 int grcanfd_read(void *d, CANFDMsg *msg, size_t ucount)
0221 {
0222     struct grcan_priv *pDev = d;
0223     CANFDMsg *dest;
0224     unsigned int count, left;
0225     int nread;
0226     int req_cnt;
0227 
0228     FUNCDBG();
0229 
0230     dest = msg;
0231     req_cnt = ucount;
0232 
0233     if ( (!dest) || (req_cnt<1) )
0234         return GRCAN_RET_INVARG;
0235 
0236     if (pDev->started != STATE_STARTED) {
0237         return GRCAN_RET_NOTSTARTED;
0238     }
0239 
0240     DBGC(DBG_RX, "grcan_read [%p]: buf: %p len: %u\n", d, msg, (unsigned int) ucount);
0241 
0242     nread = grcan_hw_read_try_fd(pDev,pDev->regs,dest,req_cnt);
0243     if (nread < 0) {
0244         return nread;
0245     }
0246     count = nread;
0247     if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
0248         if ( count > 0 ) {
0249             /* Successfully received messages (at least one) */
0250             return count;
0251         }
0252 
0253         /* nothing read, shall we block? */
0254         if ( !pDev->rxblock ) {
0255             /* non-blocking mode */
0256             return GRCAN_RET_TIMEOUT;
0257         }
0258     }
0259 
0260     while (count == 0 || (pDev->rxcomplete && (count!=req_cnt))) {
0261         if (!pDev->rxcomplete) {
0262             left = 1; /* return as soon as there is one message available */
0263         } else {
0264             left = req_cnt - count;     /* return as soon as all data are available */
0265 
0266             /* never wait for more than the half the maximum size of the receive buffer 
0267              * Why? We need some time to copy buffer before to catch up with hw,
0268              * otherwise we would have to copy everything when the data has been
0269              * received.
0270              */
0271             if (left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2)){
0272                 left = (pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2;
0273             }
0274         }
0275 
0276         nread = grcan_wait_rxdata(pDev, left);
0277         if (nread) {
0278             /* The wait has been aborted, probably due to
0279              * the device driver has been closed by another
0280              * thread or a bus-off. Return error code.
0281              */
0282             return nread;
0283         }
0284 
0285         /* Try read bytes from circular buffer */
0286         nread = grcan_hw_read_try_fd(
0287                 pDev,
0288                 pDev->regs,
0289                 dest+count,
0290                 req_cnt-count);
0291 
0292         if (nread < 0) {
0293             /* The read was aborted by bus-off. */
0294             return nread;
0295         }
0296         count += nread;
0297     }
0298     /* no need to unmask IRQ as IRQ Handler do that for us. */
0299     return count;
0300 }
0301 
0302 static int grcan_hw_write_try_fd(
0303     struct grcan_priv *pDev,
0304     struct grcan_regs *regs,
0305     CANFDMsg *buffer,
0306     int count)
0307 {
0308     unsigned int rp, wp, size, addr;
0309     int ret;
0310     struct grcanfd_bd0 *dest, *txmax;
0311     CANFDMsg *source = (CANFDMsg *) buffer;
0312     int space_left;
0313     unsigned int tmp;
0314     int i, bds;
0315     uint64_t *dp;
0316     uint8_t dlc;
0317     SPIN_IRQFLAGS(oldLevel);
0318 
0319     DBGC(DBG_TX, "\n");
0320 
0321     rp = READ_REG(&regs->tx0rd);
0322     wp = READ_REG(&regs->tx0wr);
0323     size = READ_REG(&regs->tx0size);
0324     space_left = grcan_hw_txspace(rp, wp, size);
0325 
0326     addr = (unsigned int)pDev->tx;
0327     dest = (struct grcanfd_bd0 *)(addr + wp);
0328     txmax = (struct grcanfd_bd0 *)(addr + size);
0329     ret = 0;
0330 
0331     while (source < &buffer[count]) {
0332         /* Get the number of descriptors to wait for */
0333         if (source->fdopts & GRCAN_FDOPT_FDFRM)
0334             bds = grcan_numbds(source->len); /* next msg's buffers */
0335         else
0336             bds = 1;
0337         if (space_left < bds)
0338             break;
0339 
0340         /* Convert and write CAN message to DMA buffer */
0341         dlc = grcan_len2dlc(source->len);
0342         if (dlc < 0) {
0343             /* Bad user input. Report the number of written messages
0344              * or an error when non sent.
0345              */
0346             if (ret <= 0)
0347                 return GRCAN_RET_INVARG;
0348             break;
0349         }
0350         dest->head[1] = (dlc << 28) |
0351                 ((source->fdopts & GRCAN_FDMASK) << 25);
0352         dp = &dest->data0;
0353         for (i = 0; i < ((source->len + 7) / 8); i++) {
0354             *dp++ = source->data.dwords[i];
0355             if (dp >= (uint64_t *)txmax)
0356                 dp = (uint64_t *)addr; /* wrap around */
0357         }
0358         if (source->extended) {
0359             tmp = (1 << 31) | (source->id & 0x3fffffff);
0360         } else {
0361             tmp = (source->id & 0xfff) << 18;
0362         }
0363         if (source->rtr)
0364             tmp |= (1 << 30);
0365         dest->head[0] = tmp;
0366         source++;   /* straight user buffer */
0367         dest += bds;
0368         if (dest >= txmax)
0369             dest = (struct grcanfd_bd0 *)((void *)dest - size);
0370         space_left -= bds;
0371         ret++;
0372     }
0373 
0374     /* A bus off interrupt may have occured after checking pDev->started */
0375     SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
0376     if (pDev->started == STATE_STARTED) {
0377         regs->tx0wr = (unsigned int) dest - addr;
0378         regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
0379     } else {
0380         DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
0381         ret = state2err[pDev->started];
0382     }
0383     SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
0384 
0385     return ret;
0386 }
0387 
0388 int grcanfd_write(
0389     void *d,
0390     CANFDMsg *msg,
0391     size_t ucount)
0392 {
0393     struct grcan_priv *pDev = d;
0394     CANFDMsg *source, *curr;
0395     unsigned int count, left;
0396     int nwritten;
0397     int req_cnt;
0398 
0399     DBGC(DBG_TX,"\n");
0400 
0401     if ((pDev->started != STATE_STARTED) || pDev->config.silent || pDev->flushing)
0402         return GRCAN_RET_NOTSTARTED;
0403 
0404     req_cnt = ucount;
0405     curr = source = (CANFDMsg *) msg;
0406 
0407     /* check proper length and buffer pointer */
0408     if (( req_cnt < 1) || (source == NULL) ){
0409         return GRCAN_RET_INVARG;
0410     }
0411 
0412     nwritten = grcan_hw_write_try_fd(pDev,pDev->regs,source,req_cnt);
0413     if (nwritten < 0) {
0414         return nwritten;
0415     }
0416     count = nwritten;
0417     if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
0418         if ( count > 0 ) {
0419             /* Successfully transmitted chars (at least one char) */
0420             return count;
0421         }
0422 
0423         /* nothing written, shall we block? */
0424         if ( !pDev->txblock ) {
0425             /* non-blocking mode */
0426             return GRCAN_RET_TIMEOUT;
0427         }
0428     }
0429 
0430     /* if in txcomplete mode we need to transmit all chars */
0431     while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){
0432         /*** block until room to fit all or as much of transmit buffer
0433          * as possible before IRQ comes. Set up a valid IRQ point so
0434          * that an IRQ is triggered when we can put a chunk of data
0435          * into transmit fifo.
0436          */
0437 
0438         /* Get the number of descriptors to wait for */
0439         curr = &source[count];
0440         if (curr->fdopts & GRCAN_FDOPT_FDFRM)
0441             left = grcan_numbds(curr->len); /* next msg's buffers */
0442         else
0443             left = 1;
0444 
0445         if (pDev->txcomplete) {
0446             /* Wait for all messages to fit into descriptor table.
0447              * Assume all following msgs are single descriptors.
0448              */
0449             left += req_cnt - count - 1;
0450             if (left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2)) {
0451                 left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2;
0452             }
0453 
0454         }
0455 
0456         nwritten = grcan_wait_txspace(pDev,left);
0457         /* Wait until more room in transmit buffer */
0458         if ( nwritten ) {
0459             /* The wait has been aborted, probably due to 
0460              * the device driver has been closed by another
0461              * thread. To avoid deadlock we return directly
0462              * with error status.
0463              */
0464             return nwritten;
0465         }
0466 
0467         /* Try read bytes from circular buffer */
0468         nwritten = grcan_hw_write_try_fd(
0469             pDev,
0470             pDev->regs,
0471             source+count,
0472             req_cnt-count);
0473 
0474         if (nwritten < 0) {
0475             /* Write was aborted by bus-off. */
0476             return nwritten;
0477         }
0478         count += nwritten;
0479     }
0480     /* no need to unmask IRQ as IRQ Handler do that for us. */
0481 
0482     return count;
0483 }
0484 
0485 int grcanfd_set_speed(void *d, unsigned int nom_hz, unsigned int fd_hz)
0486 {
0487     struct grcan_priv *pDev = d;
0488     struct grlib_canbtrs_timing nom, fd;
0489     int ret;
0490 
0491     FUNCDBG();
0492 
0493     /* cannot change speed during run mode */
0494     if ((pDev->started == STATE_STARTED) || !pDev->fd_capable)
0495         return -1;
0496 
0497     /* get speed rate from argument */
0498     ret = grlib_canbtrs_calc_timing(
0499         nom_hz, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
0500         &grcanfd_nom_btrs_ranges, &nom);
0501     if ( ret )
0502         return -2;
0503     ret = grlib_canbtrs_calc_timing(
0504         fd_hz, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
0505         &grcanfd_fd_btrs_ranges, &fd);
0506     if ( ret )
0507         return -2;
0508 
0509     /* save timing/speed */
0510     pDev->config.timing = *(struct grcan_timing *)&nom;
0511     pDev->config.timing_fd.scaler = fd.scaler;
0512     pDev->config.timing_fd.ps1 = fd.ps1;
0513     pDev->config.timing_fd.ps2 = fd.ps2;
0514     pDev->config.timing_fd.sjw = fd.rsj;
0515     pDev->config.timing_fd.resv_zero = 0;
0516     pDev->config_changed = 1;
0517 
0518     return 0;
0519 
0520 }
0521 
0522 int grcanfd_set_btrs(
0523     void *d,
0524     const struct grcanfd_timing *nominal,
0525     const struct grcanfd_timing *fd)
0526 {
0527     struct grcan_priv *pDev = d;
0528 
0529     FUNCDBG();
0530 
0531     /* Set BTR registers manually
0532      * Read GRCAN/HurriCANe Manual.
0533      */
0534     if ((pDev->started == STATE_STARTED) || !pDev->fd_capable)
0535         return -1;
0536 
0537     if (!nominal)
0538         return -2;
0539 
0540     pDev->config.timing.scaler = nominal->scaler;
0541     pDev->config.timing.ps1 = nominal->ps1;
0542     pDev->config.timing.ps2 = nominal->ps2;
0543     pDev->config.timing.rsj = nominal->sjw;
0544     pDev->config.timing.bpr = 0;
0545     if (fd) {
0546         pDev->config.timing_fd = *fd;
0547     } else {
0548         memset(&pDev->config.timing_fd, 0,
0549             sizeof(struct grcanfd_timing));
0550     }
0551     pDev->config_changed = 1;
0552 
0553     return 0;
0554 }