1 /***********************license start***************
2 * Copyright (c) 2003-2008 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 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24 * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25 * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26 * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31 * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT
32 * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
35 * For any questions regarding licensing please contact marketing@caviumnetworks.com
37 ***********************license end**************************************/
47 * Support library for the SPI
49 * <hr>$Revision: 41586 $<hr>
55 #include "cvmx-sysinfo.h"
57 #define INVOKE_CB(function_p, args...) \
60 res = function_p(args); \
66 #if CVMX_ENABLE_DEBUG_PRINTS
67 static const char *modes[] = {"UNKNOWN", "TX Halfplex", "Rx Halfplex", "Duplex"};
70 /* Default callbacks, can be overridden
71 * using cvmx_spi_get_callbacks/cvmx_spi_set_callbacks
73 static cvmx_spi_callbacks_t cvmx_spi_callbacks = {
74 .reset_cb = cvmx_spi_reset_cb,
75 .calendar_setup_cb = cvmx_spi_calendar_setup_cb,
76 .clock_detect_cb = cvmx_spi_clock_detect_cb,
77 .training_cb = cvmx_spi_training_cb,
78 .calendar_sync_cb = cvmx_spi_calendar_sync_cb,
79 .interface_up_cb = cvmx_spi_interface_up_cb
83 * Get current SPI4 initialization callbacks
85 * @param callbacks Pointer to the callbacks structure.to fill
87 * @return Pointer to cvmx_spi_callbacks_t structure.
89 void cvmx_spi_get_callbacks(cvmx_spi_callbacks_t * callbacks)
91 memcpy(callbacks, &cvmx_spi_callbacks, sizeof(cvmx_spi_callbacks));
95 * Set new SPI4 initialization callbacks
97 * @param new_callbacks Pointer to an updated callbacks structure.
99 void cvmx_spi_set_callbacks(cvmx_spi_callbacks_t * new_callbacks)
101 memcpy(&cvmx_spi_callbacks, new_callbacks, sizeof(cvmx_spi_callbacks));
105 * Initialize and start the SPI interface.
107 * @param interface The identifier of the packet interface to configure and
108 * use as a SPI interface.
109 * @param mode The operating mode for the SPI interface. The interface
110 * can operate as a full duplex (both Tx and Rx data paths
111 * active) or as a halfplex (either the Tx data path is
112 * active or the Rx data path is active, but not both).
113 * @param timeout Timeout to wait for clock synchronization in seconds
114 * @param num_ports Number of SPI ports to configure
116 * @return Zero on success, negative of failure.
118 int cvmx_spi_start_interface(int interface, cvmx_spi_mode_t mode, int timeout, int num_ports)
122 if (!(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)))
125 // Callback to perform SPI4 reset
126 INVOKE_CB( cvmx_spi_callbacks.reset_cb, interface, mode);
128 // Callback to perform calendar setup
129 INVOKE_CB(cvmx_spi_callbacks.calendar_setup_cb, interface, mode, num_ports);
131 // Callback to perform clock detection
132 INVOKE_CB(cvmx_spi_callbacks.clock_detect_cb, interface, mode, timeout);
134 // Callback to perform SPI4 link training
135 INVOKE_CB(cvmx_spi_callbacks.training_cb, interface, mode, timeout);
137 // Callback to perform calendar sync
138 INVOKE_CB(cvmx_spi_callbacks.calendar_sync_cb, interface, mode, timeout);
140 // Callback to handle interface coming up
141 INVOKE_CB(cvmx_spi_callbacks.interface_up_cb, interface, mode);
147 * This routine restarts the SPI interface after it has lost synchronization
148 * with its correspondent system.
150 * @param interface The identifier of the packet interface to configure and
151 * use as a SPI interface.
152 * @param mode The operating mode for the SPI interface. The interface
153 * can operate as a full duplex (both Tx and Rx data paths
154 * active) or as a halfplex (either the Tx data path is
155 * active or the Rx data path is active, but not both).
156 * @param timeout Timeout to wait for clock synchronization in seconds
157 * @return Zero on success, negative of failure.
159 int cvmx_spi_restart_interface(int interface, cvmx_spi_mode_t mode, int timeout)
164 if (!(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)))
167 cvmx_dprintf ("SPI%d: Restart %s\n", interface, modes[mode]);
169 // Callback to perform SPI4 reset
170 INVOKE_CB(cvmx_spi_callbacks.reset_cb, interface,mode);
172 // NOTE: Calendar setup is not performed during restart
173 // Refer to cvmx_spi_start_interface() for the full sequence
175 // Callback to perform clock detection
176 INVOKE_CB(cvmx_spi_callbacks.clock_detect_cb, interface, mode, timeout);
178 // Callback to perform SPI4 link training
179 INVOKE_CB(cvmx_spi_callbacks.training_cb, interface, mode, timeout);
181 // Callback to perform calendar sync
182 INVOKE_CB(cvmx_spi_callbacks.calendar_sync_cb, interface, mode, timeout);
184 // Callback to handle interface coming up
185 INVOKE_CB(cvmx_spi_callbacks.interface_up_cb, interface, mode);
191 * Callback to perform SPI4 reset
193 * @param interface The identifier of the packet interface to configure and
194 * use as a SPI interface.
195 * @param mode The operating mode for the SPI interface. The interface
196 * can operate as a full duplex (both Tx and Rx data paths
197 * active) or as a halfplex (either the Tx data path is
198 * active or the Rx data path is active, but not both).
199 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
201 int cvmx_spi_reset_cb(int interface, cvmx_spi_mode_t mode)
203 cvmx_spxx_dbg_deskew_ctl_t spxx_dbg_deskew_ctl;
204 cvmx_spxx_clk_ctl_t spxx_clk_ctl;
205 cvmx_spxx_bist_stat_t spxx_bist_stat;
206 cvmx_spxx_int_msk_t spxx_int_msk;
207 cvmx_stxx_int_msk_t stxx_int_msk;
208 cvmx_spxx_trn4_ctl_t spxx_trn4_ctl;
210 uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000;
212 /* Disable SPI error events while we run BIST */
213 spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface));
214 cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0);
215 stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface));
216 cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0);
218 /* Run BIST in the SPI interface */
219 cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), 0);
220 cvmx_write_csr(CVMX_STXX_COM_CTL(interface), 0);
221 spxx_clk_ctl.u64 = 0;
222 spxx_clk_ctl.s.runbist = 1;
223 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
225 spxx_bist_stat.u64 = cvmx_read_csr(CVMX_SPXX_BIST_STAT(interface));
226 if (spxx_bist_stat.s.stat0)
227 cvmx_dprintf("ERROR SPI%d: BIST failed on receive datapath FIFO\n", interface);
228 if (spxx_bist_stat.s.stat1)
229 cvmx_dprintf("ERROR SPI%d: BIST failed on RX calendar table\n", interface);
230 if (spxx_bist_stat.s.stat2)
231 cvmx_dprintf("ERROR SPI%d: BIST failed on TX calendar table\n", interface);
233 /* Clear the calendar table after BIST to fix parity errors */
234 for (index=0; index<32; index++)
236 cvmx_srxx_spi4_calx_t srxx_spi4_calx;
237 cvmx_stxx_spi4_calx_t stxx_spi4_calx;
239 srxx_spi4_calx.u64 = 0;
240 srxx_spi4_calx.s.oddpar = 1;
241 cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface), srxx_spi4_calx.u64);
243 stxx_spi4_calx.u64 = 0;
244 stxx_spi4_calx.s.oddpar = 1;
245 cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface), stxx_spi4_calx.u64);
248 /* Re enable reporting of error interrupts */
249 cvmx_write_csr(CVMX_SPXX_INT_REG(interface), cvmx_read_csr(CVMX_SPXX_INT_REG(interface)));
250 cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64);
251 cvmx_write_csr(CVMX_STXX_INT_REG(interface), cvmx_read_csr(CVMX_STXX_INT_REG(interface)));
252 cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64);
254 // Setup the CLKDLY right in the middle
255 spxx_clk_ctl.u64 = 0;
256 spxx_clk_ctl.s.seetrn = 0;
257 spxx_clk_ctl.s.clkdly = 0x10;
258 spxx_clk_ctl.s.runbist = 0;
259 spxx_clk_ctl.s.statdrv = 0;
260 spxx_clk_ctl.s.statrcv = 1; /* This should always be on the opposite edge as statdrv */
261 spxx_clk_ctl.s.sndtrn = 0;
262 spxx_clk_ctl.s.drptrn = 0;
263 spxx_clk_ctl.s.rcvtrn = 0;
264 spxx_clk_ctl.s.srxdlck = 0;
265 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
266 cvmx_wait (100 * MS);
269 spxx_clk_ctl.s.srxdlck = 1;
270 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
272 // Waiting for Inf0 Spi4 RX DLL to lock
273 cvmx_wait (100 * MS);
275 // Enable dynamic alignment
276 spxx_trn4_ctl.s.trntest = 0;
277 spxx_trn4_ctl.s.jitter = 1;
278 spxx_trn4_ctl.s.clr_boot = 1;
279 spxx_trn4_ctl.s.set_boot = 0;
280 if (OCTEON_IS_MODEL(OCTEON_CN58XX))
281 spxx_trn4_ctl.s.maxdist = 3;
283 spxx_trn4_ctl.s.maxdist = 8;
284 spxx_trn4_ctl.s.macro_en = 1;
285 spxx_trn4_ctl.s.mux_en = 1;
286 cvmx_write_csr (CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64);
288 spxx_dbg_deskew_ctl.u64 = 0;
289 cvmx_write_csr (CVMX_SPXX_DBG_DESKEW_CTL(interface), spxx_dbg_deskew_ctl.u64);
295 * Callback to setup calendar and miscellaneous settings before clock detection
297 * @param interface The identifier of the packet interface to configure and
298 * use as a SPI interface.
299 * @param mode The operating mode for the SPI interface. The interface
300 * can operate as a full duplex (both Tx and Rx data paths
301 * active) or as a halfplex (either the Tx data path is
302 * active or the Rx data path is active, but not both).
303 * @param num_ports Number of ports to configure on SPI
304 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
306 int cvmx_spi_calendar_setup_cb(int interface, cvmx_spi_mode_t mode, int num_ports)
310 if (mode & CVMX_SPI_MODE_RX_HALFPLEX)
312 cvmx_srxx_com_ctl_t srxx_com_ctl;
313 cvmx_srxx_spi4_stat_t srxx_spi4_stat;
315 // SRX0 number of Ports
316 srxx_com_ctl.u64 = 0;
317 srxx_com_ctl.s.prts = num_ports - 1;
318 srxx_com_ctl.s.st_en = 0;
319 srxx_com_ctl.s.inf_en = 0;
320 cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64);
322 // SRX0 Calendar Table. This round robbins through all ports
325 while (port < num_ports)
327 cvmx_srxx_spi4_calx_t srxx_spi4_calx;
328 srxx_spi4_calx.u64 = 0;
329 srxx_spi4_calx.s.prt0 = port++;
330 srxx_spi4_calx.s.prt1 = port++;
331 srxx_spi4_calx.s.prt2 = port++;
332 srxx_spi4_calx.s.prt3 = port++;
333 srxx_spi4_calx.s.oddpar = ~(cvmx_dpop(srxx_spi4_calx.u64) & 1);
334 cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface), srxx_spi4_calx.u64);
337 srxx_spi4_stat.u64 = 0;
338 srxx_spi4_stat.s.len = num_ports;
339 srxx_spi4_stat.s.m = 1;
340 cvmx_write_csr(CVMX_SRXX_SPI4_STAT(interface), srxx_spi4_stat.u64);
343 if (mode & CVMX_SPI_MODE_TX_HALFPLEX)
345 cvmx_stxx_arb_ctl_t stxx_arb_ctl;
346 cvmx_gmxx_tx_spi_max_t gmxx_tx_spi_max;
347 cvmx_gmxx_tx_spi_thresh_t gmxx_tx_spi_thresh;
348 cvmx_gmxx_tx_spi_ctl_t gmxx_tx_spi_ctl;
349 cvmx_stxx_spi4_stat_t stxx_spi4_stat;
350 cvmx_stxx_spi4_dat_t stxx_spi4_dat;
353 stxx_arb_ctl.u64 = 0;
354 stxx_arb_ctl.s.igntpa = 0;
355 stxx_arb_ctl.s.mintrn = 0;
356 cvmx_write_csr(CVMX_STXX_ARB_CTL(interface), stxx_arb_ctl.u64);
358 gmxx_tx_spi_max.u64 = 0;
359 gmxx_tx_spi_max.s.max1 = 8;
360 gmxx_tx_spi_max.s.max2 = 4;
361 gmxx_tx_spi_max.s.slice = 0;
362 cvmx_write_csr(CVMX_GMXX_TX_SPI_MAX(interface), gmxx_tx_spi_max.u64);
364 gmxx_tx_spi_thresh.u64 = 0;
365 gmxx_tx_spi_thresh.s.thresh = 4;
366 cvmx_write_csr(CVMX_GMXX_TX_SPI_THRESH(interface), gmxx_tx_spi_thresh.u64);
368 gmxx_tx_spi_ctl.u64 = 0;
369 gmxx_tx_spi_ctl.s.tpa_clr = 0;
370 gmxx_tx_spi_ctl.s.cont_pkt = 0;
371 cvmx_write_csr(CVMX_GMXX_TX_SPI_CTL(interface), gmxx_tx_spi_ctl.u64);
373 // STX0 Training Control
374 stxx_spi4_dat.u64 = 0;
375 stxx_spi4_dat.s.alpha = 32; /*Minimum needed by dynamic alignment*/
376 stxx_spi4_dat.s.max_t = 0xFFFF; /*Minimum interval is 0x20*/
377 cvmx_write_csr(CVMX_STXX_SPI4_DAT(interface), stxx_spi4_dat.u64);
379 // STX0 Calendar Table. This round robbins through all ports
382 while (port < num_ports)
384 cvmx_stxx_spi4_calx_t stxx_spi4_calx;
385 stxx_spi4_calx.u64 = 0;
386 stxx_spi4_calx.s.prt0 = port++;
387 stxx_spi4_calx.s.prt1 = port++;
388 stxx_spi4_calx.s.prt2 = port++;
389 stxx_spi4_calx.s.prt3 = port++;
390 stxx_spi4_calx.s.oddpar = ~(cvmx_dpop(stxx_spi4_calx.u64) & 1);
391 cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface), stxx_spi4_calx.u64);
394 stxx_spi4_stat.u64 = 0;
395 stxx_spi4_stat.s.len = num_ports;
396 stxx_spi4_stat.s.m = 1;
397 cvmx_write_csr(CVMX_STXX_SPI4_STAT(interface), stxx_spi4_stat.u64);
404 * Callback to perform clock detection
406 * @param interface The identifier of the packet interface to configure and
407 * use as a SPI interface.
408 * @param mode The operating mode for the SPI interface. The interface
409 * can operate as a full duplex (both Tx and Rx data paths
410 * active) or as a halfplex (either the Tx data path is
411 * active or the Rx data path is active, but not both).
412 * @param timeout Timeout to wait for clock synchronization in seconds
413 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
415 int cvmx_spi_clock_detect_cb(int interface, cvmx_spi_mode_t mode, int timeout)
417 int clock_transitions;
418 cvmx_spxx_clk_stat_t stat;
419 uint64_t timeout_time;
420 uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000;
422 /* Regardless of operating mode, both Tx and Rx clocks must be present
423 for the SPI interface to operate. */
424 cvmx_dprintf ("SPI%d: Waiting to see TsClk...\n", interface);
425 timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
426 /* Require 100 clock transitions in order to avoid any noise in the
428 clock_transitions = 100;
431 stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface));
432 if (stat.s.s4clk0 && stat.s.s4clk1 && clock_transitions)
434 /* We've seen a clock transition, so decrement the number we still
437 cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64);
441 if (cvmx_get_cycle() > timeout_time)
443 cvmx_dprintf ("SPI%d: Timeout\n", interface);
446 } while (stat.s.s4clk0 == 0 || stat.s.s4clk1 == 0);
448 cvmx_dprintf ("SPI%d: Waiting to see RsClk...\n", interface);
449 timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
450 /* Require 100 clock transitions in order to avoid any noise in the
452 clock_transitions = 100;
455 stat.u64 = cvmx_read_csr (CVMX_SPXX_CLK_STAT(interface));
456 if (stat.s.d4clk0 && stat.s.d4clk1 && clock_transitions)
458 /* We've seen a clock transition, so decrement the number we still
461 cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64);
465 if (cvmx_get_cycle() > timeout_time)
467 cvmx_dprintf ("SPI%d: Timeout\n", interface);
470 } while (stat.s.d4clk0 == 0 || stat.s.d4clk1 == 0);
476 * Callback to perform link training
478 * @param interface The identifier of the packet interface to configure and
479 * use as a SPI interface.
480 * @param mode The operating mode for the SPI interface. The interface
481 * can operate as a full duplex (both Tx and Rx data paths
482 * active) or as a halfplex (either the Tx data path is
483 * active or the Rx data path is active, but not both).
484 * @param timeout Timeout to wait for link to be trained (in seconds)
485 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
487 int cvmx_spi_training_cb(int interface, cvmx_spi_mode_t mode, int timeout)
489 cvmx_spxx_trn4_ctl_t spxx_trn4_ctl;
490 cvmx_spxx_clk_stat_t stat;
491 uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000;
492 uint64_t timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
493 int rx_training_needed;
495 // SRX0 & STX0 Inf0 Links are configured - begin training
496 cvmx_spxx_clk_ctl_t spxx_clk_ctl;
497 spxx_clk_ctl.u64 = 0;
498 spxx_clk_ctl.s.seetrn = 0;
499 spxx_clk_ctl.s.clkdly = 0x10;
500 spxx_clk_ctl.s.runbist = 0;
501 spxx_clk_ctl.s.statdrv = 0;
502 spxx_clk_ctl.s.statrcv = 1; /* This should always be on the opposite edge as statdrv */
503 spxx_clk_ctl.s.sndtrn = 1;
504 spxx_clk_ctl.s.drptrn = 1;
505 spxx_clk_ctl.s.rcvtrn = 1;
506 spxx_clk_ctl.s.srxdlck = 1;
507 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
508 cvmx_wait (1000 * MS);
510 // SRX0 clear the boot bit
511 spxx_trn4_ctl.u64 = cvmx_read_csr(CVMX_SPXX_TRN4_CTL(interface));
512 spxx_trn4_ctl.s.clr_boot = 1;
513 cvmx_write_csr (CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64);
515 // Wait for the training sequence to complete
516 cvmx_dprintf ("SPI%d: Waiting for training\n", interface);
517 cvmx_wait (1000 * MS);
518 #if !defined(OCTEON_VENDOR_LANNER)
519 timeout_time = cvmx_get_cycle() + 1000ull * MS * 600; /* Wait a really long time here */
521 timeout_time = cvmx_get_cycle() + 1000ull * MS * 10;
523 /* The HRM says we must wait for 34 + 16 * MAXDIST training sequences.
524 We'll be pessimistic and wait for a lot more */
525 rx_training_needed = 500;
527 stat.u64 = cvmx_read_csr (CVMX_SPXX_CLK_STAT(interface));
528 if (stat.s.srxtrn && rx_training_needed)
530 rx_training_needed--;
531 cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64);
534 if (cvmx_get_cycle() > timeout_time)
536 cvmx_dprintf ("SPI%d: Timeout\n", interface);
539 } while (stat.s.srxtrn == 0);
545 * Callback to perform calendar data synchronization
547 * @param interface The identifier of the packet interface to configure and
548 * use as a SPI interface.
549 * @param mode The operating mode for the SPI interface. The interface
550 * can operate as a full duplex (both Tx and Rx data paths
551 * active) or as a halfplex (either the Tx data path is
552 * active or the Rx data path is active, but not both).
553 * @param timeout Timeout to wait for calendar data in seconds
554 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
556 int cvmx_spi_calendar_sync_cb(int interface, cvmx_spi_mode_t mode, int timeout)
558 uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000;
559 if (mode & CVMX_SPI_MODE_RX_HALFPLEX) {
560 // SRX0 interface should be good, send calendar data
561 cvmx_srxx_com_ctl_t srxx_com_ctl;
562 cvmx_dprintf ("SPI%d: Rx is synchronized, start sending calendar data\n", interface);
563 srxx_com_ctl.u64 = cvmx_read_csr(CVMX_SRXX_COM_CTL(interface));
564 srxx_com_ctl.s.inf_en = 1;
565 srxx_com_ctl.s.st_en = 1;
566 cvmx_write_csr (CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64);
569 if (mode & CVMX_SPI_MODE_TX_HALFPLEX) {
570 // STX0 has achieved sync
571 // The corespondant board should be sending calendar data
572 // Enable the STX0 STAT receiver.
573 cvmx_spxx_clk_stat_t stat;
574 uint64_t timeout_time;
575 cvmx_stxx_com_ctl_t stxx_com_ctl;
576 stxx_com_ctl.u64 = 0;
577 stxx_com_ctl.s.st_en = 1;
578 cvmx_write_csr (CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64);
580 // Waiting for calendar sync on STX0 STAT
581 cvmx_dprintf ("SPI%d: Waiting to sync on STX[%d] STAT\n", interface, interface);
582 timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
583 // SPX0_CLK_STAT - SPX0_CLK_STAT[STXCAL] should be 1 (bit10)
585 stat.u64 = cvmx_read_csr (CVMX_SPXX_CLK_STAT (interface));
586 if (cvmx_get_cycle() > timeout_time)
588 cvmx_dprintf ("SPI%d: Timeout\n", interface);
591 } while (stat.s.stxcal == 0);
598 * Callback to handle interface up
600 * @param interface The identifier of the packet interface to configure and
601 * use as a SPI interface.
602 * @param mode The operating mode for the SPI interface. The interface
603 * can operate as a full duplex (both Tx and Rx data paths
604 * active) or as a halfplex (either the Tx data path is
605 * active or the Rx data path is active, but not both).
606 * @return Zero on success, non-zero error code on failure (will cause SPI initialization to abort)
608 int cvmx_spi_interface_up_cb(int interface, cvmx_spi_mode_t mode)
610 cvmx_gmxx_rxx_frm_min_t gmxx_rxx_frm_min;
611 cvmx_gmxx_rxx_frm_max_t gmxx_rxx_frm_max;
612 cvmx_gmxx_rxx_jabber_t gmxx_rxx_jabber;
614 if (mode & CVMX_SPI_MODE_RX_HALFPLEX) {
615 cvmx_srxx_com_ctl_t srxx_com_ctl;
616 srxx_com_ctl.u64 = cvmx_read_csr(CVMX_SRXX_COM_CTL(interface));
617 srxx_com_ctl.s.inf_en = 1;
618 cvmx_write_csr (CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64);
619 cvmx_dprintf ("SPI%d: Rx is now up\n", interface);
622 if (mode & CVMX_SPI_MODE_TX_HALFPLEX) {
623 cvmx_stxx_com_ctl_t stxx_com_ctl;
624 stxx_com_ctl.u64 = cvmx_read_csr(CVMX_STXX_COM_CTL(interface));
625 stxx_com_ctl.s.inf_en = 1;
626 cvmx_write_csr (CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64);
627 cvmx_dprintf ("SPI%d: Tx is now up\n", interface);
630 gmxx_rxx_frm_min.u64 = 0;
631 gmxx_rxx_frm_min.s.len = 64;
632 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MIN(0,interface), gmxx_rxx_frm_min.u64);
633 gmxx_rxx_frm_max.u64 = 0;
634 gmxx_rxx_frm_max.s.len = 64*1024 - 4;
635 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(0,interface), gmxx_rxx_frm_max.u64);
636 gmxx_rxx_jabber.u64 = 0;
637 gmxx_rxx_jabber.s.cnt = 64*1024 - 4;
638 cvmx_write_csr(CVMX_GMXX_RXX_JABBER(0,interface), gmxx_rxx_jabber.u64);