1210284Sjmallett/***********************license start***************
2232812Sjmallett * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3215990Sjmallett * reserved.
4210284Sjmallett *
5210284Sjmallett *
6215990Sjmallett * Redistribution and use in source and binary forms, with or without
7215990Sjmallett * modification, are permitted provided that the following conditions are
8215990Sjmallett * met:
9210284Sjmallett *
10215990Sjmallett *   * Redistributions of source code must retain the above copyright
11215990Sjmallett *     notice, this list of conditions and the following disclaimer.
12210284Sjmallett *
13215990Sjmallett *   * Redistributions in binary form must reproduce the above
14215990Sjmallett *     copyright notice, this list of conditions and the following
15215990Sjmallett *     disclaimer in the documentation and/or other materials provided
16215990Sjmallett *     with the distribution.
17215990Sjmallett
18232812Sjmallett *   * Neither the name of Cavium Inc. nor the names of
19215990Sjmallett *     its contributors may be used to endorse or promote products
20215990Sjmallett *     derived from this software without specific prior written
21215990Sjmallett *     permission.
22215990Sjmallett
23215990Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24215990Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25215990Sjmallett * regulations, and may be subject to export or import  regulations in other
26215990Sjmallett * countries.
27215990Sjmallett
28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38210284Sjmallett ***********************license end**************************************/
39210284Sjmallett
40210284Sjmallett
41210284Sjmallett
42210284Sjmallett
43210284Sjmallett
44210284Sjmallett
45215990Sjmallett
46210284Sjmallett/**
47210284Sjmallett * @file
48210284Sjmallett *
49210284Sjmallett * Support library for the SPI4000 card
50210284Sjmallett *
51232812Sjmallett * <hr>$Revision: 70030 $<hr>
52210284Sjmallett */
53215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
54215990Sjmallett#include <linux/module.h>
55215990Sjmallett#include <asm/octeon/cvmx.h>
56215990Sjmallett#include <asm/octeon/cvmx-spi.h>
57215990Sjmallett#include <asm/octeon/cvmx-twsi.h>
58215990Sjmallett#include <asm/octeon/cvmx-gmxx-defs.h>
59215990Sjmallett#else
60210284Sjmallett#include "cvmx.h"
61210284Sjmallett#include "cvmx-spi.h"
62210284Sjmallett#include "cvmx-twsi.h"
63215990Sjmallett#endif
64210284Sjmallett
65210284Sjmallett/* If someone is using an old config, make the SPI4000 act like RGMII for backpressure */
66210284Sjmallett#ifndef CVMX_HELPER_DISABLE_SPI4000_BACKPRESSURE
67210284Sjmallett#ifndef CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE
68210284Sjmallett#define CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE 0
69210284Sjmallett#endif
70210284Sjmallett#define CVMX_HELPER_DISABLE_SPI4000_BACKPRESSURE CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE
71210284Sjmallett#endif
72210284Sjmallett
73210284Sjmallett#define SPI4000_READ_ADDRESS_HIGH   0xf0
74210284Sjmallett#define SPI4000_READ_ADDRESS_LOW    0xf1
75210284Sjmallett#define SPI4000_WRITE_ADDRESS_HIGH  0xf2
76210284Sjmallett#define SPI4000_WRITE_ADDRESS_LOW   0xf3
77210284Sjmallett#define SPI4000_READ_DATA0          0xf4    /* High byte */
78210284Sjmallett#define SPI4000_READ_DATA1          0xf5
79210284Sjmallett#define SPI4000_READ_DATA2          0xf6
80210284Sjmallett#define SPI4000_READ_DATA3          0xf7    /* Low byte */
81210284Sjmallett#define SPI4000_WRITE_DATA0         0xf8    /* High byte */
82210284Sjmallett#define SPI4000_WRITE_DATA1         0xf9
83210284Sjmallett#define SPI4000_WRITE_DATA2         0xfa
84210284Sjmallett#define SPI4000_WRITE_DATA3         0xfb    /* Low byte */
85210284Sjmallett#define SPI4000_DO_READ             0xfc    /* Issue a read, returns read status */
86210284Sjmallett#define SPI4000_GET_READ_STATUS     0xfd    /* 0xff: initial state, 2: Read failed, 1: Read pending, 0: Read success */
87210284Sjmallett#define SPI4000_DO_WRITE            0xfe    /* Issue a write, returns write status */
88210284Sjmallett#define SPI4000_GET_WRITE_STATUS    0xff    /* 0xff: initial state, 6: Write failed, 5: Write pending, 4: Write success */
89210284Sjmallett#define SPI4000_TWSI_ID(interface)  (0x66 + interface)
90210284Sjmallett
91210284Sjmallett/* MDI Single Command (register 0x680) */
92210284Sjmalletttypedef union
93210284Sjmallett{
94210284Sjmallett    uint32_t u32;
95210284Sjmallett    struct
96210284Sjmallett    {
97210284Sjmallett        uint32_t    reserved_21_31  : 11;
98210284Sjmallett        uint32_t    mdi_command     : 1; /**< Performs an MDIO access. When set, this bit
99210284Sjmallett                                            self clears upon completion of the access. */
100210284Sjmallett        uint32_t    reserved_18_19  : 2;
101210284Sjmallett        uint32_t    op_code         : 2; /**< MDIO Op Code
102210284Sjmallett                                            00 = Reserved
103210284Sjmallett                                            01 = Write Access
104210284Sjmallett                                            10 = Read Access
105210284Sjmallett                                            11 = Reserved */
106210284Sjmallett        uint32_t    reserved_13_15  : 3;
107210284Sjmallett        uint32_t    phy_address     : 5; /**< Address of external PHY device */
108210284Sjmallett        uint32_t    reserved_5_7    : 3;
109210284Sjmallett        uint32_t    reg_address     : 5; /**< Address of register within external PHY */
110210284Sjmallett    } s;
111210284Sjmallett} mdio_single_command_t;
112210284Sjmallett
113210284Sjmallett
114210284Sjmallettstatic CVMX_SHARED int interface_is_spi4000[2] = {0,0};
115210284Sjmallett
116210284Sjmallett
117210284Sjmallett/**
118210284Sjmallett * @INTERNAL
119210284Sjmallett * Write data to the specified SPI4000 address
120210284Sjmallett *
121210284Sjmallett * @param interface Interface the SPI4000 is on. (0 or 1)
122210284Sjmallett * @param address   Address to write to
123210284Sjmallett * @param data      Data to write
124210284Sjmallett */
125210284Sjmallettstatic void __cvmx_spi4000_write(int interface, int address, uint32_t data)
126210284Sjmallett{
127210284Sjmallett    int status;
128210284Sjmallett    cvmx_twsix_write_ia(0, SPI4000_TWSI_ID(interface), SPI4000_WRITE_ADDRESS_HIGH, 2, 1, address);
129210284Sjmallett    cvmx_twsix_write_ia(0, SPI4000_TWSI_ID(interface), SPI4000_WRITE_DATA0, 4, 1, data);
130210284Sjmallett
131210284Sjmallett    status = cvmx_twsi_read8(SPI4000_TWSI_ID(interface), SPI4000_DO_WRITE);
132210284Sjmallett    while ((status == 5) || (status == 0xff))
133210284Sjmallett        status = cvmx_twsi_read8(SPI4000_TWSI_ID(interface), SPI4000_GET_WRITE_STATUS);
134210284Sjmallett
135210284Sjmallett    if (status != 4)
136210284Sjmallett        cvmx_dprintf("SPI4000: write failed with status=0x%x\n", status);
137210284Sjmallett}
138210284Sjmallett
139210284Sjmallett
140210284Sjmallett/**
141210284Sjmallett * @INTERNAL
142210284Sjmallett * Read data from the SPI4000.
143210284Sjmallett *
144210284Sjmallett * @param interface Interface the SPI4000 is on. (0 or 1)
145210284Sjmallett * @param address   Address to read from
146210284Sjmallett *
147210284Sjmallett * @return Value at the specified address
148210284Sjmallett */
149210284Sjmallettstatic uint32_t __cvmx_spi4000_read(int interface, int address)
150210284Sjmallett{
151210284Sjmallett    int status;
152210284Sjmallett    uint64_t data;
153210284Sjmallett
154210284Sjmallett    cvmx_twsix_write_ia(0, SPI4000_TWSI_ID(interface), SPI4000_READ_ADDRESS_HIGH, 2, 1, address);
155210284Sjmallett
156210284Sjmallett    status = cvmx_twsi_read8(SPI4000_TWSI_ID(interface), SPI4000_DO_READ);
157210284Sjmallett    while ((status == 1) || (status == 0xff))
158210284Sjmallett        status = cvmx_twsi_read8(SPI4000_TWSI_ID(interface), SPI4000_GET_READ_STATUS);
159210284Sjmallett
160210284Sjmallett    if (status)
161210284Sjmallett    {
162210284Sjmallett        cvmx_dprintf("SPI4000: read failed with %d\n", status);
163210284Sjmallett        return 0;
164210284Sjmallett    }
165210284Sjmallett
166210284Sjmallett    status = cvmx_twsix_read_ia(0, SPI4000_TWSI_ID(interface), SPI4000_READ_DATA0, 4, 1, &data);
167210284Sjmallett    if (status != 4)
168210284Sjmallett    {
169210284Sjmallett        cvmx_dprintf("SPI4000: read failed with %d\n", status);
170210284Sjmallett        return 0;
171210284Sjmallett    }
172210284Sjmallett
173210284Sjmallett    return data;
174210284Sjmallett}
175210284Sjmallett
176210284Sjmallett
177210284Sjmallett/**
178210284Sjmallett * @INTERNAL
179210284Sjmallett * Write to a PHY using MDIO on the SPI4000
180210284Sjmallett *
181210284Sjmallett * @param interface Interface the SPI4000 is on. (0 or 1)
182210284Sjmallett * @param port      SPI4000 RGMII port to write to. (0-9)
183210284Sjmallett * @param location  MDIO register to write
184210284Sjmallett * @param val       Value to write
185210284Sjmallett */
186210284Sjmallettstatic void __cvmx_spi4000_mdio_write(int interface, int port, int location, int val)
187210284Sjmallett{
188210284Sjmallett    static int last_value=-1;
189210284Sjmallett    mdio_single_command_t mdio;
190210284Sjmallett
191210284Sjmallett    mdio.u32 = 0;
192210284Sjmallett    mdio.s.mdi_command = 1;
193210284Sjmallett    mdio.s.op_code = 1;
194210284Sjmallett    mdio.s.phy_address = port;
195210284Sjmallett    mdio.s.reg_address = location;
196210284Sjmallett
197210284Sjmallett    /* Since the TWSI accesses are very slow, don't update the write value
198210284Sjmallett        if it is the same as the last value */
199210284Sjmallett    if (val != last_value)
200210284Sjmallett    {
201210284Sjmallett        last_value = val;
202210284Sjmallett        __cvmx_spi4000_write(interface, 0x0681, val);
203210284Sjmallett    }
204210284Sjmallett
205210284Sjmallett    __cvmx_spi4000_write(interface, 0x0680, mdio.u32);
206210284Sjmallett}
207210284Sjmallett
208210284Sjmallett
209210284Sjmallett/**
210210284Sjmallett * @INTERNAL
211210284Sjmallett * Read from a PHY using MDIO on the SPI4000
212210284Sjmallett *
213210284Sjmallett * @param interface Interface the SPI4000 is on. (0 or 1)
214210284Sjmallett * @param port      SPI4000 RGMII port to read from. (0-9)
215210284Sjmallett * @param location  MDIO register to read
216210284Sjmallett * @return The MDI read result
217210284Sjmallett */
218210284Sjmallettstatic int __cvmx_spi4000_mdio_read(int interface, int port, int location)
219210284Sjmallett{
220210284Sjmallett    mdio_single_command_t mdio;
221210284Sjmallett
222210284Sjmallett    mdio.u32 = 0;
223210284Sjmallett    mdio.s.mdi_command = 1;
224210284Sjmallett    mdio.s.op_code = 2;
225210284Sjmallett    mdio.s.phy_address = port;
226210284Sjmallett    mdio.s.reg_address = location;
227210284Sjmallett    __cvmx_spi4000_write(interface, 0x0680, mdio.u32);
228210284Sjmallett
229210284Sjmallett    do
230210284Sjmallett    {
231210284Sjmallett        mdio.u32 = __cvmx_spi4000_read(interface, 0x0680);
232210284Sjmallett    } while (mdio.s.mdi_command);
233210284Sjmallett
234210284Sjmallett    return __cvmx_spi4000_read(interface, 0x0681) >> 16;
235210284Sjmallett}
236210284Sjmallett
237210284Sjmallett
238210284Sjmallett/**
239210284Sjmallett * @INTERNAL
240210284Sjmallett * Configure the SPI4000 MACs
241210284Sjmallett */
242210284Sjmallettstatic void __cvmx_spi4000_configure_mac(int interface)
243210284Sjmallett{
244210284Sjmallett    int port;
245210284Sjmallett    // IXF1010 configuration
246210284Sjmallett    // ---------------------
247210284Sjmallett    //
248210284Sjmallett    // Step 1: Apply soft reset to TxFIFO and MAC
249210284Sjmallett    //         MAC soft reset register. address=0x505
250210284Sjmallett    //         TxFIFO soft reset. address=0x620
251210284Sjmallett    __cvmx_spi4000_write(interface, 0x0505, 0x3ff);  // reset all the MACs
252210284Sjmallett    __cvmx_spi4000_write(interface, 0x0620, 0x3ff);  // reset the TX FIFOs
253210284Sjmallett
254210284Sjmallett    //         Global address and Configuration Register. address=0x500
255210284Sjmallett    //
256210284Sjmallett    // Step 2: Apply soft reset to RxFIFO and SPI.
257210284Sjmallett    __cvmx_spi4000_write(interface, 0x059e, 0x3ff);  // reset the RX FIFOs
258210284Sjmallett
259210284Sjmallett    // Step 3a: Take the MAC out of softreset
260210284Sjmallett    //          MAC soft reset register. address=0x505
261210284Sjmallett    __cvmx_spi4000_write(interface, 0x0505, 0x0);    // reset all the MACs
262210284Sjmallett
263210284Sjmallett    // Step 3b: De-assert port enables.
264210284Sjmallett    //          Global address and Configuration Register. address=0x500
265210284Sjmallett    __cvmx_spi4000_write(interface, 0x0500, 0x0);    // disable all ports
266210284Sjmallett
267210284Sjmallett    // Step 4: Assert Clock mode change En.
268210284Sjmallett    //         Clock and interface mode Change En. address=Serdes base + 0x14
269210284Sjmallett    //         Serdes (Serializer/de-serializer). address=0x780
270210284Sjmallett    //         [Can't find this one]
271210284Sjmallett
272210284Sjmallett    for (port=0; port < 10; port++)
273210284Sjmallett    {
274210284Sjmallett        int port_offset = port << 7;
275210284Sjmallett
276210284Sjmallett        // Step 5: Set MAC interface mode GMII speed.
277210284Sjmallett        //         MAC interface mode and RGMII speed register.
278210284Sjmallett        //             address=port_index+0x10
279210284Sjmallett        //
280210284Sjmallett        //         OUT port_index+0x10, 0x07     //RGMII 1000 Mbps operation.
281210284Sjmallett        __cvmx_spi4000_write(interface, port_offset | 0x0010, 0x3);
282210284Sjmallett
283210284Sjmallett        // Set the max packet size to 16383 bytes, including the CRC
284210284Sjmallett        __cvmx_spi4000_write(interface, port_offset | 0x000f, 0x3fff);
285210284Sjmallett
286210284Sjmallett        // Step 6: Change Interface to Copper mode
287210284Sjmallett        //         Interface mode register. address=0x501
288210284Sjmallett        //         [Can't find this]
289210284Sjmallett
290210284Sjmallett        // Step 7: MAC configuration
291210284Sjmallett        //         Station address configuration.
292210284Sjmallett        //         Source MAC address low register. Source MAC address 31-0.
293210284Sjmallett        //             address=port_index+0x00
294210284Sjmallett        //         Source MAC address high register. Source MAC address 47-32.
295210284Sjmallett        //             address=port_index+0x01
296210284Sjmallett        //         where Port index is 0x0 to 0x5.
297210284Sjmallett        //         This address is inserted in the source address filed when
298210284Sjmallett        //         transmitting pause frames, and is also used to compare against
299210284Sjmallett        //         unicast pause frames at the receiving side.
300210284Sjmallett        //
301210284Sjmallett        //         OUT port_index+0x00, source MAC address low.
302210284Sjmallett        __cvmx_spi4000_write(interface, port_offset | 0x0000, 0x0000);
303210284Sjmallett        //         OUT port_index+0x01, source MAC address high.
304210284Sjmallett        __cvmx_spi4000_write(interface, port_offset | 0x0001, 0x0000);
305210284Sjmallett
306210284Sjmallett        // Step 8: Set desired duplex mode
307210284Sjmallett        //         Desired duplex register. address=port_index+0x02
308210284Sjmallett        //         [Reserved]
309210284Sjmallett
310210284Sjmallett        // Step 9: Other configuration.
311210284Sjmallett        //         FC Enable Register.             address=port_index+0x12
312210284Sjmallett        //         Discard Unknown Control Frame.  address=port_index+0x15
313210284Sjmallett        //         Diverse config write register.  address=port_index+0x18
314210284Sjmallett        //         RX Packet Filter register.      address=port_index+0x19
315210284Sjmallett        //
316210284Sjmallett        // Step 9a: Tx FD FC Enabled / Rx FD FC Enabled
317210284Sjmallett        if (CVMX_HELPER_DISABLE_SPI4000_BACKPRESSURE)
318210284Sjmallett            __cvmx_spi4000_write(interface, port_offset | 0x0012, 0);
319210284Sjmallett        else
320210284Sjmallett            __cvmx_spi4000_write(interface, port_offset | 0x0012, 0x7);
321210284Sjmallett
322210284Sjmallett        // Step 9b: Discard unknown control frames
323210284Sjmallett        __cvmx_spi4000_write(interface, port_offset | 0x0015, 0x1);
324210284Sjmallett
325210284Sjmallett        // Step 9c: Enable auto-CRC and auto-padding
326210284Sjmallett        __cvmx_spi4000_write(interface, port_offset | 0x0018, 0x11cd); //??
327210284Sjmallett
328210284Sjmallett        // Step 9d: Drop bad CRC / Drop Pause / No DAF
329210284Sjmallett        __cvmx_spi4000_write(interface, port_offset | 0x0019, 0x00);
330210284Sjmallett    }
331210284Sjmallett
332210284Sjmallett    // Step 9d: Drop frames
333210284Sjmallett    __cvmx_spi4000_write(interface, 0x059f, 0x03ff);
334210284Sjmallett
335210284Sjmallett    for (port=0; port < 10; port++)
336210284Sjmallett    {
337210284Sjmallett        // Step 9e: Set the TX FIFO marks
338210284Sjmallett        __cvmx_spi4000_write(interface, port + 0x0600, 0x0900); // TXFIFO High watermark
339210284Sjmallett        __cvmx_spi4000_write(interface, port + 0x060a, 0x0800); // TXFIFO Low watermark
340210284Sjmallett        __cvmx_spi4000_write(interface, port + 0x0614, 0x0380); // TXFIFO threshold
341210284Sjmallett    }
342210284Sjmallett
343210284Sjmallett    // Step 12: De-assert RxFIFO and SPI Rx/Tx reset
344210284Sjmallett    __cvmx_spi4000_write(interface, 0x059e, 0x0);    // reset the RX FIFOs
345210284Sjmallett
346210284Sjmallett    // Step 13: De-assert TxFIFO and MAC reset
347210284Sjmallett    __cvmx_spi4000_write(interface, 0x0620, 0x0);    // reset the TX FIFOs
348210284Sjmallett
349210284Sjmallett    // Step 14: Assert port enable
350210284Sjmallett    //          Global address and Configuration Register. address=0x500
351210284Sjmallett    __cvmx_spi4000_write(interface, 0x0500, 0x03ff); // enable all ports
352210284Sjmallett
353210284Sjmallett    // Step 15: Disable loopback
354210284Sjmallett    //          [Can't find this one]
355210284Sjmallett}
356210284Sjmallett
357210284Sjmallett
358210284Sjmallett/**
359210284Sjmallett * @INTERNAL
360210284Sjmallett * Configure the SPI4000 PHYs
361210284Sjmallett */
362210284Sjmallettstatic void __cvmx_spi4000_configure_phy(int interface)
363210284Sjmallett{
364210284Sjmallett    int port;
365210284Sjmallett
366210284Sjmallett    /* We use separate loops below since it allows us to save a write
367210284Sjmallett        to the SPI4000 for each repeated value. This adds up to a couple
368210284Sjmallett        of seconds */
369210284Sjmallett
370210284Sjmallett    /* Update the link state before resets. It takes a while for the links to
371210284Sjmallett        come back after the resets. Most likely they'll come back the same as
372210284Sjmallett        they are now */
373210284Sjmallett    for (port=0; port < 10; port++)
374210284Sjmallett        cvmx_spi4000_check_speed(interface, port);
375210284Sjmallett    /* Enable RGMII DELAYS for TX_CLK and RX_CLK (see spec) */
376210284Sjmallett    for (port=0; port < 10; port++)
377210284Sjmallett        __cvmx_spi4000_mdio_write(interface, port, 0x14, 0x00e2);
378210284Sjmallett    /* Advertise pause and 100 Full Duplex. Don't advertise half duplex or 10Mbpa */
379210284Sjmallett    for (port=0; port < 10; port++)
380210284Sjmallett        __cvmx_spi4000_mdio_write(interface, port, 0x4, 0x0d01);
381210284Sjmallett    /* Enable PHY reset */
382210284Sjmallett    for (port=0; port < 10; port++)
383210284Sjmallett        __cvmx_spi4000_mdio_write(interface, port, 0x0, 0x9140);
384210284Sjmallett}
385210284Sjmallett
386210284Sjmallett
387210284Sjmallett/**
388210284Sjmallett * Poll all the SPI4000 port and check its speed
389210284Sjmallett *
390210284Sjmallett * @param interface Interface the SPI4000 is on
391210284Sjmallett * @param port      Port to poll (0-9)
392210284Sjmallett * @return Status of the port. 0=down. All other values the port is up.
393210284Sjmallett */
394210284Sjmallettcvmx_gmxx_rxx_rx_inbnd_t cvmx_spi4000_check_speed(int interface, int port)
395210284Sjmallett{
396210284Sjmallett    static int phy_status[10] = {0,};
397210284Sjmallett    cvmx_gmxx_rxx_rx_inbnd_t link;
398210284Sjmallett    int read_status;
399210284Sjmallett
400210284Sjmallett    link.u64 = 0;
401210284Sjmallett
402210284Sjmallett    if (!interface_is_spi4000[interface])
403210284Sjmallett        return link;
404210284Sjmallett    if (port>=10)
405210284Sjmallett        return link;
406210284Sjmallett
407210284Sjmallett    /* Register 0x11: PHY Specific Status Register
408210284Sjmallett         Register   Function         Setting                     Mode   HW Rst SW Rst Notes
409210284Sjmallett                                                                 RO     00     Retain note
410210284Sjmallett         17.15:14   Speed            11 = Reserved
411210284Sjmallett                                                                                      17.a
412210284Sjmallett                                     10 = 1000 Mbps
413210284Sjmallett                                     01 = 100 Mbps
414210284Sjmallett                                     00 = 10 Mbps
415210284Sjmallett         17.13      Duplex           1 = Full-duplex             RO     0      Retain note
416210284Sjmallett                                     0 = Half-duplex                                  17.a
417210284Sjmallett         17.12      Page Received    1 = Page received           RO, LH 0      0
418210284Sjmallett                                     0 = Page not received
419210284Sjmallett                                     1 = Resolved                RO     0      0      note
420210284Sjmallett         17.11      Speed and
421210284Sjmallett                                     0 = Not resolved                                 17.a
422210284Sjmallett                    Duplex
423210284Sjmallett                    Resolved
424210284Sjmallett         17.10      Link (real time) 1 = Link up                 RO     0      0
425210284Sjmallett                                     0 = Link down
426210284Sjmallett                                                                 RO     000    000    note
427210284Sjmallett                                     000 = < 50m
428210284Sjmallett         17.9:7     Cable Length
429210284Sjmallett                                     001 = 50 - 80m                                   17.b
430210284Sjmallett                    (100/1000
431210284Sjmallett                                     010 = 80 - 110m
432210284Sjmallett                    modes only)
433210284Sjmallett                                     011 = 110 - 140m
434210284Sjmallett                                     100 = >140m
435210284Sjmallett         17.6       MDI Crossover    1 = MDIX                    RO     0      0      note
436210284Sjmallett                    Status           0 = MDI                                          17.a
437210284Sjmallett         17.5       Downshift Sta-   1 = Downshift               RO     0      0
438210284Sjmallett                    tus              0 = No Downshift
439210284Sjmallett         17.4       Energy Detect    1 = Sleep                   RO     0      0
440210284Sjmallett                    Status           0 = Active
441210284Sjmallett         17.3       Transmit Pause   1 = Transmit pause enabled  RO     0      0      note17.
442210284Sjmallett                    Enabled          0 = Transmit pause disabled                      a, 17.c
443210284Sjmallett         17.2       Receive Pause    1 = Receive pause enabled   RO     0      0      note17.
444210284Sjmallett                    Enabled          0 = Receive pause disabled                       a, 17.c
445210284Sjmallett         17.1       Polarity (real   1 = Reversed                RO     0      0
446210284Sjmallett                    time)            0 = Normal
447210284Sjmallett         17.0       Jabber (real     1 = Jabber                  RO     0      Retain
448210284Sjmallett                    time)            0 = No jabber
449210284Sjmallett    */
450210284Sjmallett    read_status = __cvmx_spi4000_mdio_read(interface, port, 0x11);
451210284Sjmallett    if ((read_status & (1<<10)) == 0)
452210284Sjmallett        read_status = 0; /* If the link is down, force zero */
453210284Sjmallett    else
454210284Sjmallett        read_status &= 0xe400; /* Strip off all the don't care bits */
455210284Sjmallett    if (read_status != phy_status[port])
456210284Sjmallett    {
457210284Sjmallett        phy_status[port] = read_status;
458210284Sjmallett        if (read_status & (1<<10))
459210284Sjmallett        {
460210284Sjmallett            /* If the link is up, we need to set the speed based on the PHY status */
461210284Sjmallett            if (read_status & (1<<15))
462210284Sjmallett                __cvmx_spi4000_write(interface, (port<<7) | 0x0010, 0x3); /* 1Gbps */
463210284Sjmallett            else
464210284Sjmallett                __cvmx_spi4000_write(interface, (port<<7) | 0x0010, 0x1); /* 100Mbps */
465210284Sjmallett        }
466210284Sjmallett        else
467210284Sjmallett        {
468210284Sjmallett            /* If the link is down, force 1Gbps so TX traffic dumps fast */
469210284Sjmallett            __cvmx_spi4000_write(interface, (port<<7) | 0x0010, 0x3); /* 1Gbps */
470210284Sjmallett        }
471210284Sjmallett    }
472210284Sjmallett
473210284Sjmallett    if (read_status & (1<<10))
474210284Sjmallett    {
475210284Sjmallett        link.s.status = 1; /* Link up */
476210284Sjmallett        if (read_status & (1<<15))
477210284Sjmallett            link.s.speed = 2;
478210284Sjmallett        else
479210284Sjmallett            link.s.speed = 1;
480210284Sjmallett    }
481210284Sjmallett    else
482210284Sjmallett    {
483210284Sjmallett        link.s.speed = 2; /* Use 1Gbps when down */
484210284Sjmallett        link.s.status = 0; /* Link Down */
485210284Sjmallett    }
486210284Sjmallett    link.s.duplex = ((read_status & (1<<13)) != 0);
487210284Sjmallett
488210284Sjmallett    return link;
489210284Sjmallett}
490215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
491215990SjmallettEXPORT_SYMBOL(cvmx_spi4000_check_speed);
492215990Sjmallett#endif
493210284Sjmallett
494210284Sjmallett
495210284Sjmallett/**
496210284Sjmallett * Return non-zero if the SPI interface has a SPI4000 attached
497210284Sjmallett *
498210284Sjmallett * @param interface SPI interface the SPI4000 is connected to
499210284Sjmallett *
500210284Sjmallett * @return
501210284Sjmallett */
502210284Sjmallettint cvmx_spi4000_is_present(int interface)
503210284Sjmallett{
504210284Sjmallett    if (!(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)))
505210284Sjmallett        return 0;
506210284Sjmallett    // Check for the presence of a SPI4000. If it isn't there,
507210284Sjmallett    // these writes will timeout.
508210284Sjmallett    if (cvmx_twsi_write8(SPI4000_TWSI_ID(interface), SPI4000_WRITE_ADDRESS_HIGH, 0))
509210284Sjmallett        return 0;
510210284Sjmallett    if (cvmx_twsi_write8(SPI4000_TWSI_ID(interface), SPI4000_WRITE_ADDRESS_LOW, 0))
511210284Sjmallett        return 0;
512210284Sjmallett    interface_is_spi4000[interface] = 1;
513210284Sjmallett    return 1;
514210284Sjmallett}
515210284Sjmallett
516210284Sjmallett
517210284Sjmallett/**
518210284Sjmallett * Initialize the SPI4000 for use
519210284Sjmallett *
520210284Sjmallett * @param interface SPI interface the SPI4000 is connected to
521210284Sjmallett */
522210284Sjmallettint cvmx_spi4000_initialize(int interface)
523210284Sjmallett{
524210284Sjmallett    if (!cvmx_spi4000_is_present(interface))
525210284Sjmallett        return -1;
526210284Sjmallett
527210284Sjmallett    __cvmx_spi4000_configure_mac(interface);
528210284Sjmallett    __cvmx_spi4000_configure_phy(interface);
529210284Sjmallett    return 0;
530210284Sjmallett}
531210284Sjmallett
532