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 | ||
1a4c6940 | 10 | #define SJA1105_SIZE_PORT_CTRL 4 |
8aa9ebcc VO |
11 | #define SJA1105_SIZE_RESET_CMD 4 |
12 | #define SJA1105_SIZE_SPI_MSG_HEADER 4 | |
13 | #define SJA1105_SIZE_SPI_MSG_MAXLEN (64 * 4) | |
14 | #define SJA1105_SIZE_SPI_TRANSFER_MAX \ | |
15 | (SJA1105_SIZE_SPI_MSG_HEADER + SJA1105_SIZE_SPI_MSG_MAXLEN) | |
16 | ||
17 | static int sja1105_spi_transfer(const struct sja1105_private *priv, | |
18 | const void *tx, void *rx, int size) | |
19 | { | |
20 | struct spi_device *spi = priv->spidev; | |
21 | struct spi_transfer transfer = { | |
22 | .tx_buf = tx, | |
23 | .rx_buf = rx, | |
24 | .len = size, | |
25 | }; | |
26 | struct spi_message msg; | |
27 | int rc; | |
28 | ||
29 | if (size > SJA1105_SIZE_SPI_TRANSFER_MAX) { | |
30 | dev_err(&spi->dev, "SPI message (%d) longer than max of %d\n", | |
31 | size, SJA1105_SIZE_SPI_TRANSFER_MAX); | |
32 | return -EMSGSIZE; | |
33 | } | |
34 | ||
35 | spi_message_init(&msg); | |
36 | spi_message_add_tail(&transfer, &msg); | |
37 | ||
38 | rc = spi_sync(spi, &msg); | |
39 | if (rc < 0) { | |
40 | dev_err(&spi->dev, "SPI transfer failed: %d\n", rc); | |
41 | return rc; | |
42 | } | |
43 | ||
44 | return rc; | |
45 | } | |
46 | ||
47 | static void | |
48 | sja1105_spi_message_pack(void *buf, const struct sja1105_spi_message *msg) | |
49 | { | |
50 | const int size = SJA1105_SIZE_SPI_MSG_HEADER; | |
51 | ||
52 | memset(buf, 0, size); | |
53 | ||
54 | sja1105_pack(buf, &msg->access, 31, 31, size); | |
55 | sja1105_pack(buf, &msg->read_count, 30, 25, size); | |
56 | sja1105_pack(buf, &msg->address, 24, 4, size); | |
57 | } | |
58 | ||
59 | /* If @rw is: | |
60 | * - SPI_WRITE: creates and sends an SPI write message at absolute | |
61 | * address reg_addr, taking size_bytes from *packed_buf | |
62 | * - SPI_READ: creates and sends an SPI read message from absolute | |
63 | * address reg_addr, writing size_bytes into *packed_buf | |
64 | * | |
65 | * This function should only be called if it is priorly known that | |
66 | * @size_bytes is smaller than SIZE_SPI_MSG_MAXLEN. Larger packed buffers | |
67 | * are chunked in smaller pieces by sja1105_spi_send_long_packed_buf below. | |
68 | */ | |
69 | int sja1105_spi_send_packed_buf(const struct sja1105_private *priv, | |
70 | sja1105_spi_rw_mode_t rw, u64 reg_addr, | |
71 | void *packed_buf, size_t size_bytes) | |
72 | { | |
73 | u8 tx_buf[SJA1105_SIZE_SPI_TRANSFER_MAX] = {0}; | |
74 | u8 rx_buf[SJA1105_SIZE_SPI_TRANSFER_MAX] = {0}; | |
75 | const int msg_len = size_bytes + SJA1105_SIZE_SPI_MSG_HEADER; | |
76 | struct sja1105_spi_message msg = {0}; | |
77 | int rc; | |
78 | ||
79 | if (msg_len > SJA1105_SIZE_SPI_TRANSFER_MAX) | |
80 | return -ERANGE; | |
81 | ||
82 | msg.access = rw; | |
83 | msg.address = reg_addr; | |
84 | if (rw == SPI_READ) | |
85 | msg.read_count = size_bytes / 4; | |
86 | ||
87 | sja1105_spi_message_pack(tx_buf, &msg); | |
88 | ||
89 | if (rw == SPI_WRITE) | |
90 | memcpy(tx_buf + SJA1105_SIZE_SPI_MSG_HEADER, | |
91 | packed_buf, size_bytes); | |
92 | ||
93 | rc = sja1105_spi_transfer(priv, tx_buf, rx_buf, msg_len); | |
94 | if (rc < 0) | |
95 | return rc; | |
96 | ||
97 | if (rw == SPI_READ) | |
98 | memcpy(packed_buf, rx_buf + SJA1105_SIZE_SPI_MSG_HEADER, | |
99 | size_bytes); | |
100 | ||
101 | return 0; | |
102 | } | |
103 | ||
104 | /* If @rw is: | |
105 | * - SPI_WRITE: creates and sends an SPI write message at absolute | |
106 | * address reg_addr, taking size_bytes from *packed_buf | |
107 | * - SPI_READ: creates and sends an SPI read message from absolute | |
108 | * address reg_addr, writing size_bytes into *packed_buf | |
109 | * | |
110 | * The u64 *value is unpacked, meaning that it's stored in the native | |
111 | * CPU endianness and directly usable by software running on the core. | |
112 | * | |
113 | * This is a wrapper around sja1105_spi_send_packed_buf(). | |
114 | */ | |
115 | int sja1105_spi_send_int(const struct sja1105_private *priv, | |
116 | sja1105_spi_rw_mode_t rw, u64 reg_addr, | |
117 | u64 *value, u64 size_bytes) | |
118 | { | |
119 | u8 packed_buf[SJA1105_SIZE_SPI_MSG_MAXLEN]; | |
120 | int rc; | |
121 | ||
122 | if (size_bytes > SJA1105_SIZE_SPI_MSG_MAXLEN) | |
123 | return -ERANGE; | |
124 | ||
125 | if (rw == SPI_WRITE) | |
126 | sja1105_pack(packed_buf, value, 8 * size_bytes - 1, 0, | |
127 | size_bytes); | |
128 | ||
129 | rc = sja1105_spi_send_packed_buf(priv, rw, reg_addr, packed_buf, | |
130 | size_bytes); | |
131 | ||
132 | if (rw == SPI_READ) | |
133 | sja1105_unpack(packed_buf, value, 8 * size_bytes - 1, 0, | |
134 | size_bytes); | |
135 | ||
136 | return rc; | |
137 | } | |
138 | ||
139 | /* Should be used if a @packed_buf larger than SJA1105_SIZE_SPI_MSG_MAXLEN | |
140 | * must be sent/received. Splitting the buffer into chunks and assembling | |
141 | * those into SPI messages is done automatically by this function. | |
142 | */ | |
143 | int sja1105_spi_send_long_packed_buf(const struct sja1105_private *priv, | |
144 | sja1105_spi_rw_mode_t rw, u64 base_addr, | |
145 | void *packed_buf, u64 buf_len) | |
146 | { | |
147 | struct chunk { | |
148 | void *buf_ptr; | |
149 | int len; | |
150 | u64 spi_address; | |
151 | } chunk; | |
152 | int distance_to_end; | |
153 | int rc; | |
154 | ||
155 | /* Initialize chunk */ | |
156 | chunk.buf_ptr = packed_buf; | |
157 | chunk.spi_address = base_addr; | |
158 | chunk.len = min_t(int, buf_len, SJA1105_SIZE_SPI_MSG_MAXLEN); | |
159 | ||
160 | while (chunk.len) { | |
161 | rc = sja1105_spi_send_packed_buf(priv, rw, chunk.spi_address, | |
162 | chunk.buf_ptr, chunk.len); | |
163 | if (rc < 0) | |
164 | return rc; | |
165 | ||
166 | chunk.buf_ptr += chunk.len; | |
167 | chunk.spi_address += chunk.len / 4; | |
168 | distance_to_end = (uintptr_t)(packed_buf + buf_len - | |
169 | chunk.buf_ptr); | |
170 | chunk.len = min(distance_to_end, SJA1105_SIZE_SPI_MSG_MAXLEN); | |
171 | } | |
172 | ||
173 | return 0; | |
174 | } | |
175 | ||
176 | /* Back-ported structure from UM11040 Table 112. | |
177 | * Reset control register (addr. 100440h) | |
178 | * In the SJA1105 E/T, only warm_rst and cold_rst are | |
179 | * supported (exposed in UM10944 as rst_ctrl), but the bit | |
180 | * offsets of warm_rst and cold_rst are actually reversed. | |
181 | */ | |
182 | struct sja1105_reset_cmd { | |
183 | u64 switch_rst; | |
184 | u64 cfg_rst; | |
185 | u64 car_rst; | |
186 | u64 otp_rst; | |
187 | u64 warm_rst; | |
188 | u64 cold_rst; | |
189 | u64 por_rst; | |
190 | }; | |
191 | ||
192 | static void | |
193 | sja1105et_reset_cmd_pack(void *buf, const struct sja1105_reset_cmd *reset) | |
194 | { | |
195 | const int size = SJA1105_SIZE_RESET_CMD; | |
196 | ||
197 | memset(buf, 0, size); | |
198 | ||
199 | sja1105_pack(buf, &reset->cold_rst, 3, 3, size); | |
200 | sja1105_pack(buf, &reset->warm_rst, 2, 2, size); | |
201 | } | |
202 | ||
203 | static void | |
204 | sja1105pqrs_reset_cmd_pack(void *buf, const struct sja1105_reset_cmd *reset) | |
205 | { | |
206 | const int size = SJA1105_SIZE_RESET_CMD; | |
207 | ||
208 | memset(buf, 0, size); | |
209 | ||
210 | sja1105_pack(buf, &reset->switch_rst, 8, 8, size); | |
211 | sja1105_pack(buf, &reset->cfg_rst, 7, 7, size); | |
212 | sja1105_pack(buf, &reset->car_rst, 5, 5, size); | |
213 | sja1105_pack(buf, &reset->otp_rst, 4, 4, size); | |
214 | sja1105_pack(buf, &reset->warm_rst, 3, 3, size); | |
215 | sja1105_pack(buf, &reset->cold_rst, 2, 2, size); | |
216 | sja1105_pack(buf, &reset->por_rst, 1, 1, size); | |
217 | } | |
218 | ||
219 | static int sja1105et_reset_cmd(const void *ctx, const void *data) | |
220 | { | |
221 | const struct sja1105_private *priv = ctx; | |
222 | const struct sja1105_reset_cmd *reset = data; | |
223 | const struct sja1105_regs *regs = priv->info->regs; | |
224 | struct device *dev = priv->ds->dev; | |
225 | u8 packed_buf[SJA1105_SIZE_RESET_CMD]; | |
226 | ||
227 | if (reset->switch_rst || | |
228 | reset->cfg_rst || | |
229 | reset->car_rst || | |
230 | reset->otp_rst || | |
231 | reset->por_rst) { | |
232 | dev_err(dev, "Only warm and cold reset is supported " | |
233 | "for SJA1105 E/T!\n"); | |
234 | return -EINVAL; | |
235 | } | |
236 | ||
237 | if (reset->warm_rst) | |
238 | dev_dbg(dev, "Warm reset requested\n"); | |
239 | if (reset->cold_rst) | |
240 | dev_dbg(dev, "Cold reset requested\n"); | |
241 | ||
242 | sja1105et_reset_cmd_pack(packed_buf, reset); | |
243 | ||
244 | return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->rgu, | |
245 | packed_buf, SJA1105_SIZE_RESET_CMD); | |
246 | } | |
247 | ||
248 | static int sja1105pqrs_reset_cmd(const void *ctx, const void *data) | |
249 | { | |
250 | const struct sja1105_private *priv = ctx; | |
251 | const struct sja1105_reset_cmd *reset = data; | |
252 | const struct sja1105_regs *regs = priv->info->regs; | |
253 | struct device *dev = priv->ds->dev; | |
254 | u8 packed_buf[SJA1105_SIZE_RESET_CMD]; | |
255 | ||
256 | if (reset->switch_rst) | |
257 | dev_dbg(dev, "Main reset for all functional modules requested\n"); | |
258 | if (reset->cfg_rst) | |
259 | dev_dbg(dev, "Chip configuration reset requested\n"); | |
260 | if (reset->car_rst) | |
261 | dev_dbg(dev, "Clock and reset control logic reset requested\n"); | |
262 | if (reset->otp_rst) | |
263 | dev_dbg(dev, "OTP read cycle for reading product " | |
264 | "config settings requested\n"); | |
265 | if (reset->warm_rst) | |
266 | dev_dbg(dev, "Warm reset requested\n"); | |
267 | if (reset->cold_rst) | |
268 | dev_dbg(dev, "Cold reset requested\n"); | |
269 | if (reset->por_rst) | |
270 | dev_dbg(dev, "Power-on reset requested\n"); | |
271 | ||
272 | sja1105pqrs_reset_cmd_pack(packed_buf, reset); | |
273 | ||
274 | return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->rgu, | |
275 | packed_buf, SJA1105_SIZE_RESET_CMD); | |
276 | } | |
277 | ||
278 | static int sja1105_cold_reset(const struct sja1105_private *priv) | |
279 | { | |
280 | struct sja1105_reset_cmd reset = {0}; | |
281 | ||
282 | reset.cold_rst = 1; | |
283 | return priv->info->reset_cmd(priv, &reset); | |
284 | } | |
285 | ||
d114fb04 VO |
286 | int sja1105_inhibit_tx(const struct sja1105_private *priv, |
287 | unsigned long port_bitmap, bool tx_inhibited) | |
1a4c6940 VO |
288 | { |
289 | const struct sja1105_regs *regs = priv->info->regs; | |
290 | u64 inhibit_cmd; | |
d114fb04 | 291 | int rc; |
1a4c6940 VO |
292 | |
293 | rc = sja1105_spi_send_int(priv, SPI_READ, regs->port_control, | |
294 | &inhibit_cmd, SJA1105_SIZE_PORT_CTRL); | |
295 | if (rc < 0) | |
296 | return rc; | |
297 | ||
d114fb04 VO |
298 | if (tx_inhibited) |
299 | inhibit_cmd |= port_bitmap; | |
300 | else | |
301 | inhibit_cmd &= ~port_bitmap; | |
1a4c6940 VO |
302 | |
303 | return sja1105_spi_send_int(priv, SPI_WRITE, regs->port_control, | |
304 | &inhibit_cmd, SJA1105_SIZE_PORT_CTRL); | |
305 | } | |
306 | ||
8aa9ebcc VO |
307 | struct sja1105_status { |
308 | u64 configs; | |
309 | u64 crcchkl; | |
310 | u64 ids; | |
311 | u64 crcchkg; | |
312 | }; | |
313 | ||
314 | /* This is not reading the entire General Status area, which is also | |
315 | * divergent between E/T and P/Q/R/S, but only the relevant bits for | |
316 | * ensuring that the static config upload procedure was successful. | |
317 | */ | |
318 | static void sja1105_status_unpack(void *buf, struct sja1105_status *status) | |
319 | { | |
320 | /* So that addition translates to 4 bytes */ | |
321 | u32 *p = buf; | |
322 | ||
323 | /* device_id is missing from the buffer, but we don't | |
324 | * want to diverge from the manual definition of the | |
325 | * register addresses, so we'll back off one step with | |
326 | * the register pointer, and never access p[0]. | |
327 | */ | |
328 | p--; | |
329 | sja1105_unpack(p + 0x1, &status->configs, 31, 31, 4); | |
330 | sja1105_unpack(p + 0x1, &status->crcchkl, 30, 30, 4); | |
331 | sja1105_unpack(p + 0x1, &status->ids, 29, 29, 4); | |
332 | sja1105_unpack(p + 0x1, &status->crcchkg, 28, 28, 4); | |
333 | } | |
334 | ||
335 | static int sja1105_status_get(struct sja1105_private *priv, | |
336 | struct sja1105_status *status) | |
337 | { | |
338 | const struct sja1105_regs *regs = priv->info->regs; | |
339 | u8 packed_buf[4]; | |
340 | int rc; | |
341 | ||
342 | rc = sja1105_spi_send_packed_buf(priv, SPI_READ, | |
343 | regs->status, | |
344 | packed_buf, 4); | |
345 | if (rc < 0) | |
346 | return rc; | |
347 | ||
348 | sja1105_status_unpack(packed_buf, status); | |
349 | ||
350 | return 0; | |
351 | } | |
352 | ||
353 | /* Not const because unpacking priv->static_config into buffers and preparing | |
354 | * for upload requires the recalculation of table CRCs and updating the | |
355 | * structures with these. | |
356 | */ | |
357 | static int | |
358 | static_config_buf_prepare_for_upload(struct sja1105_private *priv, | |
359 | void *config_buf, int buf_len) | |
360 | { | |
361 | struct sja1105_static_config *config = &priv->static_config; | |
362 | struct sja1105_table_header final_header; | |
363 | sja1105_config_valid_t valid; | |
364 | char *final_header_ptr; | |
365 | int crc_len; | |
366 | ||
367 | valid = sja1105_static_config_check_valid(config); | |
368 | if (valid != SJA1105_CONFIG_OK) { | |
369 | dev_err(&priv->spidev->dev, | |
370 | sja1105_static_config_error_msg[valid]); | |
371 | return -EINVAL; | |
372 | } | |
373 | ||
374 | /* Write Device ID and config tables to config_buf */ | |
375 | sja1105_static_config_pack(config_buf, config); | |
376 | /* Recalculate CRC of the last header (right now 0xDEADBEEF). | |
377 | * Don't include the CRC field itself. | |
378 | */ | |
379 | crc_len = buf_len - 4; | |
380 | /* Read the whole table header */ | |
381 | final_header_ptr = config_buf + buf_len - SJA1105_SIZE_TABLE_HEADER; | |
382 | sja1105_table_header_packing(final_header_ptr, &final_header, UNPACK); | |
383 | /* Modify */ | |
384 | final_header.crc = sja1105_crc32(config_buf, crc_len); | |
385 | /* Rewrite */ | |
386 | sja1105_table_header_packing(final_header_ptr, &final_header, PACK); | |
387 | ||
388 | return 0; | |
389 | } | |
390 | ||
391 | #define RETRIES 10 | |
392 | ||
393 | int sja1105_static_config_upload(struct sja1105_private *priv) | |
394 | { | |
1a4c6940 | 395 | unsigned long port_bitmap = GENMASK_ULL(SJA1105_NUM_PORTS - 1, 0); |
8aa9ebcc VO |
396 | struct sja1105_static_config *config = &priv->static_config; |
397 | const struct sja1105_regs *regs = priv->info->regs; | |
398 | struct device *dev = &priv->spidev->dev; | |
399 | struct sja1105_status status; | |
400 | int rc, retries = RETRIES; | |
401 | u8 *config_buf; | |
402 | int buf_len; | |
403 | ||
404 | buf_len = sja1105_static_config_get_length(config); | |
405 | config_buf = kcalloc(buf_len, sizeof(char), GFP_KERNEL); | |
406 | if (!config_buf) | |
407 | return -ENOMEM; | |
408 | ||
409 | rc = static_config_buf_prepare_for_upload(priv, config_buf, buf_len); | |
410 | if (rc < 0) { | |
411 | dev_err(dev, "Invalid config, cannot upload\n"); | |
412 | return -EINVAL; | |
413 | } | |
1a4c6940 VO |
414 | /* Prevent PHY jabbering during switch reset by inhibiting |
415 | * Tx on all ports and waiting for current packet to drain. | |
416 | * Otherwise, the PHY will see an unterminated Ethernet packet. | |
417 | */ | |
d114fb04 | 418 | rc = sja1105_inhibit_tx(priv, port_bitmap, true); |
1a4c6940 VO |
419 | if (rc < 0) { |
420 | dev_err(dev, "Failed to inhibit Tx on ports\n"); | |
421 | return -ENXIO; | |
422 | } | |
423 | /* Wait for an eventual egress packet to finish transmission | |
424 | * (reach IFG). It is guaranteed that a second one will not | |
425 | * follow, and that switch cold reset is thus safe | |
426 | */ | |
427 | usleep_range(500, 1000); | |
8aa9ebcc VO |
428 | do { |
429 | /* Put the SJA1105 in programming mode */ | |
430 | rc = sja1105_cold_reset(priv); | |
431 | if (rc < 0) { | |
432 | dev_err(dev, "Failed to reset switch, retrying...\n"); | |
433 | continue; | |
434 | } | |
435 | /* Wait for the switch to come out of reset */ | |
436 | usleep_range(1000, 5000); | |
437 | /* Upload the static config to the device */ | |
438 | rc = sja1105_spi_send_long_packed_buf(priv, SPI_WRITE, | |
439 | regs->config, | |
440 | config_buf, buf_len); | |
441 | if (rc < 0) { | |
442 | dev_err(dev, "Failed to upload config, retrying...\n"); | |
443 | continue; | |
444 | } | |
445 | /* Check that SJA1105 responded well to the config upload */ | |
446 | rc = sja1105_status_get(priv, &status); | |
447 | if (rc < 0) | |
448 | continue; | |
449 | ||
450 | if (status.ids == 1) { | |
451 | dev_err(dev, "Mismatch between hardware and static config " | |
452 | "device id. Wrote 0x%llx, wants 0x%llx\n", | |
453 | config->device_id, priv->info->device_id); | |
454 | continue; | |
455 | } | |
456 | if (status.crcchkl == 1) { | |
457 | dev_err(dev, "Switch reported invalid local CRC on " | |
458 | "the uploaded config, retrying...\n"); | |
459 | continue; | |
460 | } | |
461 | if (status.crcchkg == 1) { | |
462 | dev_err(dev, "Switch reported invalid global CRC on " | |
463 | "the uploaded config, retrying...\n"); | |
464 | continue; | |
465 | } | |
466 | if (status.configs == 0) { | |
467 | dev_err(dev, "Switch reported that configuration is " | |
468 | "invalid, retrying...\n"); | |
469 | continue; | |
470 | } | |
5425711b CIK |
471 | /* Success! */ |
472 | break; | |
473 | } while (--retries); | |
8aa9ebcc VO |
474 | |
475 | if (!retries) { | |
476 | rc = -EIO; | |
477 | dev_err(dev, "Failed to upload config to device, giving up\n"); | |
478 | goto out; | |
5425711b | 479 | } else if (retries != RETRIES) { |
8aa9ebcc VO |
480 | dev_info(dev, "Succeeded after %d tried\n", RETRIES - retries); |
481 | } | |
482 | ||
bb77f36a VO |
483 | rc = sja1105_ptp_reset(priv); |
484 | if (rc < 0) | |
485 | dev_err(dev, "Failed to reset PTP clock: %d\n", rc); | |
486 | ||
8aa9ebcc | 487 | dev_info(dev, "Reset switch and programmed static config\n"); |
bb77f36a | 488 | |
8aa9ebcc VO |
489 | out: |
490 | kfree(config_buf); | |
491 | return rc; | |
492 | } | |
493 | ||
86dc59e3 | 494 | static struct sja1105_regs sja1105et_regs = { |
8aa9ebcc VO |
495 | .device_id = 0x0, |
496 | .prod_id = 0x100BC3, | |
497 | .status = 0x1, | |
1a4c6940 | 498 | .port_control = 0x11, |
8aa9ebcc VO |
499 | .config = 0x020000, |
500 | .rgu = 0x100440, | |
b5b0c7f4 | 501 | /* UM10944.pdf, Table 86, ACU Register overview */ |
8aa9ebcc VO |
502 | .pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808}, |
503 | .rmii_pll1 = 0x10000A, | |
504 | .cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F}, | |
8aa9ebcc VO |
505 | .mac = {0x200, 0x202, 0x204, 0x206, 0x208}, |
506 | .mac_hl1 = {0x400, 0x410, 0x420, 0x430, 0x440}, | |
507 | .mac_hl2 = {0x600, 0x610, 0x620, 0x630, 0x640}, | |
508 | /* UM10944.pdf, Table 78, CGU Register overview */ | |
509 | .mii_tx_clk = {0x100013, 0x10001A, 0x100021, 0x100028, 0x10002F}, | |
510 | .mii_rx_clk = {0x100014, 0x10001B, 0x100022, 0x100029, 0x100030}, | |
511 | .mii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034}, | |
512 | .mii_ext_rx_clk = {0x100019, 0x100020, 0x100027, 0x10002E, 0x100035}, | |
513 | .rgmii_tx_clk = {0x100016, 0x10001D, 0x100024, 0x10002B, 0x100032}, | |
514 | .rmii_ref_clk = {0x100015, 0x10001C, 0x100023, 0x10002A, 0x100031}, | |
515 | .rmii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034}, | |
47ed985e | 516 | .ptpegr_ts = {0xC0, 0xC2, 0xC4, 0xC6, 0xC8}, |
bb77f36a VO |
517 | .ptp_control = 0x17, |
518 | .ptpclk = 0x18, /* Spans 0x18 to 0x19 */ | |
519 | .ptpclkrate = 0x1A, | |
520 | .ptptsclk = 0x1B, /* Spans 0x1B to 0x1C */ | |
8aa9ebcc VO |
521 | }; |
522 | ||
86dc59e3 | 523 | static struct sja1105_regs sja1105pqrs_regs = { |
8aa9ebcc VO |
524 | .device_id = 0x0, |
525 | .prod_id = 0x100BC3, | |
526 | .status = 0x1, | |
1a4c6940 | 527 | .port_control = 0x12, |
8aa9ebcc VO |
528 | .config = 0x020000, |
529 | .rgu = 0x100440, | |
b5b0c7f4 | 530 | /* UM10944.pdf, Table 86, ACU Register overview */ |
8aa9ebcc | 531 | .pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808}, |
c05ec3d4 | 532 | .pad_mii_id = {0x100810, 0x100811, 0x100812, 0x100813, 0x100814}, |
8aa9ebcc VO |
533 | .rmii_pll1 = 0x10000A, |
534 | .cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F}, | |
8aa9ebcc VO |
535 | .mac = {0x200, 0x202, 0x204, 0x206, 0x208}, |
536 | .mac_hl1 = {0x400, 0x410, 0x420, 0x430, 0x440}, | |
537 | .mac_hl2 = {0x600, 0x610, 0x620, 0x630, 0x640}, | |
538 | /* UM11040.pdf, Table 114 */ | |
539 | .mii_tx_clk = {0x100013, 0x100019, 0x10001F, 0x100025, 0x10002B}, | |
540 | .mii_rx_clk = {0x100014, 0x10001A, 0x100020, 0x100026, 0x10002C}, | |
541 | .mii_ext_tx_clk = {0x100017, 0x10001D, 0x100023, 0x100029, 0x10002F}, | |
542 | .mii_ext_rx_clk = {0x100018, 0x10001E, 0x100024, 0x10002A, 0x100030}, | |
543 | .rgmii_tx_clk = {0x100016, 0x10001C, 0x100022, 0x100028, 0x10002E}, | |
544 | .rmii_ref_clk = {0x100015, 0x10001B, 0x100021, 0x100027, 0x10002D}, | |
545 | .rmii_ext_tx_clk = {0x100017, 0x10001D, 0x100023, 0x100029, 0x10002F}, | |
546 | .qlevel = {0x604, 0x614, 0x624, 0x634, 0x644}, | |
47ed985e | 547 | .ptpegr_ts = {0xC0, 0xC4, 0xC8, 0xCC, 0xD0}, |
bb77f36a VO |
548 | .ptp_control = 0x18, |
549 | .ptpclk = 0x19, | |
550 | .ptpclkrate = 0x1B, | |
551 | .ptptsclk = 0x1C, | |
8aa9ebcc VO |
552 | }; |
553 | ||
554 | struct sja1105_info sja1105e_info = { | |
555 | .device_id = SJA1105E_DEVICE_ID, | |
556 | .part_no = SJA1105ET_PART_NO, | |
557 | .static_ops = sja1105e_table_ops, | |
558 | .dyn_ops = sja1105et_dyn_ops, | |
47ed985e VO |
559 | .ptp_ts_bits = 24, |
560 | .ptpegr_ts_bytes = 4, | |
8aa9ebcc | 561 | .reset_cmd = sja1105et_reset_cmd, |
9dfa6911 VO |
562 | .fdb_add_cmd = sja1105et_fdb_add, |
563 | .fdb_del_cmd = sja1105et_fdb_del, | |
bb77f36a | 564 | .ptp_cmd = sja1105et_ptp_cmd, |
8aa9ebcc VO |
565 | .regs = &sja1105et_regs, |
566 | .name = "SJA1105E", | |
567 | }; | |
568 | struct sja1105_info sja1105t_info = { | |
569 | .device_id = SJA1105T_DEVICE_ID, | |
570 | .part_no = SJA1105ET_PART_NO, | |
571 | .static_ops = sja1105t_table_ops, | |
572 | .dyn_ops = sja1105et_dyn_ops, | |
47ed985e VO |
573 | .ptp_ts_bits = 24, |
574 | .ptpegr_ts_bytes = 4, | |
8aa9ebcc | 575 | .reset_cmd = sja1105et_reset_cmd, |
9dfa6911 VO |
576 | .fdb_add_cmd = sja1105et_fdb_add, |
577 | .fdb_del_cmd = sja1105et_fdb_del, | |
bb77f36a | 578 | .ptp_cmd = sja1105et_ptp_cmd, |
8aa9ebcc VO |
579 | .regs = &sja1105et_regs, |
580 | .name = "SJA1105T", | |
581 | }; | |
582 | struct sja1105_info sja1105p_info = { | |
583 | .device_id = SJA1105PR_DEVICE_ID, | |
584 | .part_no = SJA1105P_PART_NO, | |
585 | .static_ops = sja1105p_table_ops, | |
586 | .dyn_ops = sja1105pqrs_dyn_ops, | |
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, | |
bb77f36a | 593 | .ptp_cmd = sja1105pqrs_ptp_cmd, |
8aa9ebcc VO |
594 | .regs = &sja1105pqrs_regs, |
595 | .name = "SJA1105P", | |
596 | }; | |
597 | struct sja1105_info sja1105q_info = { | |
598 | .device_id = SJA1105QS_DEVICE_ID, | |
599 | .part_no = SJA1105Q_PART_NO, | |
600 | .static_ops = sja1105q_table_ops, | |
601 | .dyn_ops = sja1105pqrs_dyn_ops, | |
47ed985e VO |
602 | .ptp_ts_bits = 32, |
603 | .ptpegr_ts_bytes = 8, | |
c05ec3d4 | 604 | .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay, |
8aa9ebcc | 605 | .reset_cmd = sja1105pqrs_reset_cmd, |
9dfa6911 VO |
606 | .fdb_add_cmd = sja1105pqrs_fdb_add, |
607 | .fdb_del_cmd = sja1105pqrs_fdb_del, | |
bb77f36a | 608 | .ptp_cmd = sja1105pqrs_ptp_cmd, |
8aa9ebcc VO |
609 | .regs = &sja1105pqrs_regs, |
610 | .name = "SJA1105Q", | |
611 | }; | |
612 | struct sja1105_info sja1105r_info = { | |
613 | .device_id = SJA1105PR_DEVICE_ID, | |
614 | .part_no = SJA1105R_PART_NO, | |
615 | .static_ops = sja1105r_table_ops, | |
616 | .dyn_ops = sja1105pqrs_dyn_ops, | |
47ed985e VO |
617 | .ptp_ts_bits = 32, |
618 | .ptpegr_ts_bytes = 8, | |
c05ec3d4 | 619 | .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay, |
8aa9ebcc | 620 | .reset_cmd = sja1105pqrs_reset_cmd, |
9dfa6911 VO |
621 | .fdb_add_cmd = sja1105pqrs_fdb_add, |
622 | .fdb_del_cmd = sja1105pqrs_fdb_del, | |
bb77f36a | 623 | .ptp_cmd = sja1105pqrs_ptp_cmd, |
8aa9ebcc VO |
624 | .regs = &sja1105pqrs_regs, |
625 | .name = "SJA1105R", | |
626 | }; | |
627 | struct sja1105_info sja1105s_info = { | |
628 | .device_id = SJA1105QS_DEVICE_ID, | |
629 | .part_no = SJA1105S_PART_NO, | |
630 | .static_ops = sja1105s_table_ops, | |
631 | .dyn_ops = sja1105pqrs_dyn_ops, | |
632 | .regs = &sja1105pqrs_regs, | |
47ed985e VO |
633 | .ptp_ts_bits = 32, |
634 | .ptpegr_ts_bytes = 8, | |
c05ec3d4 | 635 | .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay, |
8aa9ebcc | 636 | .reset_cmd = sja1105pqrs_reset_cmd, |
9dfa6911 VO |
637 | .fdb_add_cmd = sja1105pqrs_fdb_add, |
638 | .fdb_del_cmd = sja1105pqrs_fdb_del, | |
bb77f36a | 639 | .ptp_cmd = sja1105pqrs_ptp_cmd, |
8aa9ebcc VO |
640 | .name = "SJA1105S", |
641 | }; |