1 /***********************license start***************
2 * Copyright (c) 2003-2010 Cavium Networks (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 Networks 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 NETWORKS 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: 49448 $<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 #if CVMX_ENABLE_DEBUG_PRINTS
186 cvmx_dprintf ("SPI%d: Restart %s\n", interface, modes[mode]);
189 // Callback to perform SPI4 reset
190 INVOKE_CB(cvmx_spi_callbacks.reset_cb, interface,mode);
192 // NOTE: Calendar setup is not performed during restart
193 // Refer to cvmx_spi_start_interface() for the full sequence
195 // Callback to perform clock detection
196 INVOKE_CB(cvmx_spi_callbacks.clock_detect_cb, interface, mode, timeout);
198 // Callback to perform SPI4 link training
199 INVOKE_CB(cvmx_spi_callbacks.training_cb, interface, mode, timeout);
201 // Callback to perform calendar sync
202 INVOKE_CB(cvmx_spi_callbacks.calendar_sync_cb, interface, mode, timeout);
204 // Callback to handle interface coming up
205 INVOKE_CB(cvmx_spi_callbacks.interface_up_cb, interface, mode);
209 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
210 EXPORT_SYMBOL(cvmx_spi_restart_interface);
214 * Callback to perform SPI4 reset
216 * @param interface The identifier of the packet interface to configure and
217 * use as a SPI interface.
218 * @param mode The operating mode for the SPI interface. The interface
219 * can operate as a full duplex (both Tx and Rx data paths
220 * active) or as a halfplex (either the Tx data path is
221 * active or the Rx data path is active, but not both).
222 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
224 int cvmx_spi_reset_cb(int interface, cvmx_spi_mode_t mode)
226 cvmx_spxx_dbg_deskew_ctl_t spxx_dbg_deskew_ctl;
227 cvmx_spxx_clk_ctl_t spxx_clk_ctl;
228 cvmx_spxx_bist_stat_t spxx_bist_stat;
229 cvmx_spxx_int_msk_t spxx_int_msk;
230 cvmx_stxx_int_msk_t stxx_int_msk;
231 cvmx_spxx_trn4_ctl_t spxx_trn4_ctl;
233 uint64_t MS = cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000;
235 /* Disable SPI error events while we run BIST */
236 spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface));
237 cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0);
238 stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface));
239 cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0);
241 /* Run BIST in the SPI interface */
242 cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), 0);
243 cvmx_write_csr(CVMX_STXX_COM_CTL(interface), 0);
244 spxx_clk_ctl.u64 = 0;
245 spxx_clk_ctl.s.runbist = 1;
246 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
248 spxx_bist_stat.u64 = cvmx_read_csr(CVMX_SPXX_BIST_STAT(interface));
249 if (spxx_bist_stat.s.stat0)
250 cvmx_dprintf("ERROR SPI%d: BIST failed on receive datapath FIFO\n", interface);
251 if (spxx_bist_stat.s.stat1)
252 cvmx_dprintf("ERROR SPI%d: BIST failed on RX calendar table\n", interface);
253 if (spxx_bist_stat.s.stat2)
254 cvmx_dprintf("ERROR SPI%d: BIST failed on TX calendar table\n", interface);
256 /* Clear the calendar table after BIST to fix parity errors */
257 for (index=0; index<32; index++)
259 cvmx_srxx_spi4_calx_t srxx_spi4_calx;
260 cvmx_stxx_spi4_calx_t stxx_spi4_calx;
262 srxx_spi4_calx.u64 = 0;
263 srxx_spi4_calx.s.oddpar = 1;
264 cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface), srxx_spi4_calx.u64);
266 stxx_spi4_calx.u64 = 0;
267 stxx_spi4_calx.s.oddpar = 1;
268 cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface), stxx_spi4_calx.u64);
271 /* Re enable reporting of error interrupts */
272 cvmx_write_csr(CVMX_SPXX_INT_REG(interface), cvmx_read_csr(CVMX_SPXX_INT_REG(interface)));
273 cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64);
274 cvmx_write_csr(CVMX_STXX_INT_REG(interface), cvmx_read_csr(CVMX_STXX_INT_REG(interface)));
275 cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64);
277 // Setup the CLKDLY right in the middle
278 spxx_clk_ctl.u64 = 0;
279 spxx_clk_ctl.s.seetrn = 0;
280 spxx_clk_ctl.s.clkdly = 0x10;
281 spxx_clk_ctl.s.runbist = 0;
282 spxx_clk_ctl.s.statdrv = 0;
283 spxx_clk_ctl.s.statrcv = 1; /* This should always be on the opposite edge as statdrv */
284 spxx_clk_ctl.s.sndtrn = 0;
285 spxx_clk_ctl.s.drptrn = 0;
286 spxx_clk_ctl.s.rcvtrn = 0;
287 spxx_clk_ctl.s.srxdlck = 0;
288 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
289 cvmx_wait (100 * MS);
292 spxx_clk_ctl.s.srxdlck = 1;
293 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
295 // Waiting for Inf0 Spi4 RX DLL to lock
296 cvmx_wait (100 * MS);
298 // Enable dynamic alignment
299 spxx_trn4_ctl.s.trntest = 0;
300 spxx_trn4_ctl.s.jitter = 1;
301 spxx_trn4_ctl.s.clr_boot = 1;
302 spxx_trn4_ctl.s.set_boot = 0;
303 if (OCTEON_IS_MODEL(OCTEON_CN58XX))
304 spxx_trn4_ctl.s.maxdist = 3;
306 spxx_trn4_ctl.s.maxdist = 8;
307 spxx_trn4_ctl.s.macro_en = 1;
308 spxx_trn4_ctl.s.mux_en = 1;
309 cvmx_write_csr (CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64);
311 spxx_dbg_deskew_ctl.u64 = 0;
312 cvmx_write_csr (CVMX_SPXX_DBG_DESKEW_CTL(interface), spxx_dbg_deskew_ctl.u64);
318 * Callback to setup calendar and miscellaneous settings before clock detection
320 * @param interface The identifier of the packet interface to configure and
321 * use as a SPI interface.
322 * @param mode The operating mode for the SPI interface. The interface
323 * can operate as a full duplex (both Tx and Rx data paths
324 * active) or as a halfplex (either the Tx data path is
325 * active or the Rx data path is active, but not both).
326 * @param num_ports Number of ports to configure on SPI
327 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
329 int cvmx_spi_calendar_setup_cb(int interface, cvmx_spi_mode_t mode, int num_ports)
333 if (mode & CVMX_SPI_MODE_RX_HALFPLEX)
335 cvmx_srxx_com_ctl_t srxx_com_ctl;
336 cvmx_srxx_spi4_stat_t srxx_spi4_stat;
338 // SRX0 number of Ports
339 srxx_com_ctl.u64 = 0;
340 srxx_com_ctl.s.prts = num_ports - 1;
341 srxx_com_ctl.s.st_en = 0;
342 srxx_com_ctl.s.inf_en = 0;
343 cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64);
345 // SRX0 Calendar Table. This round robbins through all ports
348 while (port < num_ports)
350 cvmx_srxx_spi4_calx_t srxx_spi4_calx;
351 srxx_spi4_calx.u64 = 0;
352 srxx_spi4_calx.s.prt0 = port++;
353 srxx_spi4_calx.s.prt1 = port++;
354 srxx_spi4_calx.s.prt2 = port++;
355 srxx_spi4_calx.s.prt3 = port++;
356 srxx_spi4_calx.s.oddpar = ~(cvmx_dpop(srxx_spi4_calx.u64) & 1);
357 cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface), srxx_spi4_calx.u64);
360 srxx_spi4_stat.u64 = 0;
361 srxx_spi4_stat.s.len = num_ports;
362 srxx_spi4_stat.s.m = 1;
363 cvmx_write_csr(CVMX_SRXX_SPI4_STAT(interface), srxx_spi4_stat.u64);
366 if (mode & CVMX_SPI_MODE_TX_HALFPLEX)
368 cvmx_stxx_arb_ctl_t stxx_arb_ctl;
369 cvmx_gmxx_tx_spi_max_t gmxx_tx_spi_max;
370 cvmx_gmxx_tx_spi_thresh_t gmxx_tx_spi_thresh;
371 cvmx_gmxx_tx_spi_ctl_t gmxx_tx_spi_ctl;
372 cvmx_stxx_spi4_stat_t stxx_spi4_stat;
373 cvmx_stxx_spi4_dat_t stxx_spi4_dat;
376 stxx_arb_ctl.u64 = 0;
377 stxx_arb_ctl.s.igntpa = 0;
378 stxx_arb_ctl.s.mintrn = 0;
379 cvmx_write_csr(CVMX_STXX_ARB_CTL(interface), stxx_arb_ctl.u64);
381 gmxx_tx_spi_max.u64 = 0;
382 gmxx_tx_spi_max.s.max1 = 8;
383 gmxx_tx_spi_max.s.max2 = 4;
384 gmxx_tx_spi_max.s.slice = 0;
385 cvmx_write_csr(CVMX_GMXX_TX_SPI_MAX(interface), gmxx_tx_spi_max.u64);
387 gmxx_tx_spi_thresh.u64 = 0;
388 gmxx_tx_spi_thresh.s.thresh = 4;
389 cvmx_write_csr(CVMX_GMXX_TX_SPI_THRESH(interface), gmxx_tx_spi_thresh.u64);
391 gmxx_tx_spi_ctl.u64 = 0;
392 gmxx_tx_spi_ctl.s.tpa_clr = 0;
393 gmxx_tx_spi_ctl.s.cont_pkt = 0;
394 cvmx_write_csr(CVMX_GMXX_TX_SPI_CTL(interface), gmxx_tx_spi_ctl.u64);
396 // STX0 Training Control
397 stxx_spi4_dat.u64 = 0;
398 stxx_spi4_dat.s.alpha = 32; /*Minimum needed by dynamic alignment*/
399 stxx_spi4_dat.s.max_t = 0xFFFF; /*Minimum interval is 0x20*/
400 cvmx_write_csr(CVMX_STXX_SPI4_DAT(interface), stxx_spi4_dat.u64);
402 // STX0 Calendar Table. This round robbins through all ports
405 while (port < num_ports)
407 cvmx_stxx_spi4_calx_t stxx_spi4_calx;
408 stxx_spi4_calx.u64 = 0;
409 stxx_spi4_calx.s.prt0 = port++;
410 stxx_spi4_calx.s.prt1 = port++;
411 stxx_spi4_calx.s.prt2 = port++;
412 stxx_spi4_calx.s.prt3 = port++;
413 stxx_spi4_calx.s.oddpar = ~(cvmx_dpop(stxx_spi4_calx.u64) & 1);
414 cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface), stxx_spi4_calx.u64);
417 stxx_spi4_stat.u64 = 0;
418 stxx_spi4_stat.s.len = num_ports;
419 stxx_spi4_stat.s.m = 1;
420 cvmx_write_csr(CVMX_STXX_SPI4_STAT(interface), stxx_spi4_stat.u64);
427 * Callback to perform clock detection
429 * @param interface The identifier of the packet interface to configure and
430 * use as a SPI interface.
431 * @param mode The operating mode for the SPI interface. The interface
432 * can operate as a full duplex (both Tx and Rx data paths
433 * active) or as a halfplex (either the Tx data path is
434 * active or the Rx data path is active, but not both).
435 * @param timeout Timeout to wait for clock synchronization in seconds
436 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
438 int cvmx_spi_clock_detect_cb(int interface, cvmx_spi_mode_t mode, int timeout)
440 int clock_transitions;
441 cvmx_spxx_clk_stat_t stat;
442 uint64_t timeout_time;
443 uint64_t MS = cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000;
445 /* Regardless of operating mode, both Tx and Rx clocks must be present
446 for the SPI interface to operate. */
447 cvmx_dprintf ("SPI%d: Waiting to see TsClk...\n", interface);
448 timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
449 /* Require 100 clock transitions in order to avoid any noise in the
451 clock_transitions = 100;
454 stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface));
455 if (stat.s.s4clk0 && stat.s.s4clk1 && clock_transitions)
457 /* We've seen a clock transition, so decrement the number we still
460 cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64);
464 if (cvmx_get_cycle() > timeout_time)
466 cvmx_dprintf ("SPI%d: Timeout\n", interface);
469 } while (stat.s.s4clk0 == 0 || stat.s.s4clk1 == 0);
471 cvmx_dprintf ("SPI%d: Waiting to see RsClk...\n", interface);
472 timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
473 /* Require 100 clock transitions in order to avoid any noise in the
475 clock_transitions = 100;
478 stat.u64 = cvmx_read_csr (CVMX_SPXX_CLK_STAT(interface));
479 if (stat.s.d4clk0 && stat.s.d4clk1 && clock_transitions)
481 /* We've seen a clock transition, so decrement the number we still
484 cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64);
488 if (cvmx_get_cycle() > timeout_time)
490 cvmx_dprintf ("SPI%d: Timeout\n", interface);
493 } while (stat.s.d4clk0 == 0 || stat.s.d4clk1 == 0);
499 * Callback to perform link training
501 * @param interface The identifier of the packet interface to configure and
502 * use as a SPI interface.
503 * @param mode The operating mode for the SPI interface. The interface
504 * can operate as a full duplex (both Tx and Rx data paths
505 * active) or as a halfplex (either the Tx data path is
506 * active or the Rx data path is active, but not both).
507 * @param timeout Timeout to wait for link to be trained (in seconds)
508 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
510 int cvmx_spi_training_cb(int interface, cvmx_spi_mode_t mode, int timeout)
512 cvmx_spxx_trn4_ctl_t spxx_trn4_ctl;
513 cvmx_spxx_clk_stat_t stat;
514 uint64_t MS = cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000;
515 uint64_t timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
516 int rx_training_needed;
518 // SRX0 & STX0 Inf0 Links are configured - begin training
519 cvmx_spxx_clk_ctl_t spxx_clk_ctl;
520 spxx_clk_ctl.u64 = 0;
521 spxx_clk_ctl.s.seetrn = 0;
522 spxx_clk_ctl.s.clkdly = 0x10;
523 spxx_clk_ctl.s.runbist = 0;
524 spxx_clk_ctl.s.statdrv = 0;
525 spxx_clk_ctl.s.statrcv = 1; /* This should always be on the opposite edge as statdrv */
526 spxx_clk_ctl.s.sndtrn = 1;
527 spxx_clk_ctl.s.drptrn = 1;
528 spxx_clk_ctl.s.rcvtrn = 1;
529 spxx_clk_ctl.s.srxdlck = 1;
530 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
531 cvmx_wait (1000 * MS);
533 // SRX0 clear the boot bit
534 spxx_trn4_ctl.u64 = cvmx_read_csr(CVMX_SPXX_TRN4_CTL(interface));
535 spxx_trn4_ctl.s.clr_boot = 1;
536 cvmx_write_csr (CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64);
538 // Wait for the training sequence to complete
539 cvmx_dprintf ("SPI%d: Waiting for training\n", interface);
540 cvmx_wait (1000 * MS);
541 #if !defined(OCTEON_VENDOR_LANNER)
542 timeout_time = cvmx_get_cycle() + 1000ull * MS * 600; /* Wait a really long time here */
544 timeout_time = cvmx_get_cycle() + 1000ull * MS * 10;
546 /* The HRM says we must wait for 34 + 16 * MAXDIST training sequences.
547 We'll be pessimistic and wait for a lot more */
548 rx_training_needed = 500;
550 stat.u64 = cvmx_read_csr (CVMX_SPXX_CLK_STAT(interface));
551 if (stat.s.srxtrn && rx_training_needed)
553 rx_training_needed--;
554 cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64);
557 if (cvmx_get_cycle() > timeout_time)
559 cvmx_dprintf ("SPI%d: Timeout\n", interface);
562 } while (stat.s.srxtrn == 0);
568 * Callback to perform calendar data synchronization
570 * @param interface The identifier of the packet interface to configure and
571 * use as a SPI interface.
572 * @param mode The operating mode for the SPI interface. The interface
573 * can operate as a full duplex (both Tx and Rx data paths
574 * active) or as a halfplex (either the Tx data path is
575 * active or the Rx data path is active, but not both).
576 * @param timeout Timeout to wait for calendar data in seconds
577 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
579 int cvmx_spi_calendar_sync_cb(int interface, cvmx_spi_mode_t mode, int timeout)
581 uint64_t MS = cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000;
582 if (mode & CVMX_SPI_MODE_RX_HALFPLEX) {
583 // SRX0 interface should be good, send calendar data
584 cvmx_srxx_com_ctl_t srxx_com_ctl;
585 cvmx_dprintf ("SPI%d: Rx is synchronized, start sending calendar data\n", interface);
586 srxx_com_ctl.u64 = cvmx_read_csr(CVMX_SRXX_COM_CTL(interface));
587 srxx_com_ctl.s.inf_en = 1;
588 srxx_com_ctl.s.st_en = 1;
589 cvmx_write_csr (CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64);
592 if (mode & CVMX_SPI_MODE_TX_HALFPLEX) {
593 // STX0 has achieved sync
594 // The corespondant board should be sending calendar data
595 // Enable the STX0 STAT receiver.
596 cvmx_spxx_clk_stat_t stat;
597 uint64_t timeout_time;
598 cvmx_stxx_com_ctl_t stxx_com_ctl;
599 stxx_com_ctl.u64 = 0;
600 stxx_com_ctl.s.st_en = 1;
601 cvmx_write_csr (CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64);
603 // Waiting for calendar sync on STX0 STAT
604 cvmx_dprintf ("SPI%d: Waiting to sync on STX[%d] STAT\n", interface, interface);
605 timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
606 // SPX0_CLK_STAT - SPX0_CLK_STAT[STXCAL] should be 1 (bit10)
608 stat.u64 = cvmx_read_csr (CVMX_SPXX_CLK_STAT (interface));
609 if (cvmx_get_cycle() > timeout_time)
611 cvmx_dprintf ("SPI%d: Timeout\n", interface);
614 } while (stat.s.stxcal == 0);
621 * Callback to handle interface up
623 * @param interface The identifier of the packet interface to configure and
624 * use as a SPI interface.
625 * @param mode The operating mode for the SPI interface. The interface
626 * can operate as a full duplex (both Tx and Rx data paths
627 * active) or as a halfplex (either the Tx data path is
628 * active or the Rx data path is active, but not both).
629 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
631 int cvmx_spi_interface_up_cb(int interface, cvmx_spi_mode_t mode)
633 cvmx_gmxx_rxx_frm_min_t gmxx_rxx_frm_min;
634 cvmx_gmxx_rxx_frm_max_t gmxx_rxx_frm_max;
635 cvmx_gmxx_rxx_jabber_t gmxx_rxx_jabber;
637 if (mode & CVMX_SPI_MODE_RX_HALFPLEX) {
638 cvmx_srxx_com_ctl_t srxx_com_ctl;
639 srxx_com_ctl.u64 = cvmx_read_csr(CVMX_SRXX_COM_CTL(interface));
640 srxx_com_ctl.s.inf_en = 1;
641 cvmx_write_csr (CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64);
642 cvmx_dprintf ("SPI%d: Rx is now up\n", interface);
645 if (mode & CVMX_SPI_MODE_TX_HALFPLEX) {
646 cvmx_stxx_com_ctl_t stxx_com_ctl;
647 stxx_com_ctl.u64 = cvmx_read_csr(CVMX_STXX_COM_CTL(interface));
648 stxx_com_ctl.s.inf_en = 1;
649 cvmx_write_csr (CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64);
650 cvmx_dprintf ("SPI%d: Tx is now up\n", interface);
653 gmxx_rxx_frm_min.u64 = 0;
654 gmxx_rxx_frm_min.s.len = 64;
655 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MIN(0,interface), gmxx_rxx_frm_min.u64);
656 gmxx_rxx_frm_max.u64 = 0;
657 gmxx_rxx_frm_max.s.len = 64*1024 - 4;
658 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(0,interface), gmxx_rxx_frm_max.u64);
659 gmxx_rxx_jabber.u64 = 0;
660 gmxx_rxx_jabber.s.cnt = 64*1024 - 4;
661 cvmx_write_csr(CVMX_GMXX_RXX_JABBER(0,interface), gmxx_rxx_jabber.u64);