Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // mcp251xfd - Microchip MCP251xFD Family CAN controller driver
0004 //
0005 // Copyright (c) 2019, 2020, 2021 Pengutronix,
0006 //               Marc Kleine-Budde <kernel@pengutronix.de>
0007 //
0008 // Based on:
0009 //
0010 // CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
0011 //
0012 // Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
0013 //
0014 
0015 #include <linux/bitfield.h>
0016 
0017 #include "mcp251xfd.h"
0018 
0019 static int
0020 mcp251xfd_chip_rx_fifo_init_one(const struct mcp251xfd_priv *priv,
0021                 const struct mcp251xfd_rx_ring *ring)
0022 {
0023     u32 fifo_con;
0024 
0025     /* Enable RXOVIE on _all_ RX FIFOs, not just the last one.
0026      *
0027      * FIFOs hit by a RX MAB overflow and RXOVIE enabled will
0028      * generate a RXOVIF, use this to properly detect RX MAB
0029      * overflows.
0030      */
0031     fifo_con = FIELD_PREP(MCP251XFD_REG_FIFOCON_FSIZE_MASK,
0032                   ring->obj_num - 1) |
0033         MCP251XFD_REG_FIFOCON_RXTSEN |
0034         MCP251XFD_REG_FIFOCON_RXOVIE |
0035         MCP251XFD_REG_FIFOCON_TFNRFNIE;
0036 
0037     if (mcp251xfd_is_fd_mode(priv))
0038         fifo_con |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK,
0039                        MCP251XFD_REG_FIFOCON_PLSIZE_64);
0040     else
0041         fifo_con |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK,
0042                        MCP251XFD_REG_FIFOCON_PLSIZE_8);
0043 
0044     return regmap_write(priv->map_reg,
0045                 MCP251XFD_REG_FIFOCON(ring->fifo_nr), fifo_con);
0046 }
0047 
0048 static int
0049 mcp251xfd_chip_rx_filter_init_one(const struct mcp251xfd_priv *priv,
0050                   const struct mcp251xfd_rx_ring *ring)
0051 {
0052     u32 fltcon;
0053 
0054     fltcon = MCP251XFD_REG_FLTCON_FLTEN(ring->nr) |
0055         MCP251XFD_REG_FLTCON_FBP(ring->nr, ring->fifo_nr);
0056 
0057     return regmap_update_bits(priv->map_reg,
0058                   MCP251XFD_REG_FLTCON(ring->nr >> 2),
0059                   MCP251XFD_REG_FLTCON_FLT_MASK(ring->nr),
0060                   fltcon);
0061 }
0062 
0063 int mcp251xfd_chip_fifo_init(const struct mcp251xfd_priv *priv)
0064 {
0065     const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
0066     const struct mcp251xfd_rx_ring *rx_ring;
0067     u32 val;
0068     int err, n;
0069 
0070     /* TEF */
0071     val = FIELD_PREP(MCP251XFD_REG_TEFCON_FSIZE_MASK,
0072              tx_ring->obj_num - 1) |
0073         MCP251XFD_REG_TEFCON_TEFTSEN |
0074         MCP251XFD_REG_TEFCON_TEFOVIE |
0075         MCP251XFD_REG_TEFCON_TEFNEIE;
0076 
0077     err = regmap_write(priv->map_reg, MCP251XFD_REG_TEFCON, val);
0078     if (err)
0079         return err;
0080 
0081     /* TX FIFO */
0082     val = FIELD_PREP(MCP251XFD_REG_FIFOCON_FSIZE_MASK,
0083              tx_ring->obj_num - 1) |
0084         MCP251XFD_REG_FIFOCON_TXEN |
0085         MCP251XFD_REG_FIFOCON_TXATIE;
0086 
0087     if (mcp251xfd_is_fd_mode(priv))
0088         val |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK,
0089                   MCP251XFD_REG_FIFOCON_PLSIZE_64);
0090     else
0091         val |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK,
0092                   MCP251XFD_REG_FIFOCON_PLSIZE_8);
0093 
0094     if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
0095         val |= FIELD_PREP(MCP251XFD_REG_FIFOCON_TXAT_MASK,
0096                   MCP251XFD_REG_FIFOCON_TXAT_ONE_SHOT);
0097     else
0098         val |= FIELD_PREP(MCP251XFD_REG_FIFOCON_TXAT_MASK,
0099                   MCP251XFD_REG_FIFOCON_TXAT_UNLIMITED);
0100 
0101     err = regmap_write(priv->map_reg,
0102                MCP251XFD_REG_FIFOCON(priv->tx->fifo_nr),
0103                val);
0104     if (err)
0105         return err;
0106 
0107     /* RX FIFOs */
0108     mcp251xfd_for_each_rx_ring(priv, rx_ring, n) {
0109         err = mcp251xfd_chip_rx_fifo_init_one(priv, rx_ring);
0110         if (err)
0111             return err;
0112 
0113         err = mcp251xfd_chip_rx_filter_init_one(priv, rx_ring);
0114         if (err)
0115             return err;
0116     }
0117 
0118     return 0;
0119 }