162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright (c) 2019, 2020, 2021 Pengutronix,
662306a36Sopenharmony_ci//               Marc Kleine-Budde <kernel@pengutronix.de>
762306a36Sopenharmony_ci//
862306a36Sopenharmony_ci// Based on:
962306a36Sopenharmony_ci//
1062306a36Sopenharmony_ci// CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
1162306a36Sopenharmony_ci//
1262306a36Sopenharmony_ci// Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
1362306a36Sopenharmony_ci//
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <asm/unaligned.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "mcp251xfd.h"
1862306a36Sopenharmony_ci#include "mcp251xfd-ram.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic inline u8
2162306a36Sopenharmony_cimcp251xfd_cmd_prepare_write_reg(const struct mcp251xfd_priv *priv,
2262306a36Sopenharmony_ci				union mcp251xfd_write_reg_buf *write_reg_buf,
2362306a36Sopenharmony_ci				const u16 reg, const u32 mask, const u32 val)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	u8 first_byte, last_byte, len;
2662306a36Sopenharmony_ci	u8 *data;
2762306a36Sopenharmony_ci	__le32 val_le32;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	first_byte = mcp251xfd_first_byte_set(mask);
3062306a36Sopenharmony_ci	last_byte = mcp251xfd_last_byte_set(mask);
3162306a36Sopenharmony_ci	len = last_byte - first_byte + 1;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	data = mcp251xfd_spi_cmd_write(priv, write_reg_buf, reg + first_byte, len);
3462306a36Sopenharmony_ci	val_le32 = cpu_to_le32(val >> BITS_PER_BYTE * first_byte);
3562306a36Sopenharmony_ci	memcpy(data, &val_le32, len);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG)) {
3862306a36Sopenharmony_ci		len += sizeof(write_reg_buf->nocrc.cmd);
3962306a36Sopenharmony_ci	} else if (len == 1) {
4062306a36Sopenharmony_ci		u16 crc;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci		/* CRC */
4362306a36Sopenharmony_ci		len += sizeof(write_reg_buf->safe.cmd);
4462306a36Sopenharmony_ci		crc = mcp251xfd_crc16_compute(&write_reg_buf->safe, len);
4562306a36Sopenharmony_ci		put_unaligned_be16(crc, (void *)write_reg_buf + len);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci		/* Total length */
4862306a36Sopenharmony_ci		len += sizeof(write_reg_buf->safe.crc);
4962306a36Sopenharmony_ci	} else {
5062306a36Sopenharmony_ci		u16 crc;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci		mcp251xfd_spi_cmd_crc_set_len_in_reg(&write_reg_buf->crc.cmd,
5362306a36Sopenharmony_ci						     len);
5462306a36Sopenharmony_ci		/* CRC */
5562306a36Sopenharmony_ci		len += sizeof(write_reg_buf->crc.cmd);
5662306a36Sopenharmony_ci		crc = mcp251xfd_crc16_compute(&write_reg_buf->crc, len);
5762306a36Sopenharmony_ci		put_unaligned_be16(crc, (void *)write_reg_buf + len);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci		/* Total length */
6062306a36Sopenharmony_ci		len += sizeof(write_reg_buf->crc.crc);
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return len;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic void
6762306a36Sopenharmony_cimcp251xfd_ring_init_tef(struct mcp251xfd_priv *priv, u16 *base)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct mcp251xfd_tef_ring *tef_ring;
7062306a36Sopenharmony_ci	struct spi_transfer *xfer;
7162306a36Sopenharmony_ci	u32 val;
7262306a36Sopenharmony_ci	u16 addr;
7362306a36Sopenharmony_ci	u8 len;
7462306a36Sopenharmony_ci	int i;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	/* TEF */
7762306a36Sopenharmony_ci	tef_ring = priv->tef;
7862306a36Sopenharmony_ci	tef_ring->head = 0;
7962306a36Sopenharmony_ci	tef_ring->tail = 0;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/* TEF- and TX-FIFO have same number of objects */
8262306a36Sopenharmony_ci	*base = mcp251xfd_get_tef_obj_addr(priv->tx->obj_num);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	/* FIFO IRQ enable */
8562306a36Sopenharmony_ci	addr = MCP251XFD_REG_TEFCON;
8662306a36Sopenharmony_ci	val = MCP251XFD_REG_TEFCON_TEFOVIE | MCP251XFD_REG_TEFCON_TEFNEIE;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	len = mcp251xfd_cmd_prepare_write_reg(priv, &tef_ring->irq_enable_buf,
8962306a36Sopenharmony_ci					      addr, val, val);
9062306a36Sopenharmony_ci	tef_ring->irq_enable_xfer.tx_buf = &tef_ring->irq_enable_buf;
9162306a36Sopenharmony_ci	tef_ring->irq_enable_xfer.len = len;
9262306a36Sopenharmony_ci	spi_message_init_with_transfers(&tef_ring->irq_enable_msg,
9362306a36Sopenharmony_ci					&tef_ring->irq_enable_xfer, 1);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	/* FIFO increment TEF tail pointer */
9662306a36Sopenharmony_ci	addr = MCP251XFD_REG_TEFCON;
9762306a36Sopenharmony_ci	val = MCP251XFD_REG_TEFCON_UINC;
9862306a36Sopenharmony_ci	len = mcp251xfd_cmd_prepare_write_reg(priv, &tef_ring->uinc_buf,
9962306a36Sopenharmony_ci					      addr, val, val);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tef_ring->uinc_xfer); i++) {
10262306a36Sopenharmony_ci		xfer = &tef_ring->uinc_xfer[i];
10362306a36Sopenharmony_ci		xfer->tx_buf = &tef_ring->uinc_buf;
10462306a36Sopenharmony_ci		xfer->len = len;
10562306a36Sopenharmony_ci		xfer->cs_change = 1;
10662306a36Sopenharmony_ci		xfer->cs_change_delay.value = 0;
10762306a36Sopenharmony_ci		xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* "cs_change == 1" on the last transfer results in an active
11162306a36Sopenharmony_ci	 * chip select after the complete SPI message. This causes the
11262306a36Sopenharmony_ci	 * controller to interpret the next register access as
11362306a36Sopenharmony_ci	 * data. Set "cs_change" of the last transfer to "0" to
11462306a36Sopenharmony_ci	 * properly deactivate the chip select at the end of the
11562306a36Sopenharmony_ci	 * message.
11662306a36Sopenharmony_ci	 */
11762306a36Sopenharmony_ci	xfer->cs_change = 0;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (priv->tx_coalesce_usecs_irq || priv->tx_obj_num_coalesce_irq) {
12062306a36Sopenharmony_ci		val = MCP251XFD_REG_TEFCON_UINC |
12162306a36Sopenharmony_ci			MCP251XFD_REG_TEFCON_TEFOVIE |
12262306a36Sopenharmony_ci			MCP251XFD_REG_TEFCON_TEFHIE;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci		len = mcp251xfd_cmd_prepare_write_reg(priv,
12562306a36Sopenharmony_ci						      &tef_ring->uinc_irq_disable_buf,
12662306a36Sopenharmony_ci						      addr, val, val);
12762306a36Sopenharmony_ci		xfer->tx_buf = &tef_ring->uinc_irq_disable_buf;
12862306a36Sopenharmony_ci		xfer->len = len;
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic void
13362306a36Sopenharmony_cimcp251xfd_tx_ring_init_tx_obj(const struct mcp251xfd_priv *priv,
13462306a36Sopenharmony_ci			      const struct mcp251xfd_tx_ring *ring,
13562306a36Sopenharmony_ci			      struct mcp251xfd_tx_obj *tx_obj,
13662306a36Sopenharmony_ci			      const u8 rts_buf_len,
13762306a36Sopenharmony_ci			      const u8 n)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct spi_transfer *xfer;
14062306a36Sopenharmony_ci	u16 addr;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* FIFO load */
14362306a36Sopenharmony_ci	addr = mcp251xfd_get_tx_obj_addr(ring, n);
14462306a36Sopenharmony_ci	if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_TX)
14562306a36Sopenharmony_ci		mcp251xfd_spi_cmd_write_crc_set_addr(&tx_obj->buf.crc.cmd,
14662306a36Sopenharmony_ci						     addr);
14762306a36Sopenharmony_ci	else
14862306a36Sopenharmony_ci		mcp251xfd_spi_cmd_write_nocrc(&tx_obj->buf.nocrc.cmd,
14962306a36Sopenharmony_ci					      addr);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	xfer = &tx_obj->xfer[0];
15262306a36Sopenharmony_ci	xfer->tx_buf = &tx_obj->buf;
15362306a36Sopenharmony_ci	xfer->len = 0;	/* actual len is assigned on the fly */
15462306a36Sopenharmony_ci	xfer->cs_change = 1;
15562306a36Sopenharmony_ci	xfer->cs_change_delay.value = 0;
15662306a36Sopenharmony_ci	xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* FIFO request to send */
15962306a36Sopenharmony_ci	xfer = &tx_obj->xfer[1];
16062306a36Sopenharmony_ci	xfer->tx_buf = &ring->rts_buf;
16162306a36Sopenharmony_ci	xfer->len = rts_buf_len;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	/* SPI message */
16462306a36Sopenharmony_ci	spi_message_init_with_transfers(&tx_obj->msg, tx_obj->xfer,
16562306a36Sopenharmony_ci					ARRAY_SIZE(tx_obj->xfer));
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic void
16962306a36Sopenharmony_cimcp251xfd_ring_init_tx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct mcp251xfd_tx_ring *tx_ring;
17262306a36Sopenharmony_ci	struct mcp251xfd_tx_obj *tx_obj;
17362306a36Sopenharmony_ci	u32 val;
17462306a36Sopenharmony_ci	u16 addr;
17562306a36Sopenharmony_ci	u8 len;
17662306a36Sopenharmony_ci	int i;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	tx_ring = priv->tx;
17962306a36Sopenharmony_ci	tx_ring->head = 0;
18062306a36Sopenharmony_ci	tx_ring->tail = 0;
18162306a36Sopenharmony_ci	tx_ring->base = *base;
18262306a36Sopenharmony_ci	tx_ring->nr = 0;
18362306a36Sopenharmony_ci	tx_ring->fifo_nr = *fifo_nr;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	*base = mcp251xfd_get_tx_obj_addr(tx_ring, tx_ring->obj_num);
18662306a36Sopenharmony_ci	*fifo_nr += 1;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* FIFO request to send */
18962306a36Sopenharmony_ci	addr = MCP251XFD_REG_FIFOCON(tx_ring->fifo_nr);
19062306a36Sopenharmony_ci	val = MCP251XFD_REG_FIFOCON_TXREQ | MCP251XFD_REG_FIFOCON_UINC;
19162306a36Sopenharmony_ci	len = mcp251xfd_cmd_prepare_write_reg(priv, &tx_ring->rts_buf,
19262306a36Sopenharmony_ci					      addr, val, val);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	mcp251xfd_for_each_tx_obj(tx_ring, tx_obj, i)
19562306a36Sopenharmony_ci		mcp251xfd_tx_ring_init_tx_obj(priv, tx_ring, tx_obj, len, i);
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic void
19962306a36Sopenharmony_cimcp251xfd_ring_init_rx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct mcp251xfd_rx_ring *rx_ring;
20262306a36Sopenharmony_ci	struct spi_transfer *xfer;
20362306a36Sopenharmony_ci	u32 val;
20462306a36Sopenharmony_ci	u16 addr;
20562306a36Sopenharmony_ci	u8 len;
20662306a36Sopenharmony_ci	int i, j;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	mcp251xfd_for_each_rx_ring(priv, rx_ring, i) {
20962306a36Sopenharmony_ci		rx_ring->head = 0;
21062306a36Sopenharmony_ci		rx_ring->tail = 0;
21162306a36Sopenharmony_ci		rx_ring->base = *base;
21262306a36Sopenharmony_ci		rx_ring->nr = i;
21362306a36Sopenharmony_ci		rx_ring->fifo_nr = *fifo_nr;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		*base = mcp251xfd_get_rx_obj_addr(rx_ring, rx_ring->obj_num);
21662306a36Sopenharmony_ci		*fifo_nr += 1;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci		/* FIFO IRQ enable */
21962306a36Sopenharmony_ci		addr = MCP251XFD_REG_FIFOCON(rx_ring->fifo_nr);
22062306a36Sopenharmony_ci		val = MCP251XFD_REG_FIFOCON_RXOVIE |
22162306a36Sopenharmony_ci			MCP251XFD_REG_FIFOCON_TFNRFNIE;
22262306a36Sopenharmony_ci		len = mcp251xfd_cmd_prepare_write_reg(priv, &rx_ring->irq_enable_buf,
22362306a36Sopenharmony_ci						      addr, val, val);
22462306a36Sopenharmony_ci		rx_ring->irq_enable_xfer.tx_buf = &rx_ring->irq_enable_buf;
22562306a36Sopenharmony_ci		rx_ring->irq_enable_xfer.len = len;
22662306a36Sopenharmony_ci		spi_message_init_with_transfers(&rx_ring->irq_enable_msg,
22762306a36Sopenharmony_ci						&rx_ring->irq_enable_xfer, 1);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci		/* FIFO increment RX tail pointer */
23062306a36Sopenharmony_ci		val = MCP251XFD_REG_FIFOCON_UINC;
23162306a36Sopenharmony_ci		len = mcp251xfd_cmd_prepare_write_reg(priv, &rx_ring->uinc_buf,
23262306a36Sopenharmony_ci						      addr, val, val);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(rx_ring->uinc_xfer); j++) {
23562306a36Sopenharmony_ci			xfer = &rx_ring->uinc_xfer[j];
23662306a36Sopenharmony_ci			xfer->tx_buf = &rx_ring->uinc_buf;
23762306a36Sopenharmony_ci			xfer->len = len;
23862306a36Sopenharmony_ci			xfer->cs_change = 1;
23962306a36Sopenharmony_ci			xfer->cs_change_delay.value = 0;
24062306a36Sopenharmony_ci			xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
24162306a36Sopenharmony_ci		}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		/* "cs_change == 1" on the last transfer results in an
24462306a36Sopenharmony_ci		 * active chip select after the complete SPI
24562306a36Sopenharmony_ci		 * message. This causes the controller to interpret
24662306a36Sopenharmony_ci		 * the next register access as data. Set "cs_change"
24762306a36Sopenharmony_ci		 * of the last transfer to "0" to properly deactivate
24862306a36Sopenharmony_ci		 * the chip select at the end of the message.
24962306a36Sopenharmony_ci		 */
25062306a36Sopenharmony_ci		xfer->cs_change = 0;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci		/* Use 1st RX-FIFO for IRQ coalescing. If enabled
25362306a36Sopenharmony_ci		 * (rx_coalesce_usecs_irq or rx_max_coalesce_frames_irq
25462306a36Sopenharmony_ci		 * is activated), use the last transfer to disable:
25562306a36Sopenharmony_ci		 *
25662306a36Sopenharmony_ci		 * - TFNRFNIE (Receive FIFO Not Empty Interrupt)
25762306a36Sopenharmony_ci		 *
25862306a36Sopenharmony_ci		 * and enable:
25962306a36Sopenharmony_ci		 *
26062306a36Sopenharmony_ci		 * - TFHRFHIE (Receive FIFO Half Full Interrupt)
26162306a36Sopenharmony_ci		 *   - or -
26262306a36Sopenharmony_ci		 * - TFERFFIE (Receive FIFO Full Interrupt)
26362306a36Sopenharmony_ci		 *
26462306a36Sopenharmony_ci		 * depending on rx_max_coalesce_frames_irq.
26562306a36Sopenharmony_ci		 *
26662306a36Sopenharmony_ci		 * The RXOVIE (Overflow Interrupt) is always enabled.
26762306a36Sopenharmony_ci		 */
26862306a36Sopenharmony_ci		if (rx_ring->nr == 0 && (priv->rx_coalesce_usecs_irq ||
26962306a36Sopenharmony_ci					 priv->rx_obj_num_coalesce_irq)) {
27062306a36Sopenharmony_ci			val = MCP251XFD_REG_FIFOCON_UINC |
27162306a36Sopenharmony_ci				MCP251XFD_REG_FIFOCON_RXOVIE;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci			if (priv->rx_obj_num_coalesce_irq == rx_ring->obj_num)
27462306a36Sopenharmony_ci				val |= MCP251XFD_REG_FIFOCON_TFERFFIE;
27562306a36Sopenharmony_ci			else if (priv->rx_obj_num_coalesce_irq)
27662306a36Sopenharmony_ci				val |= MCP251XFD_REG_FIFOCON_TFHRFHIE;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci			len = mcp251xfd_cmd_prepare_write_reg(priv,
27962306a36Sopenharmony_ci							      &rx_ring->uinc_irq_disable_buf,
28062306a36Sopenharmony_ci							      addr, val, val);
28162306a36Sopenharmony_ci			xfer->tx_buf = &rx_ring->uinc_irq_disable_buf;
28262306a36Sopenharmony_ci			xfer->len = len;
28362306a36Sopenharmony_ci		}
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ciint mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	const struct mcp251xfd_rx_ring *rx_ring;
29062306a36Sopenharmony_ci	u16 base = 0, ram_used;
29162306a36Sopenharmony_ci	u8 fifo_nr = 1;
29262306a36Sopenharmony_ci	int i;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	netdev_reset_queue(priv->ndev);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	mcp251xfd_ring_init_tef(priv, &base);
29762306a36Sopenharmony_ci	mcp251xfd_ring_init_rx(priv, &base, &fifo_nr);
29862306a36Sopenharmony_ci	mcp251xfd_ring_init_tx(priv, &base, &fifo_nr);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	/* mcp251xfd_handle_rxif() will iterate over all RX rings.
30162306a36Sopenharmony_ci	 * Rings with their corresponding bit set in
30262306a36Sopenharmony_ci	 * priv->regs_status.rxif are read out.
30362306a36Sopenharmony_ci	 *
30462306a36Sopenharmony_ci	 * If the chip is configured for only 1 RX-FIFO, and if there
30562306a36Sopenharmony_ci	 * is an RX interrupt pending (RXIF in INT register is set),
30662306a36Sopenharmony_ci	 * it must be the 1st RX-FIFO.
30762306a36Sopenharmony_ci	 *
30862306a36Sopenharmony_ci	 * We mark the RXIF of the 1st FIFO as pending here, so that
30962306a36Sopenharmony_ci	 * we can skip the read of the RXIF register in
31062306a36Sopenharmony_ci	 * mcp251xfd_read_regs_status() for the 1 RX-FIFO only case.
31162306a36Sopenharmony_ci	 *
31262306a36Sopenharmony_ci	 * If we use more than 1 RX-FIFO, this value gets overwritten
31362306a36Sopenharmony_ci	 * in mcp251xfd_read_regs_status(), so set it unconditionally
31462306a36Sopenharmony_ci	 * here.
31562306a36Sopenharmony_ci	 */
31662306a36Sopenharmony_ci	priv->regs_status.rxif = BIT(priv->rx[0]->fifo_nr);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (priv->tx_obj_num_coalesce_irq) {
31962306a36Sopenharmony_ci		netdev_dbg(priv->ndev,
32062306a36Sopenharmony_ci			   "FIFO setup: TEF:         0x%03x: %2d*%zu bytes = %4zu bytes (coalesce)\n",
32162306a36Sopenharmony_ci			   mcp251xfd_get_tef_obj_addr(0),
32262306a36Sopenharmony_ci			   priv->tx_obj_num_coalesce_irq,
32362306a36Sopenharmony_ci			   sizeof(struct mcp251xfd_hw_tef_obj),
32462306a36Sopenharmony_ci			   priv->tx_obj_num_coalesce_irq *
32562306a36Sopenharmony_ci			   sizeof(struct mcp251xfd_hw_tef_obj));
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci		netdev_dbg(priv->ndev,
32862306a36Sopenharmony_ci			   "                         0x%03x: %2d*%zu bytes = %4zu bytes\n",
32962306a36Sopenharmony_ci			   mcp251xfd_get_tef_obj_addr(priv->tx_obj_num_coalesce_irq),
33062306a36Sopenharmony_ci			   priv->tx->obj_num - priv->tx_obj_num_coalesce_irq,
33162306a36Sopenharmony_ci			   sizeof(struct mcp251xfd_hw_tef_obj),
33262306a36Sopenharmony_ci			   (priv->tx->obj_num - priv->tx_obj_num_coalesce_irq) *
33362306a36Sopenharmony_ci			   sizeof(struct mcp251xfd_hw_tef_obj));
33462306a36Sopenharmony_ci	} else {
33562306a36Sopenharmony_ci		netdev_dbg(priv->ndev,
33662306a36Sopenharmony_ci			   "FIFO setup: TEF:         0x%03x: %2d*%zu bytes = %4zu bytes\n",
33762306a36Sopenharmony_ci			   mcp251xfd_get_tef_obj_addr(0),
33862306a36Sopenharmony_ci			   priv->tx->obj_num, sizeof(struct mcp251xfd_hw_tef_obj),
33962306a36Sopenharmony_ci			   priv->tx->obj_num * sizeof(struct mcp251xfd_hw_tef_obj));
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	mcp251xfd_for_each_rx_ring(priv, rx_ring, i) {
34362306a36Sopenharmony_ci		if (rx_ring->nr == 0 && priv->rx_obj_num_coalesce_irq) {
34462306a36Sopenharmony_ci			netdev_dbg(priv->ndev,
34562306a36Sopenharmony_ci				   "FIFO setup: RX-%u: FIFO %u/0x%03x: %2u*%u bytes = %4u bytes (coalesce)\n",
34662306a36Sopenharmony_ci				   rx_ring->nr, rx_ring->fifo_nr,
34762306a36Sopenharmony_ci				   mcp251xfd_get_rx_obj_addr(rx_ring, 0),
34862306a36Sopenharmony_ci				   priv->rx_obj_num_coalesce_irq, rx_ring->obj_size,
34962306a36Sopenharmony_ci				   priv->rx_obj_num_coalesce_irq * rx_ring->obj_size);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci			if (priv->rx_obj_num_coalesce_irq == MCP251XFD_FIFO_DEPTH)
35262306a36Sopenharmony_ci				continue;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci			netdev_dbg(priv->ndev,
35562306a36Sopenharmony_ci				   "                         0x%03x: %2u*%u bytes = %4u bytes\n",
35662306a36Sopenharmony_ci				   mcp251xfd_get_rx_obj_addr(rx_ring,
35762306a36Sopenharmony_ci							     priv->rx_obj_num_coalesce_irq),
35862306a36Sopenharmony_ci				   rx_ring->obj_num - priv->rx_obj_num_coalesce_irq,
35962306a36Sopenharmony_ci				   rx_ring->obj_size,
36062306a36Sopenharmony_ci				   (rx_ring->obj_num - priv->rx_obj_num_coalesce_irq) *
36162306a36Sopenharmony_ci				   rx_ring->obj_size);
36262306a36Sopenharmony_ci		} else {
36362306a36Sopenharmony_ci			netdev_dbg(priv->ndev,
36462306a36Sopenharmony_ci				   "FIFO setup: RX-%u: FIFO %u/0x%03x: %2u*%u bytes = %4u bytes\n",
36562306a36Sopenharmony_ci				   rx_ring->nr, rx_ring->fifo_nr,
36662306a36Sopenharmony_ci				   mcp251xfd_get_rx_obj_addr(rx_ring, 0),
36762306a36Sopenharmony_ci				   rx_ring->obj_num, rx_ring->obj_size,
36862306a36Sopenharmony_ci				   rx_ring->obj_num * rx_ring->obj_size);
36962306a36Sopenharmony_ci		}
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	netdev_dbg(priv->ndev,
37362306a36Sopenharmony_ci		   "FIFO setup: TX:   FIFO %u/0x%03x: %2u*%u bytes = %4u bytes\n",
37462306a36Sopenharmony_ci		   priv->tx->fifo_nr,
37562306a36Sopenharmony_ci		   mcp251xfd_get_tx_obj_addr(priv->tx, 0),
37662306a36Sopenharmony_ci		   priv->tx->obj_num, priv->tx->obj_size,
37762306a36Sopenharmony_ci		   priv->tx->obj_num * priv->tx->obj_size);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	netdev_dbg(priv->ndev,
38062306a36Sopenharmony_ci		   "FIFO setup: free:                             %4d bytes\n",
38162306a36Sopenharmony_ci		   MCP251XFD_RAM_SIZE - (base - MCP251XFD_RAM_START));
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	ram_used = base - MCP251XFD_RAM_START;
38462306a36Sopenharmony_ci	if (ram_used > MCP251XFD_RAM_SIZE) {
38562306a36Sopenharmony_ci		netdev_err(priv->ndev,
38662306a36Sopenharmony_ci			   "Error during ring configuration, using more RAM (%u bytes) than available (%u bytes).\n",
38762306a36Sopenharmony_ci			   ram_used, MCP251XFD_RAM_SIZE);
38862306a36Sopenharmony_ci		return -ENOMEM;
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	return 0;
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_civoid mcp251xfd_ring_free(struct mcp251xfd_priv *priv)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	int i;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	for (i = ARRAY_SIZE(priv->rx) - 1; i >= 0; i--) {
39962306a36Sopenharmony_ci		kfree(priv->rx[i]);
40062306a36Sopenharmony_ci		priv->rx[i] = NULL;
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic enum hrtimer_restart mcp251xfd_rx_irq_timer(struct hrtimer *t)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	struct mcp251xfd_priv *priv = container_of(t, struct mcp251xfd_priv,
40762306a36Sopenharmony_ci						   rx_irq_timer);
40862306a36Sopenharmony_ci	struct mcp251xfd_rx_ring *ring = priv->rx[0];
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	if (test_bit(MCP251XFD_FLAGS_DOWN, priv->flags))
41162306a36Sopenharmony_ci		return HRTIMER_NORESTART;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	spi_async(priv->spi, &ring->irq_enable_msg);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	return HRTIMER_NORESTART;
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic enum hrtimer_restart mcp251xfd_tx_irq_timer(struct hrtimer *t)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	struct mcp251xfd_priv *priv = container_of(t, struct mcp251xfd_priv,
42162306a36Sopenharmony_ci						   tx_irq_timer);
42262306a36Sopenharmony_ci	struct mcp251xfd_tef_ring *ring = priv->tef;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	if (test_bit(MCP251XFD_FLAGS_DOWN, priv->flags))
42562306a36Sopenharmony_ci		return HRTIMER_NORESTART;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	spi_async(priv->spi, &ring->irq_enable_msg);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	return HRTIMER_NORESTART;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ciconst struct can_ram_config mcp251xfd_ram_config = {
43362306a36Sopenharmony_ci	.rx = {
43462306a36Sopenharmony_ci		.size[CAN_RAM_MODE_CAN] = sizeof(struct mcp251xfd_hw_rx_obj_can),
43562306a36Sopenharmony_ci		.size[CAN_RAM_MODE_CANFD] = sizeof(struct mcp251xfd_hw_rx_obj_canfd),
43662306a36Sopenharmony_ci		.min = MCP251XFD_RX_OBJ_NUM_MIN,
43762306a36Sopenharmony_ci		.max = MCP251XFD_RX_OBJ_NUM_MAX,
43862306a36Sopenharmony_ci		.def[CAN_RAM_MODE_CAN] = CAN_RAM_NUM_MAX,
43962306a36Sopenharmony_ci		.def[CAN_RAM_MODE_CANFD] = CAN_RAM_NUM_MAX,
44062306a36Sopenharmony_ci		.fifo_num = MCP251XFD_FIFO_RX_NUM,
44162306a36Sopenharmony_ci		.fifo_depth_min = MCP251XFD_RX_FIFO_DEPTH_MIN,
44262306a36Sopenharmony_ci		.fifo_depth_coalesce_min = MCP251XFD_RX_FIFO_DEPTH_COALESCE_MIN,
44362306a36Sopenharmony_ci	},
44462306a36Sopenharmony_ci	.tx = {
44562306a36Sopenharmony_ci		.size[CAN_RAM_MODE_CAN] = sizeof(struct mcp251xfd_hw_tef_obj) +
44662306a36Sopenharmony_ci			sizeof(struct mcp251xfd_hw_tx_obj_can),
44762306a36Sopenharmony_ci		.size[CAN_RAM_MODE_CANFD] = sizeof(struct mcp251xfd_hw_tef_obj) +
44862306a36Sopenharmony_ci			sizeof(struct mcp251xfd_hw_tx_obj_canfd),
44962306a36Sopenharmony_ci		.min = MCP251XFD_TX_OBJ_NUM_MIN,
45062306a36Sopenharmony_ci		.max = MCP251XFD_TX_OBJ_NUM_MAX,
45162306a36Sopenharmony_ci		.def[CAN_RAM_MODE_CAN] = MCP251XFD_TX_OBJ_NUM_CAN_DEFAULT,
45262306a36Sopenharmony_ci		.def[CAN_RAM_MODE_CANFD] = MCP251XFD_TX_OBJ_NUM_CANFD_DEFAULT,
45362306a36Sopenharmony_ci		.fifo_num = MCP251XFD_FIFO_TX_NUM,
45462306a36Sopenharmony_ci		.fifo_depth_min = MCP251XFD_TX_FIFO_DEPTH_MIN,
45562306a36Sopenharmony_ci		.fifo_depth_coalesce_min = MCP251XFD_TX_FIFO_DEPTH_COALESCE_MIN,
45662306a36Sopenharmony_ci	},
45762306a36Sopenharmony_ci	.size = MCP251XFD_RAM_SIZE,
45862306a36Sopenharmony_ci	.fifo_depth = MCP251XFD_FIFO_DEPTH,
45962306a36Sopenharmony_ci};
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ciint mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	const bool fd_mode = mcp251xfd_is_fd_mode(priv);
46462306a36Sopenharmony_ci	struct mcp251xfd_tx_ring *tx_ring = priv->tx;
46562306a36Sopenharmony_ci	struct mcp251xfd_rx_ring *rx_ring;
46662306a36Sopenharmony_ci	u8 tx_obj_size, rx_obj_size;
46762306a36Sopenharmony_ci	u8 rem, i;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	/* switching from CAN-2.0 to CAN-FD mode or vice versa */
47062306a36Sopenharmony_ci	if (fd_mode != test_bit(MCP251XFD_FLAGS_FD_MODE, priv->flags)) {
47162306a36Sopenharmony_ci		struct can_ram_layout layout;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci		can_ram_get_layout(&layout, &mcp251xfd_ram_config, NULL, NULL, fd_mode);
47462306a36Sopenharmony_ci		priv->rx_obj_num = layout.default_rx;
47562306a36Sopenharmony_ci		tx_ring->obj_num = layout.default_tx;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	if (fd_mode) {
47962306a36Sopenharmony_ci		tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_canfd);
48062306a36Sopenharmony_ci		rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_canfd);
48162306a36Sopenharmony_ci		set_bit(MCP251XFD_FLAGS_FD_MODE, priv->flags);
48262306a36Sopenharmony_ci	} else {
48362306a36Sopenharmony_ci		tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_can);
48462306a36Sopenharmony_ci		rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_can);
48562306a36Sopenharmony_ci		clear_bit(MCP251XFD_FLAGS_FD_MODE, priv->flags);
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	tx_ring->obj_size = tx_obj_size;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	rem = priv->rx_obj_num;
49162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(priv->rx) && rem; i++) {
49262306a36Sopenharmony_ci		u8 rx_obj_num;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci		if (i == 0 && priv->rx_obj_num_coalesce_irq)
49562306a36Sopenharmony_ci			rx_obj_num = min_t(u8, priv->rx_obj_num_coalesce_irq * 2,
49662306a36Sopenharmony_ci					   MCP251XFD_FIFO_DEPTH);
49762306a36Sopenharmony_ci		else
49862306a36Sopenharmony_ci			rx_obj_num = min_t(u8, rounddown_pow_of_two(rem),
49962306a36Sopenharmony_ci					   MCP251XFD_FIFO_DEPTH);
50062306a36Sopenharmony_ci		rem -= rx_obj_num;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci		rx_ring = kzalloc(sizeof(*rx_ring) + rx_obj_size * rx_obj_num,
50362306a36Sopenharmony_ci				  GFP_KERNEL);
50462306a36Sopenharmony_ci		if (!rx_ring) {
50562306a36Sopenharmony_ci			mcp251xfd_ring_free(priv);
50662306a36Sopenharmony_ci			return -ENOMEM;
50762306a36Sopenharmony_ci		}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci		rx_ring->obj_num = rx_obj_num;
51062306a36Sopenharmony_ci		rx_ring->obj_size = rx_obj_size;
51162306a36Sopenharmony_ci		priv->rx[i] = rx_ring;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci	priv->rx_ring_num = i;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	hrtimer_init(&priv->rx_irq_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
51662306a36Sopenharmony_ci	priv->rx_irq_timer.function = mcp251xfd_rx_irq_timer;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	hrtimer_init(&priv->tx_irq_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
51962306a36Sopenharmony_ci	priv->tx_irq_timer.function = mcp251xfd_tx_irq_timer;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	return 0;
52262306a36Sopenharmony_ci}
523