]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/octeon-sdk/cvmx-helper-board.c
Merge libpcap-1.1.1.
[FreeBSD/FreeBSD.git] / sys / contrib / octeon-sdk / cvmx-helper-board.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  * Helper functions to abstract board specific data about
48  * network ports from the rest of the cvmx-helper files.
49  *
50  * <hr>$Revision: 41946 $<hr>
51  */
52 #include "cvmx.h"
53 #include "cvmx-app-init.h"
54 #include "cvmx-mdio.h"
55 #include "cvmx-sysinfo.h"
56 #include "cvmx-helper.h"
57 #include "cvmx-helper-util.h"
58 #include "cvmx-helper-board.h"
59
60 /**
61  * cvmx_override_board_link_get(int ipd_port) is a function
62  * pointer. It is meant to allow customization of the process of
63  * talking to a PHY to determine link speed. It is called every
64  * time a PHY must be polled for link status. Users should set
65  * this pointer to a function before calling any cvmx-helper
66  * operations.
67  */
68 CVMX_SHARED cvmx_helper_link_info_t (*cvmx_override_board_link_get)(int ipd_port) = NULL;
69
70 /**
71  * Return the MII PHY address associated with the given IPD
72  * port. A result of -1 means there isn't a MII capable PHY
73  * connected to this port. On chips supporting multiple MII
74  * busses the bus number is encoded in bits <15:8>.
75  *
76  * This function must be modified for every new Octeon board.
77  * Internally it uses switch statements based on the cvmx_sysinfo
78  * data to determine board types and revisions. It replies on the
79  * fact that every Octeon board receives a unique board type
80  * enumeration from the bootloader.
81  *
82  * @param ipd_port Octeon IPD port to get the MII address for.
83  *
84  * @return MII PHY address and bus number or -1.
85  */
86 int cvmx_helper_board_get_mii_address(int ipd_port)
87 {
88     /*
89      * Board types we have to know at compile-time.
90      */
91 #ifdef OCTEON_BOARD_CAPK_0100ND
92     switch (ipd_port) {
93     case 0:
94         return 2;
95     case 1:
96         return 3;
97     case 2:
98         /* XXX Switch PHY?  */
99         return -1;
100     default:
101         return -1;
102     }
103 #endif
104
105     /*
106      * For board types we can determine at runtime.
107      */
108     switch (cvmx_sysinfo_get()->board_type)
109     {
110         case CVMX_BOARD_TYPE_SIM:
111             /* Simulator doesn't have MII */
112             return -1;
113         case CVMX_BOARD_TYPE_EBT3000:
114         case CVMX_BOARD_TYPE_EBT5800:
115         case CVMX_BOARD_TYPE_THUNDER:
116         case CVMX_BOARD_TYPE_NICPRO2:
117 #if defined(OCTEON_VENDOR_LANNER)
118         case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
119 #endif
120             /* Interface 0 is SPI4, interface 1 is RGMII */
121             if ((ipd_port >= 16) && (ipd_port < 20))
122                 return ipd_port - 16;
123             else
124                 return -1;
125         case CVMX_BOARD_TYPE_KODAMA:
126         case CVMX_BOARD_TYPE_EBH3100:
127         case CVMX_BOARD_TYPE_HIKARI:
128         case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
129         case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
130         case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
131             /* Port 0 is WAN connected to a PHY, Port 1 is GMII connected to a
132                 switch */
133             if (ipd_port == 0)
134                 return 4;
135             else if (ipd_port == 1)
136                 return 9;
137             else
138                 return -1;
139         case CVMX_BOARD_TYPE_NAC38:
140             /* Board has 8 RGMII ports PHYs are 0-7 */
141             if ((ipd_port >= 0) && (ipd_port < 4))
142                 return ipd_port;
143             else if ((ipd_port >= 16) && (ipd_port < 20))
144                 return ipd_port - 16 + 4;
145             else
146                 return -1;
147         case CVMX_BOARD_TYPE_EBH3000:
148             /* Board has dual SPI4 and no PHYs */
149             return -1;
150         case CVMX_BOARD_TYPE_EBH5200:
151         case CVMX_BOARD_TYPE_EBH5201:
152         case CVMX_BOARD_TYPE_EBT5200:
153             /* Board has 4 SGMII ports. The PHYs start right after the MII
154                 ports MII0 = 0, MII1 = 1, SGMII = 2-5 */
155             if ((ipd_port >= 0) && (ipd_port < 4))
156                 return ipd_port+2;
157             else
158                 return -1;
159         case CVMX_BOARD_TYPE_EBH5600:
160         case CVMX_BOARD_TYPE_EBH5601:
161             /* Board has 8 SGMII ports. 4 connect out, two connect to a switch,
162                 and 2 loop to each other */
163             if ((ipd_port >= 0) && (ipd_port < 4))
164                 return ipd_port+1;
165             else
166                 return -1;
167         case CVMX_BOARD_TYPE_CUST_NB5:
168             if (ipd_port == 2)
169                 return 4;
170             else
171                 return -1;
172         case CVMX_BOARD_TYPE_NIC_XLE_4G:
173             /* Board has 4 SGMII ports. connected QLM3(interface 1) */
174             if ((ipd_port >= 16) && (ipd_port < 20))
175                 return ipd_port - 16 + 1;
176             else
177                 return -1;
178         case CVMX_BOARD_TYPE_BBGW_REF:
179             return -1;  /* No PHYs are connected to Octeon, everything is through switch */
180
181         /* Private vendor-defined boards.  */
182 #if defined(OCTEON_VENDOR_LANNER)
183         case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
184             /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell
185                88E1111 interfaces.  */
186             switch (ipd_port) {
187             case 0:
188                 return 16;
189             case 1:
190                 return 1;
191             case 2:
192                 return 2;
193             default:
194                 return -1;
195             }
196 #endif
197     }
198
199     /* Some unknown board. Somebody forgot to update this function... */
200     cvmx_dprintf("cvmx_helper_board_get_mii_address: Unknown board type %d\n",
201                  cvmx_sysinfo_get()->board_type);
202     return -1;
203 }
204
205
206 /**
207  * @INTERNAL
208  * This function is the board specific method of determining an
209  * ethernet ports link speed. Most Octeon boards have Marvell PHYs
210  * and are handled by the fall through case. This function must be
211  * updated for boards that don't have the normal Marvell PHYs.
212  *
213  * This function must be modified for every new Octeon board.
214  * Internally it uses switch statements based on the cvmx_sysinfo
215  * data to determine board types and revisions. It relies on the
216  * fact that every Octeon board receives a unique board type
217  * enumeration from the bootloader.
218  *
219  * @param ipd_port IPD input port associated with the port we want to get link
220  *                 status for.
221  *
222  * @return The ports link status. If the link isn't fully resolved, this must
223  *         return zero.
224  */
225 cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
226 {
227     cvmx_helper_link_info_t result;
228     int phy_addr;
229     int is_broadcom_phy = 0;
230
231     /* Give the user a chance to override the processing of this function */
232     if (cvmx_override_board_link_get)
233         return cvmx_override_board_link_get(ipd_port);
234
235     /* Unless we fix it later, all links are defaulted to down */
236     result.u64 = 0;
237
238 #if !defined(OCTEON_BOARD_CAPK_0100ND)
239     /* This switch statement should handle all ports that either don't use
240         Marvell PHYS, or don't support in-band status */
241     switch (cvmx_sysinfo_get()->board_type)
242     {
243         case CVMX_BOARD_TYPE_SIM:
244             /* The simulator gives you a simulated 1Gbps full duplex link */
245             result.s.link_up = 1;
246             result.s.full_duplex = 1;
247             result.s.speed = 1000;
248             return result;
249         case CVMX_BOARD_TYPE_EBH3100:
250         case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
251         case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
252         case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
253             /* Port 1 on these boards is always Gigabit */
254             if (ipd_port == 1)
255             {
256                 result.s.link_up = 1;
257                 result.s.full_duplex = 1;
258                 result.s.speed = 1000;
259                 return result;
260             }
261             /* Fall through to the generic code below */
262             break;
263         case CVMX_BOARD_TYPE_CUST_NB5:
264             /* Port 1 on these boards is always Gigabit */
265             if (ipd_port == 1)
266             {
267                 result.s.link_up = 1;
268                 result.s.full_duplex = 1;
269                 result.s.speed = 1000;
270                 return result;
271             }
272             else /* The other port uses a broadcom PHY */
273                 is_broadcom_phy = 1;
274             break;
275         case CVMX_BOARD_TYPE_BBGW_REF:
276             /* Port 1 on these boards is always Gigabit */
277             if (ipd_port == 2)
278             {   
279                 /* Port 2 is not hooked up */
280                 result.u64 = 0;
281                 return result;
282             }
283             else
284             {
285                 /* Ports 0 and 1 connect to the switch */
286                 result.s.link_up = 1;
287                 result.s.full_duplex = 1;
288                 result.s.speed = 1000;
289                 return result;
290             }
291             break;
292         /* Private vendor-defined boards.  */
293 #if defined(OCTEON_VENDOR_LANNER)
294         case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
295             /* Port 0 connects to the switch */
296             if (ipd_port == 0)
297             {
298                 result.s.link_up = 1;
299                 result.s.full_duplex = 1;
300                 result.s.speed = 1000;
301                 return result;
302             }
303             break;
304 #endif
305     }
306 #endif
307
308     phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
309     if (phy_addr != -1)
310     {
311         if (is_broadcom_phy)
312         {
313             /* Below we are going to read SMI/MDIO register 0x19 which works
314                 on Broadcom parts */
315             int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19);
316             switch ((phy_status>>8) & 0x7)
317             {
318                 case 0:
319                     result.u64 = 0;
320                     break;
321                 case 1:
322                     result.s.link_up = 1;
323                     result.s.full_duplex = 0;
324                     result.s.speed = 10;
325                     break;
326                 case 2:
327                     result.s.link_up = 1;
328                     result.s.full_duplex = 1;
329                     result.s.speed = 10;
330                     break;
331                 case 3:
332                     result.s.link_up = 1;
333                     result.s.full_duplex = 0;
334                     result.s.speed = 100;
335                     break;
336                 case 4:
337                     result.s.link_up = 1;
338                     result.s.full_duplex = 1;
339                     result.s.speed = 100;
340                     break;
341                 case 5:
342                     result.s.link_up = 1;
343                     result.s.full_duplex = 1;
344                     result.s.speed = 100;
345                     break;
346                 case 6:
347                     result.s.link_up = 1;
348                     result.s.full_duplex = 0;
349                     result.s.speed = 1000;
350                     break;
351                 case 7:
352                     result.s.link_up = 1;
353                     result.s.full_duplex = 1;
354                     result.s.speed = 1000;
355                     break;
356             }
357         }
358         else
359         {
360             /* This code assumes we are using a Marvell Gigabit PHY. All the
361                 speed information can be read from register 17 in one go. Somebody
362                 using a different PHY will need to handle it above in the board
363                 specific area */
364             int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
365
366             /* If the resolve bit 11 isn't set, see if autoneg is turned off
367                 (bit 12, reg 0). The resolve bit doesn't get set properly when
368                 autoneg is off, so force it */
369             if ((phy_status & (1<<11)) == 0)
370             {
371                 int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0);
372                 if ((auto_status & (1<<12)) == 0)
373                     phy_status |= 1<<11;
374             }
375
376             /* Only return a link if the PHY has finished auto negotiation
377                 and set the resolved bit (bit 11) */
378             if (phy_status & (1<<11))
379             {
380 #if defined(OCTEON_BOARD_CAPK_0100ND)
381                 result.s.link_up = (phy_status>>10)&1;
382 #else
383                 result.s.link_up = 1;
384 #endif
385                 result.s.full_duplex = ((phy_status>>13)&1);
386                 switch ((phy_status>>14)&3)
387                 {
388                     case 0: /* 10 Mbps */
389                         result.s.speed = 10;
390                         break;
391                     case 1: /* 100 Mbps */
392                         result.s.speed = 100;
393                         break;
394                     case 2: /* 1 Gbps */
395                         result.s.speed = 1000;
396                         break;
397                     case 3: /* Illegal */
398                         result.u64 = 0;
399                         break;
400                 }
401             }
402         }
403     }
404     else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
405     {
406         /* We don't have a PHY address, so attempt to use in-band status. It is
407             really important that boards not supporting in-band status never get
408             here. Reading broken in-band status tends to do bad things */
409         cvmx_gmxx_rxx_rx_inbnd_t inband_status;
410         int interface = cvmx_helper_get_interface_num(ipd_port);
411         int index = cvmx_helper_get_interface_index_num(ipd_port);
412         inband_status.u64 = cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface));
413
414         result.s.link_up = inband_status.s.status;
415         result.s.full_duplex = inband_status.s.duplex;
416         switch (inband_status.s.speed)
417         {
418             case 0: /* 10 Mbps */
419                 result.s.speed = 10;
420                 break;
421             case 1: /* 100 Mbps */
422                 result.s.speed = 100;
423                 break;
424             case 2: /* 1 Gbps */
425                 result.s.speed = 1000;
426                 break;
427             case 3: /* Illegal */
428                 result.u64 = 0;
429                 break;
430         }
431     }
432     else
433     {
434         /* We don't have a PHY address and we don't have in-band status. There
435             is no way to determine the link speed. Return down assuming this
436             port isn't wired */
437         result.u64 = 0;
438     }
439
440     /* If link is down, return all fields as zero. */
441     if (!result.s.link_up)
442         result.u64 = 0;
443
444     return result;
445 }
446
447
448 /**
449  * This function as a board specific method of changing the PHY
450  * speed, duplex, and auto-negotiation. This programs the PHY and
451  * not Octeon. This can be used to force Octeon's links to
452  * specific settings.
453  *
454  * @param phy_addr  The address of the PHY to program
455  * @param enable_autoneg
456  *                  Non zero if you want to enable auto-negotiation.
457  * @param link_info Link speed to program. If the speed is zero and auto-negotiation
458  *                  is enabled, all possible negotiation speeds are advertised.
459  *
460  * @return Zero on success, negative on failure
461  */
462 int cvmx_helper_board_link_set_phy(int phy_addr, cvmx_helper_board_set_phy_link_flags_types_t link_flags,
463                                    cvmx_helper_link_info_t link_info)
464 {
465
466     /* Set the flow control settings based on link_flags */
467     if ((link_flags & set_phy_link_flags_flow_control_mask) != set_phy_link_flags_flow_control_dont_touch)
468     {
469         cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
470         reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
471         reg_autoneg_adver.s.asymmetric_pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
472         reg_autoneg_adver.s.pause = (link_flags & set_phy_link_flags_flow_control_mask) == set_phy_link_flags_flow_control_enable;
473         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
474     }
475
476     /* If speed isn't set and autoneg is on advertise all supported modes */
477     if ((link_flags & set_phy_link_flags_autoneg) && (link_info.s.speed == 0))
478     {
479         cvmx_mdio_phy_reg_control_t reg_control;
480         cvmx_mdio_phy_reg_status_t reg_status;
481         cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
482         cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
483         cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
484
485         reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
486         reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
487         reg_autoneg_adver.s.advert_100base_t4 = reg_status.s.capable_100base_t4;
488         reg_autoneg_adver.s.advert_10base_tx_full = reg_status.s.capable_10_full;
489         reg_autoneg_adver.s.advert_10base_tx_half = reg_status.s.capable_10_half;
490         reg_autoneg_adver.s.advert_100base_tx_full = reg_status.s.capable_100base_x_full;
491         reg_autoneg_adver.s.advert_100base_tx_half = reg_status.s.capable_100base_x_half;
492         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
493         if (reg_status.s.capable_extended_status)
494         {
495             reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
496             reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
497             reg_control_1000.s.advert_1000base_t_full = reg_extended_status.s.capable_1000base_t_full;
498             reg_control_1000.s.advert_1000base_t_half = reg_extended_status.s.capable_1000base_t_half;
499             cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
500         }
501         reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
502         reg_control.s.autoneg_enable = 1;
503         reg_control.s.restart_autoneg = 1;
504         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
505     }
506     else if ((link_flags & set_phy_link_flags_autoneg))
507     {
508         cvmx_mdio_phy_reg_control_t reg_control;
509         cvmx_mdio_phy_reg_status_t reg_status;
510         cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
511         cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
512         cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
513
514         reg_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_STATUS);
515         reg_autoneg_adver.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
516         reg_autoneg_adver.s.advert_100base_t4 = 0;
517         reg_autoneg_adver.s.advert_10base_tx_full = 0;
518         reg_autoneg_adver.s.advert_10base_tx_half = 0;
519         reg_autoneg_adver.s.advert_100base_tx_full = 0;
520         reg_autoneg_adver.s.advert_100base_tx_half = 0;
521         if (reg_status.s.capable_extended_status)
522         {
523             reg_extended_status.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
524             reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000);
525             reg_control_1000.s.advert_1000base_t_full = 0;
526             reg_control_1000.s.advert_1000base_t_half = 0;
527         }
528         switch (link_info.s.speed)
529         {
530             case 10:
531                 reg_autoneg_adver.s.advert_10base_tx_full = link_info.s.full_duplex;
532                 reg_autoneg_adver.s.advert_10base_tx_half = !link_info.s.full_duplex;
533                 break;
534             case 100:
535                 reg_autoneg_adver.s.advert_100base_tx_full = link_info.s.full_duplex;
536                 reg_autoneg_adver.s.advert_100base_tx_half = !link_info.s.full_duplex;
537                 break;
538             case 1000:
539                 reg_control_1000.s.advert_1000base_t_full = link_info.s.full_duplex;
540                 reg_control_1000.s.advert_1000base_t_half = !link_info.s.full_duplex;
541                 break;
542         }
543         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_AUTONEG_ADVER, reg_autoneg_adver.u16);
544         if (reg_status.s.capable_extended_status)
545             cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000, reg_control_1000.u16);
546         reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
547         reg_control.s.autoneg_enable = 1;
548         reg_control.s.restart_autoneg = 1;
549         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
550     }
551     else
552     {
553         cvmx_mdio_phy_reg_control_t reg_control;
554         reg_control.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL);
555         reg_control.s.autoneg_enable = 0;
556         reg_control.s.restart_autoneg = 1;
557         reg_control.s.duplex = link_info.s.full_duplex;
558         if (link_info.s.speed == 1000)
559         {
560             reg_control.s.speed_msb = 1;
561             reg_control.s.speed_lsb = 0;
562         }
563         else if (link_info.s.speed == 100)
564         {
565             reg_control.s.speed_msb = 0;
566             reg_control.s.speed_lsb = 1;
567         }
568         else if (link_info.s.speed == 10)
569         {
570             reg_control.s.speed_msb = 0;
571             reg_control.s.speed_lsb = 0;
572         }
573         cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
574     }
575     return 0;
576 }
577
578
579 /**
580  * @INTERNAL
581  * This function is called by cvmx_helper_interface_probe() after it
582  * determines the number of ports Octeon can support on a specific
583  * interface. This function is the per board location to override
584  * this value. It is called with the number of ports Octeon might
585  * support and should return the number of actual ports on the
586  * board.
587  *
588  * This function must be modifed for every new Octeon board.
589  * Internally it uses switch statements based on the cvmx_sysinfo
590  * data to determine board types and revisions. It relys on the
591  * fact that every Octeon board receives a unique board type
592  * enumeration from the bootloader.
593  *
594  * @param interface Interface to probe
595  * @param supported_ports
596  *                  Number of ports Octeon supports.
597  *
598  * @return Number of ports the actual board supports. Many times this will
599  *         simple be "support_ports".
600  */
601 int __cvmx_helper_board_interface_probe(int interface, int supported_ports)
602 {
603     switch (cvmx_sysinfo_get()->board_type)
604     {
605         case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
606             if (interface == 0)
607                 return 2;
608             break;
609         case CVMX_BOARD_TYPE_BBGW_REF:
610             if (interface == 0)
611                 return 2;
612             break;
613         case CVMX_BOARD_TYPE_NIC_XLE_4G:
614             if (interface == 0)
615                 return 0;
616             break;
617         /* The 2nd interface on the EBH5600 is connected to the Marvel switch,
618             which we don't support. Disable ports connected to it */
619         case CVMX_BOARD_TYPE_EBH5600:
620             if (interface == 1)
621                 return 0;
622             break;
623 #if defined(OCTEON_VENDOR_LANNER)
624         case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
625             if (interface == 1)
626                 return 12;
627             break;
628 #endif
629     }
630 #ifdef CVMX_BUILD_FOR_UBOOT
631     if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi"))
632         return 0;
633 #endif
634     return supported_ports;
635 }
636
637
638 /**
639  * @INTERNAL
640  * Enable packet input/output from the hardware. This function is
641  * called after by cvmx_helper_packet_hardware_enable() to
642  * perform board specific initialization. For most boards
643  * nothing is needed.
644  *
645  * @param interface Interface to enable
646  *
647  * @return Zero on success, negative on failure
648  */
649 int __cvmx_helper_board_hardware_enable(int interface)
650 {
651     if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5)
652     {
653         if (interface == 0)
654         {
655             /* Different config for switch port */
656             cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0);
657             cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0);
658             /* Boards with gigabit WAN ports need a different setting that is
659                 compatible with 100 Mbit settings */
660             cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 0xc);
661             cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 0xc);
662         }
663     }
664     else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3010_EVB_HS5)
665     {
666         /* Broadcom PHYs require differnet ASX clocks. Unfortunately
667             many customer don't define a new board Id and simply
668             mangle the CN3010_EVB_HS5 */
669         if (interface == 0)
670         {
671             /* Some customers boards use a hacked up bootloader that identifies them as
672             ** CN3010_EVB_HS5 evaluation boards.  This leads to all kinds of configuration
673             ** problems.  Detect one case, and print warning, while trying to do the right thing.
674             */
675             int phy_addr = cvmx_helper_board_get_mii_address(0);
676             if (phy_addr != -1)
677             {
678                 int phy_identifier = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x2);
679                 /* Is it a Broadcom PHY? */
680                 if (phy_identifier == 0x0143)
681                 {
682                     cvmx_dprintf("\n");
683                     cvmx_dprintf("ERROR:\n");
684                     cvmx_dprintf("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n");
685                     cvmx_dprintf("ERROR: The board type is mis-configured, and software malfunctions are likely.\n");
686                     cvmx_dprintf("ERROR: All boards require a unique board type to identify them.\n");
687                     cvmx_dprintf("ERROR:\n");
688                     cvmx_dprintf("\n");
689                     cvmx_wait(1000000000);
690                     cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), 5);
691                     cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), 5);
692                 }
693             }
694         }
695     }
696     return 0;
697 }
698
699 cvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void)
700 {
701     switch (cvmx_sysinfo_get()->board_type) {
702     case CVMX_BOARD_TYPE_BBGW_REF:
703 #if defined(OCTEON_VENDOR_LANNER)
704     case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
705 #endif
706             return USB_CLOCK_TYPE_CRYSTAL_12;
707     }
708     return USB_CLOCK_TYPE_REF_48;
709 }
710
711 int __cvmx_helper_board_usb_get_num_ports(int supported_ports)
712 {
713     switch (cvmx_sysinfo_get()->board_type) {
714         case CVMX_BOARD_TYPE_NIC_XLE_4G:
715             return 0;
716     }
717
718     return supported_ports;
719 }
720
721