1 /***********************license start***************
2 * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * * Neither the name of Cavium Inc. nor the names of
19 * its contributors may be used to endorse or promote products
20 * derived from this software without specific prior written
23 * This Software, including technical data, may be subject to U.S. export control
24 * laws, including the U.S. Export Administration Act and its associated
25 * regulations, and may be subject to export or import regulations in other
28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR
37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
49 * Support library for the SPI
51 * <hr>$Revision: 70030 $<hr>
53 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
54 #include <linux/module.h>
55 #include <asm/octeon/cvmx.h>
56 #include <asm/octeon/cvmx-config.h>
57 #include <asm/octeon/cvmx-spxx-defs.h>
58 #include <asm/octeon/cvmx-stxx-defs.h>
59 #include <asm/octeon/cvmx-srxx-defs.h>
60 #include <asm/octeon/cvmx-pko.h>
61 #include <asm/octeon/cvmx-spi.h>
62 #include <asm/octeon/cvmx-clock.h>
65 #if !defined(__FreeBSD__) || !defined(_KERNEL)
66 #include "cvmx-config.h"
68 #include "cvmx-sysinfo.h"
71 #include "cvmx-clock.h"
75 #define INVOKE_CB(function_p, args...) \
78 res = function_p(args); \
84 #if CVMX_ENABLE_DEBUG_PRINTS
85 static const char *modes[] = {"UNKNOWN", "TX Halfplex", "Rx Halfplex", "Duplex"};
88 /* Default callbacks, can be overridden
89 * using cvmx_spi_get_callbacks/cvmx_spi_set_callbacks
91 static cvmx_spi_callbacks_t cvmx_spi_callbacks = {
92 .reset_cb = cvmx_spi_reset_cb,
93 .calendar_setup_cb = cvmx_spi_calendar_setup_cb,
94 .clock_detect_cb = cvmx_spi_clock_detect_cb,
95 .training_cb = cvmx_spi_training_cb,
96 .calendar_sync_cb = cvmx_spi_calendar_sync_cb,
97 .interface_up_cb = cvmx_spi_interface_up_cb
101 * Get current SPI4 initialization callbacks
103 * @param callbacks Pointer to the callbacks structure.to fill
105 * @return Pointer to cvmx_spi_callbacks_t structure.
107 void cvmx_spi_get_callbacks(cvmx_spi_callbacks_t * callbacks)
109 memcpy(callbacks, &cvmx_spi_callbacks, sizeof(cvmx_spi_callbacks));
113 * Set new SPI4 initialization callbacks
115 * @param new_callbacks Pointer to an updated callbacks structure.
117 void cvmx_spi_set_callbacks(cvmx_spi_callbacks_t * new_callbacks)
119 memcpy(&cvmx_spi_callbacks, new_callbacks, sizeof(cvmx_spi_callbacks));
123 * Initialize and start the SPI interface.
125 * @param interface The identifier of the packet interface to configure and
126 * use as a SPI interface.
127 * @param mode The operating mode for the SPI interface. The interface
128 * can operate as a full duplex (both Tx and Rx data paths
129 * active) or as a halfplex (either the Tx data path is
130 * active or the Rx data path is active, but not both).
131 * @param timeout Timeout to wait for clock synchronization in seconds
132 * @param num_ports Number of SPI ports to configure
134 * @return Zero on success, negative of failure.
136 int cvmx_spi_start_interface(int interface, cvmx_spi_mode_t mode, int timeout, int num_ports)
140 if (!(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)))
143 // Callback to perform SPI4 reset
144 INVOKE_CB( cvmx_spi_callbacks.reset_cb, interface, mode);
146 // Callback to perform calendar setup
147 INVOKE_CB(cvmx_spi_callbacks.calendar_setup_cb, interface, mode, num_ports);
149 // Callback to perform clock detection
150 INVOKE_CB(cvmx_spi_callbacks.clock_detect_cb, interface, mode, timeout);
152 // Callback to perform SPI4 link training
153 INVOKE_CB(cvmx_spi_callbacks.training_cb, interface, mode, timeout);
155 // Callback to perform calendar sync
156 INVOKE_CB(cvmx_spi_callbacks.calendar_sync_cb, interface, mode, timeout);
158 // Callback to handle interface coming up
159 INVOKE_CB(cvmx_spi_callbacks.interface_up_cb, interface, mode);
165 * This routine restarts the SPI interface after it has lost synchronization
166 * with its correspondent system.
168 * @param interface The identifier of the packet interface to configure and
169 * use as a SPI interface.
170 * @param mode The operating mode for the SPI interface. The interface
171 * can operate as a full duplex (both Tx and Rx data paths
172 * active) or as a halfplex (either the Tx data path is
173 * active or the Rx data path is active, but not both).
174 * @param timeout Timeout to wait for clock synchronization in seconds
175 * @return Zero on success, negative of failure.
177 int cvmx_spi_restart_interface(int interface, cvmx_spi_mode_t mode, int timeout)
182 if (!(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)))
185 cvmx_dprintf ("SPI%d: Restart %s\n", interface, modes[mode]);
187 // Callback to perform SPI4 reset
188 INVOKE_CB(cvmx_spi_callbacks.reset_cb, interface,mode);
190 // NOTE: Calendar setup is not performed during restart
191 // Refer to cvmx_spi_start_interface() for the full sequence
193 // Callback to perform clock detection
194 INVOKE_CB(cvmx_spi_callbacks.clock_detect_cb, interface, mode, timeout);
196 // Callback to perform SPI4 link training
197 INVOKE_CB(cvmx_spi_callbacks.training_cb, interface, mode, timeout);
199 // Callback to perform calendar sync
200 INVOKE_CB(cvmx_spi_callbacks.calendar_sync_cb, interface, mode, timeout);
202 // Callback to handle interface coming up
203 INVOKE_CB(cvmx_spi_callbacks.interface_up_cb, interface, mode);
207 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
208 EXPORT_SYMBOL(cvmx_spi_restart_interface);
212 * Callback to perform SPI4 reset
214 * @param interface The identifier of the packet interface to configure and
215 * use as a SPI interface.
216 * @param mode The operating mode for the SPI interface. The interface
217 * can operate as a full duplex (both Tx and Rx data paths
218 * active) or as a halfplex (either the Tx data path is
219 * active or the Rx data path is active, but not both).
220 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
222 int cvmx_spi_reset_cb(int interface, cvmx_spi_mode_t mode)
224 cvmx_spxx_dbg_deskew_ctl_t spxx_dbg_deskew_ctl;
225 cvmx_spxx_clk_ctl_t spxx_clk_ctl;
226 cvmx_spxx_bist_stat_t spxx_bist_stat;
227 cvmx_spxx_int_msk_t spxx_int_msk;
228 cvmx_stxx_int_msk_t stxx_int_msk;
229 cvmx_spxx_trn4_ctl_t spxx_trn4_ctl;
231 uint64_t MS = cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000;
233 /* Disable SPI error events while we run BIST */
234 spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface));
235 cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0);
236 stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface));
237 cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0);
239 /* Run BIST in the SPI interface */
240 cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), 0);
241 cvmx_write_csr(CVMX_STXX_COM_CTL(interface), 0);
242 spxx_clk_ctl.u64 = 0;
243 spxx_clk_ctl.s.runbist = 1;
244 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
246 spxx_bist_stat.u64 = cvmx_read_csr(CVMX_SPXX_BIST_STAT(interface));
247 if (spxx_bist_stat.s.stat0)
248 cvmx_dprintf("ERROR SPI%d: BIST failed on receive datapath FIFO\n", interface);
249 if (spxx_bist_stat.s.stat1)
250 cvmx_dprintf("ERROR SPI%d: BIST failed on RX calendar table\n", interface);
251 if (spxx_bist_stat.s.stat2)
252 cvmx_dprintf("ERROR SPI%d: BIST failed on TX calendar table\n", interface);
254 /* Clear the calendar table after BIST to fix parity errors */
255 for (index=0; index<32; index++)
257 cvmx_srxx_spi4_calx_t srxx_spi4_calx;
258 cvmx_stxx_spi4_calx_t stxx_spi4_calx;
260 srxx_spi4_calx.u64 = 0;
261 srxx_spi4_calx.s.oddpar = 1;
262 cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface), srxx_spi4_calx.u64);
264 stxx_spi4_calx.u64 = 0;
265 stxx_spi4_calx.s.oddpar = 1;
266 cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface), stxx_spi4_calx.u64);
269 /* Re enable reporting of error interrupts */
270 cvmx_write_csr(CVMX_SPXX_INT_REG(interface), cvmx_read_csr(CVMX_SPXX_INT_REG(interface)));
271 cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64);
272 cvmx_write_csr(CVMX_STXX_INT_REG(interface), cvmx_read_csr(CVMX_STXX_INT_REG(interface)));
273 cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64);
275 // Setup the CLKDLY right in the middle
276 spxx_clk_ctl.u64 = 0;
277 spxx_clk_ctl.s.seetrn = 0;
278 spxx_clk_ctl.s.clkdly = 0x10;
279 spxx_clk_ctl.s.runbist = 0;
280 spxx_clk_ctl.s.statdrv = 0;
281 spxx_clk_ctl.s.statrcv = 1; /* This should always be on the opposite edge as statdrv */
282 spxx_clk_ctl.s.sndtrn = 0;
283 spxx_clk_ctl.s.drptrn = 0;
284 spxx_clk_ctl.s.rcvtrn = 0;
285 spxx_clk_ctl.s.srxdlck = 0;
286 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
287 cvmx_wait (100 * MS);
290 spxx_clk_ctl.s.srxdlck = 1;
291 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
293 // Waiting for Inf0 Spi4 RX DLL to lock
294 cvmx_wait (100 * MS);
296 // Enable dynamic alignment
297 spxx_trn4_ctl.s.trntest = 0;
298 spxx_trn4_ctl.s.jitter = 1;
299 spxx_trn4_ctl.s.clr_boot = 1;
300 spxx_trn4_ctl.s.set_boot = 0;
301 if (OCTEON_IS_MODEL(OCTEON_CN58XX))
302 spxx_trn4_ctl.s.maxdist = 3;
304 spxx_trn4_ctl.s.maxdist = 8;
305 spxx_trn4_ctl.s.macro_en = 1;
306 spxx_trn4_ctl.s.mux_en = 1;
307 cvmx_write_csr (CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64);
309 spxx_dbg_deskew_ctl.u64 = 0;
310 cvmx_write_csr (CVMX_SPXX_DBG_DESKEW_CTL(interface), spxx_dbg_deskew_ctl.u64);
316 * Callback to setup calendar and miscellaneous settings before clock detection
318 * @param interface The identifier of the packet interface to configure and
319 * use as a SPI interface.
320 * @param mode The operating mode for the SPI interface. The interface
321 * can operate as a full duplex (both Tx and Rx data paths
322 * active) or as a halfplex (either the Tx data path is
323 * active or the Rx data path is active, but not both).
324 * @param num_ports Number of ports to configure on SPI
325 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
327 int cvmx_spi_calendar_setup_cb(int interface, cvmx_spi_mode_t mode, int num_ports)
331 if (mode & CVMX_SPI_MODE_RX_HALFPLEX)
333 cvmx_srxx_com_ctl_t srxx_com_ctl;
334 cvmx_srxx_spi4_stat_t srxx_spi4_stat;
336 // SRX0 number of Ports
337 srxx_com_ctl.u64 = 0;
338 srxx_com_ctl.s.prts = num_ports - 1;
339 srxx_com_ctl.s.st_en = 0;
340 srxx_com_ctl.s.inf_en = 0;
341 cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64);
343 // SRX0 Calendar Table. This round robbins through all ports
346 while (port < num_ports)
348 cvmx_srxx_spi4_calx_t srxx_spi4_calx;
349 srxx_spi4_calx.u64 = 0;
350 srxx_spi4_calx.s.prt0 = port++;
351 srxx_spi4_calx.s.prt1 = port++;
352 srxx_spi4_calx.s.prt2 = port++;
353 srxx_spi4_calx.s.prt3 = port++;
354 srxx_spi4_calx.s.oddpar = ~(cvmx_dpop(srxx_spi4_calx.u64) & 1);
355 cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface), srxx_spi4_calx.u64);
358 srxx_spi4_stat.u64 = 0;
359 srxx_spi4_stat.s.len = num_ports;
360 srxx_spi4_stat.s.m = 1;
361 cvmx_write_csr(CVMX_SRXX_SPI4_STAT(interface), srxx_spi4_stat.u64);
364 if (mode & CVMX_SPI_MODE_TX_HALFPLEX)
366 cvmx_stxx_arb_ctl_t stxx_arb_ctl;
367 cvmx_gmxx_tx_spi_max_t gmxx_tx_spi_max;
368 cvmx_gmxx_tx_spi_thresh_t gmxx_tx_spi_thresh;
369 cvmx_gmxx_tx_spi_ctl_t gmxx_tx_spi_ctl;
370 cvmx_stxx_spi4_stat_t stxx_spi4_stat;
371 cvmx_stxx_spi4_dat_t stxx_spi4_dat;
374 stxx_arb_ctl.u64 = 0;
375 stxx_arb_ctl.s.igntpa = 0;
376 stxx_arb_ctl.s.mintrn = 0;
377 cvmx_write_csr(CVMX_STXX_ARB_CTL(interface), stxx_arb_ctl.u64);
379 gmxx_tx_spi_max.u64 = 0;
380 gmxx_tx_spi_max.s.max1 = 8;
381 gmxx_tx_spi_max.s.max2 = 4;
382 gmxx_tx_spi_max.s.slice = 0;
383 cvmx_write_csr(CVMX_GMXX_TX_SPI_MAX(interface), gmxx_tx_spi_max.u64);
385 gmxx_tx_spi_thresh.u64 = 0;
386 gmxx_tx_spi_thresh.s.thresh = 4;
387 cvmx_write_csr(CVMX_GMXX_TX_SPI_THRESH(interface), gmxx_tx_spi_thresh.u64);
389 gmxx_tx_spi_ctl.u64 = 0;
390 gmxx_tx_spi_ctl.s.tpa_clr = 0;
391 gmxx_tx_spi_ctl.s.cont_pkt = 0;
392 cvmx_write_csr(CVMX_GMXX_TX_SPI_CTL(interface), gmxx_tx_spi_ctl.u64);
394 // STX0 Training Control
395 stxx_spi4_dat.u64 = 0;
396 stxx_spi4_dat.s.alpha = 32; /*Minimum needed by dynamic alignment*/
397 stxx_spi4_dat.s.max_t = 0xFFFF; /*Minimum interval is 0x20*/
398 cvmx_write_csr(CVMX_STXX_SPI4_DAT(interface), stxx_spi4_dat.u64);
400 // STX0 Calendar Table. This round robbins through all ports
403 while (port < num_ports)
405 cvmx_stxx_spi4_calx_t stxx_spi4_calx;
406 stxx_spi4_calx.u64 = 0;
407 stxx_spi4_calx.s.prt0 = port++;
408 stxx_spi4_calx.s.prt1 = port++;
409 stxx_spi4_calx.s.prt2 = port++;
410 stxx_spi4_calx.s.prt3 = port++;
411 stxx_spi4_calx.s.oddpar = ~(cvmx_dpop(stxx_spi4_calx.u64) & 1);
412 cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface), stxx_spi4_calx.u64);
415 stxx_spi4_stat.u64 = 0;
416 stxx_spi4_stat.s.len = num_ports;
417 stxx_spi4_stat.s.m = 1;
418 cvmx_write_csr(CVMX_STXX_SPI4_STAT(interface), stxx_spi4_stat.u64);
425 * Callback to perform clock detection
427 * @param interface The identifier of the packet interface to configure and
428 * use as a SPI interface.
429 * @param mode The operating mode for the SPI interface. The interface
430 * can operate as a full duplex (both Tx and Rx data paths
431 * active) or as a halfplex (either the Tx data path is
432 * active or the Rx data path is active, but not both).
433 * @param timeout Timeout to wait for clock synchronization in seconds
434 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
436 int cvmx_spi_clock_detect_cb(int interface, cvmx_spi_mode_t mode, int timeout)
438 int clock_transitions;
439 cvmx_spxx_clk_stat_t stat;
440 uint64_t timeout_time;
441 uint64_t MS = cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000;
443 /* Regardless of operating mode, both Tx and Rx clocks must be present
444 for the SPI interface to operate. */
445 cvmx_dprintf ("SPI%d: Waiting to see TsClk...\n", interface);
446 timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
447 /* Require 100 clock transitions in order to avoid any noise in the
449 clock_transitions = 100;
452 stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface));
453 if (stat.s.s4clk0 && stat.s.s4clk1 && clock_transitions)
455 /* We've seen a clock transition, so decrement the number we still
458 cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64);
462 if (cvmx_get_cycle() > timeout_time)
464 cvmx_dprintf ("SPI%d: Timeout\n", interface);
467 } while (stat.s.s4clk0 == 0 || stat.s.s4clk1 == 0);
469 cvmx_dprintf ("SPI%d: Waiting to see RsClk...\n", interface);
470 timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
471 /* Require 100 clock transitions in order to avoid any noise in the
473 clock_transitions = 100;
476 stat.u64 = cvmx_read_csr (CVMX_SPXX_CLK_STAT(interface));
477 if (stat.s.d4clk0 && stat.s.d4clk1 && clock_transitions)
479 /* We've seen a clock transition, so decrement the number we still
482 cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64);
486 if (cvmx_get_cycle() > timeout_time)
488 cvmx_dprintf ("SPI%d: Timeout\n", interface);
491 } while (stat.s.d4clk0 == 0 || stat.s.d4clk1 == 0);
497 * Callback to perform link training
499 * @param interface The identifier of the packet interface to configure and
500 * use as a SPI interface.
501 * @param mode The operating mode for the SPI interface. The interface
502 * can operate as a full duplex (both Tx and Rx data paths
503 * active) or as a halfplex (either the Tx data path is
504 * active or the Rx data path is active, but not both).
505 * @param timeout Timeout to wait for link to be trained (in seconds)
506 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
508 int cvmx_spi_training_cb(int interface, cvmx_spi_mode_t mode, int timeout)
510 cvmx_spxx_trn4_ctl_t spxx_trn4_ctl;
511 cvmx_spxx_clk_stat_t stat;
512 uint64_t MS = cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000;
513 uint64_t timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
514 int rx_training_needed;
516 // SRX0 & STX0 Inf0 Links are configured - begin training
517 cvmx_spxx_clk_ctl_t spxx_clk_ctl;
518 spxx_clk_ctl.u64 = 0;
519 spxx_clk_ctl.s.seetrn = 0;
520 spxx_clk_ctl.s.clkdly = 0x10;
521 spxx_clk_ctl.s.runbist = 0;
522 spxx_clk_ctl.s.statdrv = 0;
523 spxx_clk_ctl.s.statrcv = 1; /* This should always be on the opposite edge as statdrv */
524 spxx_clk_ctl.s.sndtrn = 1;
525 spxx_clk_ctl.s.drptrn = 1;
526 spxx_clk_ctl.s.rcvtrn = 1;
527 spxx_clk_ctl.s.srxdlck = 1;
528 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
529 cvmx_wait (1000 * MS);
531 // SRX0 clear the boot bit
532 spxx_trn4_ctl.u64 = cvmx_read_csr(CVMX_SPXX_TRN4_CTL(interface));
533 spxx_trn4_ctl.s.clr_boot = 1;
534 cvmx_write_csr (CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64);
536 // Wait for the training sequence to complete
537 cvmx_dprintf ("SPI%d: Waiting for training\n", interface);
538 cvmx_wait (1000 * MS);
539 #if !defined(OCTEON_VENDOR_LANNER)
540 timeout_time = cvmx_get_cycle() + 1000ull * MS * 600; /* Wait a really long time here */
542 timeout_time = cvmx_get_cycle() + 1000ull * MS * 10;
544 /* The HRM says we must wait for 34 + 16 * MAXDIST training sequences.
545 We'll be pessimistic and wait for a lot more */
546 rx_training_needed = 500;
548 stat.u64 = cvmx_read_csr (CVMX_SPXX_CLK_STAT(interface));
549 if (stat.s.srxtrn && rx_training_needed)
551 rx_training_needed--;
552 cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64);
555 if (cvmx_get_cycle() > timeout_time)
557 cvmx_dprintf ("SPI%d: Timeout\n", interface);
560 } while (stat.s.srxtrn == 0);
566 * Callback to perform calendar data synchronization
568 * @param interface The identifier of the packet interface to configure and
569 * use as a SPI interface.
570 * @param mode The operating mode for the SPI interface. The interface
571 * can operate as a full duplex (both Tx and Rx data paths
572 * active) or as a halfplex (either the Tx data path is
573 * active or the Rx data path is active, but not both).
574 * @param timeout Timeout to wait for calendar data in seconds
575 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
577 int cvmx_spi_calendar_sync_cb(int interface, cvmx_spi_mode_t mode, int timeout)
579 uint64_t MS = cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000;
580 if (mode & CVMX_SPI_MODE_RX_HALFPLEX) {
581 // SRX0 interface should be good, send calendar data
582 cvmx_srxx_com_ctl_t srxx_com_ctl;
583 cvmx_dprintf ("SPI%d: Rx is synchronized, start sending calendar data\n", interface);
584 srxx_com_ctl.u64 = cvmx_read_csr(CVMX_SRXX_COM_CTL(interface));
585 srxx_com_ctl.s.inf_en = 1;
586 srxx_com_ctl.s.st_en = 1;
587 cvmx_write_csr (CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64);
590 if (mode & CVMX_SPI_MODE_TX_HALFPLEX) {
591 // STX0 has achieved sync
592 // The corespondant board should be sending calendar data
593 // Enable the STX0 STAT receiver.
594 cvmx_spxx_clk_stat_t stat;
595 uint64_t timeout_time;
596 cvmx_stxx_com_ctl_t stxx_com_ctl;
597 stxx_com_ctl.u64 = 0;
598 stxx_com_ctl.s.st_en = 1;
599 cvmx_write_csr (CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64);
601 // Waiting for calendar sync on STX0 STAT
602 cvmx_dprintf ("SPI%d: Waiting to sync on STX[%d] STAT\n", interface, interface);
603 timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
604 // SPX0_CLK_STAT - SPX0_CLK_STAT[STXCAL] should be 1 (bit10)
606 stat.u64 = cvmx_read_csr (CVMX_SPXX_CLK_STAT (interface));
607 if (cvmx_get_cycle() > timeout_time)
609 cvmx_dprintf ("SPI%d: Timeout\n", interface);
612 } while (stat.s.stxcal == 0);
619 * Callback to handle interface up
621 * @param interface The identifier of the packet interface to configure and
622 * use as a SPI interface.
623 * @param mode The operating mode for the SPI interface. The interface
624 * can operate as a full duplex (both Tx and Rx data paths
625 * active) or as a halfplex (either the Tx data path is
626 * active or the Rx data path is active, but not both).
627 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
629 int cvmx_spi_interface_up_cb(int interface, cvmx_spi_mode_t mode)
631 cvmx_gmxx_rxx_frm_min_t gmxx_rxx_frm_min;
632 cvmx_gmxx_rxx_frm_max_t gmxx_rxx_frm_max;
633 cvmx_gmxx_rxx_jabber_t gmxx_rxx_jabber;
635 if (mode & CVMX_SPI_MODE_RX_HALFPLEX) {
636 cvmx_srxx_com_ctl_t srxx_com_ctl;
637 srxx_com_ctl.u64 = cvmx_read_csr(CVMX_SRXX_COM_CTL(interface));
638 srxx_com_ctl.s.inf_en = 1;
639 cvmx_write_csr (CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64);
640 cvmx_dprintf ("SPI%d: Rx is now up\n", interface);
643 if (mode & CVMX_SPI_MODE_TX_HALFPLEX) {
644 cvmx_stxx_com_ctl_t stxx_com_ctl;
645 stxx_com_ctl.u64 = cvmx_read_csr(CVMX_STXX_COM_CTL(interface));
646 stxx_com_ctl.s.inf_en = 1;
647 cvmx_write_csr (CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64);
648 cvmx_dprintf ("SPI%d: Tx is now up\n", interface);
651 gmxx_rxx_frm_min.u64 = 0;
652 gmxx_rxx_frm_min.s.len = 64;
653 #ifdef OCTEON_VENDOR_RADISYS
655 * Incoming packets on the RSYS4GBE have the FCS stripped.
657 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE)
658 gmxx_rxx_frm_min.s.len -= 4;
660 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MIN(0,interface), gmxx_rxx_frm_min.u64);
661 gmxx_rxx_frm_max.u64 = 0;
662 gmxx_rxx_frm_max.s.len = 64*1024 - 4;
663 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(0,interface), gmxx_rxx_frm_max.u64);
664 gmxx_rxx_jabber.u64 = 0;
665 gmxx_rxx_jabber.s.cnt = 64*1024 - 4;
666 cvmx_write_csr(CVMX_GMXX_RXX_JABBER(0,interface), gmxx_rxx_jabber.u64);