mcp251xfd-chip-fifo.c (3158B)
1// SPDX-License-Identifier: GPL-2.0 2// 3// mcp251xfd - Microchip MCP251xFD Family CAN controller driver 4// 5// Copyright (c) 2019, 2020, 2021 Pengutronix, 6// Marc Kleine-Budde <kernel@pengutronix.de> 7// 8// Based on: 9// 10// CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface 11// 12// Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org> 13// 14 15#include <linux/bitfield.h> 16 17#include "mcp251xfd.h" 18 19static int 20mcp251xfd_chip_rx_fifo_init_one(const struct mcp251xfd_priv *priv, 21 const struct mcp251xfd_rx_ring *ring) 22{ 23 u32 fifo_con; 24 25 /* Enable RXOVIE on _all_ RX FIFOs, not just the last one. 26 * 27 * FIFOs hit by a RX MAB overflow and RXOVIE enabled will 28 * generate a RXOVIF, use this to properly detect RX MAB 29 * overflows. 30 */ 31 fifo_con = FIELD_PREP(MCP251XFD_REG_FIFOCON_FSIZE_MASK, 32 ring->obj_num - 1) | 33 MCP251XFD_REG_FIFOCON_RXTSEN | 34 MCP251XFD_REG_FIFOCON_RXOVIE | 35 MCP251XFD_REG_FIFOCON_TFNRFNIE; 36 37 if (mcp251xfd_is_fd_mode(priv)) 38 fifo_con |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, 39 MCP251XFD_REG_FIFOCON_PLSIZE_64); 40 else 41 fifo_con |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, 42 MCP251XFD_REG_FIFOCON_PLSIZE_8); 43 44 return regmap_write(priv->map_reg, 45 MCP251XFD_REG_FIFOCON(ring->fifo_nr), fifo_con); 46} 47 48static int 49mcp251xfd_chip_rx_filter_init_one(const struct mcp251xfd_priv *priv, 50 const struct mcp251xfd_rx_ring *ring) 51{ 52 u32 fltcon; 53 54 fltcon = MCP251XFD_REG_FLTCON_FLTEN(ring->nr) | 55 MCP251XFD_REG_FLTCON_FBP(ring->nr, ring->fifo_nr); 56 57 return regmap_update_bits(priv->map_reg, 58 MCP251XFD_REG_FLTCON(ring->nr >> 2), 59 MCP251XFD_REG_FLTCON_FLT_MASK(ring->nr), 60 fltcon); 61} 62 63int mcp251xfd_chip_fifo_init(const struct mcp251xfd_priv *priv) 64{ 65 const struct mcp251xfd_tx_ring *tx_ring = priv->tx; 66 const struct mcp251xfd_rx_ring *rx_ring; 67 u32 val; 68 int err, n; 69 70 /* TEF */ 71 val = FIELD_PREP(MCP251XFD_REG_TEFCON_FSIZE_MASK, 72 tx_ring->obj_num - 1) | 73 MCP251XFD_REG_TEFCON_TEFTSEN | 74 MCP251XFD_REG_TEFCON_TEFOVIE | 75 MCP251XFD_REG_TEFCON_TEFNEIE; 76 77 err = regmap_write(priv->map_reg, MCP251XFD_REG_TEFCON, val); 78 if (err) 79 return err; 80 81 /* TX FIFO */ 82 val = FIELD_PREP(MCP251XFD_REG_FIFOCON_FSIZE_MASK, 83 tx_ring->obj_num - 1) | 84 MCP251XFD_REG_FIFOCON_TXEN | 85 MCP251XFD_REG_FIFOCON_TXATIE; 86 87 if (mcp251xfd_is_fd_mode(priv)) 88 val |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, 89 MCP251XFD_REG_FIFOCON_PLSIZE_64); 90 else 91 val |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, 92 MCP251XFD_REG_FIFOCON_PLSIZE_8); 93 94 if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) 95 val |= FIELD_PREP(MCP251XFD_REG_FIFOCON_TXAT_MASK, 96 MCP251XFD_REG_FIFOCON_TXAT_ONE_SHOT); 97 else 98 val |= FIELD_PREP(MCP251XFD_REG_FIFOCON_TXAT_MASK, 99 MCP251XFD_REG_FIFOCON_TXAT_UNLIMITED); 100 101 err = regmap_write(priv->map_reg, 102 MCP251XFD_REG_FIFOCON(priv->tx->fifo_nr), 103 val); 104 if (err) 105 return err; 106 107 /* RX FIFOs */ 108 mcp251xfd_for_each_rx_ring(priv, rx_ring, n) { 109 err = mcp251xfd_chip_rx_fifo_init_one(priv, rx_ring); 110 if (err) 111 return err; 112 113 err = mcp251xfd_chip_rx_filter_init_one(priv, rx_ring); 114 if (err) 115 return err; 116 } 117 118 return 0; 119}