Commit | Line | Data |
---|---|---|
55bc37c8 MKB |
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 | ||
617283b9 MKB |
55 | static void |
56 | mcp251xfd_ring_init_tef(struct mcp251xfd_priv *priv, u16 *base) | |
d2d5397f MKB |
57 | { |
58 | struct mcp251xfd_tef_ring *tef_ring; | |
59 | struct spi_transfer *xfer; | |
60 | u32 val; | |
61 | u16 addr; | |
62 | u8 len; | |
63 | int i; | |
64 | ||
65 | /* TEF */ | |
66 | tef_ring = priv->tef; | |
67 | tef_ring->head = 0; | |
68 | tef_ring->tail = 0; | |
69 | ||
617283b9 MKB |
70 | /* TEF- and TX-FIFO have same number of objects */ |
71 | *base = mcp251xfd_get_tef_obj_addr(priv->tx->obj_num); | |
72 | ||
d2d5397f MKB |
73 | /* FIFO increment TEF tail pointer */ |
74 | addr = MCP251XFD_REG_TEFCON; | |
75 | val = MCP251XFD_REG_TEFCON_UINC; | |
76 | len = mcp251xfd_cmd_prepare_write_reg(priv, &tef_ring->uinc_buf, | |
77 | addr, val, val); | |
78 | ||
79 | for (i = 0; i < ARRAY_SIZE(tef_ring->uinc_xfer); i++) { | |
80 | xfer = &tef_ring->uinc_xfer[i]; | |
81 | xfer->tx_buf = &tef_ring->uinc_buf; | |
82 | xfer->len = len; | |
83 | xfer->cs_change = 1; | |
84 | xfer->cs_change_delay.value = 0; | |
85 | xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; | |
86 | } | |
87 | ||
88 | /* "cs_change == 1" on the last transfer results in an active | |
89 | * chip select after the complete SPI message. This causes the | |
90 | * controller to interpret the next register access as | |
91 | * data. Set "cs_change" of the last transfer to "0" to | |
92 | * properly deactivate the chip select at the end of the | |
93 | * message. | |
94 | */ | |
95 | xfer->cs_change = 0; | |
96 | } | |
97 | ||
55bc37c8 MKB |
98 | static void |
99 | mcp251xfd_tx_ring_init_tx_obj(const struct mcp251xfd_priv *priv, | |
100 | const struct mcp251xfd_tx_ring *ring, | |
101 | struct mcp251xfd_tx_obj *tx_obj, | |
102 | const u8 rts_buf_len, | |
103 | const u8 n) | |
104 | { | |
105 | struct spi_transfer *xfer; | |
106 | u16 addr; | |
107 | ||
108 | /* FIFO load */ | |
109 | addr = mcp251xfd_get_tx_obj_addr(ring, n); | |
110 | if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_TX) | |
111 | mcp251xfd_spi_cmd_write_crc_set_addr(&tx_obj->buf.crc.cmd, | |
112 | addr); | |
113 | else | |
114 | mcp251xfd_spi_cmd_write_nocrc(&tx_obj->buf.nocrc.cmd, | |
115 | addr); | |
116 | ||
117 | xfer = &tx_obj->xfer[0]; | |
118 | xfer->tx_buf = &tx_obj->buf; | |
119 | xfer->len = 0; /* actual len is assigned on the fly */ | |
120 | xfer->cs_change = 1; | |
121 | xfer->cs_change_delay.value = 0; | |
122 | xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; | |
123 | ||
124 | /* FIFO request to send */ | |
125 | xfer = &tx_obj->xfer[1]; | |
126 | xfer->tx_buf = &ring->rts_buf; | |
127 | xfer->len = rts_buf_len; | |
128 | ||
129 | /* SPI message */ | |
130 | spi_message_init_with_transfers(&tx_obj->msg, tx_obj->xfer, | |
131 | ARRAY_SIZE(tx_obj->xfer)); | |
132 | } | |
133 | ||
617283b9 MKB |
134 | static void |
135 | mcp251xfd_ring_init_tx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr) | |
55bc37c8 | 136 | { |
55bc37c8 | 137 | struct mcp251xfd_tx_ring *tx_ring; |
55bc37c8 | 138 | struct mcp251xfd_tx_obj *tx_obj; |
55bc37c8 MKB |
139 | u32 val; |
140 | u16 addr; | |
141 | u8 len; | |
d2d5397f | 142 | int i; |
55bc37c8 | 143 | |
55bc37c8 MKB |
144 | tx_ring = priv->tx; |
145 | tx_ring->head = 0; | |
146 | tx_ring->tail = 0; | |
617283b9 | 147 | tx_ring->base = *base; |
c912f19e | 148 | tx_ring->nr = 0; |
617283b9 MKB |
149 | tx_ring->fifo_nr = *fifo_nr; |
150 | ||
151 | *base = mcp251xfd_get_tx_obj_addr(tx_ring, tx_ring->obj_num); | |
152 | *fifo_nr += 1; | |
55bc37c8 MKB |
153 | |
154 | /* FIFO request to send */ | |
c912f19e | 155 | addr = MCP251XFD_REG_FIFOCON(tx_ring->fifo_nr); |
55bc37c8 MKB |
156 | val = MCP251XFD_REG_FIFOCON_TXREQ | MCP251XFD_REG_FIFOCON_UINC; |
157 | len = mcp251xfd_cmd_prepare_write_reg(priv, &tx_ring->rts_buf, | |
158 | addr, val, val); | |
159 | ||
160 | mcp251xfd_for_each_tx_obj(tx_ring, tx_obj, i) | |
161 | mcp251xfd_tx_ring_init_tx_obj(priv, tx_ring, tx_obj, len, i); | |
d2d5397f MKB |
162 | } |
163 | ||
617283b9 MKB |
164 | static void |
165 | mcp251xfd_ring_init_rx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr) | |
d2d5397f | 166 | { |
617283b9 | 167 | struct mcp251xfd_rx_ring *rx_ring; |
d2d5397f MKB |
168 | struct spi_transfer *xfer; |
169 | u32 val; | |
170 | u16 addr; | |
171 | u8 len; | |
172 | int i, j; | |
55bc37c8 | 173 | |
55bc37c8 MKB |
174 | mcp251xfd_for_each_rx_ring(priv, rx_ring, i) { |
175 | rx_ring->head = 0; | |
176 | rx_ring->tail = 0; | |
617283b9 | 177 | rx_ring->base = *base; |
55bc37c8 | 178 | rx_ring->nr = i; |
617283b9 | 179 | rx_ring->fifo_nr = *fifo_nr; |
55bc37c8 | 180 | |
617283b9 MKB |
181 | *base = mcp251xfd_get_rx_obj_addr(rx_ring, rx_ring->obj_num); |
182 | *fifo_nr += 1; | |
55bc37c8 MKB |
183 | |
184 | /* FIFO increment RX tail pointer */ | |
185 | addr = MCP251XFD_REG_FIFOCON(rx_ring->fifo_nr); | |
186 | val = MCP251XFD_REG_FIFOCON_UINC; | |
187 | len = mcp251xfd_cmd_prepare_write_reg(priv, &rx_ring->uinc_buf, | |
188 | addr, val, val); | |
189 | ||
190 | for (j = 0; j < ARRAY_SIZE(rx_ring->uinc_xfer); j++) { | |
191 | xfer = &rx_ring->uinc_xfer[j]; | |
192 | xfer->tx_buf = &rx_ring->uinc_buf; | |
193 | xfer->len = len; | |
194 | xfer->cs_change = 1; | |
195 | xfer->cs_change_delay.value = 0; | |
196 | xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; | |
197 | } | |
198 | ||
199 | /* "cs_change == 1" on the last transfer results in an | |
200 | * active chip select after the complete SPI | |
201 | * message. This causes the controller to interpret | |
202 | * the next register access as data. Set "cs_change" | |
203 | * of the last transfer to "0" to properly deactivate | |
204 | * the chip select at the end of the message. | |
205 | */ | |
206 | xfer->cs_change = 0; | |
207 | } | |
208 | } | |
209 | ||
fa0b68df | 210 | int mcp251xfd_ring_init(struct mcp251xfd_priv *priv) |
d2d5397f | 211 | { |
83daa863 | 212 | const struct mcp251xfd_rx_ring *rx_ring; |
fa0b68df | 213 | u16 base = 0, ram_used; |
617283b9 | 214 | u8 fifo_nr = 1; |
83daa863 | 215 | int i; |
617283b9 | 216 | |
d2d5397f MKB |
217 | netdev_reset_queue(priv->ndev); |
218 | ||
617283b9 | 219 | mcp251xfd_ring_init_tef(priv, &base); |
617283b9 | 220 | mcp251xfd_ring_init_rx(priv, &base, &fifo_nr); |
62713f0d | 221 | mcp251xfd_ring_init_tx(priv, &base, &fifo_nr); |
fa0b68df | 222 | |
887e359d MKB |
223 | /* mcp251xfd_handle_rxif() will iterate over all RX rings. |
224 | * Rings with their corresponding bit set in | |
225 | * priv->regs_status.rxif are read out. | |
226 | * | |
227 | * If the chip is configured for only 1 RX-FIFO, and if there | |
228 | * is an RX interrupt pending (RXIF in INT register is set), | |
229 | * it must be the 1st RX-FIFO. | |
230 | * | |
231 | * We mark the RXIF of the 1st FIFO as pending here, so that | |
232 | * we can skip the read of the RXIF register in | |
233 | * mcp251xfd_read_regs_status() for the 1 RX-FIFO only case. | |
234 | * | |
235 | * If we use more than 1 RX-FIFO, this value gets overwritten | |
236 | * in mcp251xfd_read_regs_status(), so set it unconditionally | |
237 | * here. | |
238 | */ | |
239 | priv->regs_status.rxif = BIT(priv->rx[0]->fifo_nr); | |
240 | ||
83daa863 MKB |
241 | netdev_dbg(priv->ndev, |
242 | "FIFO setup: TEF: 0x%03x: %2d*%zu bytes = %4zu bytes\n", | |
243 | mcp251xfd_get_tef_obj_addr(0), | |
244 | priv->tx->obj_num, sizeof(struct mcp251xfd_hw_tef_obj), | |
245 | priv->tx->obj_num * sizeof(struct mcp251xfd_hw_tef_obj)); | |
246 | ||
247 | mcp251xfd_for_each_rx_ring(priv, rx_ring, i) { | |
248 | netdev_dbg(priv->ndev, | |
249 | "FIFO setup: RX-%u: FIFO %u/0x%03x: %2u*%u bytes = %4u bytes\n", | |
250 | rx_ring->nr, rx_ring->fifo_nr, | |
251 | mcp251xfd_get_rx_obj_addr(rx_ring, 0), | |
252 | rx_ring->obj_num, rx_ring->obj_size, | |
253 | rx_ring->obj_num * rx_ring->obj_size); | |
254 | } | |
255 | ||
256 | netdev_dbg(priv->ndev, | |
257 | "FIFO setup: TX: FIFO %u/0x%03x: %2u*%u bytes = %4u bytes\n", | |
258 | priv->tx->fifo_nr, | |
259 | mcp251xfd_get_tx_obj_addr(priv->tx, 0), | |
260 | priv->tx->obj_num, priv->tx->obj_size, | |
261 | priv->tx->obj_num * priv->tx->obj_size); | |
262 | ||
263 | netdev_dbg(priv->ndev, | |
c47675b1 | 264 | "FIFO setup: free: %4d bytes\n", |
83daa863 MKB |
265 | MCP251XFD_RAM_SIZE - (base - MCP251XFD_RAM_START)); |
266 | ||
fa0b68df MKB |
267 | ram_used = base - MCP251XFD_RAM_START; |
268 | if (ram_used > MCP251XFD_RAM_SIZE) { | |
269 | netdev_err(priv->ndev, | |
270 | "Error during ring configuration, using more RAM (%u bytes) than available (%u bytes).\n", | |
271 | ram_used, MCP251XFD_RAM_SIZE); | |
272 | return -ENOMEM; | |
273 | } | |
274 | ||
275 | return 0; | |
d2d5397f MKB |
276 | } |
277 | ||
55bc37c8 MKB |
278 | void mcp251xfd_ring_free(struct mcp251xfd_priv *priv) |
279 | { | |
280 | int i; | |
281 | ||
282 | for (i = ARRAY_SIZE(priv->rx) - 1; i >= 0; i--) { | |
283 | kfree(priv->rx[i]); | |
284 | priv->rx[i] = NULL; | |
285 | } | |
286 | } | |
287 | ||
288 | int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv) | |
289 | { | |
290 | struct mcp251xfd_tx_ring *tx_ring; | |
291 | struct mcp251xfd_rx_ring *rx_ring; | |
0a1f2e65 MKB |
292 | u8 tef_obj_size, tx_obj_size, rx_obj_size; |
293 | u8 tx_obj_num; | |
294 | u8 rem, i; | |
55bc37c8 MKB |
295 | |
296 | tef_obj_size = sizeof(struct mcp251xfd_hw_tef_obj); | |
3044a4f2 | 297 | if (mcp251xfd_is_fd_mode(priv)) { |
c9e6b80d | 298 | tx_obj_num = MCP251XFD_TX_OBJ_NUM_CANFD_DEFAULT; |
55bc37c8 MKB |
299 | tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_canfd); |
300 | rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_canfd); | |
301 | } else { | |
c9e6b80d | 302 | tx_obj_num = MCP251XFD_TX_OBJ_NUM_CAN_DEFAULT; |
55bc37c8 MKB |
303 | tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_can); |
304 | rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_can); | |
305 | } | |
306 | ||
d86ba8db MKB |
307 | priv->rx_obj_num = 0; |
308 | ||
55bc37c8 MKB |
309 | tx_ring = priv->tx; |
310 | tx_ring->obj_num = tx_obj_num; | |
311 | tx_ring->obj_size = tx_obj_size; | |
312 | ||
0a1f2e65 MKB |
313 | rem = (MCP251XFD_RAM_SIZE - tx_obj_num * |
314 | (tef_obj_size + tx_obj_size)) / rx_obj_size; | |
315 | for (i = 0; i < ARRAY_SIZE(priv->rx) && rem; i++) { | |
316 | u8 rx_obj_num; | |
55bc37c8 | 317 | |
0a1f2e65 MKB |
318 | rx_obj_num = min_t(u8, rounddown_pow_of_two(rem), |
319 | MCP251XFD_FIFO_DEPTH); | |
320 | rem -= rx_obj_num; | |
55bc37c8 | 321 | |
d86ba8db MKB |
322 | priv->rx_obj_num += rx_obj_num; |
323 | ||
55bc37c8 MKB |
324 | rx_ring = kzalloc(sizeof(*rx_ring) + rx_obj_size * rx_obj_num, |
325 | GFP_KERNEL); | |
326 | if (!rx_ring) { | |
327 | mcp251xfd_ring_free(priv); | |
328 | return -ENOMEM; | |
329 | } | |
0a1f2e65 | 330 | |
55bc37c8 MKB |
331 | rx_ring->obj_num = rx_obj_num; |
332 | rx_ring->obj_size = rx_obj_size; | |
333 | priv->rx[i] = rx_ring; | |
55bc37c8 MKB |
334 | } |
335 | priv->rx_ring_num = i; | |
336 | ||
55bc37c8 MKB |
337 | return 0; |
338 | } |