]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/contrib/octeon-sdk/cvmx-spi4000.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / contrib / octeon-sdk / cvmx-spi4000.c
1 /***********************license start***************
2  *  Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights
3  *  reserved.
4  *
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions are
8  *  met:
9  *
10  *      * Redistributions of source code must retain the above copyright
11  *        notice, this list of conditions and the following disclaimer.
12  *
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.
17  *
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
21  *        permission.
22  *
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.
33  *
34  *
35  *  For any questions regarding licensing please contact marketing@caviumnetworks.com
36  *
37  ***********************license end**************************************/
38
39
40
41
42
43
44 /**
45  * @file
46  *
47  * Support library for the SPI4000 card
48  *
49  * <hr>$Revision: 41586 $<hr>
50  */
51 #include "cvmx.h"
52 #include "cvmx-mio.h"
53 #include "cvmx-spi.h"
54 #include "cvmx-twsi.h"
55
56 /* If someone is using an old config, make the SPI4000 act like RGMII for backpressure */
57 #ifndef CVMX_HELPER_DISABLE_SPI4000_BACKPRESSURE
58 #ifndef CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE
59 #define CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE 0
60 #endif
61 #define CVMX_HELPER_DISABLE_SPI4000_BACKPRESSURE CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE
62 #endif
63
64 #define SPI4000_READ_ADDRESS_HIGH   0xf0
65 #define SPI4000_READ_ADDRESS_LOW    0xf1
66 #define SPI4000_WRITE_ADDRESS_HIGH  0xf2
67 #define SPI4000_WRITE_ADDRESS_LOW   0xf3
68 #define SPI4000_READ_DATA0          0xf4    /* High byte */
69 #define SPI4000_READ_DATA1          0xf5
70 #define SPI4000_READ_DATA2          0xf6
71 #define SPI4000_READ_DATA3          0xf7    /* Low byte */
72 #define SPI4000_WRITE_DATA0         0xf8    /* High byte */
73 #define SPI4000_WRITE_DATA1         0xf9
74 #define SPI4000_WRITE_DATA2         0xfa
75 #define SPI4000_WRITE_DATA3         0xfb    /* Low byte */
76 #define SPI4000_DO_READ             0xfc    /* Issue a read, returns read status */
77 #define SPI4000_GET_READ_STATUS     0xfd    /* 0xff: initial state, 2: Read failed, 1: Read pending, 0: Read success */
78 #define SPI4000_DO_WRITE            0xfe    /* Issue a write, returns write status */
79 #define SPI4000_GET_WRITE_STATUS    0xff    /* 0xff: initial state, 6: Write failed, 5: Write pending, 4: Write success */
80 #define SPI4000_TWSI_ID(interface)  (0x66 + interface)
81
82 /* MDI Single Command (register 0x680) */
83 typedef union
84 {
85     uint32_t u32;
86     struct
87     {
88         uint32_t    reserved_21_31  : 11;
89         uint32_t    mdi_command     : 1; /**< Performs an MDIO access. When set, this bit
90                                             self clears upon completion of the access. */
91         uint32_t    reserved_18_19  : 2;
92         uint32_t    op_code         : 2; /**< MDIO Op Code
93                                             00 = Reserved
94                                             01 = Write Access
95                                             10 = Read Access
96                                             11 = Reserved */
97         uint32_t    reserved_13_15  : 3;
98         uint32_t    phy_address     : 5; /**< Address of external PHY device */
99         uint32_t    reserved_5_7    : 3;
100         uint32_t    reg_address     : 5; /**< Address of register within external PHY */
101     } s;
102 } mdio_single_command_t;
103
104
105 static CVMX_SHARED int interface_is_spi4000[2] = {0,0};
106
107
108 /**
109  * @INTERNAL
110  * Write data to the specified SPI4000 address
111  *
112  * @param interface Interface the SPI4000 is on. (0 or 1)
113  * @param address   Address to write to
114  * @param data      Data to write
115  */
116 static void __cvmx_spi4000_write(int interface, int address, uint32_t data)
117 {
118     int status;
119
120     cvmx_twsix_write_ia(0, SPI4000_TWSI_ID(interface), SPI4000_WRITE_ADDRESS_HIGH, 2, 1, address);
121     cvmx_twsix_write_ia(0, SPI4000_TWSI_ID(interface), SPI4000_WRITE_DATA0, 4, 1, data);
122
123     status = cvmx_twsi_read8(SPI4000_TWSI_ID(interface), SPI4000_DO_WRITE);
124     while ((status == 5) || (status == 0xff))
125         status = cvmx_twsi_read8(SPI4000_TWSI_ID(interface), SPI4000_GET_WRITE_STATUS);
126
127     if (status != 4)
128         cvmx_dprintf("SPI4000: write failed with status=0x%x\n", status);
129 }
130
131
132 /**
133  * @INTERNAL
134  * Read data from the SPI4000.
135  *
136  * @param interface Interface the SPI4000 is on. (0 or 1)
137  * @param address   Address to read from
138  *
139  * @return Value at the specified address
140  */
141 static uint32_t __cvmx_spi4000_read(int interface, int address)
142 {
143     int status;
144     uint64_t data;
145
146     cvmx_twsix_write_ia(0, SPI4000_TWSI_ID(interface), SPI4000_READ_ADDRESS_HIGH, 2, 1, address);
147
148     status = cvmx_twsi_read8(SPI4000_TWSI_ID(interface), SPI4000_DO_READ);
149     while ((status == 1) || (status == 0xff))
150         status = cvmx_twsi_read8(SPI4000_TWSI_ID(interface), SPI4000_GET_READ_STATUS);
151
152     if (status)
153     {
154         cvmx_dprintf("SPI4000: read failed with %d\n", status);
155         return 0;
156     }
157
158     status = cvmx_twsix_read_ia(0, SPI4000_TWSI_ID(interface), SPI4000_READ_DATA0, 4, 1, &data);
159     if (status != 4)
160     {
161         cvmx_dprintf("SPI4000: read failed with %d\n", status);
162         return 0;
163     }
164
165     return data;
166 }
167
168
169 /**
170  * @INTERNAL
171  * Write to a PHY using MDIO on the SPI4000
172  *
173  * @param interface Interface the SPI4000 is on. (0 or 1)
174  * @param port      SPI4000 RGMII port to write to. (0-9)
175  * @param location  MDIO register to write
176  * @param val       Value to write
177  */
178 static void __cvmx_spi4000_mdio_write(int interface, int port, int location, int val)
179 {
180     static int last_value=-1;
181     mdio_single_command_t mdio;
182
183     mdio.u32 = 0;
184     mdio.s.mdi_command = 1;
185     mdio.s.op_code = 1;
186     mdio.s.phy_address = port;
187     mdio.s.reg_address = location;
188
189     /* Since the TWSI accesses are very slow, don't update the write value
190         if it is the same as the last value */
191     if (val != last_value)
192     {
193         last_value = val;
194         __cvmx_spi4000_write(interface, 0x0681, val);
195     }
196
197     __cvmx_spi4000_write(interface, 0x0680, mdio.u32);
198 }
199
200
201 /**
202  * @INTERNAL
203  * Read from a PHY using MDIO on the SPI4000
204  *
205  * @param interface Interface the SPI4000 is on. (0 or 1)
206  * @param port      SPI4000 RGMII port to read from. (0-9)
207  * @param location  MDIO register to read
208  * @return The MDI read result
209  */
210 static int __cvmx_spi4000_mdio_read(int interface, int port, int location)
211 {
212     mdio_single_command_t mdio;
213
214     mdio.u32 = 0;
215     mdio.s.mdi_command = 1;
216     mdio.s.op_code = 2;
217     mdio.s.phy_address = port;
218     mdio.s.reg_address = location;
219     __cvmx_spi4000_write(interface, 0x0680, mdio.u32);
220
221     do
222     {
223         mdio.u32 = __cvmx_spi4000_read(interface, 0x0680);
224     } while (mdio.s.mdi_command);
225
226     return __cvmx_spi4000_read(interface, 0x0681) >> 16;
227 }
228
229
230 /**
231  * @INTERNAL
232  * Configure the SPI4000 MACs
233  */
234 static void __cvmx_spi4000_configure_mac(int interface)
235 {
236     int port;
237     // IXF1010 configuration
238     // ---------------------
239     //
240     // Step 1: Apply soft reset to TxFIFO and MAC
241     //         MAC soft reset register. address=0x505
242     //         TxFIFO soft reset. address=0x620
243     __cvmx_spi4000_write(interface, 0x0505, 0x3ff);  // reset all the MACs
244     __cvmx_spi4000_write(interface, 0x0620, 0x3ff);  // reset the TX FIFOs
245
246     //         Global address and Configuration Register. address=0x500
247     //
248     // Step 2: Apply soft reset to RxFIFO and SPI.
249     __cvmx_spi4000_write(interface, 0x059e, 0x3ff);  // reset the RX FIFOs
250
251     // Step 3a: Take the MAC out of softreset
252     //          MAC soft reset register. address=0x505
253     __cvmx_spi4000_write(interface, 0x0505, 0x0);    // reset all the MACs
254
255     // Step 3b: De-assert port enables.
256     //          Global address and Configuration Register. address=0x500
257     __cvmx_spi4000_write(interface, 0x0500, 0x0);    // disable all ports
258
259     // Step 4: Assert Clock mode change En.
260     //         Clock and interface mode Change En. address=Serdes base + 0x14
261     //         Serdes (Serializer/de-serializer). address=0x780
262     //         [Can't find this one]
263
264     for (port=0; port < 10; port++)
265     {
266         int port_offset = port << 7;
267
268         // Step 5: Set MAC interface mode GMII speed.
269         //         MAC interface mode and RGMII speed register.
270         //             address=port_index+0x10
271         //
272         //         OUT port_index+0x10, 0x07     //RGMII 1000 Mbps operation.
273         __cvmx_spi4000_write(interface, port_offset | 0x0010, 0x3);
274
275         // Set the max packet size to 16383 bytes, including the CRC
276         __cvmx_spi4000_write(interface, port_offset | 0x000f, 0x3fff);
277
278         // Step 6: Change Interface to Copper mode
279         //         Interface mode register. address=0x501
280         //         [Can't find this]
281
282         // Step 7: MAC configuration
283         //         Station address configuration.
284         //         Source MAC address low register. Source MAC address 31-0.
285         //             address=port_index+0x00
286         //         Source MAC address high register. Source MAC address 47-32.
287         //             address=port_index+0x01
288         //         where Port index is 0x0 to 0x5.
289         //         This address is inserted in the source address filed when
290         //         transmitting pause frames, and is also used to compare against
291         //         unicast pause frames at the receiving side.
292         //
293         //         OUT port_index+0x00, source MAC address low.
294         __cvmx_spi4000_write(interface, port_offset | 0x0000, 0x0000);
295         //         OUT port_index+0x01, source MAC address high.
296         __cvmx_spi4000_write(interface, port_offset | 0x0001, 0x0000);
297
298         // Step 8: Set desired duplex mode
299         //         Desired duplex register. address=port_index+0x02
300         //         [Reserved]
301
302         // Step 9: Other configuration.
303         //         FC Enable Register.             address=port_index+0x12
304         //         Discard Unknown Control Frame.  address=port_index+0x15
305         //         Diverse config write register.  address=port_index+0x18
306         //         RX Packet Filter register.      address=port_index+0x19
307         //
308         // Step 9a: Tx FD FC Enabled / Rx FD FC Enabled
309         if (CVMX_HELPER_DISABLE_SPI4000_BACKPRESSURE)
310             __cvmx_spi4000_write(interface, port_offset | 0x0012, 0);
311         else
312             __cvmx_spi4000_write(interface, port_offset | 0x0012, 0x7);
313
314         // Step 9b: Discard unknown control frames
315         __cvmx_spi4000_write(interface, port_offset | 0x0015, 0x1);
316
317         // Step 9c: Enable auto-CRC and auto-padding
318         __cvmx_spi4000_write(interface, port_offset | 0x0018, 0x11cd); //??
319
320         // Step 9d: Drop bad CRC / Drop Pause / No DAF
321         __cvmx_spi4000_write(interface, port_offset | 0x0019, 0x00);
322     }
323
324     // Step 9d: Drop frames
325     __cvmx_spi4000_write(interface, 0x059f, 0x03ff);
326
327     for (port=0; port < 10; port++)
328     {
329         // Step 9e: Set the TX FIFO marks
330         __cvmx_spi4000_write(interface, port + 0x0600, 0x0900); // TXFIFO High watermark
331         __cvmx_spi4000_write(interface, port + 0x060a, 0x0800); // TXFIFO Low watermark
332         __cvmx_spi4000_write(interface, port + 0x0614, 0x0380); // TXFIFO threshold
333     }
334
335     // Step 12: De-assert RxFIFO and SPI Rx/Tx reset
336     __cvmx_spi4000_write(interface, 0x059e, 0x0);    // reset the RX FIFOs
337
338     // Step 13: De-assert TxFIFO and MAC reset
339     __cvmx_spi4000_write(interface, 0x0620, 0x0);    // reset the TX FIFOs
340
341     // Step 14: Assert port enable
342     //          Global address and Configuration Register. address=0x500
343     __cvmx_spi4000_write(interface, 0x0500, 0x03ff); // enable all ports
344
345     // Step 15: Disable loopback
346     //          [Can't find this one]
347 }
348
349
350 /**
351  * @INTERNAL
352  * Configure the SPI4000 PHYs
353  */
354 static void __cvmx_spi4000_configure_phy(int interface)
355 {
356     int port;
357
358     /* We use separate loops below since it allows us to save a write
359         to the SPI4000 for each repeated value. This adds up to a couple
360         of seconds */
361
362     /* Update the link state before resets. It takes a while for the links to
363         come back after the resets. Most likely they'll come back the same as
364         they are now */
365     for (port=0; port < 10; port++)
366         cvmx_spi4000_check_speed(interface, port);
367     /* Enable RGMII DELAYS for TX_CLK and RX_CLK (see spec) */
368     for (port=0; port < 10; port++)
369         __cvmx_spi4000_mdio_write(interface, port, 0x14, 0x00e2);
370     /* Advertise pause and 100 Full Duplex. Don't advertise half duplex or 10Mbpa */
371     for (port=0; port < 10; port++)
372         __cvmx_spi4000_mdio_write(interface, port, 0x4, 0x0d01);
373     /* Enable PHY reset */
374     for (port=0; port < 10; port++)
375         __cvmx_spi4000_mdio_write(interface, port, 0x0, 0x9140);
376 }
377
378
379 /**
380  * Poll all the SPI4000 port and check its speed
381  *
382  * @param interface Interface the SPI4000 is on
383  * @param port      Port to poll (0-9)
384  * @return Status of the port. 0=down. All other values the port is up.
385  */
386 cvmx_gmxx_rxx_rx_inbnd_t cvmx_spi4000_check_speed(int interface, int port)
387 {
388     static int phy_status[10] = {0,};
389     cvmx_gmxx_rxx_rx_inbnd_t link;
390     int read_status;
391
392     link.u64 = 0;
393
394     if (!interface_is_spi4000[interface])
395         return link;
396     if (port>=10)
397         return link;
398
399     /* Register 0x11: PHY Specific Status Register
400          Register   Function         Setting                     Mode   HW Rst SW Rst Notes
401                                                                  RO     00     Retain note
402          17.15:14   Speed            11 = Reserved
403                                                                                       17.a
404                                      10 = 1000 Mbps
405                                      01 = 100 Mbps
406                                      00 = 10 Mbps
407          17.13      Duplex           1 = Full-duplex             RO     0      Retain note
408                                      0 = Half-duplex                                  17.a
409          17.12      Page Received    1 = Page received           RO, LH 0      0
410                                      0 = Page not received
411                                      1 = Resolved                RO     0      0      note
412          17.11      Speed and
413                                      0 = Not resolved                                 17.a
414                     Duplex
415                     Resolved
416          17.10      Link (real time) 1 = Link up                 RO     0      0
417                                      0 = Link down
418                                                                  RO     000    000    note
419                                      000 = < 50m
420          17.9:7     Cable Length
421                                      001 = 50 - 80m                                   17.b
422                     (100/1000
423                                      010 = 80 - 110m
424                     modes only)
425                                      011 = 110 - 140m
426                                      100 = >140m
427          17.6       MDI Crossover    1 = MDIX                    RO     0      0      note
428                     Status           0 = MDI                                          17.a
429          17.5       Downshift Sta-   1 = Downshift               RO     0      0
430                     tus              0 = No Downshift
431          17.4       Energy Detect    1 = Sleep                   RO     0      0
432                     Status           0 = Active
433          17.3       Transmit Pause   1 = Transmit pause enabled  RO     0      0      note17.
434                     Enabled          0 = Transmit pause disabled                      a, 17.c
435          17.2       Receive Pause    1 = Receive pause enabled   RO     0      0      note17.
436                     Enabled          0 = Receive pause disabled                       a, 17.c
437          17.1       Polarity (real   1 = Reversed                RO     0      0
438                     time)            0 = Normal
439          17.0       Jabber (real     1 = Jabber                  RO     0      Retain
440                     time)            0 = No jabber
441     */
442     read_status = __cvmx_spi4000_mdio_read(interface, port, 0x11);
443     if ((read_status & (1<<10)) == 0)
444         read_status = 0; /* If the link is down, force zero */
445     else
446         read_status &= 0xe400; /* Strip off all the don't care bits */
447     if (read_status != phy_status[port])
448     {
449         phy_status[port] = read_status;
450         if (read_status & (1<<10))
451         {
452             /* If the link is up, we need to set the speed based on the PHY status */
453             if (read_status & (1<<15))
454                 __cvmx_spi4000_write(interface, (port<<7) | 0x0010, 0x3); /* 1Gbps */
455             else
456                 __cvmx_spi4000_write(interface, (port<<7) | 0x0010, 0x1); /* 100Mbps */
457         }
458         else
459         {
460             /* If the link is down, force 1Gbps so TX traffic dumps fast */
461             __cvmx_spi4000_write(interface, (port<<7) | 0x0010, 0x3); /* 1Gbps */
462         }
463     }
464
465     if (read_status & (1<<10))
466     {
467         link.s.status = 1; /* Link up */
468         if (read_status & (1<<15))
469             link.s.speed = 2;
470         else
471             link.s.speed = 1;
472     }
473     else
474     {
475         link.s.speed = 2; /* Use 1Gbps when down */
476         link.s.status = 0; /* Link Down */
477     }
478     link.s.duplex = ((read_status & (1<<13)) != 0);
479
480     return link;
481 }
482
483
484 /**
485  * Return non-zero if the SPI interface has a SPI4000 attached
486  *
487  * @param interface SPI interface the SPI4000 is connected to
488  *
489  * @return
490  */
491 int cvmx_spi4000_is_present(int interface)
492 {
493     if (!(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)))
494         return 0;
495     // Check for the presence of a SPI4000. If it isn't there,
496     // these writes will timeout.
497     if (cvmx_twsi_write8(SPI4000_TWSI_ID(interface), SPI4000_WRITE_ADDRESS_HIGH, 0))
498         return 0;
499     if (cvmx_twsi_write8(SPI4000_TWSI_ID(interface), SPI4000_WRITE_ADDRESS_LOW, 0))
500         return 0;
501     interface_is_spi4000[interface] = 1;
502     return 1;
503 }
504
505
506 /**
507  * Initialize the SPI4000 for use
508  *
509  * @param interface SPI interface the SPI4000 is connected to
510  */
511 int cvmx_spi4000_initialize(int interface)
512 {
513     if (!cvmx_spi4000_is_present(interface))
514         return -1;
515
516     __cvmx_spi4000_configure_mac(interface);
517     __cvmx_spi4000_configure_phy(interface);
518     return 0;
519 }
520