]>
Commit | Line | Data |
---|---|---|
8aa9ebcc VO |
1 | // SPDX-License-Identifier: BSD-3-Clause |
2 | /* Copyright (c) 2016-2018, NXP Semiconductors | |
3 | * Copyright (c) 2018, Sensor-Technik Wiedemann GmbH | |
4 | * Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com> | |
5 | */ | |
6 | #include <linux/spi/spi.h> | |
7 | #include <linux/packing.h> | |
8 | #include "sja1105.h" | |
9 | ||
10 | #define SJA1105_SIZE_RESET_CMD 4 | |
11 | #define SJA1105_SIZE_SPI_MSG_HEADER 4 | |
12 | #define SJA1105_SIZE_SPI_MSG_MAXLEN (64 * 4) | |
08839c06 VO |
13 | |
14 | struct sja1105_chunk { | |
15 | u8 *buf; | |
16 | size_t len; | |
17 | u64 reg_addr; | |
18 | }; | |
8aa9ebcc | 19 | |
8aa9ebcc VO |
20 | static void |
21 | sja1105_spi_message_pack(void *buf, const struct sja1105_spi_message *msg) | |
22 | { | |
23 | const int size = SJA1105_SIZE_SPI_MSG_HEADER; | |
24 | ||
25 | memset(buf, 0, size); | |
26 | ||
27 | sja1105_pack(buf, &msg->access, 31, 31, size); | |
28 | sja1105_pack(buf, &msg->read_count, 30, 25, size); | |
29 | sja1105_pack(buf, &msg->address, 24, 4, size); | |
30 | } | |
31 | ||
08839c06 VO |
32 | #define sja1105_hdr_xfer(xfers, chunk) \ |
33 | ((xfers) + 2 * (chunk)) | |
34 | #define sja1105_chunk_xfer(xfers, chunk) \ | |
35 | ((xfers) + 2 * (chunk) + 1) | |
36 | #define sja1105_hdr_buf(hdr_bufs, chunk) \ | |
37 | ((hdr_bufs) + (chunk) * SJA1105_SIZE_SPI_MSG_HEADER) | |
38 | ||
8aa9ebcc VO |
39 | /* If @rw is: |
40 | * - SPI_WRITE: creates and sends an SPI write message at absolute | |
08839c06 | 41 | * address reg_addr, taking @len bytes from *buf |
8aa9ebcc | 42 | * - SPI_READ: creates and sends an SPI read message from absolute |
08839c06 | 43 | * address reg_addr, writing @len bytes into *buf |
8aa9ebcc | 44 | */ |
34d76e9f VO |
45 | static int sja1105_xfer(const struct sja1105_private *priv, |
46 | sja1105_spi_rw_mode_t rw, u64 reg_addr, u8 *buf, | |
47 | size_t len, struct ptp_system_timestamp *ptp_sts) | |
8aa9ebcc | 48 | { |
08839c06 VO |
49 | struct sja1105_chunk chunk = { |
50 | .len = min_t(size_t, len, SJA1105_SIZE_SPI_MSG_MAXLEN), | |
51 | .reg_addr = reg_addr, | |
52 | .buf = buf, | |
8a559400 | 53 | }; |
08839c06 VO |
54 | struct spi_device *spi = priv->spidev; |
55 | struct spi_transfer *xfers; | |
56 | int num_chunks; | |
57 | int rc, i = 0; | |
58 | u8 *hdr_bufs; | |
8aa9ebcc | 59 | |
08839c06 | 60 | num_chunks = DIV_ROUND_UP(len, SJA1105_SIZE_SPI_MSG_MAXLEN); |
8aa9ebcc | 61 | |
08839c06 VO |
62 | /* One transfer for each message header, one for each message |
63 | * payload (chunk). | |
64 | */ | |
65 | xfers = kcalloc(2 * num_chunks, sizeof(struct spi_transfer), | |
66 | GFP_KERNEL); | |
67 | if (!xfers) | |
68 | return -ENOMEM; | |
8aa9ebcc | 69 | |
08839c06 VO |
70 | /* Packed buffers for the num_chunks SPI message headers, |
71 | * stored as a contiguous array | |
72 | */ | |
73 | hdr_bufs = kcalloc(num_chunks, SJA1105_SIZE_SPI_MSG_HEADER, | |
74 | GFP_KERNEL); | |
75 | if (!hdr_bufs) { | |
76 | kfree(xfers); | |
77 | return -ENOMEM; | |
78 | } | |
8aa9ebcc | 79 | |
08839c06 VO |
80 | for (i = 0; i < num_chunks; i++) { |
81 | struct spi_transfer *chunk_xfer = sja1105_chunk_xfer(xfers, i); | |
82 | struct spi_transfer *hdr_xfer = sja1105_hdr_xfer(xfers, i); | |
83 | u8 *hdr_buf = sja1105_hdr_buf(hdr_bufs, i); | |
34d76e9f | 84 | struct spi_transfer *ptp_sts_xfer; |
08839c06 VO |
85 | struct sja1105_spi_message msg; |
86 | ||
87 | /* Populate the transfer's header buffer */ | |
88 | msg.address = chunk.reg_addr; | |
89 | msg.access = rw; | |
90 | if (rw == SPI_READ) | |
91 | msg.read_count = chunk.len / 4; | |
92 | else | |
93 | /* Ignored */ | |
94 | msg.read_count = 0; | |
95 | sja1105_spi_message_pack(hdr_buf, &msg); | |
96 | hdr_xfer->tx_buf = hdr_buf; | |
97 | hdr_xfer->len = SJA1105_SIZE_SPI_MSG_HEADER; | |
98 | ||
99 | /* Populate the transfer's data buffer */ | |
100 | if (rw == SPI_READ) | |
101 | chunk_xfer->rx_buf = chunk.buf; | |
102 | else | |
103 | chunk_xfer->tx_buf = chunk.buf; | |
104 | chunk_xfer->len = chunk.len; | |
105 | ||
34d76e9f VO |
106 | /* Request timestamping for the transfer. Instead of letting |
107 | * callers specify which byte they want to timestamp, we can | |
108 | * make certain assumptions: | |
109 | * - A read operation will request a software timestamp when | |
110 | * what's being read is the PTP time. That is snapshotted by | |
111 | * the switch hardware at the end of the command portion | |
112 | * (hdr_xfer). | |
113 | * - A write operation will request a software timestamp on | |
114 | * actions that modify the PTP time. Taking clock stepping as | |
115 | * an example, the switch writes the PTP time at the end of | |
116 | * the data portion (chunk_xfer). | |
117 | */ | |
118 | if (rw == SPI_READ) | |
119 | ptp_sts_xfer = hdr_xfer; | |
120 | else | |
121 | ptp_sts_xfer = chunk_xfer; | |
122 | ptp_sts_xfer->ptp_sts_word_pre = ptp_sts_xfer->len - 1; | |
123 | ptp_sts_xfer->ptp_sts_word_post = ptp_sts_xfer->len - 1; | |
124 | ptp_sts_xfer->ptp_sts = ptp_sts; | |
125 | ||
08839c06 VO |
126 | /* Calculate next chunk */ |
127 | chunk.buf += chunk.len; | |
128 | chunk.reg_addr += chunk.len / 4; | |
129 | chunk.len = min_t(size_t, (ptrdiff_t)(buf + len - chunk.buf), | |
130 | SJA1105_SIZE_SPI_MSG_MAXLEN); | |
131 | ||
132 | /* De-assert the chip select after each chunk. */ | |
133 | if (chunk.len) | |
134 | chunk_xfer->cs_change = 1; | |
135 | } | |
8a559400 | 136 | |
08839c06 VO |
137 | rc = spi_sync_transfer(spi, xfers, 2 * num_chunks); |
138 | if (rc < 0) | |
8a559400 | 139 | dev_err(&spi->dev, "SPI transfer failed: %d\n", rc); |
8aa9ebcc | 140 | |
08839c06 VO |
141 | kfree(hdr_bufs); |
142 | kfree(xfers); | |
8aa9ebcc | 143 | |
08839c06 | 144 | return rc; |
8aa9ebcc VO |
145 | } |
146 | ||
34d76e9f VO |
147 | int sja1105_xfer_buf(const struct sja1105_private *priv, |
148 | sja1105_spi_rw_mode_t rw, u64 reg_addr, | |
149 | u8 *buf, size_t len) | |
150 | { | |
151 | return sja1105_xfer(priv, rw, reg_addr, buf, len, NULL); | |
152 | } | |
153 | ||
8aa9ebcc VO |
154 | /* If @rw is: |
155 | * - SPI_WRITE: creates and sends an SPI write message at absolute | |
dff79620 | 156 | * address reg_addr |
8aa9ebcc | 157 | * - SPI_READ: creates and sends an SPI read message from absolute |
dff79620 | 158 | * address reg_addr |
8aa9ebcc VO |
159 | * |
160 | * The u64 *value is unpacked, meaning that it's stored in the native | |
161 | * CPU endianness and directly usable by software running on the core. | |
8aa9ebcc | 162 | */ |
dff79620 | 163 | int sja1105_xfer_u64(const struct sja1105_private *priv, |
34d76e9f VO |
164 | sja1105_spi_rw_mode_t rw, u64 reg_addr, u64 *value, |
165 | struct ptp_system_timestamp *ptp_sts) | |
8aa9ebcc | 166 | { |
dff79620 | 167 | u8 packed_buf[8]; |
8aa9ebcc VO |
168 | int rc; |
169 | ||
8aa9ebcc | 170 | if (rw == SPI_WRITE) |
dff79620 | 171 | sja1105_pack(packed_buf, value, 63, 0, 8); |
8aa9ebcc | 172 | |
34d76e9f | 173 | rc = sja1105_xfer(priv, rw, reg_addr, packed_buf, 8, ptp_sts); |
8aa9ebcc VO |
174 | |
175 | if (rw == SPI_READ) | |
dff79620 VO |
176 | sja1105_unpack(packed_buf, value, 63, 0, 8); |
177 | ||
178 | return rc; | |
179 | } | |
180 | ||
181 | /* Same as above, but transfers only a 4 byte word */ | |
182 | int sja1105_xfer_u32(const struct sja1105_private *priv, | |
34d76e9f VO |
183 | sja1105_spi_rw_mode_t rw, u64 reg_addr, u32 *value, |
184 | struct ptp_system_timestamp *ptp_sts) | |
dff79620 VO |
185 | { |
186 | u8 packed_buf[4]; | |
187 | u64 tmp; | |
188 | int rc; | |
189 | ||
190 | if (rw == SPI_WRITE) { | |
191 | /* The packing API only supports u64 as CPU word size, | |
192 | * so we need to convert. | |
193 | */ | |
194 | tmp = *value; | |
195 | sja1105_pack(packed_buf, &tmp, 31, 0, 4); | |
196 | } | |
197 | ||
34d76e9f | 198 | rc = sja1105_xfer(priv, rw, reg_addr, packed_buf, 4, ptp_sts); |
dff79620 VO |
199 | |
200 | if (rw == SPI_READ) { | |
201 | sja1105_unpack(packed_buf, &tmp, 31, 0, 4); | |
202 | *value = tmp; | |
203 | } | |
8aa9ebcc VO |
204 | |
205 | return rc; | |
206 | } | |
207 | ||
abfb228a | 208 | static int sja1105et_reset_cmd(struct dsa_switch *ds) |
8aa9ebcc | 209 | { |
abfb228a | 210 | struct sja1105_private *priv = ds->priv; |
8aa9ebcc | 211 | const struct sja1105_regs *regs = priv->info->regs; |
abfb228a VO |
212 | u8 packed_buf[SJA1105_SIZE_RESET_CMD] = {0}; |
213 | const int size = SJA1105_SIZE_RESET_CMD; | |
214 | u64 cold_rst = 1; | |
8aa9ebcc | 215 | |
abfb228a | 216 | sja1105_pack(packed_buf, &cold_rst, 3, 3, size); |
8aa9ebcc | 217 | |
1bd44870 VO |
218 | return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgu, packed_buf, |
219 | SJA1105_SIZE_RESET_CMD); | |
8aa9ebcc VO |
220 | } |
221 | ||
abfb228a | 222 | static int sja1105pqrs_reset_cmd(struct dsa_switch *ds) |
8aa9ebcc | 223 | { |
abfb228a | 224 | struct sja1105_private *priv = ds->priv; |
8aa9ebcc | 225 | const struct sja1105_regs *regs = priv->info->regs; |
abfb228a VO |
226 | u8 packed_buf[SJA1105_SIZE_RESET_CMD] = {0}; |
227 | const int size = SJA1105_SIZE_RESET_CMD; | |
228 | u64 cold_rst = 1; | |
229 | ||
230 | sja1105_pack(packed_buf, &cold_rst, 2, 2, size); | |
8aa9ebcc | 231 | |
1bd44870 VO |
232 | return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgu, packed_buf, |
233 | SJA1105_SIZE_RESET_CMD); | |
8aa9ebcc VO |
234 | } |
235 | ||
d114fb04 VO |
236 | int sja1105_inhibit_tx(const struct sja1105_private *priv, |
237 | unsigned long port_bitmap, bool tx_inhibited) | |
1a4c6940 VO |
238 | { |
239 | const struct sja1105_regs *regs = priv->info->regs; | |
dff79620 | 240 | u32 inhibit_cmd; |
d114fb04 | 241 | int rc; |
1a4c6940 | 242 | |
dff79620 | 243 | rc = sja1105_xfer_u32(priv, SPI_READ, regs->port_control, |
34d76e9f | 244 | &inhibit_cmd, NULL); |
1a4c6940 VO |
245 | if (rc < 0) |
246 | return rc; | |
247 | ||
d114fb04 VO |
248 | if (tx_inhibited) |
249 | inhibit_cmd |= port_bitmap; | |
250 | else | |
251 | inhibit_cmd &= ~port_bitmap; | |
1a4c6940 | 252 | |
dff79620 | 253 | return sja1105_xfer_u32(priv, SPI_WRITE, regs->port_control, |
34d76e9f | 254 | &inhibit_cmd, NULL); |
1a4c6940 VO |
255 | } |
256 | ||
8aa9ebcc VO |
257 | struct sja1105_status { |
258 | u64 configs; | |
259 | u64 crcchkl; | |
260 | u64 ids; | |
261 | u64 crcchkg; | |
262 | }; | |
263 | ||
264 | /* This is not reading the entire General Status area, which is also | |
265 | * divergent between E/T and P/Q/R/S, but only the relevant bits for | |
266 | * ensuring that the static config upload procedure was successful. | |
267 | */ | |
268 | static void sja1105_status_unpack(void *buf, struct sja1105_status *status) | |
269 | { | |
270 | /* So that addition translates to 4 bytes */ | |
271 | u32 *p = buf; | |
272 | ||
273 | /* device_id is missing from the buffer, but we don't | |
274 | * want to diverge from the manual definition of the | |
275 | * register addresses, so we'll back off one step with | |
276 | * the register pointer, and never access p[0]. | |
277 | */ | |
278 | p--; | |
279 | sja1105_unpack(p + 0x1, &status->configs, 31, 31, 4); | |
280 | sja1105_unpack(p + 0x1, &status->crcchkl, 30, 30, 4); | |
281 | sja1105_unpack(p + 0x1, &status->ids, 29, 29, 4); | |
282 | sja1105_unpack(p + 0x1, &status->crcchkg, 28, 28, 4); | |
283 | } | |
284 | ||
285 | static int sja1105_status_get(struct sja1105_private *priv, | |
286 | struct sja1105_status *status) | |
287 | { | |
288 | const struct sja1105_regs *regs = priv->info->regs; | |
289 | u8 packed_buf[4]; | |
290 | int rc; | |
291 | ||
1bd44870 | 292 | rc = sja1105_xfer_buf(priv, SPI_READ, regs->status, packed_buf, 4); |
8aa9ebcc VO |
293 | if (rc < 0) |
294 | return rc; | |
295 | ||
296 | sja1105_status_unpack(packed_buf, status); | |
297 | ||
298 | return 0; | |
299 | } | |
300 | ||
301 | /* Not const because unpacking priv->static_config into buffers and preparing | |
302 | * for upload requires the recalculation of table CRCs and updating the | |
303 | * structures with these. | |
304 | */ | |
305 | static int | |
306 | static_config_buf_prepare_for_upload(struct sja1105_private *priv, | |
307 | void *config_buf, int buf_len) | |
308 | { | |
309 | struct sja1105_static_config *config = &priv->static_config; | |
310 | struct sja1105_table_header final_header; | |
311 | sja1105_config_valid_t valid; | |
312 | char *final_header_ptr; | |
313 | int crc_len; | |
314 | ||
315 | valid = sja1105_static_config_check_valid(config); | |
316 | if (valid != SJA1105_CONFIG_OK) { | |
317 | dev_err(&priv->spidev->dev, | |
318 | sja1105_static_config_error_msg[valid]); | |
319 | return -EINVAL; | |
320 | } | |
321 | ||
322 | /* Write Device ID and config tables to config_buf */ | |
323 | sja1105_static_config_pack(config_buf, config); | |
324 | /* Recalculate CRC of the last header (right now 0xDEADBEEF). | |
325 | * Don't include the CRC field itself. | |
326 | */ | |
327 | crc_len = buf_len - 4; | |
328 | /* Read the whole table header */ | |
329 | final_header_ptr = config_buf + buf_len - SJA1105_SIZE_TABLE_HEADER; | |
330 | sja1105_table_header_packing(final_header_ptr, &final_header, UNPACK); | |
331 | /* Modify */ | |
332 | final_header.crc = sja1105_crc32(config_buf, crc_len); | |
333 | /* Rewrite */ | |
334 | sja1105_table_header_packing(final_header_ptr, &final_header, PACK); | |
335 | ||
336 | return 0; | |
337 | } | |
338 | ||
339 | #define RETRIES 10 | |
340 | ||
341 | int sja1105_static_config_upload(struct sja1105_private *priv) | |
342 | { | |
1a4c6940 | 343 | unsigned long port_bitmap = GENMASK_ULL(SJA1105_NUM_PORTS - 1, 0); |
8aa9ebcc VO |
344 | struct sja1105_static_config *config = &priv->static_config; |
345 | const struct sja1105_regs *regs = priv->info->regs; | |
346 | struct device *dev = &priv->spidev->dev; | |
347 | struct sja1105_status status; | |
348 | int rc, retries = RETRIES; | |
349 | u8 *config_buf; | |
350 | int buf_len; | |
351 | ||
352 | buf_len = sja1105_static_config_get_length(config); | |
353 | config_buf = kcalloc(buf_len, sizeof(char), GFP_KERNEL); | |
354 | if (!config_buf) | |
355 | return -ENOMEM; | |
356 | ||
357 | rc = static_config_buf_prepare_for_upload(priv, config_buf, buf_len); | |
358 | if (rc < 0) { | |
359 | dev_err(dev, "Invalid config, cannot upload\n"); | |
68501df9 NE |
360 | rc = -EINVAL; |
361 | goto out; | |
8aa9ebcc | 362 | } |
1a4c6940 VO |
363 | /* Prevent PHY jabbering during switch reset by inhibiting |
364 | * Tx on all ports and waiting for current packet to drain. | |
365 | * Otherwise, the PHY will see an unterminated Ethernet packet. | |
366 | */ | |
d114fb04 | 367 | rc = sja1105_inhibit_tx(priv, port_bitmap, true); |
1a4c6940 VO |
368 | if (rc < 0) { |
369 | dev_err(dev, "Failed to inhibit Tx on ports\n"); | |
68501df9 NE |
370 | rc = -ENXIO; |
371 | goto out; | |
1a4c6940 VO |
372 | } |
373 | /* Wait for an eventual egress packet to finish transmission | |
374 | * (reach IFG). It is guaranteed that a second one will not | |
375 | * follow, and that switch cold reset is thus safe | |
376 | */ | |
377 | usleep_range(500, 1000); | |
8aa9ebcc VO |
378 | do { |
379 | /* Put the SJA1105 in programming mode */ | |
abfb228a | 380 | rc = priv->info->reset_cmd(priv->ds); |
8aa9ebcc VO |
381 | if (rc < 0) { |
382 | dev_err(dev, "Failed to reset switch, retrying...\n"); | |
383 | continue; | |
384 | } | |
385 | /* Wait for the switch to come out of reset */ | |
386 | usleep_range(1000, 5000); | |
387 | /* Upload the static config to the device */ | |
08839c06 VO |
388 | rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->config, |
389 | config_buf, buf_len); | |
8aa9ebcc VO |
390 | if (rc < 0) { |
391 | dev_err(dev, "Failed to upload config, retrying...\n"); | |
392 | continue; | |
393 | } | |
394 | /* Check that SJA1105 responded well to the config upload */ | |
395 | rc = sja1105_status_get(priv, &status); | |
396 | if (rc < 0) | |
397 | continue; | |
398 | ||
399 | if (status.ids == 1) { | |
400 | dev_err(dev, "Mismatch between hardware and static config " | |
401 | "device id. Wrote 0x%llx, wants 0x%llx\n", | |
402 | config->device_id, priv->info->device_id); | |
403 | continue; | |
404 | } | |
405 | if (status.crcchkl == 1) { | |
406 | dev_err(dev, "Switch reported invalid local CRC on " | |
407 | "the uploaded config, retrying...\n"); | |
408 | continue; | |
409 | } | |
410 | if (status.crcchkg == 1) { | |
411 | dev_err(dev, "Switch reported invalid global CRC on " | |
412 | "the uploaded config, retrying...\n"); | |
413 | continue; | |
414 | } | |
415 | if (status.configs == 0) { | |
416 | dev_err(dev, "Switch reported that configuration is " | |
417 | "invalid, retrying...\n"); | |
418 | continue; | |
419 | } | |
5425711b CIK |
420 | /* Success! */ |
421 | break; | |
422 | } while (--retries); | |
8aa9ebcc VO |
423 | |
424 | if (!retries) { | |
425 | rc = -EIO; | |
426 | dev_err(dev, "Failed to upload config to device, giving up\n"); | |
427 | goto out; | |
5425711b | 428 | } else if (retries != RETRIES) { |
8aa9ebcc VO |
429 | dev_info(dev, "Succeeded after %d tried\n", RETRIES - retries); |
430 | } | |
431 | ||
8aa9ebcc VO |
432 | out: |
433 | kfree(config_buf); | |
434 | return rc; | |
435 | } | |
436 | ||
86dc59e3 | 437 | static struct sja1105_regs sja1105et_regs = { |
8aa9ebcc VO |
438 | .device_id = 0x0, |
439 | .prod_id = 0x100BC3, | |
440 | .status = 0x1, | |
1a4c6940 | 441 | .port_control = 0x11, |
8aa9ebcc VO |
442 | .config = 0x020000, |
443 | .rgu = 0x100440, | |
b5b0c7f4 | 444 | /* UM10944.pdf, Table 86, ACU Register overview */ |
8aa9ebcc | 445 | .pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808}, |
135e3018 | 446 | .pad_mii_rx = {0x100801, 0x100803, 0x100805, 0x100807, 0x100809}, |
8aa9ebcc VO |
447 | .rmii_pll1 = 0x10000A, |
448 | .cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F}, | |
8aa9ebcc VO |
449 | .mac = {0x200, 0x202, 0x204, 0x206, 0x208}, |
450 | .mac_hl1 = {0x400, 0x410, 0x420, 0x430, 0x440}, | |
451 | .mac_hl2 = {0x600, 0x610, 0x620, 0x630, 0x640}, | |
452 | /* UM10944.pdf, Table 78, CGU Register overview */ | |
453 | .mii_tx_clk = {0x100013, 0x10001A, 0x100021, 0x100028, 0x10002F}, | |
454 | .mii_rx_clk = {0x100014, 0x10001B, 0x100022, 0x100029, 0x100030}, | |
455 | .mii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034}, | |
456 | .mii_ext_rx_clk = {0x100019, 0x100020, 0x100027, 0x10002E, 0x100035}, | |
457 | .rgmii_tx_clk = {0x100016, 0x10001D, 0x100024, 0x10002B, 0x100032}, | |
458 | .rmii_ref_clk = {0x100015, 0x10001C, 0x100023, 0x10002A, 0x100031}, | |
459 | .rmii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034}, | |
47ed985e | 460 | .ptpegr_ts = {0xC0, 0xC2, 0xC4, 0xC6, 0xC8}, |
86db36a3 | 461 | .ptpschtm = 0x12, /* Spans 0x12 to 0x13 */ |
747e5eb3 VO |
462 | .ptppinst = 0x14, |
463 | .ptppindur = 0x16, | |
bb77f36a | 464 | .ptp_control = 0x17, |
2fb079a2 | 465 | .ptpclkval = 0x18, /* Spans 0x18 to 0x19 */ |
bb77f36a | 466 | .ptpclkrate = 0x1A, |
86db36a3 | 467 | .ptpclkcorp = 0x1D, |
8aa9ebcc VO |
468 | }; |
469 | ||
86dc59e3 | 470 | static struct sja1105_regs sja1105pqrs_regs = { |
8aa9ebcc VO |
471 | .device_id = 0x0, |
472 | .prod_id = 0x100BC3, | |
473 | .status = 0x1, | |
1a4c6940 | 474 | .port_control = 0x12, |
8aa9ebcc VO |
475 | .config = 0x020000, |
476 | .rgu = 0x100440, | |
b5b0c7f4 | 477 | /* UM10944.pdf, Table 86, ACU Register overview */ |
8aa9ebcc | 478 | .pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808}, |
135e3018 | 479 | .pad_mii_rx = {0x100801, 0x100803, 0x100805, 0x100807, 0x100809}, |
c05ec3d4 | 480 | .pad_mii_id = {0x100810, 0x100811, 0x100812, 0x100813, 0x100814}, |
ffe10e67 | 481 | .sgmii = 0x1F0000, |
8aa9ebcc VO |
482 | .rmii_pll1 = 0x10000A, |
483 | .cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F}, | |
8aa9ebcc VO |
484 | .mac = {0x200, 0x202, 0x204, 0x206, 0x208}, |
485 | .mac_hl1 = {0x400, 0x410, 0x420, 0x430, 0x440}, | |
486 | .mac_hl2 = {0x600, 0x610, 0x620, 0x630, 0x640}, | |
336aa67b | 487 | .ether_stats = {0x1400, 0x1418, 0x1430, 0x1448, 0x1460}, |
8aa9ebcc VO |
488 | /* UM11040.pdf, Table 114 */ |
489 | .mii_tx_clk = {0x100013, 0x100019, 0x10001F, 0x100025, 0x10002B}, | |
490 | .mii_rx_clk = {0x100014, 0x10001A, 0x100020, 0x100026, 0x10002C}, | |
491 | .mii_ext_tx_clk = {0x100017, 0x10001D, 0x100023, 0x100029, 0x10002F}, | |
492 | .mii_ext_rx_clk = {0x100018, 0x10001E, 0x100024, 0x10002A, 0x100030}, | |
493 | .rgmii_tx_clk = {0x100016, 0x10001C, 0x100022, 0x100028, 0x10002E}, | |
494 | .rmii_ref_clk = {0x100015, 0x10001B, 0x100021, 0x100027, 0x10002D}, | |
495 | .rmii_ext_tx_clk = {0x100017, 0x10001D, 0x100023, 0x100029, 0x10002F}, | |
496 | .qlevel = {0x604, 0x614, 0x624, 0x634, 0x644}, | |
47ed985e | 497 | .ptpegr_ts = {0xC0, 0xC4, 0xC8, 0xCC, 0xD0}, |
86db36a3 | 498 | .ptpschtm = 0x13, /* Spans 0x13 to 0x14 */ |
747e5eb3 VO |
499 | .ptppinst = 0x15, |
500 | .ptppindur = 0x17, | |
bb77f36a | 501 | .ptp_control = 0x18, |
2fb079a2 | 502 | .ptpclkval = 0x19, |
bb77f36a | 503 | .ptpclkrate = 0x1B, |
86db36a3 | 504 | .ptpclkcorp = 0x1E, |
747e5eb3 | 505 | .ptpsyncts = 0x1F, |
8aa9ebcc VO |
506 | }; |
507 | ||
508 | struct sja1105_info sja1105e_info = { | |
509 | .device_id = SJA1105E_DEVICE_ID, | |
510 | .part_no = SJA1105ET_PART_NO, | |
511 | .static_ops = sja1105e_table_ops, | |
512 | .dyn_ops = sja1105et_dyn_ops, | |
47ed985e VO |
513 | .ptp_ts_bits = 24, |
514 | .ptpegr_ts_bytes = 4, | |
8aa9ebcc | 515 | .reset_cmd = sja1105et_reset_cmd, |
9dfa6911 VO |
516 | .fdb_add_cmd = sja1105et_fdb_add, |
517 | .fdb_del_cmd = sja1105et_fdb_del, | |
41603d78 | 518 | .ptp_cmd_packing = sja1105et_ptp_cmd_packing, |
8aa9ebcc VO |
519 | .regs = &sja1105et_regs, |
520 | .name = "SJA1105E", | |
521 | }; | |
522 | struct sja1105_info sja1105t_info = { | |
523 | .device_id = SJA1105T_DEVICE_ID, | |
524 | .part_no = SJA1105ET_PART_NO, | |
525 | .static_ops = sja1105t_table_ops, | |
526 | .dyn_ops = sja1105et_dyn_ops, | |
47ed985e VO |
527 | .ptp_ts_bits = 24, |
528 | .ptpegr_ts_bytes = 4, | |
8aa9ebcc | 529 | .reset_cmd = sja1105et_reset_cmd, |
9dfa6911 VO |
530 | .fdb_add_cmd = sja1105et_fdb_add, |
531 | .fdb_del_cmd = sja1105et_fdb_del, | |
41603d78 | 532 | .ptp_cmd_packing = sja1105et_ptp_cmd_packing, |
8aa9ebcc VO |
533 | .regs = &sja1105et_regs, |
534 | .name = "SJA1105T", | |
535 | }; | |
536 | struct sja1105_info sja1105p_info = { | |
537 | .device_id = SJA1105PR_DEVICE_ID, | |
538 | .part_no = SJA1105P_PART_NO, | |
539 | .static_ops = sja1105p_table_ops, | |
540 | .dyn_ops = sja1105pqrs_dyn_ops, | |
47ed985e VO |
541 | .ptp_ts_bits = 32, |
542 | .ptpegr_ts_bytes = 8, | |
c05ec3d4 | 543 | .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay, |
8aa9ebcc | 544 | .reset_cmd = sja1105pqrs_reset_cmd, |
9dfa6911 VO |
545 | .fdb_add_cmd = sja1105pqrs_fdb_add, |
546 | .fdb_del_cmd = sja1105pqrs_fdb_del, | |
41603d78 | 547 | .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, |
8aa9ebcc VO |
548 | .regs = &sja1105pqrs_regs, |
549 | .name = "SJA1105P", | |
550 | }; | |
551 | struct sja1105_info sja1105q_info = { | |
552 | .device_id = SJA1105QS_DEVICE_ID, | |
553 | .part_no = SJA1105Q_PART_NO, | |
554 | .static_ops = sja1105q_table_ops, | |
555 | .dyn_ops = sja1105pqrs_dyn_ops, | |
47ed985e VO |
556 | .ptp_ts_bits = 32, |
557 | .ptpegr_ts_bytes = 8, | |
c05ec3d4 | 558 | .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay, |
8aa9ebcc | 559 | .reset_cmd = sja1105pqrs_reset_cmd, |
9dfa6911 VO |
560 | .fdb_add_cmd = sja1105pqrs_fdb_add, |
561 | .fdb_del_cmd = sja1105pqrs_fdb_del, | |
41603d78 | 562 | .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, |
8aa9ebcc VO |
563 | .regs = &sja1105pqrs_regs, |
564 | .name = "SJA1105Q", | |
565 | }; | |
566 | struct sja1105_info sja1105r_info = { | |
567 | .device_id = SJA1105PR_DEVICE_ID, | |
568 | .part_no = SJA1105R_PART_NO, | |
569 | .static_ops = sja1105r_table_ops, | |
570 | .dyn_ops = sja1105pqrs_dyn_ops, | |
47ed985e VO |
571 | .ptp_ts_bits = 32, |
572 | .ptpegr_ts_bytes = 8, | |
c05ec3d4 | 573 | .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay, |
8aa9ebcc | 574 | .reset_cmd = sja1105pqrs_reset_cmd, |
9dfa6911 VO |
575 | .fdb_add_cmd = sja1105pqrs_fdb_add, |
576 | .fdb_del_cmd = sja1105pqrs_fdb_del, | |
41603d78 | 577 | .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, |
8aa9ebcc VO |
578 | .regs = &sja1105pqrs_regs, |
579 | .name = "SJA1105R", | |
580 | }; | |
581 | struct sja1105_info sja1105s_info = { | |
582 | .device_id = SJA1105QS_DEVICE_ID, | |
583 | .part_no = SJA1105S_PART_NO, | |
584 | .static_ops = sja1105s_table_ops, | |
585 | .dyn_ops = sja1105pqrs_dyn_ops, | |
586 | .regs = &sja1105pqrs_regs, | |
47ed985e VO |
587 | .ptp_ts_bits = 32, |
588 | .ptpegr_ts_bytes = 8, | |
c05ec3d4 | 589 | .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay, |
8aa9ebcc | 590 | .reset_cmd = sja1105pqrs_reset_cmd, |
9dfa6911 VO |
591 | .fdb_add_cmd = sja1105pqrs_fdb_add, |
592 | .fdb_del_cmd = sja1105pqrs_fdb_del, | |
41603d78 | 593 | .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, |
8aa9ebcc VO |
594 | .name = "SJA1105S", |
595 | }; |