]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/contrib/octeon-sdk/cvmx-helper-sgmii.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-helper-sgmii.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  * Functions for SGMII initialization, configuration,
48  * and monitoring.
49  *
50  * <hr>$Revision: 42417 $<hr>
51  */
52 #include "cvmx.h"
53 #include "cvmx-sysinfo.h"
54 #include "cvmx-mdio.h"
55 #include "cvmx-helper.h"
56 #include "cvmx-helper-board.h"
57
58 #ifdef CVMX_ENABLE_PKO_FUNCTIONS
59 /**
60  * @INTERNAL
61  * Perform initialization required only once for an SGMII port.
62  *
63  * @param interface Interface to init
64  * @param index     Index of prot on the interface
65  *
66  * @return Zero on success, negative on failure
67  */
68 static int __cvmx_helper_sgmii_hardware_init_one_time(int interface, int index)
69 {
70     const uint64_t clock_mhz = cvmx_sysinfo_get()->cpu_clock_hz / 1000000;
71     cvmx_pcsx_miscx_ctl_reg_t pcs_misc_ctl_reg;
72     cvmx_pcsx_linkx_timer_count_reg_t pcsx_linkx_timer_count_reg;
73     cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg;
74
75     /* Disable GMX */
76     gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
77     gmxx_prtx_cfg.s.en = 0;
78     cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
79
80     /* Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the appropriate
81         value. 1000BASE-X specifies a 10ms interval. SGMII specifies a 1.6ms
82         interval. */
83     pcs_misc_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
84     pcsx_linkx_timer_count_reg.u64 = cvmx_read_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface));
85     if (pcs_misc_ctl_reg.s.mode)
86     {
87         /* 1000BASE-X */
88         pcsx_linkx_timer_count_reg.s.count = (10000ull * clock_mhz) >> 10;
89     }
90     else
91     {
92         /* SGMII */
93         pcsx_linkx_timer_count_reg.s.count = (1600ull * clock_mhz) >> 10;
94     }
95     cvmx_write_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface), pcsx_linkx_timer_count_reg.u64);
96
97     /* Write the advertisement register to be used as the
98         tx_Config_Reg<D15:D0> of the autonegotiation.
99         In 1000BASE-X mode, tx_Config_Reg<D15:D0> is PCS*_AN*_ADV_REG.
100         In SGMII PHY mode, tx_Config_Reg<D15:D0> is PCS*_SGM*_AN_ADV_REG.
101         In SGMII MAC mode, tx_Config_Reg<D15:D0> is the fixed value 0x4001, so
102         this step can be skipped. */
103     if (pcs_misc_ctl_reg.s.mode)
104     {
105         /* 1000BASE-X */
106         cvmx_pcsx_anx_adv_reg_t pcsx_anx_adv_reg;
107         pcsx_anx_adv_reg.u64 = cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface));
108         pcsx_anx_adv_reg.s.rem_flt = 0;
109         pcsx_anx_adv_reg.s.pause = 3;
110         pcsx_anx_adv_reg.s.hfd = 1;
111         pcsx_anx_adv_reg.s.fd = 1;
112         cvmx_write_csr(CVMX_PCSX_ANX_ADV_REG(index, interface), pcsx_anx_adv_reg.u64);
113     }
114     else
115     {
116         cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg;
117         pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
118         if (pcsx_miscx_ctl_reg.s.mac_phy)
119         {
120             /* PHY Mode */
121             cvmx_pcsx_sgmx_an_adv_reg_t pcsx_sgmx_an_adv_reg;
122             pcsx_sgmx_an_adv_reg.u64 = cvmx_read_csr(CVMX_PCSX_SGMX_AN_ADV_REG(index, interface));
123             pcsx_sgmx_an_adv_reg.s.link = 1;
124             pcsx_sgmx_an_adv_reg.s.dup = 1;
125             pcsx_sgmx_an_adv_reg.s.speed= 2;
126             cvmx_write_csr(CVMX_PCSX_SGMX_AN_ADV_REG(index, interface), pcsx_sgmx_an_adv_reg.u64);
127         }
128         else
129         {
130             /* MAC Mode - Nothing to do */
131         }
132     }
133     return 0;
134 }
135
136
137 /**
138  * @INTERNAL
139  * Initialize the SERTES link for the first time or after a loss
140  * of link.
141  *
142  * @param interface Interface to init
143  * @param index     Index of prot on the interface
144  *
145  * @return Zero on success, negative on failure
146  */
147 static int __cvmx_helper_sgmii_hardware_init_link(int interface, int index)
148 {
149     cvmx_pcsx_mrx_control_reg_t control_reg;
150
151     /* Take PCS through a reset sequence.
152         PCS*_MR*_CONTROL_REG[PWR_DN] should be cleared to zero.
153         Write PCS*_MR*_CONTROL_REG[RESET]=1 (while not changing the value of
154             the other PCS*_MR*_CONTROL_REG bits).
155         Read PCS*_MR*_CONTROL_REG[RESET] until it changes value to zero. */
156     control_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
157     if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM)
158     {
159         control_reg.s.reset = 1;
160         cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), control_reg.u64);
161         if (CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_CONTROL_REG(index, interface), cvmx_pcsx_mrx_control_reg_t, reset, ==, 0, 10000))
162         {
163             cvmx_dprintf("SGMII%d: Timeout waiting for port %d to finish reset\n", interface, index);
164             return -1;
165         }
166     }
167
168     /* Write PCS*_MR*_CONTROL_REG[RST_AN]=1 to ensure a fresh sgmii negotiation starts. */
169     control_reg.s.rst_an = 1;
170     control_reg.s.an_en = 1;
171     control_reg.s.pwr_dn = 0;
172     cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), control_reg.u64);
173
174     /* Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating that
175         sgmii autonegotiation is complete. In MAC mode this isn't an ethernet
176         link, but a link between Octeon and the PHY */
177     if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
178         CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index, interface), cvmx_pcsx_mrx_status_reg_t, an_cpt, ==, 1, 10000))
179     {
180         //cvmx_dprintf("SGMII%d: Port %d link timeout\n", interface, index);
181         return -1;
182     }
183     return 0;
184 }
185
186
187 /**
188  * @INTERNAL
189  * Configure an SGMII link to the specified speed after the SERTES
190  * link is up.
191  *
192  * @param interface Interface to init
193  * @param index     Index of prot on the interface
194  * @param link_info Link state to configure
195  *
196  * @return Zero on success, negative on failure
197  */
198 static int __cvmx_helper_sgmii_hardware_init_link_speed(int interface, int index, cvmx_helper_link_info_t link_info)
199 {
200     int is_enabled;
201     cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg;
202     cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg;
203
204     /* Disable GMX before we make any changes. Remember the enable state */
205     gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
206     is_enabled = gmxx_prtx_cfg.s.en;
207     gmxx_prtx_cfg.s.en = 0;
208     cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
209
210     /* Wait for GMX to be idle */
211     if (CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface), cvmx_gmxx_prtx_cfg_t, rx_idle, ==, 1, 10000) ||
212         CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface), cvmx_gmxx_prtx_cfg_t, tx_idle, ==, 1, 10000))
213     {
214         cvmx_dprintf("SGMII%d: Timeout waiting for port %d to be idle\n", interface, index);
215         return -1;
216     }
217
218     /* Read GMX CFG again to make sure the disable completed */
219     gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
220
221     /* Get the misc control for PCS. We will need to set the duplication amount */
222     pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
223
224     /* Use GMXENO to force the link down if the status we get says it should be down */
225     pcsx_miscx_ctl_reg.s.gmxeno = !link_info.s.link_up;
226
227     /* Only change the duplex setting if the link is up */
228     if (link_info.s.link_up)
229         gmxx_prtx_cfg.s.duplex = link_info.s.full_duplex;
230
231     /* Do speed based setting for GMX */
232     switch (link_info.s.speed)
233     {
234         case 10:
235             gmxx_prtx_cfg.s.speed = 0;
236             gmxx_prtx_cfg.s.speed_msb = 1;
237             gmxx_prtx_cfg.s.slottime = 0;
238             pcsx_miscx_ctl_reg.s.samp_pt = 25; /* Setting from GMX-603 */
239             cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
240             cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
241             break;
242         case 100:
243             gmxx_prtx_cfg.s.speed = 0;
244             gmxx_prtx_cfg.s.speed_msb = 0;
245             gmxx_prtx_cfg.s.slottime = 0;
246             pcsx_miscx_ctl_reg.s.samp_pt = 0x5;
247             cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
248             cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
249             break;
250         case 1000:
251             gmxx_prtx_cfg.s.speed = 1;
252             gmxx_prtx_cfg.s.speed_msb = 0;
253             gmxx_prtx_cfg.s.slottime = 1;
254             pcsx_miscx_ctl_reg.s.samp_pt = 1;
255             cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 512);
256             cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 8192);
257             break;
258         default:
259             break;
260     }
261
262     /* Write the new misc control for PCS */
263     cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), pcsx_miscx_ctl_reg.u64);
264
265     /* Write the new GMX settings with the port still disabled */
266     cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
267
268     /* Read GMX CFG again to make sure the config completed */
269     gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
270
271     /* Restore the enabled / disabled state */
272     gmxx_prtx_cfg.s.en = is_enabled;
273     cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
274
275     return 0;
276 }
277
278
279 /**
280  * @INTERNAL
281  * Bring up the SGMII interface to be ready for packet I/O but
282  * leave I/O disabled using the GMX override. This function
283  * follows the bringup documented in 10.6.3 of the manual.
284  *
285  * @param interface Interface to bringup
286  * @param num_ports Number of ports on the interface
287  *
288  * @return Zero on success, negative on failure
289  */
290 static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports)
291 {
292     int index;
293
294     __cvmx_helper_setup_gmx(interface, num_ports);
295
296     for (index=0; index<num_ports; index++)
297     {
298         int ipd_port = cvmx_helper_get_ipd_port(interface, index);
299         __cvmx_helper_sgmii_hardware_init_one_time(interface, index);
300         __cvmx_helper_sgmii_link_set(ipd_port, __cvmx_helper_sgmii_link_get(ipd_port));
301
302     }
303
304     return 0;
305 }
306
307
308 /**
309  * @INTERNAL
310  * Probe a SGMII interface and determine the number of ports
311  * connected to it. The SGMII interface should still be down after
312  * this call.
313  *
314  * @param interface Interface to probe
315  *
316  * @return Number of ports on the interface. Zero to disable.
317  */
318 int __cvmx_helper_sgmii_probe(int interface)
319 {
320     cvmx_gmxx_inf_mode_t mode;
321
322     /* Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the interface
323         needs to be enabled before IPD otherwise per port backpressure
324         may not work properly */
325     mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
326     mode.s.en = 1;
327     cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
328     return 4;
329 }
330
331
332 /**
333  * @INTERNAL
334  * Bringup and enable a SGMII interface. After this call packet
335  * I/O should be fully functional. This is called with IPD
336  * enabled but PKO disabled.
337  *
338  * @param interface Interface to bring up
339  *
340  * @return Zero on success, negative on failure
341  */
342 int __cvmx_helper_sgmii_enable(int interface)
343 {
344     int num_ports = cvmx_helper_ports_on_interface(interface);
345     int index;
346
347     __cvmx_helper_sgmii_hardware_init(interface, num_ports);
348
349     for (index=0; index<num_ports; index++)
350     {
351         cvmx_gmxx_prtx_cfg_t gmxx_prtx_cfg;
352         gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
353         gmxx_prtx_cfg.s.en = 1;
354         cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
355     }
356     return 0;
357 }
358
359
360 /**
361  * @INTERNAL
362  * Return the link state of an IPD/PKO port as returned by
363  * auto negotiation. The result of this function may not match
364  * Octeon's link config if auto negotiation has changed since
365  * the last call to cvmx_helper_link_set().
366  *
367  * @param ipd_port IPD/PKO port to query
368  *
369  * @return Link state
370  */
371 cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port)
372 {
373     cvmx_helper_link_info_t result;
374     cvmx_pcsx_miscx_ctl_reg_t pcs_misc_ctl_reg;
375     int interface = cvmx_helper_get_interface_num(ipd_port);
376     int index = cvmx_helper_get_interface_index_num(ipd_port);
377     cvmx_pcsx_mrx_control_reg_t pcsx_mrx_control_reg;
378
379     result.u64 = 0;
380
381     if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
382     {
383         /* The simulator gives you a simulated 1Gbps full duplex link */
384         result.s.link_up = 1;
385         result.s.full_duplex = 1;
386         result.s.speed = 1000;
387         return result;
388     }
389
390     pcsx_mrx_control_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
391     if (pcsx_mrx_control_reg.s.loopbck1)
392     {
393         /* Force 1Gbps full duplex link for internal loopback */
394         result.s.link_up = 1;
395         result.s.full_duplex = 1;
396         result.s.speed = 1000;
397         return result;
398     }
399
400
401     pcs_misc_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
402     if (pcs_misc_ctl_reg.s.mode)
403     {
404         /* 1000BASE-X */
405         // FIXME
406     }
407     else
408     {
409         cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg;
410         pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
411         if (pcsx_miscx_ctl_reg.s.mac_phy)
412         {
413             /* PHY Mode */
414             cvmx_pcsx_mrx_status_reg_t pcsx_mrx_status_reg;
415             cvmx_pcsx_anx_results_reg_t pcsx_anx_results_reg;
416
417             /* Don't bother continuing if the SERTES low level link is down */
418             pcsx_mrx_status_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG(index, interface));
419             if (pcsx_mrx_status_reg.s.lnk_st == 0)
420             {
421                 if (__cvmx_helper_sgmii_hardware_init_link(interface, index) != 0)
422                     return result;
423             }
424
425             /* Read the autoneg results */
426             pcsx_anx_results_reg.u64 = cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG(index, interface));
427             if (pcsx_anx_results_reg.s.an_cpt)
428             {
429                 /* Auto negotiation is complete. Set status accordingly */
430                 result.s.full_duplex = pcsx_anx_results_reg.s.dup;
431                 result.s.link_up = pcsx_anx_results_reg.s.link_ok;
432                 switch (pcsx_anx_results_reg.s.spd)
433                 {
434                     case 0:
435                         result.s.speed = 10;
436                         break;
437                     case 1:
438                         result.s.speed = 100;
439                         break;
440                     case 2:
441                         result.s.speed = 1000;
442                         break;
443                     default:
444                         result.s.speed = 0;
445                         result.s.link_up = 0;
446                         break;
447                 }
448             }
449             else
450             {
451                 /* Auto negotiation isn't complete. Return link down */
452                 result.s.speed = 0;
453                 result.s.link_up = 0;
454             }
455         }
456         else /* MAC Mode */
457         {
458             result = __cvmx_helper_board_link_get(ipd_port);
459         }
460     }
461     return result;
462 }
463
464
465 /**
466  * @INTERNAL
467  * Configure an IPD/PKO port for the specified link state. This
468  * function does not influence auto negotiation at the PHY level.
469  * The passed link state must always match the link state returned
470  * by cvmx_helper_link_get(). It is normally best to use
471  * cvmx_helper_link_autoconf() instead.
472  *
473  * @param ipd_port  IPD/PKO port to configure
474  * @param link_info The new link state
475  *
476  * @return Zero on success, negative on failure
477  */
478 int __cvmx_helper_sgmii_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
479 {
480     int interface = cvmx_helper_get_interface_num(ipd_port);
481     int index = cvmx_helper_get_interface_index_num(ipd_port);
482     __cvmx_helper_sgmii_hardware_init_link(interface, index);
483     return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index, link_info);
484 }
485
486 /**
487  * @INTERNAL
488  * Configure a port for internal and/or external loopback. Internal loopback
489  * causes packets sent by the port to be received by Octeon. External loopback
490  * causes packets received from the wire to sent out again.
491  *
492  * @param ipd_port IPD/PKO port to loopback.
493  * @param enable_internal
494  *                 Non zero if you want internal loopback
495  * @param enable_external
496  *                 Non zero if you want external loopback
497  *
498  * @return Zero on success, negative on failure.
499  */
500 int __cvmx_helper_sgmii_configure_loopback(int ipd_port, int enable_internal, int enable_external)
501 {
502     int interface = cvmx_helper_get_interface_num(ipd_port);
503     int index = cvmx_helper_get_interface_index_num(ipd_port);
504     cvmx_pcsx_mrx_control_reg_t pcsx_mrx_control_reg;
505     cvmx_pcsx_miscx_ctl_reg_t pcsx_miscx_ctl_reg;
506
507     pcsx_mrx_control_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
508     pcsx_mrx_control_reg.s.loopbck1 = enable_internal;
509     cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), pcsx_mrx_control_reg.u64);
510
511     pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
512     pcsx_miscx_ctl_reg.s.loopbck2 = enable_external;
513     cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), pcsx_miscx_ctl_reg.u64);
514
515     __cvmx_helper_sgmii_hardware_init_link(interface, index);
516     return 0;
517 }
518
519 #endif /* CVMX_ENABLE_PKO_FUNCTIONS */