Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cvmx-helper-board.c
Go to the documentation of this file.
1 /***********************license start***************
2  * Author: Cavium Networks
3  *
4  * Contact: [email protected]
5  * This file is part of the OCTEON SDK
6  *
7  * Copyright (c) 2003-2008 Cavium Networks
8  *
9  * This file is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License, Version 2, as
11  * published by the Free Software Foundation.
12  *
13  * This file is distributed in the hope that it will be useful, but
14  * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16  * NONINFRINGEMENT. See the GNU General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this file; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22  * or visit http://www.gnu.org/licenses/.
23  *
24  * This file may also be available under a different license from Cavium.
25  * Contact Cavium Networks for more information
26  ***********************license end**************************************/
27 
28 /*
29  *
30  * Helper functions to abstract board specific data about
31  * network ports from the rest of the cvmx-helper files.
32  */
33 
34 #include <asm/octeon/octeon.h>
36 
37 #include <asm/octeon/cvmx-config.h>
38 
39 #include <asm/octeon/cvmx-mdio.h>
40 
41 #include <asm/octeon/cvmx-helper.h>
44 
47 
57  NULL;
58 
76 {
77  switch (cvmx_sysinfo_get()->board_type) {
79  /* Simulator doesn't have MII */
80  return -1;
85  /* Interface 0 is SPI4, interface 1 is RGMII */
86  if ((ipd_port >= 16) && (ipd_port < 20))
87  return ipd_port - 16;
88  else
89  return -1;
96  /*
97  * Port 0 is WAN connected to a PHY, Port 1 is GMII
98  * connected to a switch
99  */
100  if (ipd_port == 0)
101  return 4;
102  else if (ipd_port == 1)
103  return 9;
104  else
105  return -1;
107  /* Board has 8 RGMII ports PHYs are 0-7 */
108  if ((ipd_port >= 0) && (ipd_port < 4))
109  return ipd_port;
110  else if ((ipd_port >= 16) && (ipd_port < 20))
111  return ipd_port - 16 + 4;
112  else
113  return -1;
115  /* Board has dual SPI4 and no PHYs */
116  return -1;
120  /* Board has 2 management ports */
121  if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) &&
122  (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
123  return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT;
124  /*
125  * Board has 4 SGMII ports. The PHYs start right after the MII
126  * ports MII0 = 0, MII1 = 1, SGMII = 2-5.
127  */
128  if ((ipd_port >= 0) && (ipd_port < 4))
129  return ipd_port + 2;
130  else
131  return -1;
135  /* Board has 1 management port */
136  if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
137  return 0;
138  /*
139  * Board has 8 SGMII ports. 4 connect out, two connect
140  * to a switch, and 2 loop to each other
141  */
142  if ((ipd_port >= 0) && (ipd_port < 4))
143  return ipd_port + 1;
144  else
145  return -1;
147  if (ipd_port == 2)
148  return 4;
149  else
150  return -1;
152  /* Board has 4 SGMII ports. connected QLM3(interface 1) */
153  if ((ipd_port >= 16) && (ipd_port < 20))
154  return ipd_port - 16 + 1;
155  else
156  return -1;
159  return -1;
161  if (ipd_port >= 0 && ipd_port <= 3)
162  return (ipd_port + 0x1f) & 0x1f;
163  else
164  return -1;
166  if (ipd_port >= 0 && ipd_port <= 1)
167  return ipd_port + 1;
168  else
169  return -1;
171  /*
172  * No PHYs are connected to Octeon, everything is
173  * through switch.
174  */
175  return -1;
176 
178  if (ipd_port >= 0 && ipd_port <= 3)
179  return ipd_port;
180  else if (ipd_port >= 16 && ipd_port <= 19)
181  return ipd_port - 16 + 4;
182  else
183  return -1;
184  }
185 
186  /* Some unknown board. Somebody forgot to update this function... */
188  ("cvmx_helper_board_get_mii_address: Unknown board type %d\n",
190  return -1;
191 }
192 
212 {
214  int phy_addr;
215  int is_broadcom_phy = 0;
216 
217  /* Give the user a chance to override the processing of this function */
219  return cvmx_override_board_link_get(ipd_port);
220 
221  /* Unless we fix it later, all links are defaulted to down */
222  result.u64 = 0;
223 
224  /*
225  * This switch statement should handle all ports that either don't use
226  * Marvell PHYS, or don't support in-band status.
227  */
228  switch (cvmx_sysinfo_get()->board_type) {
229  case CVMX_BOARD_TYPE_SIM:
230  /* The simulator gives you a simulated 1Gbps full duplex link */
231  result.s.link_up = 1;
232  result.s.full_duplex = 1;
233  result.s.speed = 1000;
234  return result;
239  /* Port 1 on these boards is always Gigabit */
240  if (ipd_port == 1) {
241  result.s.link_up = 1;
242  result.s.full_duplex = 1;
243  result.s.speed = 1000;
244  return result;
245  }
246  /* Fall through to the generic code below */
247  break;
249  /* Port 1 on these boards is always Gigabit */
250  if (ipd_port == 1) {
251  result.s.link_up = 1;
252  result.s.full_duplex = 1;
253  result.s.speed = 1000;
254  return result;
255  } else /* The other port uses a broadcom PHY */
256  is_broadcom_phy = 1;
257  break;
259  /* Port 1 on these boards is always Gigabit */
260  if (ipd_port == 2) {
261  /* Port 2 is not hooked up */
262  result.u64 = 0;
263  return result;
264  } else {
265  /* Ports 0 and 1 connect to the switch */
266  result.s.link_up = 1;
267  result.s.full_duplex = 1;
268  result.s.speed = 1000;
269  return result;
270  }
271  break;
272  }
273 
274  phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
275  if (phy_addr != -1) {
276  if (is_broadcom_phy) {
277  /*
278  * Below we are going to read SMI/MDIO
279  * register 0x19 which works on Broadcom
280  * parts
281  */
282  int phy_status =
283  cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
284  0x19);
285  switch ((phy_status >> 8) & 0x7) {
286  case 0:
287  result.u64 = 0;
288  break;
289  case 1:
290  result.s.link_up = 1;
291  result.s.full_duplex = 0;
292  result.s.speed = 10;
293  break;
294  case 2:
295  result.s.link_up = 1;
296  result.s.full_duplex = 1;
297  result.s.speed = 10;
298  break;
299  case 3:
300  result.s.link_up = 1;
301  result.s.full_duplex = 0;
302  result.s.speed = 100;
303  break;
304  case 4:
305  result.s.link_up = 1;
306  result.s.full_duplex = 1;
307  result.s.speed = 100;
308  break;
309  case 5:
310  result.s.link_up = 1;
311  result.s.full_duplex = 1;
312  result.s.speed = 100;
313  break;
314  case 6:
315  result.s.link_up = 1;
316  result.s.full_duplex = 0;
317  result.s.speed = 1000;
318  break;
319  case 7:
320  result.s.link_up = 1;
321  result.s.full_duplex = 1;
322  result.s.speed = 1000;
323  break;
324  }
325  } else {
326  /*
327  * This code assumes we are using a Marvell
328  * Gigabit PHY. All the speed information can
329  * be read from register 17 in one
330  * go. Somebody using a different PHY will
331  * need to handle it above in the board
332  * specific area.
333  */
334  int phy_status =
335  cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
336 
337  /*
338  * If the resolve bit 11 isn't set, see if
339  * autoneg is turned off (bit 12, reg 0). The
340  * resolve bit doesn't get set properly when
341  * autoneg is off, so force it.
342  */
343  if ((phy_status & (1 << 11)) == 0) {
344  int auto_status =
345  cvmx_mdio_read(phy_addr >> 8,
346  phy_addr & 0xff, 0);
347  if ((auto_status & (1 << 12)) == 0)
348  phy_status |= 1 << 11;
349  }
350 
351  /*
352  * Only return a link if the PHY has finished
353  * auto negotiation and set the resolved bit
354  * (bit 11)
355  */
356  if (phy_status & (1 << 11)) {
357  result.s.link_up = 1;
358  result.s.full_duplex = ((phy_status >> 13) & 1);
359  switch ((phy_status >> 14) & 3) {
360  case 0: /* 10 Mbps */
361  result.s.speed = 10;
362  break;
363  case 1: /* 100 Mbps */
364  result.s.speed = 100;
365  break;
366  case 2: /* 1 Gbps */
367  result.s.speed = 1000;
368  break;
369  case 3: /* Illegal */
370  result.u64 = 0;
371  break;
372  }
373  }
374  }
375  } else if (OCTEON_IS_MODEL(OCTEON_CN3XXX)
378  /*
379  * We don't have a PHY address, so attempt to use
380  * in-band status. It is really important that boards
381  * not supporting in-band status never get
382  * here. Reading broken in-band status tends to do bad
383  * things
384  */
385  union cvmx_gmxx_rxx_rx_inbnd inband_status;
386  int interface = cvmx_helper_get_interface_num(ipd_port);
388  inband_status.u64 =
389  cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface));
390 
391  result.s.link_up = inband_status.s.status;
392  result.s.full_duplex = inband_status.s.duplex;
393  switch (inband_status.s.speed) {
394  case 0: /* 10 Mbps */
395  result.s.speed = 10;
396  break;
397  case 1: /* 100 Mbps */
398  result.s.speed = 100;
399  break;
400  case 2: /* 1 Gbps */
401  result.s.speed = 1000;
402  break;
403  case 3: /* Illegal */
404  result.u64 = 0;
405  break;
406  }
407  } else {
408  /*
409  * We don't have a PHY address and we don't have
410  * in-band status. There is no way to determine the
411  * link speed. Return down assuming this port isn't
412  * wired
413  */
414  result.u64 = 0;
415  }
416 
417  /* If link is down, return all fields as zero. */
418  if (!result.s.link_up)
419  result.u64 = 0;
420 
421  return result;
422 }
423 
440  link_flags,
441  cvmx_helper_link_info_t link_info)
442 {
443 
444  /* Set the flow control settings based on link_flags */
445  if ((link_flags & set_phy_link_flags_flow_control_mask) !=
447  cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
448  reg_autoneg_adver.u16 =
449  cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
451  reg_autoneg_adver.s.asymmetric_pause =
452  (link_flags & set_phy_link_flags_flow_control_mask) ==
454  reg_autoneg_adver.s.pause =
455  (link_flags & set_phy_link_flags_flow_control_mask) ==
457  cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
459  reg_autoneg_adver.u16);
460  }
461 
462  /* If speed isn't set and autoneg is on advertise all supported modes */
463  if ((link_flags & set_phy_link_flags_autoneg)
464  && (link_info.s.speed == 0)) {
467  cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
468  cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
469  cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
470 
471  reg_status.u16 =
472  cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
474  reg_autoneg_adver.u16 =
475  cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
477  reg_autoneg_adver.s.advert_100base_t4 =
478  reg_status.s.capable_100base_t4;
479  reg_autoneg_adver.s.advert_10base_tx_full =
480  reg_status.s.capable_10_full;
481  reg_autoneg_adver.s.advert_10base_tx_half =
482  reg_status.s.capable_10_half;
483  reg_autoneg_adver.s.advert_100base_tx_full =
484  reg_status.s.capable_100base_x_full;
485  reg_autoneg_adver.s.advert_100base_tx_half =
486  reg_status.s.capable_100base_x_half;
487  cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
489  reg_autoneg_adver.u16);
490  if (reg_status.s.capable_extended_status) {
491  reg_extended_status.u16 =
492  cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
494  reg_control_1000.u16 =
495  cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
497  reg_control_1000.s.advert_1000base_t_full =
498  reg_extended_status.s.capable_1000base_t_full;
499  reg_control_1000.s.advert_1000base_t_half =
500  reg_extended_status.s.capable_1000base_t_half;
501  cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
503  reg_control_1000.u16);
504  }
505  reg_control.u16 =
506  cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
508  reg_control.s.autoneg_enable = 1;
509  reg_control.s.restart_autoneg = 1;
510  cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
511  CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
512  } else if ((link_flags & set_phy_link_flags_autoneg)) {
515  cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
516  cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
517 
518  reg_status.u16 =
519  cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
521  reg_autoneg_adver.u16 =
522  cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
524  reg_autoneg_adver.s.advert_100base_t4 = 0;
525  reg_autoneg_adver.s.advert_10base_tx_full = 0;
526  reg_autoneg_adver.s.advert_10base_tx_half = 0;
527  reg_autoneg_adver.s.advert_100base_tx_full = 0;
528  reg_autoneg_adver.s.advert_100base_tx_half = 0;
529  if (reg_status.s.capable_extended_status) {
530  reg_control_1000.u16 =
531  cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
533  reg_control_1000.s.advert_1000base_t_full = 0;
534  reg_control_1000.s.advert_1000base_t_half = 0;
535  }
536  switch (link_info.s.speed) {
537  case 10:
538  reg_autoneg_adver.s.advert_10base_tx_full =
539  link_info.s.full_duplex;
540  reg_autoneg_adver.s.advert_10base_tx_half =
541  !link_info.s.full_duplex;
542  break;
543  case 100:
544  reg_autoneg_adver.s.advert_100base_tx_full =
545  link_info.s.full_duplex;
546  reg_autoneg_adver.s.advert_100base_tx_half =
547  !link_info.s.full_duplex;
548  break;
549  case 1000:
550  reg_control_1000.s.advert_1000base_t_full =
551  link_info.s.full_duplex;
552  reg_control_1000.s.advert_1000base_t_half =
553  !link_info.s.full_duplex;
554  break;
555  }
556  cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
558  reg_autoneg_adver.u16);
559  if (reg_status.s.capable_extended_status)
560  cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
562  reg_control_1000.u16);
563  reg_control.u16 =
564  cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
566  reg_control.s.autoneg_enable = 1;
567  reg_control.s.restart_autoneg = 1;
568  cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
569  CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
570  } else {
572  reg_control.u16 =
573  cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
575  reg_control.s.autoneg_enable = 0;
576  reg_control.s.restart_autoneg = 1;
577  reg_control.s.duplex = link_info.s.full_duplex;
578  if (link_info.s.speed == 1000) {
579  reg_control.s.speed_msb = 1;
580  reg_control.s.speed_lsb = 0;
581  } else if (link_info.s.speed == 100) {
582  reg_control.s.speed_msb = 0;
583  reg_control.s.speed_lsb = 1;
584  } else if (link_info.s.speed == 10) {
585  reg_control.s.speed_msb = 0;
586  reg_control.s.speed_lsb = 0;
587  }
588  cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
589  CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
590  }
591  return 0;
592 }
593 
615 int __cvmx_helper_board_interface_probe(int interface, int supported_ports)
616 {
617  switch (cvmx_sysinfo_get()->board_type) {
619  if (interface == 0)
620  return 2;
621  break;
623  if (interface == 0)
624  return 2;
625  break;
627  if (interface == 0)
628  return 0;
629  break;
630  /* The 2nd interface on the EBH5600 is connected to the Marvel switch,
631  which we don't support. Disable ports connected to it */
633  if (interface == 1)
634  return 0;
635  break;
636  }
637  return supported_ports;
638 }
639 
651 {
653  if (interface == 0) {
654  /* Different config for switch port */
655  cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0);
656  cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0);
657  /*
658  * Boards with gigabit WAN ports need a
659  * different setting that is compatible with
660  * 100 Mbit settings
661  */
662  cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface),
663  0xc);
664  cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface),
665  0xc);
666  }
667  } else if (cvmx_sysinfo_get()->board_type ==
669  /*
670  * Broadcom PHYs require differnet ASX
671  * clocks. Unfortunately many boards don't define a
672  * new board Id and simply mangle the
673  * CN3010_EVB_HS5
674  */
675  if (interface == 0) {
676  /*
677  * Some boards use a hacked up bootloader that
678  * identifies them as CN3010_EVB_HS5
679  * evaluation boards. This leads to all kinds
680  * of configuration problems. Detect one
681  * case, and print warning, while trying to do
682  * the right thing.
683  */
684  int phy_addr = cvmx_helper_board_get_mii_address(0);
685  if (phy_addr != -1) {
686  int phy_identifier =
687  cvmx_mdio_read(phy_addr >> 8,
688  phy_addr & 0xff, 0x2);
689  /* Is it a Broadcom PHY? */
690  if (phy_identifier == 0x0143) {
691  cvmx_dprintf("\n");
692  cvmx_dprintf("ERROR:\n");
694  ("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n");
696  ("ERROR: The board type is mis-configured, and software malfunctions are likely.\n");
698  ("ERROR: All boards require a unique board type to identify them.\n");
699  cvmx_dprintf("ERROR:\n");
700  cvmx_dprintf("\n");
701  cvmx_wait(1000000000);
702  cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX
703  (0, interface), 5);
704  cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX
705  (0, interface), 5);
706  }
707  }
708  }
709  }
710  return 0;
711 }