^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /***********************license start***************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Author: Cavium Networks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Contact: support@caviumnetworks.com
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * This file is part of the OCTEON SDK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (c) 2003-2008 Cavium Networks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * This file is free software; you can redistribute it and/or modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * it under the terms of the GNU General Public License, Version 2, as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * published by the Free Software Foundation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * This file is distributed in the hope that it will be useful, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * NONINFRINGEMENT. See the GNU General Public License for more
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * You should have received a copy of the GNU General Public License
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * along with this file; if not, write to the Free Software
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * or visit http://www.gnu.org/licenses/.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * This file may also be available under a different license from Cavium.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * Contact Cavium Networks for more information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) ***********************license end**************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * Support library for the SPI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <asm/octeon/octeon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <asm/octeon/cvmx-config.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <asm/octeon/cvmx-pko.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <asm/octeon/cvmx-spi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <asm/octeon/cvmx-spxx-defs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <asm/octeon/cvmx-stxx-defs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <asm/octeon/cvmx-srxx-defs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define INVOKE_CB(function_p, args...) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) if (function_p) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) res = function_p(args); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (res) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return res; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #if CVMX_ENABLE_DEBUG_PRINTS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static const char *modes[] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) { "UNKNOWN", "TX Halfplex", "Rx Halfplex", "Duplex" };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* Default callbacks, can be overridden
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * using cvmx_spi_get_callbacks/cvmx_spi_set_callbacks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static cvmx_spi_callbacks_t cvmx_spi_callbacks = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) .reset_cb = cvmx_spi_reset_cb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) .calendar_setup_cb = cvmx_spi_calendar_setup_cb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) .clock_detect_cb = cvmx_spi_clock_detect_cb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) .training_cb = cvmx_spi_training_cb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) .calendar_sync_cb = cvmx_spi_calendar_sync_cb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) .interface_up_cb = cvmx_spi_interface_up_cb
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * Get current SPI4 initialization callbacks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * @callbacks: Pointer to the callbacks structure.to fill
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * Returns Pointer to cvmx_spi_callbacks_t structure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) void cvmx_spi_get_callbacks(cvmx_spi_callbacks_t *callbacks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) memcpy(callbacks, &cvmx_spi_callbacks, sizeof(cvmx_spi_callbacks));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * Set new SPI4 initialization callbacks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * @new_callbacks: Pointer to an updated callbacks structure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) void cvmx_spi_set_callbacks(cvmx_spi_callbacks_t *new_callbacks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) memcpy(&cvmx_spi_callbacks, new_callbacks, sizeof(cvmx_spi_callbacks));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * Initialize and start the SPI interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * @interface: The identifier of the packet interface to configure and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * use as a SPI interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * @mode: The operating mode for the SPI interface. The interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * can operate as a full duplex (both Tx and Rx data paths
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * active) or as a halfplex (either the Tx data path is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * active or the Rx data path is active, but not both).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * @timeout: Timeout to wait for clock synchronization in seconds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * @num_ports: Number of SPI ports to configure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * Returns Zero on success, negative of failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) int cvmx_spi_start_interface(int interface, cvmx_spi_mode_t mode, int timeout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) int num_ports)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) int res = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (!(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /* Callback to perform SPI4 reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) INVOKE_CB(cvmx_spi_callbacks.reset_cb, interface, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* Callback to perform calendar setup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) INVOKE_CB(cvmx_spi_callbacks.calendar_setup_cb, interface, mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) num_ports);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /* Callback to perform clock detection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) INVOKE_CB(cvmx_spi_callbacks.clock_detect_cb, interface, mode, timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /* Callback to perform SPI4 link training */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) INVOKE_CB(cvmx_spi_callbacks.training_cb, interface, mode, timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) /* Callback to perform calendar sync */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) INVOKE_CB(cvmx_spi_callbacks.calendar_sync_cb, interface, mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /* Callback to handle interface coming up */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) INVOKE_CB(cvmx_spi_callbacks.interface_up_cb, interface, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * This routine restarts the SPI interface after it has lost synchronization
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * with its correspondent system.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * @interface: The identifier of the packet interface to configure and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * use as a SPI interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * @mode: The operating mode for the SPI interface. The interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * can operate as a full duplex (both Tx and Rx data paths
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * active) or as a halfplex (either the Tx data path is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * active or the Rx data path is active, but not both).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * @timeout: Timeout to wait for clock synchronization in seconds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * Returns Zero on success, negative of failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) int cvmx_spi_restart_interface(int interface, cvmx_spi_mode_t mode, int timeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) int res = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (!(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) cvmx_dprintf("SPI%d: Restart %s\n", interface, modes[mode]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /* Callback to perform SPI4 reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) INVOKE_CB(cvmx_spi_callbacks.reset_cb, interface, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /* NOTE: Calendar setup is not performed during restart */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) /* Refer to cvmx_spi_start_interface() for the full sequence */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) /* Callback to perform clock detection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) INVOKE_CB(cvmx_spi_callbacks.clock_detect_cb, interface, mode, timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /* Callback to perform SPI4 link training */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) INVOKE_CB(cvmx_spi_callbacks.training_cb, interface, mode, timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) /* Callback to perform calendar sync */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) INVOKE_CB(cvmx_spi_callbacks.calendar_sync_cb, interface, mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /* Callback to handle interface coming up */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) INVOKE_CB(cvmx_spi_callbacks.interface_up_cb, interface, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) EXPORT_SYMBOL_GPL(cvmx_spi_restart_interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * Callback to perform SPI4 reset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * @interface: The identifier of the packet interface to configure and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * use as a SPI interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * @mode: The operating mode for the SPI interface. The interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * can operate as a full duplex (both Tx and Rx data paths
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * active) or as a halfplex (either the Tx data path is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * active or the Rx data path is active, but not both).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * Returns Zero on success, non-zero error code on failure (will cause
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) * SPI initialization to abort)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) int cvmx_spi_reset_cb(int interface, cvmx_spi_mode_t mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) union cvmx_spxx_dbg_deskew_ctl spxx_dbg_deskew_ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) union cvmx_spxx_clk_ctl spxx_clk_ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) union cvmx_spxx_bist_stat spxx_bist_stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) union cvmx_spxx_int_msk spxx_int_msk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) union cvmx_stxx_int_msk stxx_int_msk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) union cvmx_spxx_trn4_ctl spxx_trn4_ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) /* Disable SPI error events while we run BIST */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) /* Run BIST in the SPI interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) cvmx_write_csr(CVMX_STXX_COM_CTL(interface), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) spxx_clk_ctl.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) spxx_clk_ctl.s.runbist = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) __delay(10 * MS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) spxx_bist_stat.u64 = cvmx_read_csr(CVMX_SPXX_BIST_STAT(interface));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (spxx_bist_stat.s.stat0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) cvmx_dprintf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) ("ERROR SPI%d: BIST failed on receive datapath FIFO\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (spxx_bist_stat.s.stat1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) cvmx_dprintf("ERROR SPI%d: BIST failed on RX calendar table\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (spxx_bist_stat.s.stat2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) cvmx_dprintf("ERROR SPI%d: BIST failed on TX calendar table\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) /* Clear the calendar table after BIST to fix parity errors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) for (index = 0; index < 32; index++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) union cvmx_srxx_spi4_calx srxx_spi4_calx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) union cvmx_stxx_spi4_calx stxx_spi4_calx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) srxx_spi4_calx.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) srxx_spi4_calx.s.oddpar = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) srxx_spi4_calx.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) stxx_spi4_calx.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) stxx_spi4_calx.s.oddpar = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) stxx_spi4_calx.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /* Re enable reporting of error interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) cvmx_write_csr(CVMX_SPXX_INT_REG(interface),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) cvmx_read_csr(CVMX_SPXX_INT_REG(interface)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) cvmx_write_csr(CVMX_STXX_INT_REG(interface),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) cvmx_read_csr(CVMX_STXX_INT_REG(interface)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) /* Setup the CLKDLY right in the middle */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) spxx_clk_ctl.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) spxx_clk_ctl.s.seetrn = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) spxx_clk_ctl.s.clkdly = 0x10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) spxx_clk_ctl.s.runbist = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) spxx_clk_ctl.s.statdrv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) /* This should always be on the opposite edge as statdrv */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) spxx_clk_ctl.s.statrcv = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) spxx_clk_ctl.s.sndtrn = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) spxx_clk_ctl.s.drptrn = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) spxx_clk_ctl.s.rcvtrn = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) spxx_clk_ctl.s.srxdlck = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) __delay(100 * MS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) /* Reset SRX0 DLL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) spxx_clk_ctl.s.srxdlck = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) /* Waiting for Inf0 Spi4 RX DLL to lock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) __delay(100 * MS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) /* Enable dynamic alignment */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) spxx_trn4_ctl.s.trntest = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) spxx_trn4_ctl.s.jitter = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) spxx_trn4_ctl.s.clr_boot = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) spxx_trn4_ctl.s.set_boot = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (OCTEON_IS_MODEL(OCTEON_CN58XX))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) spxx_trn4_ctl.s.maxdist = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) spxx_trn4_ctl.s.maxdist = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) spxx_trn4_ctl.s.macro_en = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) spxx_trn4_ctl.s.mux_en = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) cvmx_write_csr(CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) spxx_dbg_deskew_ctl.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) cvmx_write_csr(CVMX_SPXX_DBG_DESKEW_CTL(interface),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) spxx_dbg_deskew_ctl.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) * Callback to setup calendar and miscellaneous settings before clock detection
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) * @interface: The identifier of the packet interface to configure and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) * use as a SPI interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) * @mode: The operating mode for the SPI interface. The interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) * can operate as a full duplex (both Tx and Rx data paths
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) * active) or as a halfplex (either the Tx data path is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) * active or the Rx data path is active, but not both).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) * @num_ports: Number of ports to configure on SPI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) * Returns Zero on success, non-zero error code on failure (will cause
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) * SPI initialization to abort)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) int cvmx_spi_calendar_setup_cb(int interface, cvmx_spi_mode_t mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) int num_ports)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) int port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) if (mode & CVMX_SPI_MODE_RX_HALFPLEX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) union cvmx_srxx_com_ctl srxx_com_ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) union cvmx_srxx_spi4_stat srxx_spi4_stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) /* SRX0 number of Ports */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) srxx_com_ctl.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) srxx_com_ctl.s.prts = num_ports - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) srxx_com_ctl.s.st_en = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) srxx_com_ctl.s.inf_en = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) /* SRX0 Calendar Table. This round robbins through all ports */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) port = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) index = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) while (port < num_ports) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) union cvmx_srxx_spi4_calx srxx_spi4_calx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) srxx_spi4_calx.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) srxx_spi4_calx.s.prt0 = port++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) srxx_spi4_calx.s.prt1 = port++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) srxx_spi4_calx.s.prt2 = port++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) srxx_spi4_calx.s.prt3 = port++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) srxx_spi4_calx.s.oddpar =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) ~(cvmx_dpop(srxx_spi4_calx.u64) & 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) srxx_spi4_calx.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) index++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) srxx_spi4_stat.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) srxx_spi4_stat.s.len = num_ports;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) srxx_spi4_stat.s.m = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) cvmx_write_csr(CVMX_SRXX_SPI4_STAT(interface),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) srxx_spi4_stat.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (mode & CVMX_SPI_MODE_TX_HALFPLEX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) union cvmx_stxx_arb_ctl stxx_arb_ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) union cvmx_gmxx_tx_spi_max gmxx_tx_spi_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) union cvmx_gmxx_tx_spi_thresh gmxx_tx_spi_thresh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) union cvmx_gmxx_tx_spi_ctl gmxx_tx_spi_ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) union cvmx_stxx_spi4_stat stxx_spi4_stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) union cvmx_stxx_spi4_dat stxx_spi4_dat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) /* STX0 Config */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) stxx_arb_ctl.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) stxx_arb_ctl.s.igntpa = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) stxx_arb_ctl.s.mintrn = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) cvmx_write_csr(CVMX_STXX_ARB_CTL(interface), stxx_arb_ctl.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) gmxx_tx_spi_max.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) gmxx_tx_spi_max.s.max1 = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) gmxx_tx_spi_max.s.max2 = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) gmxx_tx_spi_max.s.slice = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) cvmx_write_csr(CVMX_GMXX_TX_SPI_MAX(interface),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) gmxx_tx_spi_max.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) gmxx_tx_spi_thresh.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) gmxx_tx_spi_thresh.s.thresh = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) cvmx_write_csr(CVMX_GMXX_TX_SPI_THRESH(interface),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) gmxx_tx_spi_thresh.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) gmxx_tx_spi_ctl.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) gmxx_tx_spi_ctl.s.tpa_clr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) gmxx_tx_spi_ctl.s.cont_pkt = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) cvmx_write_csr(CVMX_GMXX_TX_SPI_CTL(interface),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) gmxx_tx_spi_ctl.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) /* STX0 Training Control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) stxx_spi4_dat.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) /*Minimum needed by dynamic alignment */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) stxx_spi4_dat.s.alpha = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) stxx_spi4_dat.s.max_t = 0xFFFF; /*Minimum interval is 0x20 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) cvmx_write_csr(CVMX_STXX_SPI4_DAT(interface),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) stxx_spi4_dat.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) /* STX0 Calendar Table. This round robbins through all ports */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) port = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) index = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) while (port < num_ports) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) union cvmx_stxx_spi4_calx stxx_spi4_calx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) stxx_spi4_calx.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) stxx_spi4_calx.s.prt0 = port++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) stxx_spi4_calx.s.prt1 = port++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) stxx_spi4_calx.s.prt2 = port++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) stxx_spi4_calx.s.prt3 = port++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) stxx_spi4_calx.s.oddpar =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) ~(cvmx_dpop(stxx_spi4_calx.u64) & 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) stxx_spi4_calx.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) index++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) stxx_spi4_stat.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) stxx_spi4_stat.s.len = num_ports;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) stxx_spi4_stat.s.m = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) cvmx_write_csr(CVMX_STXX_SPI4_STAT(interface),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) stxx_spi4_stat.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) * Callback to perform clock detection
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) * @interface: The identifier of the packet interface to configure and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) * use as a SPI interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) * @mode: The operating mode for the SPI interface. The interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) * can operate as a full duplex (both Tx and Rx data paths
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) * active) or as a halfplex (either the Tx data path is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) * active or the Rx data path is active, but not both).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) * @timeout: Timeout to wait for clock synchronization in seconds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * Returns Zero on success, non-zero error code on failure (will cause
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * SPI initialization to abort)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) int cvmx_spi_clock_detect_cb(int interface, cvmx_spi_mode_t mode, int timeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) int clock_transitions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) union cvmx_spxx_clk_stat stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) uint64_t timeout_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * Regardless of operating mode, both Tx and Rx clocks must be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) * present for the SPI interface to operate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) cvmx_dprintf("SPI%d: Waiting to see TsClk...\n", interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) * Require 100 clock transitions in order to avoid any noise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) * in the beginning.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) clock_transitions = 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (stat.s.s4clk0 && stat.s.s4clk1 && clock_transitions) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * We've seen a clock transition, so decrement
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) * the number we still need.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) clock_transitions--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) stat.s.s4clk0 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) stat.s.s4clk1 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) if (cvmx_get_cycle() > timeout_time) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) cvmx_dprintf("SPI%d: Timeout\n", interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) } while (stat.s.s4clk0 == 0 || stat.s.s4clk1 == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) cvmx_dprintf("SPI%d: Waiting to see RsClk...\n", interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) * Require 100 clock transitions in order to avoid any noise in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) * beginning.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) clock_transitions = 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) if (stat.s.d4clk0 && stat.s.d4clk1 && clock_transitions) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) * We've seen a clock transition, so decrement
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) * the number we still need
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) clock_transitions--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) stat.s.d4clk0 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) stat.s.d4clk1 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) if (cvmx_get_cycle() > timeout_time) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) cvmx_dprintf("SPI%d: Timeout\n", interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) } while (stat.s.d4clk0 == 0 || stat.s.d4clk1 == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) * Callback to perform link training
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) * @interface: The identifier of the packet interface to configure and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) * use as a SPI interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) * @mode: The operating mode for the SPI interface. The interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) * can operate as a full duplex (both Tx and Rx data paths
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) * active) or as a halfplex (either the Tx data path is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) * active or the Rx data path is active, but not both).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) * @timeout: Timeout to wait for link to be trained (in seconds)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) * Returns Zero on success, non-zero error code on failure (will cause
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) * SPI initialization to abort)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) int cvmx_spi_training_cb(int interface, cvmx_spi_mode_t mode, int timeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) union cvmx_spxx_trn4_ctl spxx_trn4_ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) union cvmx_spxx_clk_stat stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) uint64_t timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) int rx_training_needed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) /* SRX0 & STX0 Inf0 Links are configured - begin training */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) union cvmx_spxx_clk_ctl spxx_clk_ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) spxx_clk_ctl.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) spxx_clk_ctl.s.seetrn = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) spxx_clk_ctl.s.clkdly = 0x10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) spxx_clk_ctl.s.runbist = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) spxx_clk_ctl.s.statdrv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) /* This should always be on the opposite edge as statdrv */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) spxx_clk_ctl.s.statrcv = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) spxx_clk_ctl.s.sndtrn = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) spxx_clk_ctl.s.drptrn = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) spxx_clk_ctl.s.rcvtrn = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) spxx_clk_ctl.s.srxdlck = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) __delay(1000 * MS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) /* SRX0 clear the boot bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) spxx_trn4_ctl.u64 = cvmx_read_csr(CVMX_SPXX_TRN4_CTL(interface));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) spxx_trn4_ctl.s.clr_boot = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) cvmx_write_csr(CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) /* Wait for the training sequence to complete */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) cvmx_dprintf("SPI%d: Waiting for training\n", interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) __delay(1000 * MS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) /* Wait a really long time here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) timeout_time = cvmx_get_cycle() + 1000ull * MS * 600;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) * The HRM says we must wait for 34 + 16 * MAXDIST training sequences.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) * We'll be pessimistic and wait for a lot more.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) rx_training_needed = 500;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) if (stat.s.srxtrn && rx_training_needed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) rx_training_needed--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) stat.s.srxtrn = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) if (cvmx_get_cycle() > timeout_time) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) cvmx_dprintf("SPI%d: Timeout\n", interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) } while (stat.s.srxtrn == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) * Callback to perform calendar data synchronization
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) * @interface: The identifier of the packet interface to configure and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) * use as a SPI interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) * @mode: The operating mode for the SPI interface. The interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) * can operate as a full duplex (both Tx and Rx data paths
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) * active) or as a halfplex (either the Tx data path is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) * active or the Rx data path is active, but not both).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) * @timeout: Timeout to wait for calendar data in seconds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) * Returns Zero on success, non-zero error code on failure (will cause
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) * SPI initialization to abort)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) int cvmx_spi_calendar_sync_cb(int interface, cvmx_spi_mode_t mode, int timeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) if (mode & CVMX_SPI_MODE_RX_HALFPLEX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) /* SRX0 interface should be good, send calendar data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) union cvmx_srxx_com_ctl srxx_com_ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) cvmx_dprintf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) ("SPI%d: Rx is synchronized, start sending calendar data\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) srxx_com_ctl.u64 = cvmx_read_csr(CVMX_SRXX_COM_CTL(interface));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) srxx_com_ctl.s.inf_en = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) srxx_com_ctl.s.st_en = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) if (mode & CVMX_SPI_MODE_TX_HALFPLEX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) /* STX0 has achieved sync */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) /* The corespondant board should be sending calendar data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) /* Enable the STX0 STAT receiver. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) union cvmx_spxx_clk_stat stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) uint64_t timeout_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) union cvmx_stxx_com_ctl stxx_com_ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) stxx_com_ctl.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) stxx_com_ctl.s.st_en = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) cvmx_write_csr(CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) /* Waiting for calendar sync on STX0 STAT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) cvmx_dprintf("SPI%d: Waiting to sync on STX[%d] STAT\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) interface, interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) /* SPX0_CLK_STAT - SPX0_CLK_STAT[STXCAL] should be 1 (bit10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) if (cvmx_get_cycle() > timeout_time) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) cvmx_dprintf("SPI%d: Timeout\n", interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) } while (stat.s.stxcal == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) * Callback to handle interface up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) * @interface: The identifier of the packet interface to configure and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) * use as a SPI interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) * @mode: The operating mode for the SPI interface. The interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) * can operate as a full duplex (both Tx and Rx data paths
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) * active) or as a halfplex (either the Tx data path is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) * active or the Rx data path is active, but not both).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) * Returns Zero on success, non-zero error code on failure (will cause
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) * SPI initialization to abort)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) int cvmx_spi_interface_up_cb(int interface, cvmx_spi_mode_t mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) union cvmx_gmxx_rxx_frm_min gmxx_rxx_frm_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) union cvmx_gmxx_rxx_frm_max gmxx_rxx_frm_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) union cvmx_gmxx_rxx_jabber gmxx_rxx_jabber;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) if (mode & CVMX_SPI_MODE_RX_HALFPLEX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) union cvmx_srxx_com_ctl srxx_com_ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) srxx_com_ctl.u64 = cvmx_read_csr(CVMX_SRXX_COM_CTL(interface));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) srxx_com_ctl.s.inf_en = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) cvmx_dprintf("SPI%d: Rx is now up\n", interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) if (mode & CVMX_SPI_MODE_TX_HALFPLEX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) union cvmx_stxx_com_ctl stxx_com_ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) stxx_com_ctl.u64 = cvmx_read_csr(CVMX_STXX_COM_CTL(interface));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) stxx_com_ctl.s.inf_en = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) cvmx_write_csr(CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) cvmx_dprintf("SPI%d: Tx is now up\n", interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) gmxx_rxx_frm_min.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) gmxx_rxx_frm_min.s.len = 64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) cvmx_write_csr(CVMX_GMXX_RXX_FRM_MIN(0, interface),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) gmxx_rxx_frm_min.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) gmxx_rxx_frm_max.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) gmxx_rxx_frm_max.s.len = 64 * 1024 - 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(0, interface),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) gmxx_rxx_frm_max.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) gmxx_rxx_jabber.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) gmxx_rxx_jabber.s.cnt = 64 * 1024 - 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) cvmx_write_csr(CVMX_GMXX_RXX_JABBER(0, interface), gmxx_rxx_jabber.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) }