xref: /linux/drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c (revision d5c8725cc913f1ab8e2f10a4eda2930bfdc03f1f)
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 <asm/unaligned.h>
16 
17 #include "mcp251xfd.h"
18 
19 static inline u8
20 mcp251xfd_cmd_prepare_write_reg(const struct mcp251xfd_priv *priv,
21 				union mcp251xfd_write_reg_buf *write_reg_buf,
22 				const u16 reg, const u32 mask, const u32 val)
23 {
24 	u8 first_byte, last_byte, len;
25 	u8 *data;
26 	__le32 val_le32;
27 
28 	first_byte = mcp251xfd_first_byte_set(mask);
29 	last_byte = mcp251xfd_last_byte_set(mask);
30 	len = last_byte - first_byte + 1;
31 
32 	data = mcp251xfd_spi_cmd_write(priv, write_reg_buf, reg + first_byte);
33 	val_le32 = cpu_to_le32(val >> BITS_PER_BYTE * first_byte);
34 	memcpy(data, &val_le32, len);
35 
36 	if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG) {
37 		u16 crc;
38 
39 		mcp251xfd_spi_cmd_crc_set_len_in_reg(&write_reg_buf->crc.cmd,
40 						     len);
41 		/* CRC */
42 		len += sizeof(write_reg_buf->crc.cmd);
43 		crc = mcp251xfd_crc16_compute(&write_reg_buf->crc, len);
44 		put_unaligned_be16(crc, (void *)write_reg_buf + len);
45 
46 		/* Total length */
47 		len += sizeof(write_reg_buf->crc.crc);
48 	} else {
49 		len += sizeof(write_reg_buf->nocrc.cmd);
50 	}
51 
52 	return len;
53 }
54 
55 static void
56 mcp251xfd_tx_ring_init_tx_obj(const struct mcp251xfd_priv *priv,
57 			      const struct mcp251xfd_tx_ring *ring,
58 			      struct mcp251xfd_tx_obj *tx_obj,
59 			      const u8 rts_buf_len,
60 			      const u8 n)
61 {
62 	struct spi_transfer *xfer;
63 	u16 addr;
64 
65 	/* FIFO load */
66 	addr = mcp251xfd_get_tx_obj_addr(ring, n);
67 	if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_TX)
68 		mcp251xfd_spi_cmd_write_crc_set_addr(&tx_obj->buf.crc.cmd,
69 						     addr);
70 	else
71 		mcp251xfd_spi_cmd_write_nocrc(&tx_obj->buf.nocrc.cmd,
72 					      addr);
73 
74 	xfer = &tx_obj->xfer[0];
75 	xfer->tx_buf = &tx_obj->buf;
76 	xfer->len = 0;	/* actual len is assigned on the fly */
77 	xfer->cs_change = 1;
78 	xfer->cs_change_delay.value = 0;
79 	xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
80 
81 	/* FIFO request to send */
82 	xfer = &tx_obj->xfer[1];
83 	xfer->tx_buf = &ring->rts_buf;
84 	xfer->len = rts_buf_len;
85 
86 	/* SPI message */
87 	spi_message_init_with_transfers(&tx_obj->msg, tx_obj->xfer,
88 					ARRAY_SIZE(tx_obj->xfer));
89 }
90 
91 void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
92 {
93 	struct mcp251xfd_tef_ring *tef_ring;
94 	struct mcp251xfd_tx_ring *tx_ring;
95 	struct mcp251xfd_rx_ring *rx_ring, *prev_rx_ring = NULL;
96 	struct mcp251xfd_tx_obj *tx_obj;
97 	struct spi_transfer *xfer;
98 	u32 val;
99 	u16 addr;
100 	u8 len;
101 	int i, j;
102 
103 	netdev_reset_queue(priv->ndev);
104 
105 	/* TEF */
106 	tef_ring = priv->tef;
107 	tef_ring->head = 0;
108 	tef_ring->tail = 0;
109 
110 	/* FIFO increment TEF tail pointer */
111 	addr = MCP251XFD_REG_TEFCON;
112 	val = MCP251XFD_REG_TEFCON_UINC;
113 	len = mcp251xfd_cmd_prepare_write_reg(priv, &tef_ring->uinc_buf,
114 					      addr, val, val);
115 
116 	for (j = 0; j < ARRAY_SIZE(tef_ring->uinc_xfer); j++) {
117 		xfer = &tef_ring->uinc_xfer[j];
118 		xfer->tx_buf = &tef_ring->uinc_buf;
119 		xfer->len = len;
120 		xfer->cs_change = 1;
121 		xfer->cs_change_delay.value = 0;
122 		xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
123 	}
124 
125 	/* "cs_change == 1" on the last transfer results in an active
126 	 * chip select after the complete SPI message. This causes the
127 	 * controller to interpret the next register access as
128 	 * data. Set "cs_change" of the last transfer to "0" to
129 	 * properly deactivate the chip select at the end of the
130 	 * message.
131 	 */
132 	xfer->cs_change = 0;
133 
134 	/* TX */
135 	tx_ring = priv->tx;
136 	tx_ring->head = 0;
137 	tx_ring->tail = 0;
138 	tx_ring->base = mcp251xfd_get_tef_obj_addr(tx_ring->obj_num);
139 
140 	/* FIFO request to send */
141 	addr = MCP251XFD_REG_FIFOCON(MCP251XFD_TX_FIFO);
142 	val = MCP251XFD_REG_FIFOCON_TXREQ | MCP251XFD_REG_FIFOCON_UINC;
143 	len = mcp251xfd_cmd_prepare_write_reg(priv, &tx_ring->rts_buf,
144 					      addr, val, val);
145 
146 	mcp251xfd_for_each_tx_obj(tx_ring, tx_obj, i)
147 		mcp251xfd_tx_ring_init_tx_obj(priv, tx_ring, tx_obj, len, i);
148 
149 	/* RX */
150 	mcp251xfd_for_each_rx_ring(priv, rx_ring, i) {
151 		rx_ring->head = 0;
152 		rx_ring->tail = 0;
153 		rx_ring->nr = i;
154 		rx_ring->fifo_nr = MCP251XFD_RX_FIFO(i);
155 
156 		if (!prev_rx_ring)
157 			rx_ring->base =
158 				mcp251xfd_get_tx_obj_addr(tx_ring,
159 							  tx_ring->obj_num);
160 		else
161 			rx_ring->base = prev_rx_ring->base +
162 				prev_rx_ring->obj_size *
163 				prev_rx_ring->obj_num;
164 
165 		prev_rx_ring = rx_ring;
166 
167 		/* FIFO increment RX tail pointer */
168 		addr = MCP251XFD_REG_FIFOCON(rx_ring->fifo_nr);
169 		val = MCP251XFD_REG_FIFOCON_UINC;
170 		len = mcp251xfd_cmd_prepare_write_reg(priv, &rx_ring->uinc_buf,
171 						      addr, val, val);
172 
173 		for (j = 0; j < ARRAY_SIZE(rx_ring->uinc_xfer); j++) {
174 			xfer = &rx_ring->uinc_xfer[j];
175 			xfer->tx_buf = &rx_ring->uinc_buf;
176 			xfer->len = len;
177 			xfer->cs_change = 1;
178 			xfer->cs_change_delay.value = 0;
179 			xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
180 		}
181 
182 		/* "cs_change == 1" on the last transfer results in an
183 		 * active chip select after the complete SPI
184 		 * message. This causes the controller to interpret
185 		 * the next register access as data. Set "cs_change"
186 		 * of the last transfer to "0" to properly deactivate
187 		 * the chip select at the end of the message.
188 		 */
189 		xfer->cs_change = 0;
190 	}
191 }
192 
193 void mcp251xfd_ring_free(struct mcp251xfd_priv *priv)
194 {
195 	int i;
196 
197 	for (i = ARRAY_SIZE(priv->rx) - 1; i >= 0; i--) {
198 		kfree(priv->rx[i]);
199 		priv->rx[i] = NULL;
200 	}
201 }
202 
203 int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
204 {
205 	struct mcp251xfd_tx_ring *tx_ring;
206 	struct mcp251xfd_rx_ring *rx_ring;
207 	int tef_obj_size, tx_obj_size, rx_obj_size;
208 	int tx_obj_num;
209 	int ram_free, i;
210 
211 	tef_obj_size = sizeof(struct mcp251xfd_hw_tef_obj);
212 	if (mcp251xfd_is_fd_mode(priv)) {
213 		tx_obj_num = MCP251XFD_TX_OBJ_NUM_CANFD;
214 		tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_canfd);
215 		rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_canfd);
216 	} else {
217 		tx_obj_num = MCP251XFD_TX_OBJ_NUM_CAN;
218 		tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_can);
219 		rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_can);
220 	}
221 
222 	tx_ring = priv->tx;
223 	tx_ring->obj_num = tx_obj_num;
224 	tx_ring->obj_size = tx_obj_size;
225 
226 	ram_free = MCP251XFD_RAM_SIZE - tx_obj_num *
227 		(tef_obj_size + tx_obj_size);
228 
229 	for (i = 0;
230 	     i < ARRAY_SIZE(priv->rx) && ram_free >= rx_obj_size;
231 	     i++) {
232 		int rx_obj_num;
233 
234 		rx_obj_num = ram_free / rx_obj_size;
235 		rx_obj_num = min(1 << (fls(rx_obj_num) - 1),
236 				 MCP251XFD_RX_OBJ_NUM_MAX);
237 
238 		rx_ring = kzalloc(sizeof(*rx_ring) + rx_obj_size * rx_obj_num,
239 				  GFP_KERNEL);
240 		if (!rx_ring) {
241 			mcp251xfd_ring_free(priv);
242 			return -ENOMEM;
243 		}
244 		rx_ring->obj_num = rx_obj_num;
245 		rx_ring->obj_size = rx_obj_size;
246 		priv->rx[i] = rx_ring;
247 
248 		ram_free -= rx_ring->obj_num * rx_ring->obj_size;
249 	}
250 	priv->rx_ring_num = i;
251 
252 	netdev_dbg(priv->ndev,
253 		   "FIFO setup: TEF: %d*%d bytes = %d bytes, TX: %d*%d bytes = %d bytes\n",
254 		   tx_obj_num, tef_obj_size, tef_obj_size * tx_obj_num,
255 		   tx_obj_num, tx_obj_size, tx_obj_size * tx_obj_num);
256 
257 	mcp251xfd_for_each_rx_ring(priv, rx_ring, i) {
258 		netdev_dbg(priv->ndev,
259 			   "FIFO setup: RX-%d: %d*%d bytes = %d bytes\n",
260 			   i, rx_ring->obj_num, rx_ring->obj_size,
261 			   rx_ring->obj_size * rx_ring->obj_num);
262 	}
263 
264 	netdev_dbg(priv->ndev,
265 		   "FIFO setup: free: %d bytes\n",
266 		   ram_free);
267 
268 	return 0;
269 }
270