blob: 6dcc4e557e12fc06943641358f0a733ef04d13de [file] [log] [blame]
Aaron Williamsc0066752022-04-07 09:11:13 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018-2022 Marvell International Ltd.
4 *
5 * Helper functions to abstract board specific data about
6 * network ports from the rest of the cvmx-helper files.
7 */
8
9#include <i2c.h>
10#include <log.h>
11#include <malloc.h>
12#include <net.h>
13#include <linux/delay.h>
14
15#include <mach/cvmx-regs.h>
16#include <mach/cvmx-csr.h>
17#include <mach/cvmx-bootmem.h>
18#include <mach/octeon-model.h>
19#include <mach/octeon_fdt.h>
20#include <mach/cvmx-helper.h>
21#include <mach/cvmx-helper-board.h>
22#include <mach/cvmx-helper-cfg.h>
23#include <mach/cvmx-helper-fdt.h>
24#include <mach/cvmx-helper-gpio.h>
25
26#include <mach/cvmx-smix-defs.h>
27#include <mach/cvmx-mdio.h>
28#include <mach/cvmx-qlm.h>
29
30DECLARE_GLOBAL_DATA_PTR;
31
32static bool sfp_parsed;
33
34static int __cvmx_helper_78xx_parse_phy(struct cvmx_phy_info *phy_info,
35 int ipd_port);
36static int __get_phy_info_from_dt(cvmx_phy_info_t *phy_info, int ipd_port);
37
38/**
39 * Writes to a Microsemi VSC7224 16-bit register
40 *
41 * @param[in] i2c_bus i2c bus data structure (must be enabled)
42 * @param addr Address of VSC7224 on the i2c bus
43 * @param reg 8-bit register number to write to
44 * @param val 16-bit value to write
45 *
46 * @return 0 for success
47 */
48static int cvmx_write_vsc7224_reg(const struct cvmx_fdt_i2c_bus_info *i2c_bus,
49 u8 addr, u8 reg, u16 val)
50{
51 struct udevice *dev;
52 u8 buffer[2];
53 int ret;
54
55 ret = i2c_get_chip(i2c_bus->i2c_bus, addr, 1, &dev);
56 if (ret) {
57 debug("Cannot find I2C device: %d\n", ret);
58 return -1;
59 }
60
61 ret = dm_i2c_write(dev, reg, buffer, 2);
62 if (ret) {
63 debug("Cannot write I2C device: %d\n", ret);
64 return -1;
65 }
66
67 return 0;
68}
69
70/**
71 * Writes to a Microsemi VSC7224 16-bit register
72 *
73 * @param[in] i2c_bus i2c bus data structure (must be enabled)
74 * @param addr Address of VSC7224 on the i2c bus
75 * @param reg 8-bit register number to write to
76 *
77 * @return 16-bit value or error if < 0
78 */
79static int cvmx_read_vsc7224_reg(const struct cvmx_fdt_i2c_bus_info *i2c_bus,
80 u8 addr, u8 reg)
81{
82 struct udevice *dev;
83 u8 buffer[2];
84 int ret;
85
86 ret = i2c_get_chip(i2c_bus->i2c_bus, addr, 1, &dev);
87 if (ret) {
88 debug("Cannot find I2C device: %d\n", ret);
89 return -1;
90 }
91
92 ret = dm_i2c_read(dev, reg, buffer, 2);
93 if (ret) {
94 debug("Cannot read I2C device: %d\n", ret);
95 return -1;
96 }
97
98 return (buffer[0] << 8) | buffer[1];
99}
100
101/**
102 * Function called whenever mod_abs/mod_prs has changed for Microsemi VSC7224
103 *
104 * @param sfp pointer to SFP data structure
105 * @param val 1 if absent, 0 if present, otherwise not set
106 * @param data user-defined data
107 *
108 * @return 0 for success, -1 on error
109 */
110int cvmx_sfp_vsc7224_mod_abs_changed(struct cvmx_fdt_sfp_info *sfp, int val,
111 void *data)
112{
113 int err;
114 struct cvmx_sfp_mod_info *mod_info;
115 int length;
116 struct cvmx_vsc7224 *vsc7224;
117 struct cvmx_vsc7224_chan *vsc7224_chan;
118 struct cvmx_vsc7224_tap *taps, *match = NULL;
119 int i;
120
121 debug("%s(%s, %d, %p): Module %s\n", __func__, sfp->name, val, data,
122 val ? "absent" : "present");
123 if (val)
124 return 0;
125
126 /* We're here if we detect that the module is now present */
127 err = cvmx_sfp_read_i2c_eeprom(sfp);
128 if (err) {
129 debug("%s: Error reading the SFP module eeprom for %s\n",
130 __func__, sfp->name);
131 return err;
132 }
133 mod_info = &sfp->sfp_info;
134
135 if (!mod_info->valid || !sfp->valid) {
136 debug("%s: Module data is invalid\n", __func__);
137 return -1;
138 }
139
140 vsc7224_chan = sfp->vsc7224_chan;
141 while (vsc7224_chan) {
142 /* We don't do any rx tuning */
143 if (!vsc7224_chan->is_tx) {
144 vsc7224_chan = vsc7224_chan->next;
145 continue;
146 }
147
148 /* Walk through all the channels */
149 taps = vsc7224_chan->taps;
150 if (mod_info->limiting)
151 length = 0;
152 else
153 length = mod_info->max_copper_cable_len;
154 debug("%s: limiting: %d, length: %d\n", __func__,
155 mod_info->limiting, length);
156
157 /* Find a matching length in the taps table */
158 for (i = 0; i < vsc7224_chan->num_taps; i++) {
159 if (length >= taps->len)
160 match = taps;
161 taps++;
162 }
163 if (!match) {
164 debug("%s(%s, %d, %p): Error: no matching tap for length %d\n",
165 __func__, sfp->name, val, data, length);
166 return -1;
167 }
168 debug("%s(%s): Applying %cx taps to vsc7224 %s:%d for cable length %d+\n",
169 __func__, sfp->name, vsc7224_chan->is_tx ? 't' : 'r',
170 vsc7224_chan->vsc7224->name, vsc7224_chan->lane,
171 match->len);
172 /* Program the taps */
173 vsc7224 = vsc7224_chan->vsc7224;
174 cvmx_write_vsc7224_reg(vsc7224->i2c_bus, vsc7224->i2c_addr,
175 0x7f, vsc7224_chan->lane);
176 if (!vsc7224_chan->maintap_disable)
177 cvmx_write_vsc7224_reg(vsc7224->i2c_bus,
178 vsc7224->i2c_addr, 0x99,
179 match->main_tap);
180 if (!vsc7224_chan->pretap_disable)
181 cvmx_write_vsc7224_reg(vsc7224->i2c_bus,
182 vsc7224->i2c_addr, 0x9a,
183 match->pre_tap);
184 if (!vsc7224_chan->posttap_disable)
185 cvmx_write_vsc7224_reg(vsc7224->i2c_bus,
186 vsc7224->i2c_addr, 0x9b,
187 match->post_tap);
188
189 /* Re-use val and disable taps if needed */
190 if (vsc7224_chan->maintap_disable ||
191 vsc7224_chan->pretap_disable ||
192 vsc7224_chan->posttap_disable) {
193 val = cvmx_read_vsc7224_reg(vsc7224->i2c_bus,
194 vsc7224->i2c_addr, 0x97);
195 if (vsc7224_chan->maintap_disable)
196 val |= 0x800;
197 if (vsc7224_chan->pretap_disable)
198 val |= 0x1000;
199 if (vsc7224_chan->posttap_disable)
200 val |= 0x400;
201 cvmx_write_vsc7224_reg(vsc7224->i2c_bus,
202 vsc7224->i2c_addr, 0x97, val);
203 }
204 vsc7224_chan = vsc7224_chan->next;
205 }
206
207 return err;
208}
209
210/**
211 * Update the mod_abs and error LED
212 *
213 * @param ipd_port ipd port number
214 * @param link link information
215 */
216static void __cvmx_helper_update_sfp(int ipd_port,
217 struct cvmx_fdt_sfp_info *sfp_info,
218 cvmx_helper_link_info_t link)
219{
220 debug("%s(%d): checking mod_abs\n", __func__, ipd_port);
221
222 cvmx_sfp_check_mod_abs(sfp_info, sfp_info->mod_abs_data);
223}
224
225static void cvmx_sfp_update_link(struct cvmx_fdt_sfp_info *sfp,
226 cvmx_helper_link_info_t link)
227{
228 while (sfp) {
229 debug("%s(%s): checking mod_abs\n", __func__, sfp->name);
230 if (link.s.link_up && sfp->last_mod_abs)
231 cvmx_sfp_check_mod_abs(sfp, sfp->mod_abs_data);
232 sfp = sfp->next_iface_sfp;
233 }
234}
235
236/**
237 * @INTERNAL
238 * This function is used ethernet ports link speed. This functions uses the
239 * device tree information to determine the phy address and type of PHY.
240 * The only supproted PHYs are Marvell and Broadcom.
241 *
242 * @param ipd_port IPD input port associated with the port we want to get link
243 * status for.
244 *
245 * @return The ports link status. If the link isn't fully resolved, this must
246 * return zero.
247 */
248cvmx_helper_link_info_t __cvmx_helper_board_link_get_from_dt(int ipd_port)
249{
250 cvmx_helper_link_info_t result;
251 cvmx_phy_info_t *phy_info = NULL;
252 cvmx_phy_info_t local_phy_info;
253 int xiface = 0, index = 0;
254 bool use_inband = false;
255 struct cvmx_fdt_sfp_info *sfp_info;
256 const void *fdt_addr = CASTPTR(const void *, gd->fdt_blob);
257
258 result.u64 = 0;
259
260 if (ipd_port >= 0) {
261 int mode;
262
263 xiface = cvmx_helper_get_interface_num(ipd_port);
264 index = cvmx_helper_get_interface_index_num(ipd_port);
265 mode = cvmx_helper_interface_get_mode(xiface);
266 if (!cvmx_helper_get_port_autonegotiation(xiface, index)) {
267 result.s.link_up = 1;
268 result.s.full_duplex = 1;
269 switch (mode) {
270 case CVMX_HELPER_INTERFACE_MODE_RGMII:
271 case CVMX_HELPER_INTERFACE_MODE_GMII:
272 case CVMX_HELPER_INTERFACE_MODE_SGMII:
273 case CVMX_HELPER_INTERFACE_MODE_QSGMII:
274 case CVMX_HELPER_INTERFACE_MODE_AGL:
275 case CVMX_HELPER_INTERFACE_MODE_SPI:
276 if (OCTEON_IS_MODEL(OCTEON_CN70XX)) {
277 struct cvmx_xiface xi =
278 cvmx_helper_xiface_to_node_interface(
279 xiface);
280 u64 gbaud = cvmx_qlm_get_gbaud_mhz(0);
281
282 result.s.speed = gbaud * 8 / 10;
283 if (cvmx_qlm_get_dlm_mode(
284 0, xi.interface) ==
285 CVMX_QLM_MODE_SGMII)
286 result.s.speed >>= 1;
287 else
288 result.s.speed >>= 2;
289 } else {
290 result.s.speed = 1000;
291 }
292 break;
293 case CVMX_HELPER_INTERFACE_MODE_RXAUI:
294 case CVMX_HELPER_INTERFACE_MODE_XAUI:
295 case CVMX_HELPER_INTERFACE_MODE_10G_KR:
296 case CVMX_HELPER_INTERFACE_MODE_XFI:
297 result.s.speed = 10000;
298 break;
299 case CVMX_HELPER_INTERFACE_MODE_XLAUI:
300 case CVMX_HELPER_INTERFACE_MODE_40G_KR4:
301 result.s.speed = 40000;
302 break;
303 default:
304 break;
305 }
306
307 sfp_info = cvmx_helper_cfg_get_sfp_info(xiface, index);
308 /* Initialize the SFP info if it hasn't already been
309 * done.
310 */
311 if (!sfp_info && !sfp_parsed) {
312 cvmx_sfp_parse_device_tree(fdt_addr);
313 sfp_parsed = true;
314 cvmx_sfp_read_all_modules();
315 sfp_info = cvmx_helper_cfg_get_sfp_info(xiface,
316 index);
317 }
318 /* If the link is down or the link is up but we still
319 * register the module as being absent, re-check
320 * mod_abs.
321 */
322 cvmx_sfp_update_link(sfp_info, result);
323
324 cvmx_helper_update_link_led(xiface, index, result);
325
326 return result;
327 }
328 phy_info = cvmx_helper_get_port_phy_info(xiface, index);
329 if (!phy_info) {
330 debug("%s: phy info not saved in config, allocating for 0x%x:%d\n",
331 __func__, xiface, index);
332
333 phy_info = (cvmx_phy_info_t *)cvmx_bootmem_alloc(
334 sizeof(*phy_info), 0);
335 if (!phy_info) {
336 debug("%s: Out of memory\n", __func__);
337 return result;
338 }
339 memset(phy_info, 0, sizeof(*phy_info));
340 phy_info->phy_addr = -1;
341 debug("%s: Setting phy info for 0x%x:%d to %p\n",
342 __func__, xiface, index, phy_info);
343 cvmx_helper_set_port_phy_info(xiface, index, phy_info);
344 }
345 } else {
346 /* For management ports we don't store the PHY information
347 * so we use a local copy instead.
348 */
349 phy_info = &local_phy_info;
350 memset(phy_info, 0, sizeof(*phy_info));
351 phy_info->phy_addr = -1;
352 }
353
354 if (phy_info->phy_addr == -1) {
355 if (octeon_has_feature(OCTEON_FEATURE_BGX)) {
356 if (__cvmx_helper_78xx_parse_phy(phy_info, ipd_port)) {
357 phy_info->phy_addr = -1;
358 use_inband = true;
359 }
360 } else if (__get_phy_info_from_dt(phy_info, ipd_port) < 0) {
361 phy_info->phy_addr = -1;
362 use_inband = true;
363 }
364 }
365
366 /* If we can't get the PHY info from the device tree then try
367 * the inband state.
368 */
369 if (use_inband) {
370 result.s.full_duplex = 1;
371 result.s.link_up = 1;
372 result.s.speed = 1000;
373 return result;
374 }
375
376 if (phy_info->phy_addr < 0)
377 return result;
378
379 if (phy_info->link_function)
380 result = phy_info->link_function(phy_info);
381 else
382 result = cvmx_helper_link_get(ipd_port);
383
384 sfp_info = cvmx_helper_cfg_get_sfp_info(xiface, index);
385 while (sfp_info) {
386 /* If the link is down or the link is up but we still register
387 * the module as being absent, re-check mod_abs.
388 */
389 if (!result.s.link_up ||
390 (result.s.link_up && sfp_info->last_mod_abs))
391 __cvmx_helper_update_sfp(ipd_port, sfp_info, result);
392 sfp_info = sfp_info->next_iface_sfp;
393 }
394
395 return result;
396}
397
398cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
399{
400 cvmx_helper_link_info_t result;
401
402 /* Unless we fix it later, all links are defaulted to down */
403 result.u64 = 0;
404
405 return __cvmx_helper_board_link_get_from_dt(ipd_port);
406}
407
408void cvmx_helper_update_link_led(int xiface, int index,
409 cvmx_helper_link_info_t result)
410{
411}
412
413void cvmx_helper_leds_show_error(struct cvmx_phy_gpio_leds *leds, bool error)
414{
415}
416
417int __cvmx_helper_board_interface_probe(int interface, int supported_ports)
418{
419 return supported_ports;
420}
421
422/**
423 * Returns the Ethernet node offset in the device tree
424 *
425 * @param fdt_addr - pointer to flat device tree in memory
426 * @param aliases - offset of alias in device tree
427 * @param ipd_port - ipd port number to look up
428 *
429 * @returns offset of Ethernet node if >= 0, error if -1
430 */
431int __pip_eth_node(const void *fdt_addr, int aliases, int ipd_port)
432{
433 char name_buffer[20];
434 const char *pip_path;
435 int pip, iface, eth;
436 int interface_num = cvmx_helper_get_interface_num(ipd_port);
437 int interface_index = cvmx_helper_get_interface_index_num(ipd_port);
438 cvmx_helper_interface_mode_t interface_mode =
439 cvmx_helper_interface_get_mode(interface_num);
440
441 /* The following are not found in the device tree */
442 switch (interface_mode) {
443 case CVMX_HELPER_INTERFACE_MODE_ILK:
444 case CVMX_HELPER_INTERFACE_MODE_LOOP:
445 case CVMX_HELPER_INTERFACE_MODE_SRIO:
446 debug("ERROR: No node expected for interface: %d, port: %d, mode: %s\n",
447 interface_index, ipd_port,
448 cvmx_helper_interface_mode_to_string(interface_mode));
449 return -1;
450 default:
451 break;
452 }
453 pip_path = (const char *)fdt_getprop(fdt_addr, aliases, "pip", NULL);
454 if (!pip_path) {
455 debug("ERROR: pip path not found in device tree\n");
456 return -1;
457 }
458 pip = fdt_path_offset(fdt_addr, pip_path);
459 debug("ipdd_port=%d pip_path=%s pip=%d ", ipd_port, pip_path, pip);
460 if (pip < 0) {
461 debug("ERROR: pip not found in device tree\n");
462 return -1;
463 }
464 snprintf(name_buffer, sizeof(name_buffer), "interface@%d",
465 interface_num);
466 iface = fdt_subnode_offset(fdt_addr, pip, name_buffer);
467 debug("iface=%d ", iface);
468 if (iface < 0) {
469 debug("ERROR : pip intf %d not found in device tree\n",
470 interface_num);
471 return -1;
472 }
473 snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x",
474 interface_index);
475 eth = fdt_subnode_offset(fdt_addr, iface, name_buffer);
476 debug("eth=%d\n", eth);
477 if (eth < 0) {
478 debug("ERROR : pip interface@%d ethernet@%d not found in device tree\n",
479 interface_num, interface_index);
480 return -1;
481 }
482 return eth;
483}
484
485int __mix_eth_node(const void *fdt_addr, int aliases, int interface_index)
486{
487 char name_buffer[20];
488 const char *mix_path;
489 int mix;
490
491 snprintf(name_buffer, sizeof(name_buffer), "mix%d", interface_index);
492 mix_path =
493 (const char *)fdt_getprop(fdt_addr, aliases, name_buffer, NULL);
494 if (!mix_path) {
495 debug("ERROR: mix%d path not found in device tree\n",
496 interface_index);
497 }
498 mix = fdt_path_offset(fdt_addr, mix_path);
499 if (mix < 0) {
500 debug("ERROR: %s not found in device tree\n", mix_path);
501 return -1;
502 }
503 return mix;
504}
505
506static int __mdiobus_addr_to_unit(u32 addr)
507{
508 int unit = (addr >> 7) & 3;
509
510 if (!OCTEON_IS_MODEL(OCTEON_CN68XX) && !OCTEON_IS_MODEL(OCTEON_CN78XX))
511 unit >>= 1;
512 return unit;
513}
514
515/**
516 * Parse the muxed MDIO interface information from the device tree
517 *
518 * @param phy_info - pointer to phy info data structure to update
519 * @param mdio_offset - offset of MDIO bus
520 * @param mux_offset - offset of MUX, parent of mdio_offset
521 *
522 * @return 0 for success or -1
523 */
524static int __get_muxed_mdio_info_from_dt(cvmx_phy_info_t *phy_info,
525 int mdio_offset, int mux_offset)
526{
527 const void *fdt_addr = CASTPTR(const void *, gd->fdt_blob);
528 int phandle;
529 int smi_offset;
530 int gpio_offset;
531 u64 smi_addr = 0;
532 int len;
533 u32 *pgpio_handle;
534 int gpio_count = 0;
535 u32 *prop_val;
536 int offset;
537 const char *prop_name;
538
539 debug("%s(%p, 0x%x, 0x%x)\n", __func__, phy_info, mdio_offset,
540 mux_offset);
541
542 /* Get register value to put onto the GPIO lines to select */
543 phy_info->gpio_value =
544 cvmx_fdt_get_int(fdt_addr, mdio_offset, "reg", -1);
545 if (phy_info->gpio_value < 0) {
546 debug("Could not get register value for muxed MDIO bus from DT\n");
547 return -1;
548 }
549
550 smi_offset = cvmx_fdt_lookup_phandle(fdt_addr, mux_offset,
551 "mdio-parent-bus");
552 if (smi_offset < 0) {
553 debug("Invalid SMI offset for muxed MDIO interface in device tree\n");
554 return -1;
555 }
556 smi_addr = cvmx_fdt_get_uint64(fdt_addr, smi_offset, "reg", 0);
557
558 /* Convert SMI address to a MDIO interface */
559 switch (smi_addr) {
560 case 0x1180000001800:
561 case 0x1180000003800: /* 68XX address */
562 phy_info->mdio_unit = 0;
563 break;
564 case 0x1180000001900:
565 case 0x1180000003880:
566 phy_info->mdio_unit = 1;
567 break;
568 case 0x1180000003900:
569 phy_info->mdio_unit = 2;
570 break;
571 case 0x1180000003980:
572 phy_info->mdio_unit = 3;
573 break;
574 default:
575 phy_info->mdio_unit = 1;
576 break;
577 }
578 /* Find the GPIO MUX controller */
579 pgpio_handle =
580 (u32 *)fdt_getprop(fdt_addr, mux_offset, "gpios", &len);
581 if (!pgpio_handle || len < 12 || (len % 12) != 0 ||
582 len > CVMX_PHY_MUX_MAX_GPIO * 12) {
583 debug("Invalid GPIO for muxed MDIO controller in DT\n");
584 return -1;
585 }
586
587 for (gpio_count = 0; gpio_count < len / 12; gpio_count++) {
588 phandle = fdt32_to_cpu(pgpio_handle[gpio_count * 3]);
589 phy_info->gpio[gpio_count] =
590 fdt32_to_cpu(pgpio_handle[gpio_count * 3 + 1]);
591 gpio_offset = fdt_node_offset_by_phandle(fdt_addr, phandle);
592 if (gpio_offset < 0) {
593 debug("Cannot access parent GPIO node in DT\n");
594 return -1;
595 }
596 if (!fdt_node_check_compatible(fdt_addr, gpio_offset,
597 "cavium,octeon-3860-gpio")) {
598 phy_info->gpio_type[gpio_count] = GPIO_OCTEON;
599 } else if (!fdt_node_check_compatible(fdt_addr, gpio_offset,
600 "nxp,pca8574")) {
601 /* GPIO is a TWSI GPIO unit which might sit behind
602 * another mux.
603 */
604 phy_info->gpio_type[gpio_count] = GPIO_PCA8574;
605 prop_val = (u32 *)fdt_getprop(
606 fdt_addr, gpio_offset, "reg", NULL);
607 if (!prop_val) {
608 debug("Could not find TWSI address of npx pca8574 GPIO from DT\n");
609 return -1;
610 }
611 /* Get the TWSI address of the GPIO unit */
612 phy_info->cvmx_gpio_twsi[gpio_count] =
613 fdt32_to_cpu(*prop_val);
614 /* Get the selector on the GPIO mux if present */
615 offset = fdt_parent_offset(fdt_addr, gpio_offset);
616 prop_val = (u32 *)fdt_getprop(fdt_addr, offset,
617 "reg", NULL);
618 if (prop_val) {
619 phy_info->gpio_parent_mux_select =
620 fdt32_to_cpu(*prop_val);
621 /* Go up another level */
622 offset = fdt_parent_offset(fdt_addr, offset);
623 if (!fdt_node_check_compatible(fdt_addr, offset,
624 "nxp,pca9548")) {
625 prop_val = (u32 *)fdt_getprop(
626 fdt_addr, offset, "reg", NULL);
627 if (!prop_val) {
628 debug("Could not read MUX TWSI address from DT\n");
629 return -1;
630 }
631 phy_info->gpio_parent_mux_twsi =
632 fdt32_to_cpu(*prop_val);
633 }
634 }
635 } else {
636 prop_name = (char *)fdt_getprop(fdt_addr, gpio_offset,
637 "compatible", NULL);
638 debug("Unknown GPIO type %s\n", prop_name);
639 return -1;
640 }
641 }
642 return 0;
643}
644
645/**
646 * @INTERNAL
647 * Converts a BGX address to the node, interface and port number
648 *
649 * @param bgx_addr Address of CSR register
650 *
651 * @return node, interface and port number, will be -1 for invalid address.
652 */
653static struct cvmx_xiface __cvmx_bgx_reg_addr_to_xiface(u64 bgx_addr)
654{
655 struct cvmx_xiface xi = { -1, -1 };
656
657 xi.node = cvmx_csr_addr_to_node(bgx_addr);
658 bgx_addr = cvmx_csr_addr_strip_node(bgx_addr);
659 if ((bgx_addr & 0xFFFFFFFFF0000000) != 0x00011800E0000000) {
660 debug("%s: Invalid BGX address 0x%llx\n", __func__,
661 (unsigned long long)bgx_addr);
662 xi.node = -1;
663 return xi;
664 }
665 xi.interface = (bgx_addr >> 24) & 0x0F;
666
667 return xi;
668}
669
670static cvmx_helper_link_info_t
671__get_marvell_phy_link_state(cvmx_phy_info_t *phy_info)
672{
673 cvmx_helper_link_info_t result;
674 int phy_status;
675 u32 phy_addr = phy_info->phy_addr;
676
677 result.u64 = 0;
678 /* Set to page 0 */
679 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, 22, 0);
680 /* All the speed information can be read from register 17 in one go. */
681 phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
682
683 /* If the resolve bit 11 isn't set, see if autoneg is turned off
684 * (bit 12, reg 0). The resolve bit doesn't get set properly when
685 * autoneg is off, so force it
686 */
687 if ((phy_status & (1 << 11)) == 0) {
688 int auto_status =
689 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0);
690 if ((auto_status & (1 << 12)) == 0)
691 phy_status |= 1 << 11;
692 }
693
694 /* Link is up = Speed/Duplex Resolved + RT-Link Up + G-Link Up. */
695 if ((phy_status & 0x0c08) == 0x0c08) {
696 result.s.link_up = 1;
697 result.s.full_duplex = ((phy_status >> 13) & 1);
698 switch ((phy_status >> 14) & 3) {
699 case 0: /* 10 Mbps */
700 result.s.speed = 10;
701 break;
702 case 1: /* 100 Mbps */
703 result.s.speed = 100;
704 break;
705 case 2: /* 1 Gbps */
706 result.s.speed = 1000;
707 break;
708 case 3: /* Illegal */
709 result.u64 = 0;
710 break;
711 }
712 }
713 return result;
714}
715
716/**
717 * @INTERNAL
718 * Get link state of broadcom PHY
719 *
720 * @param phy_info PHY information
721 */
722static cvmx_helper_link_info_t
723__get_broadcom_phy_link_state(cvmx_phy_info_t *phy_info)
724{
725 cvmx_helper_link_info_t result;
726 u32 phy_addr = phy_info->phy_addr;
727 int phy_status;
728
729 result.u64 = 0;
730 /* Below we are going to read SMI/MDIO register 0x19 which works
731 * on Broadcom parts
732 */
733 phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19);
734 switch ((phy_status >> 8) & 0x7) {
735 case 0:
736 result.u64 = 0;
737 break;
738 case 1:
739 result.s.link_up = 1;
740 result.s.full_duplex = 0;
741 result.s.speed = 10;
742 break;
743 case 2:
744 result.s.link_up = 1;
745 result.s.full_duplex = 1;
746 result.s.speed = 10;
747 break;
748 case 3:
749 result.s.link_up = 1;
750 result.s.full_duplex = 0;
751 result.s.speed = 100;
752 break;
753 case 4:
754 result.s.link_up = 1;
755 result.s.full_duplex = 1;
756 result.s.speed = 100;
757 break;
758 case 5:
759 result.s.link_up = 1;
760 result.s.full_duplex = 1;
761 result.s.speed = 100;
762 break;
763 case 6:
764 result.s.link_up = 1;
765 result.s.full_duplex = 0;
766 result.s.speed = 1000;
767 break;
768 case 7:
769 result.s.link_up = 1;
770 result.s.full_duplex = 1;
771 result.s.speed = 1000;
772 break;
773 }
774 return result;
775}
776
777/**
778 * @INTERNAL
779 * Get link state of generic gigabit PHY
780 *
781 * @param phy_info - information about the PHY
782 *
783 * @returns link status of the PHY
784 */
785static cvmx_helper_link_info_t
786__cvmx_get_generic_8023_c22_phy_link_state(cvmx_phy_info_t *phy_info)
787{
788 cvmx_helper_link_info_t result;
789 u32 phy_addr = phy_info->phy_addr;
790 int phy_basic_control; /* Register 0x0 */
791 int phy_basic_status; /* Register 0x1 */
792 int phy_anog_adv; /* Register 0x4 */
793 int phy_link_part_avail; /* Register 0x5 */
794 int phy_control; /* Register 0x9 */
795 int phy_status; /* Register 0xA */
796
797 result.u64 = 0;
798
799 phy_basic_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 1);
800 if (!(phy_basic_status & 0x4)) /* Check if link is up */
801 return result; /* Link is down, return link down */
802
803 result.s.link_up = 1;
804 phy_basic_control = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0);
805 /* Check if autonegotiation is enabled and completed */
806 if ((phy_basic_control & (1 << 12)) && (phy_basic_status & (1 << 5))) {
807 phy_status =
808 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0xA);
809 phy_control =
810 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x9);
811
812 phy_status &= phy_control << 2;
813 phy_link_part_avail =
814 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x5);
815 phy_anog_adv =
816 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x4);
817 phy_link_part_avail &= phy_anog_adv;
818
819 if (phy_status & 0xC00) { /* Gigabit full or half */
820 result.s.speed = 1000;
821 result.s.full_duplex = !!(phy_status & 0x800);
822 } else if (phy_link_part_avail &
823 0x0180) { /* 100 full or half */
824 result.s.speed = 100;
825 result.s.full_duplex = !!(phy_link_part_avail & 0x100);
826 } else if (phy_link_part_avail & 0x0060) {
827 result.s.speed = 10;
828 result.s.full_duplex = !!(phy_link_part_avail & 0x0040);
829 }
830 } else {
831 /* Not autonegotiated */
832 result.s.full_duplex = !!(phy_basic_control & (1 << 8));
833
834 if (phy_basic_control & (1 << 6))
835 result.s.speed = 1000;
836 else if (phy_basic_control & (1 << 13))
837 result.s.speed = 100;
838 else
839 result.s.speed = 10;
840 }
841 return result;
842}
843
844static cvmx_helper_link_info_t
845__cvmx_get_qualcomm_s17_phy_link_state(cvmx_phy_info_t *phy_info)
846{
847 cvmx_helper_link_info_t result;
848 u32 phy_addr = phy_info->phy_addr;
849 int phy_status;
850 int auto_status;
851
852 result.u64 = 0;
853
854 phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
855
856 /* If bit 11 isn't set see if autonegotiation is turned off
857 * (bit 12, reg 0). The resolved bit doesn't get set properly when
858 * autonegotiation is off, so force it.
859 */
860 if ((phy_status & (1 << 11)) == 0) {
861 auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0);
862 if ((auto_status & (1 << 12)) == 0)
863 phy_status |= 1 << 11;
864 }
865 /* Only return a link if the PHY has finished autonegotiation and set
866 * the resolved bit (bit 11).
867 */
868 if (phy_status & (1 << 11)) {
869 result.s.link_up = 1;
870 result.s.full_duplex = !!(phy_status & (1 << 13));
871 switch ((phy_status >> 14) & 3) {
872 case 0: /* 10Mbps */
873 result.s.speed = 10;
874 break;
875 case 1: /* 100Mbps */
876 result.s.speed = 100;
877 break;
878 case 2: /* 1Gbps */
879 result.s.speed = 1000;
880 break;
881 default: /* Illegal */
882 result.u64 = 0;
883 break;
884 }
885 }
886 debug(" link: %s, duplex: %s, speed: %lu\n",
887 result.s.link_up ? "up" : "down",
888 result.s.full_duplex ? "full" : "half",
889 (unsigned long)result.s.speed);
890 return result;
891}
892
893static cvmx_helper_link_info_t
894__get_generic_8023_c45_phy_link_state(cvmx_phy_info_t *phy_info)
895{
896 cvmx_helper_link_info_t result;
897 int phy_status;
898 int pma_ctrl1;
899 u32 phy_addr = phy_info->phy_addr;
900
901 result.u64 = 0;
902 pma_ctrl1 = cvmx_mdio_45_read(phy_addr >> 8, phy_addr & 0xff, 1, 0);
903 if ((pma_ctrl1 & 0x207c) == 0x2040)
904 result.s.speed = 10000;
905 /* PMA Status 1 (1x0001) */
906 phy_status = cvmx_mdio_45_read(phy_addr >> 8, phy_addr & 0xff, 1, 0xa);
907 if (phy_status < 0)
908 return result;
909
910 result.s.full_duplex = 1;
911 if ((phy_status & 1) == 0)
912 return result;
913 phy_status = cvmx_mdio_45_read(phy_addr >> 8, phy_addr & 0xff, 4, 0x18);
914 if (phy_status < 0)
915 return result;
916 result.s.link_up = (phy_status & 0x1000) ? 1 : 0;
917
918 return result;
919}
920
921static cvmx_helper_link_info_t
922__cvmx_get_cortina_phy_link_state(cvmx_phy_info_t *phy_info)
923{
924 cvmx_helper_link_info_t result;
925
926 result.s.link_up = 1;
927 result.s.full_duplex = 1;
928 result.s.speed = 1000;
929 return result;
930}
931
932static cvmx_helper_link_info_t
933__get_vitesse_vsc8490_phy_link_state(cvmx_phy_info_t *phy_info)
934{
935 cvmx_helper_link_info_t result;
936
937 result.s.link_up = 1;
938 result.s.full_duplex = 1;
939 result.s.speed = 1000;
940 return result;
941}
942
943static cvmx_helper_link_info_t
944__get_aquantia_phy_link_state(cvmx_phy_info_t *phy_info)
945{
946 cvmx_helper_link_info_t result;
947
948 result.s.link_up = 1;
949 result.s.full_duplex = 1;
950 result.s.speed = 1000;
951 return result;
952}
953
954static int __cvmx_helper_78xx_parse_phy(struct cvmx_phy_info *phy_info,
955 int ipd_port)
956{
957 const void *fdt_addr = CASTPTR(const void *, gd->fdt_blob);
958 const char *compat;
959 int phy;
960 int parent;
961 u64 mdio_base;
962 int node, bus;
963 int phy_addr;
964 int index = cvmx_helper_get_interface_index_num(ipd_port);
965 int xiface = cvmx_helper_get_interface_num(ipd_port);
966 int compat_len = 0;
967
968 debug("%s(0x%p, %d) ENTER\n", __func__, phy_info, ipd_port);
969
970 phy = cvmx_helper_get_phy_fdt_node_offset(xiface, index);
971 debug("%s: xiface: 0x%x, index: %d, ipd_port: %d, phy fdt offset: %d\n",
972 __func__, xiface, index, ipd_port, phy);
973 if (phy < 0) {
974 /* If this is the first time through we need to first parse the
975 * device tree to get the node offsets.
976 */
977 debug("No config present, calling __cvmx_helper_parse_bgx_dt\n");
978 if (__cvmx_helper_parse_bgx_dt(fdt_addr)) {
979 printf("Error: could not parse BGX device tree\n");
980 return -1;
981 }
982 if (__cvmx_fdt_parse_vsc7224(fdt_addr)) {
983 debug("Error: could not parse Microsemi VSC7224 in DT\n");
984 return -1;
985 }
986 if (octeon_has_feature(OCTEON_FEATURE_BGX_XCV) &&
987 __cvmx_helper_parse_bgx_rgmii_dt(fdt_addr)) {
988 printf("Error: could not parse BGX XCV device tree\n");
989 return -1;
990 }
991 phy = cvmx_helper_get_phy_fdt_node_offset(xiface, index);
992 if (phy < 0) {
993 debug("%s: Could not get PHY node offset for IPD port 0x%x, xiface: 0x%x, index: %d\n",
994 __func__, ipd_port, xiface, index);
995 return -1;
996 }
997 debug("%s: phy: %d (%s)\n", __func__, phy,
998 fdt_get_name(fdt_addr, phy, NULL));
999 }
1000
1001 compat = (const char *)fdt_getprop(fdt_addr, phy, "compatible",
1002 &compat_len);
1003 if (!compat) {
1004 printf("ERROR: %d:%d:no compatible prop in phy\n", xiface,
1005 index);
1006 return -1;
1007 }
1008
1009 debug(" compatible: %s\n", compat);
1010
1011 phy_info->fdt_offset = phy;
1012 phy_addr = cvmx_fdt_get_int(fdt_addr, phy, "reg", -1);
1013 if (phy_addr == -1) {
1014 printf("Error: %d:%d:could not get PHY address\n", xiface,
1015 index);
1016 return -1;
1017 }
1018 debug(" PHY address: %d, compat: %s\n", phy_addr, compat);
1019
1020 if (!memcmp("marvell", compat, strlen("marvell"))) {
1021 phy_info->phy_type = MARVELL_GENERIC_PHY;
1022 phy_info->link_function = __get_marvell_phy_link_state;
1023 } else if (!memcmp("broadcom", compat, strlen("broadcom"))) {
1024 phy_info->phy_type = BROADCOM_GENERIC_PHY;
1025 phy_info->link_function = __get_broadcom_phy_link_state;
1026 } else if (!memcmp("cortina", compat, strlen("cortina"))) {
1027 phy_info->phy_type = CORTINA_PHY;
1028 phy_info->link_function = __cvmx_get_cortina_phy_link_state;
1029 } else if (!strcmp("vitesse,vsc8490", compat)) {
1030 phy_info->phy_type = VITESSE_VSC8490_PHY;
1031 phy_info->link_function = __get_vitesse_vsc8490_phy_link_state;
1032 } else if (fdt_stringlist_contains(compat, compat_len,
1033 "ethernet-phy-ieee802.3-c22")) {
1034 phy_info->phy_type = GENERIC_8023_C22_PHY;
1035 phy_info->link_function =
1036 __cvmx_get_generic_8023_c22_phy_link_state;
1037 } else if (fdt_stringlist_contains(compat, compat_len,
1038 "ethernet-phy-ieee802.3-c45")) {
1039 phy_info->phy_type = GENERIC_8023_C22_PHY;
1040 phy_info->link_function = __get_generic_8023_c45_phy_link_state;
1041 }
1042
1043 phy_info->ipd_port = ipd_port;
1044 phy_info->phy_sub_addr = 0;
1045 phy_info->direct_connect = 1;
1046
1047 parent = fdt_parent_offset(fdt_addr, phy);
1048 if (!fdt_node_check_compatible(fdt_addr, parent,
1049 "ethernet-phy-nexus")) {
1050 debug(" nexus PHY found\n");
1051 if (phy_info->phy_type == CORTINA_PHY) {
1052 /* The Cortina CS422X uses the same PHY device for
1053 * multiple ports for XFI. In this case we use a
1054 * nexus and each PHY address is the slice or
1055 * sub-address and the actual PHY address is the
1056 * nexus address.
1057 */
1058 phy_info->phy_sub_addr = phy_addr;
1059 phy_addr =
1060 cvmx_fdt_get_int(fdt_addr, parent, "reg", -1);
1061 debug(" Cortina PHY real address: 0x%x\n", phy_addr);
1062 }
1063 parent = fdt_parent_offset(fdt_addr, parent);
1064 }
1065
1066 debug(" Parent: %s\n", fdt_get_name(fdt_addr, parent, NULL));
1067 if (!fdt_node_check_compatible(fdt_addr, parent,
1068 "cavium,octeon-3860-mdio")) {
1069 debug(" Found Octeon MDIO\n");
1070 mdio_base = cvmx_fdt_get_uint64(fdt_addr, parent, "reg",
1071 FDT_ADDR_T_NONE);
1072 debug(" MDIO address: 0x%llx\n",
1073 (unsigned long long)mdio_base);
1074
1075 mdio_base = cvmx_fdt_translate_address(fdt_addr, parent,
1076 (u32 *)&mdio_base);
1077 debug(" Translated: 0x%llx\n", (unsigned long long)mdio_base);
1078 if (mdio_base == FDT_ADDR_T_NONE) {
1079 printf("Could not get MDIO base address from reg field\n");
1080 return -1;
1081 }
1082 __cvmx_mdio_addr_to_node_bus(mdio_base, &node, &bus);
1083 if (bus < 0) {
1084 printf("Invalid MDIO address 0x%llx, could not detect bus and node\n",
1085 (unsigned long long)mdio_base);
1086 return -1;
1087 }
1088 debug(" MDIO node: %d, bus: %d\n", node, bus);
1089 phy_info->mdio_unit = (node << 2) | (bus & 3);
1090 phy_info->phy_addr = phy_addr | (phy_info->mdio_unit << 8);
1091 } else {
1092 printf("%s: Error: incompatible MDIO bus %s for IPD port %d\n",
1093 __func__,
1094 (const char *)fdt_get_name(fdt_addr, parent, NULL),
1095 ipd_port);
1096 return -1;
1097 }
1098
1099 debug("%s: EXIT 0\n", __func__);
1100
1101 return 0;
1102}
1103
1104/**
1105 * Return the MII PHY address associated with the given IPD
1106 * port. The phy address is obtained from the device tree.
1107 *
1108 * @param[out] phy_info - PHY information data structure updated
1109 * @param ipd_port Octeon IPD port to get the MII address for.
1110 *
1111 * @return MII PHY address and bus number, -1 on error, -2 if PHY info missing (OK).
1112 */
1113static int __get_phy_info_from_dt(cvmx_phy_info_t *phy_info, int ipd_port)
1114{
1115 const void *fdt_addr = CASTPTR(const void *, gd->fdt_blob);
1116 int aliases, eth, phy, phy_parent, ret, i;
1117 int mdio_parent;
1118 const char *phy_compatible_str;
1119 const char *host_mode_str = NULL;
1120 int interface;
1121 int phy_addr_offset = 0;
1122
1123 debug("%s(%p, %d)\n", __func__, phy_info, ipd_port);
1124
1125 if (octeon_has_feature(OCTEON_FEATURE_BGX))
1126 return __cvmx_helper_78xx_parse_phy(phy_info, ipd_port);
1127
1128 phy_info->phy_addr = -1;
1129 phy_info->phy_sub_addr = 0;
1130 phy_info->ipd_port = ipd_port;
1131 phy_info->direct_connect = -1;
1132 phy_info->phy_type = (cvmx_phy_type_t)-1;
1133 for (i = 0; i < CVMX_PHY_MUX_MAX_GPIO; i++)
1134 phy_info->gpio[i] = -1;
1135 phy_info->mdio_unit = -1;
1136 phy_info->gpio_value = -1;
1137 phy_info->gpio_parent_mux_twsi = -1;
1138 phy_info->gpio_parent_mux_select = -1;
1139 phy_info->link_function = NULL;
1140 phy_info->fdt_offset = -1;
1141 if (!fdt_addr) {
1142 debug("No device tree found.\n");
1143 return -1;
1144 }
1145
1146 aliases = fdt_path_offset(fdt_addr, "/aliases");
1147 if (aliases < 0) {
1148 debug("Error: No /aliases node in device tree.\n");
1149 return -1;
1150 }
1151 if (ipd_port < 0) {
1152 int interface_index =
1153 ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT;
1154 eth = __mix_eth_node(fdt_addr, aliases, interface_index);
1155 } else {
1156 eth = __pip_eth_node(fdt_addr, aliases, ipd_port);
1157 }
1158 if (eth < 0) {
1159 debug("ERROR : cannot find interface for ipd_port=%d\n",
1160 ipd_port);
1161 return -1;
1162 }
1163
1164 interface = cvmx_helper_get_interface_num(ipd_port);
1165 /* Get handle to phy */
1166 phy = cvmx_fdt_lookup_phandle(fdt_addr, eth, "phy-handle");
1167 if (phy < 0) {
1168 cvmx_helper_interface_mode_t if_mode;
1169
1170 /* Note that it's OK for RXAUI and ILK to not have a PHY
1171 * connected (i.e. EBB boards in loopback).
1172 */
1173 debug("Cannot get phy-handle for ipd_port: %d\n", ipd_port);
1174 if_mode = cvmx_helper_interface_get_mode(interface);
1175 if (if_mode != CVMX_HELPER_INTERFACE_MODE_RXAUI &&
1176 if_mode != CVMX_HELPER_INTERFACE_MODE_ILK) {
1177 debug("ERROR : phy handle not found in device tree ipd_port=%d\n",
1178 ipd_port);
1179 return -1;
1180 } else {
1181 return -2;
1182 }
1183 }
1184
1185 phy_compatible_str =
1186 (const char *)fdt_getprop(fdt_addr, phy, "compatible", NULL);
1187 if (!phy_compatible_str) {
1188 debug("ERROR: no compatible prop in phy\n");
1189 return -1;
1190 }
1191 debug("Checking compatible string \"%s\" for ipd port %d\n",
1192 phy_compatible_str, ipd_port);
1193 phy_info->fdt_offset = phy;
1194 if (!memcmp("marvell", phy_compatible_str, strlen("marvell"))) {
1195 debug("Marvell PHY detected for ipd_port %d\n", ipd_port);
1196 phy_info->phy_type = MARVELL_GENERIC_PHY;
1197 phy_info->link_function = __get_marvell_phy_link_state;
1198 } else if (!memcmp("broadcom", phy_compatible_str,
1199 strlen("broadcom"))) {
1200 phy_info->phy_type = BROADCOM_GENERIC_PHY;
1201 phy_info->link_function = __get_broadcom_phy_link_state;
1202 debug("Broadcom PHY detected for ipd_port %d\n", ipd_port);
1203 } else if (!memcmp("vitesse", phy_compatible_str, strlen("vitesse"))) {
1204 debug("Vitesse PHY detected for ipd_port %d\n", ipd_port);
1205 if (!fdt_node_check_compatible(fdt_addr, phy,
1206 "vitesse,vsc8490")) {
1207 phy_info->phy_type = VITESSE_VSC8490_PHY;
1208 debug("Vitesse VSC8490 detected\n");
1209 phy_info->link_function =
1210 __get_vitesse_vsc8490_phy_link_state;
1211 } else if (!fdt_node_check_compatible(
1212 fdt_addr, phy,
1213 "ethernet-phy-ieee802.3-c22")) {
1214 phy_info->phy_type = GENERIC_8023_C22_PHY;
1215 phy_info->link_function =
1216 __cvmx_get_generic_8023_c22_phy_link_state;
1217 debug("Vitesse 802.3 c22 detected\n");
1218 } else {
1219 phy_info->phy_type = GENERIC_8023_C45_PHY;
1220 phy_info->link_function =
1221 __get_generic_8023_c45_phy_link_state;
1222 debug("Vitesse 802.3 c45 detected\n");
1223 }
1224 } else if (!memcmp("aquantia", phy_compatible_str,
1225 strlen("aquantia"))) {
1226 phy_info->phy_type = AQUANTIA_PHY;
1227 phy_info->link_function = __get_aquantia_phy_link_state;
1228 debug("Aquantia c45 PHY detected\n");
1229 } else if (!memcmp("cortina", phy_compatible_str, strlen("cortina"))) {
1230 phy_info->phy_type = CORTINA_PHY;
1231 phy_info->link_function = __cvmx_get_cortina_phy_link_state;
1232 host_mode_str = (const char *)fdt_getprop(
1233 fdt_addr, phy, "cortina,host-mode", NULL);
1234 debug("Cortina PHY detected for ipd_port %d\n", ipd_port);
1235 } else if (!memcmp("ti", phy_compatible_str, strlen("ti"))) {
1236 phy_info->phy_type = GENERIC_8023_C45_PHY;
1237 phy_info->link_function = __get_generic_8023_c45_phy_link_state;
1238 debug("TI PHY detected for ipd_port %d\n", ipd_port);
1239 } else if (!fdt_node_check_compatible(fdt_addr, phy,
1240 "atheros,ar8334") ||
1241 !fdt_node_check_compatible(fdt_addr, phy,
1242 "qualcomm,qca8334") ||
1243 !fdt_node_check_compatible(fdt_addr, phy,
1244 "atheros,ar8337") ||
1245 !fdt_node_check_compatible(fdt_addr, phy,
1246 "qualcomm,qca8337")) {
1247 phy_info->phy_type = QUALCOMM_S17;
1248 phy_info->link_function =
1249 __cvmx_get_qualcomm_s17_phy_link_state;
1250 debug("Qualcomm QCA833X switch detected\n");
1251 } else if (!fdt_node_check_compatible(fdt_addr, phy,
1252 "ethernet-phy-ieee802.3-c22")) {
1253 phy_info->phy_type = GENERIC_8023_C22_PHY;
1254 phy_info->link_function =
1255 __cvmx_get_generic_8023_c22_phy_link_state;
1256 debug("Generic 802.3 c22 PHY detected\n");
1257 } else if (!fdt_node_check_compatible(fdt_addr, phy,
1258 "ethernet-phy-ieee802.3-c45")) {
1259 phy_info->phy_type = GENERIC_8023_C45_PHY;
1260 phy_info->link_function = __get_generic_8023_c45_phy_link_state;
1261 debug("Generic 802.3 c45 PHY detected\n");
1262 } else {
1263 debug("Unknown PHY compatibility\n");
1264 phy_info->phy_type = (cvmx_phy_type_t)-1;
1265 phy_info->link_function = NULL;
1266 }
1267
1268 phy_info->host_mode = CVMX_PHY_HOST_MODE_UNKNOWN;
1269 if (host_mode_str) {
1270 if (strcmp(host_mode_str, "rxaui") == 0)
1271 phy_info->host_mode = CVMX_PHY_HOST_MODE_RXAUI;
1272 else if (strcmp(host_mode_str, "xaui") == 0)
1273 phy_info->host_mode = CVMX_PHY_HOST_MODE_XAUI;
1274 else if (strcmp(host_mode_str, "sgmii") == 0)
1275 phy_info->host_mode = CVMX_PHY_HOST_MODE_SGMII;
1276 else if (strcmp(host_mode_str, "qsgmii") == 0)
1277 phy_info->host_mode = CVMX_PHY_HOST_MODE_QSGMII;
1278 else
1279 debug("Unknown PHY host mode\n");
1280 }
1281
1282 /* Check if PHY parent is the octeon MDIO bus. Some boards are connected
1283 * though a MUX and for them direct_connect_to_phy will be 0
1284 */
1285 phy_parent = fdt_parent_offset(fdt_addr, phy);
1286 if (phy_parent < 0) {
1287 debug("ERROR : cannot find phy parent for ipd_port=%d ret=%d\n",
1288 ipd_port, phy_parent);
1289 return -1;
1290 }
1291 /* For multi-phy devices and devices on a MUX, go to the parent */
1292 ret = fdt_node_check_compatible(fdt_addr, phy_parent,
1293 "ethernet-phy-nexus");
1294 if (ret == 0) {
1295 /* It's a nexus so check the grandparent. */
1296 phy_addr_offset =
1297 cvmx_fdt_get_int(fdt_addr, phy_parent, "reg", 0);
1298 phy_parent = fdt_parent_offset(fdt_addr, phy_parent);
1299 }
1300
1301 /* Check for a muxed MDIO interface */
1302 mdio_parent = fdt_parent_offset(fdt_addr, phy_parent);
1303 ret = fdt_node_check_compatible(fdt_addr, mdio_parent,
1304 "cavium,mdio-mux");
1305 if (ret == 0) {
1306 ret = __get_muxed_mdio_info_from_dt(phy_info, phy_parent,
1307 mdio_parent);
1308 if (ret) {
1309 printf("Error reading mdio mux information for ipd port %d\n",
1310 ipd_port);
1311 return -1;
1312 }
1313 }
1314 ret = fdt_node_check_compatible(fdt_addr, phy_parent,
1315 "cavium,octeon-3860-mdio");
1316 if (ret == 0) {
1317 u32 *mdio_reg_base =
1318 (u32 *)fdt_getprop(fdt_addr, phy_parent, "reg", 0);
1319 phy_info->direct_connect = 1;
1320 if (mdio_reg_base == 0) {
1321 debug("ERROR : unable to get reg property in phy mdio\n");
1322 return -1;
1323 }
1324 phy_info->mdio_unit =
1325 __mdiobus_addr_to_unit(fdt32_to_cpu(mdio_reg_base[1]));
1326 debug("phy parent=%s reg_base=%08x mdio_unit=%d\n",
1327 fdt_get_name(fdt_addr, phy_parent, NULL),
1328 (int)mdio_reg_base[1], phy_info->mdio_unit);
1329 } else {
1330 phy_info->direct_connect = 0;
1331 /* The PHY is not directly connected to the Octeon MDIO bus.
1332 * SE doesn't have abstractions for MDIO MUX or MDIO MUX
1333 * drivers and hence for the non direct cases code will be
1334 * needed which is board specific.
1335 * For now the MDIO Unit is defaulted to 1.
1336 */
1337 debug("%s PHY at address: %d is not directly connected\n",
1338 __func__, phy_info->phy_addr);
1339 }
1340
1341 phy_info->phy_addr = cvmx_fdt_get_int(fdt_addr, phy, "reg", -1);
1342 if (phy_info->phy_addr < 0) {
1343 debug("ERROR: Could not read phy address from reg in DT\n");
1344 return -1;
1345 }
1346 phy_info->phy_addr += phy_addr_offset;
1347 phy_info->phy_addr |= phy_info->mdio_unit << 8;
1348 debug("%s(%p, %d) => 0x%x\n", __func__, phy_info, ipd_port,
1349 phy_info->phy_addr);
1350 return phy_info->phy_addr;
1351}
1352
1353/**
1354 * @INTERNAL
1355 * Parse the device tree and set whether a port is valid or not.
1356 *
1357 * @param fdt_addr Pointer to device tree
1358 *
1359 * @return 0 for success, -1 on error.
1360 */
1361int __cvmx_helper_parse_bgx_dt(const void *fdt_addr)
1362{
1363 int port_index;
1364 struct cvmx_xiface xi;
1365 int fdt_port_node = -1;
1366 int fdt_interface_node;
1367 int fdt_phy_node;
1368 u64 reg_addr;
1369 int xiface;
1370 struct cvmx_phy_info *phy_info;
1371 static bool parsed;
1372 int err;
1373 int ipd_port;
1374
1375 if (parsed) {
1376 debug("%s: Already parsed\n", __func__);
1377 return 0;
1378 }
1379 while ((fdt_port_node = fdt_node_offset_by_compatible(
1380 fdt_addr, fdt_port_node,
1381 "cavium,octeon-7890-bgx-port")) >= 0) {
1382 /* Get the port number */
1383 port_index =
1384 cvmx_fdt_get_int(fdt_addr, fdt_port_node, "reg", -1);
1385 if (port_index < 0) {
1386 debug("Error: missing reg field for bgx port in device tree\n");
1387 return -1;
1388 }
1389 debug("%s: Parsing BGX port %d\n", __func__, port_index);
1390 /* Get the interface number */
1391 fdt_interface_node = fdt_parent_offset(fdt_addr, fdt_port_node);
1392 if (fdt_interface_node < 0) {
1393 debug("Error: device tree corrupt!\n");
1394 return -1;
1395 }
1396 if (fdt_node_check_compatible(fdt_addr, fdt_interface_node,
1397 "cavium,octeon-7890-bgx")) {
1398 debug("Error: incompatible Ethernet MAC Nexus in device tree!\n");
1399 return -1;
1400 }
1401 reg_addr =
1402 cvmx_fdt_get_addr(fdt_addr, fdt_interface_node, "reg");
1403 debug("%s: BGX interface address: 0x%llx\n", __func__,
1404 (unsigned long long)reg_addr);
1405 if (reg_addr == FDT_ADDR_T_NONE) {
1406 debug("Device tree BGX node has invalid address 0x%llx\n",
1407 (unsigned long long)reg_addr);
1408 return -1;
1409 }
1410 reg_addr = cvmx_fdt_translate_address(fdt_addr,
1411 fdt_interface_node,
1412 (u32 *)&reg_addr);
1413 xi = __cvmx_bgx_reg_addr_to_xiface(reg_addr);
1414 if (xi.node < 0) {
1415 debug("Device tree BGX node has invalid address 0x%llx\n",
1416 (unsigned long long)reg_addr);
1417 return -1;
1418 }
1419 debug("%s: Found BGX node %d, interface %d\n", __func__,
1420 xi.node, xi.interface);
1421 xiface = cvmx_helper_node_interface_to_xiface(xi.node,
1422 xi.interface);
1423 cvmx_helper_set_port_fdt_node_offset(xiface, port_index,
1424 fdt_port_node);
1425 cvmx_helper_set_port_valid(xiface, port_index, true);
1426
1427 cvmx_helper_set_port_fdt_node_offset(xiface, port_index,
1428 fdt_port_node);
1429 if (fdt_getprop(fdt_addr, fdt_port_node,
1430 "cavium,sgmii-mac-phy-mode", NULL))
1431 cvmx_helper_set_mac_phy_mode(xiface, port_index, true);
1432 else
1433 cvmx_helper_set_mac_phy_mode(xiface, port_index, false);
1434
1435 if (fdt_getprop(fdt_addr, fdt_port_node, "cavium,force-link-up",
1436 NULL))
1437 cvmx_helper_set_port_force_link_up(xiface, port_index,
1438 true);
1439 else
1440 cvmx_helper_set_port_force_link_up(xiface, port_index,
1441 false);
1442
1443 if (fdt_getprop(fdt_addr, fdt_port_node,
1444 "cavium,sgmii-mac-1000x-mode", NULL))
1445 cvmx_helper_set_1000x_mode(xiface, port_index, true);
1446 else
1447 cvmx_helper_set_1000x_mode(xiface, port_index, false);
1448
1449 if (fdt_getprop(fdt_addr, fdt_port_node,
1450 "cavium,disable-autonegotiation", NULL))
1451 cvmx_helper_set_port_autonegotiation(xiface, port_index,
1452 false);
1453 else
1454 cvmx_helper_set_port_autonegotiation(xiface, port_index,
1455 true);
1456
1457 fdt_phy_node = cvmx_fdt_lookup_phandle(fdt_addr, fdt_port_node,
1458 "phy-handle");
1459 if (fdt_phy_node >= 0) {
1460 cvmx_helper_set_phy_fdt_node_offset(xiface, port_index,
1461 fdt_phy_node);
1462 debug("%s: Setting PHY fdt node offset for interface 0x%x, port %d to %d\n",
1463 __func__, xiface, port_index, fdt_phy_node);
1464 debug("%s: PHY node name: %s\n", __func__,
1465 fdt_get_name(fdt_addr, fdt_phy_node, NULL));
1466 cvmx_helper_set_port_phy_present(xiface, port_index,
1467 true);
1468 ipd_port = cvmx_helper_get_ipd_port(xiface, port_index);
1469 if (ipd_port >= 0) {
1470 debug("%s: Allocating phy info for 0x%x:%d\n",
1471 __func__, xiface, port_index);
1472 phy_info =
1473 (cvmx_phy_info_t *)cvmx_bootmem_alloc(
1474 sizeof(*phy_info), 0);
1475 if (!phy_info) {
1476 debug("%s: Out of memory\n", __func__);
1477 return -1;
1478 }
1479 memset(phy_info, 0, sizeof(*phy_info));
1480 phy_info->phy_addr = -1;
1481 err = __get_phy_info_from_dt(phy_info,
1482 ipd_port);
1483 if (err) {
1484 debug("%s: Error parsing phy info for ipd port %d\n",
1485 __func__, ipd_port);
1486 return -1;
1487 }
1488 cvmx_helper_set_port_phy_info(
1489 xiface, port_index, phy_info);
1490 debug("%s: Saved phy info\n", __func__);
1491 }
1492 } else {
1493 cvmx_helper_set_phy_fdt_node_offset(xiface, port_index,
1494 -1);
1495 debug("%s: No PHY fdt node offset for interface 0x%x, port %d to %d\n",
1496 __func__, xiface, port_index, fdt_phy_node);
1497 cvmx_helper_set_port_phy_present(xiface, port_index,
1498 false);
1499 }
1500 }
1501 if (!sfp_parsed)
1502 if (cvmx_sfp_parse_device_tree(fdt_addr))
1503 debug("%s: Error parsing SFP device tree\n", __func__);
1504 parsed = true;
1505 return 0;
1506}
1507
1508int __cvmx_helper_parse_bgx_rgmii_dt(const void *fdt_addr)
1509{
1510 u64 reg_addr;
1511 struct cvmx_xiface xi;
1512 int fdt_port_node = -1;
1513 int fdt_interface_node;
1514 int fdt_phy_node;
1515 int port_index;
1516 int xiface;
1517
1518 /* There's only one xcv (RGMII) interface, so just search for the one
1519 * that's part of a BGX entry.
1520 */
1521 while ((fdt_port_node = fdt_node_offset_by_compatible(
1522 fdt_addr, fdt_port_node, "cavium,octeon-7360-xcv")) >=
1523 0) {
1524 fdt_interface_node = fdt_parent_offset(fdt_addr, fdt_port_node);
1525 if (fdt_interface_node < 0) {
1526 printf("Error: device tree corrupt!\n");
1527 return -1;
1528 }
1529 debug("%s: XCV parent node compatible: %s\n", __func__,
1530 (char *)fdt_getprop(fdt_addr, fdt_interface_node,
1531 "compatible", NULL));
1532 if (!fdt_node_check_compatible(fdt_addr, fdt_interface_node,
1533 "cavium,octeon-7890-bgx"))
1534 break;
1535 }
1536 if (fdt_port_node == -FDT_ERR_NOTFOUND) {
1537 debug("No XCV/RGMII interface found in device tree\n");
1538 return 0;
1539 } else if (fdt_port_node < 0) {
1540 debug("%s: Error %d parsing device tree\n", __func__,
1541 fdt_port_node);
1542 return -1;
1543 }
1544 port_index = cvmx_fdt_get_int(fdt_addr, fdt_port_node, "reg", -1);
1545 if (port_index != 0) {
1546 printf("%s: Error: port index (reg) must be 0, not %d.\n",
1547 __func__, port_index);
1548 return -1;
1549 }
1550 reg_addr = cvmx_fdt_get_addr(fdt_addr, fdt_interface_node, "reg");
1551 if (reg_addr == FDT_ADDR_T_NONE) {
1552 printf("%s: Error: could not get BGX interface address\n",
1553 __func__);
1554 return -1;
1555 }
1556 /* We don't have to bother translating since only 78xx supports OCX and
1557 * doesn't support RGMII.
1558 */
1559 xi = __cvmx_bgx_reg_addr_to_xiface(reg_addr);
1560 debug("%s: xi.node: %d, xi.interface: 0x%x, addr: 0x%llx\n", __func__,
1561 xi.node, xi.interface, (unsigned long long)reg_addr);
1562 if (xi.node < 0) {
1563 printf("%s: Device tree BGX node has invalid address 0x%llx\n",
1564 __func__, (unsigned long long)reg_addr);
1565 return -1;
1566 }
1567 debug("%s: Found XCV (RGMII) interface on interface %d\n", __func__,
1568 xi.interface);
1569 debug(" phy handle: 0x%x\n",
1570 cvmx_fdt_get_int(fdt_addr, fdt_port_node, "phy-handle", -1));
1571 fdt_phy_node =
1572 cvmx_fdt_lookup_phandle(fdt_addr, fdt_port_node, "phy-handle");
1573 debug("%s: phy-handle node: 0x%x\n", __func__, fdt_phy_node);
1574 xiface = cvmx_helper_node_interface_to_xiface(xi.node, xi.interface);
1575
1576 cvmx_helper_set_port_fdt_node_offset(xiface, port_index, fdt_port_node);
1577 if (fdt_phy_node >= 0) {
1578 debug("%s: Setting PHY fdt node offset for interface 0x%x, port %d to %d\n",
1579 __func__, xiface, port_index, fdt_phy_node);
1580 debug("%s: PHY node name: %s\n", __func__,
1581 fdt_get_name(fdt_addr, fdt_phy_node, NULL));
1582 cvmx_helper_set_phy_fdt_node_offset(xiface, port_index,
1583 fdt_phy_node);
1584 cvmx_helper_set_port_phy_present(xiface, port_index, true);
1585 } else {
1586 cvmx_helper_set_phy_fdt_node_offset(xiface, port_index, -1);
1587 debug("%s: No PHY fdt node offset for interface 0x%x, port %d to %d\n",
1588 __func__, xiface, port_index, fdt_phy_node);
1589 cvmx_helper_set_port_phy_present(xiface, port_index, false);
1590 }
1591
1592 return 0;
1593}
1594
1595/**
1596 * Returns if a port is present on an interface
1597 *
1598 * @param fdt_addr - address fo flat device tree
1599 * @param ipd_port - IPD port number
1600 *
1601 * @return 1 if port is present, 0 if not present, -1 if error
1602 */
1603int __cvmx_helper_board_get_port_from_dt(void *fdt_addr, int ipd_port)
1604{
1605 int port_index;
1606 int aliases;
1607 const char *pip_path;
1608 char name_buffer[24];
1609 int pip, iface, eth;
1610 cvmx_helper_interface_mode_t mode;
1611 int xiface = cvmx_helper_get_interface_num(ipd_port);
1612 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
1613 u32 val;
1614 int phy_node_offset;
1615 int parse_bgx_dt_err;
1616 int parse_vsc7224_err;
1617
1618 debug("%s(%p, %d)\n", __func__, fdt_addr, ipd_port);
1619 if (octeon_has_feature(OCTEON_FEATURE_BGX)) {
1620 static int fdt_ports_initialized;
1621
1622 port_index = cvmx_helper_get_interface_index_num(ipd_port);
1623
1624 if (!fdt_ports_initialized) {
1625 if (octeon_has_feature(OCTEON_FEATURE_BGX_XCV)) {
1626 if (!__cvmx_helper_parse_bgx_rgmii_dt(fdt_addr))
1627 fdt_ports_initialized = 1;
1628 parse_bgx_dt_err =
1629 __cvmx_helper_parse_bgx_dt(fdt_addr);
1630 parse_vsc7224_err =
1631 __cvmx_fdt_parse_vsc7224(fdt_addr);
1632 if (!parse_bgx_dt_err && !parse_vsc7224_err)
1633 fdt_ports_initialized = 1;
1634 } else {
1635 debug("%s: Error parsing FDT\n", __func__);
1636 return -1;
1637 }
1638 }
1639
1640 return cvmx_helper_is_port_valid(xiface, port_index);
1641 }
1642
1643 mode = cvmx_helper_interface_get_mode(xiface);
1644
1645 switch (mode) {
1646 /* Device tree has information about the following mode types. */
1647 case CVMX_HELPER_INTERFACE_MODE_RGMII:
1648 case CVMX_HELPER_INTERFACE_MODE_GMII:
1649 case CVMX_HELPER_INTERFACE_MODE_SPI:
1650 case CVMX_HELPER_INTERFACE_MODE_XAUI:
1651 case CVMX_HELPER_INTERFACE_MODE_SGMII:
1652 case CVMX_HELPER_INTERFACE_MODE_QSGMII:
1653 case CVMX_HELPER_INTERFACE_MODE_RXAUI:
1654 case CVMX_HELPER_INTERFACE_MODE_AGL:
1655 case CVMX_HELPER_INTERFACE_MODE_XLAUI:
1656 case CVMX_HELPER_INTERFACE_MODE_XFI:
1657 aliases = 1;
1658 break;
1659 default:
1660 aliases = 0;
1661 break;
1662 }
1663
1664 /* The device tree information is present on interfaces that have phy */
1665 if (!aliases)
1666 return 1;
1667
1668 port_index = cvmx_helper_get_interface_index_num(ipd_port);
1669
1670 aliases = fdt_path_offset(fdt_addr, "/aliases");
1671 if (aliases < 0) {
1672 debug("%s: ERROR: /aliases not found in device tree fdt_addr=%p\n",
1673 __func__, fdt_addr);
1674 return -1;
1675 }
1676
1677 pip_path = (const char *)fdt_getprop(fdt_addr, aliases, "pip", NULL);
1678 if (!pip_path) {
1679 debug("%s: ERROR: interface %x pip path not found in device tree\n",
1680 __func__, xiface);
1681 return -1;
1682 }
1683 pip = fdt_path_offset(fdt_addr, pip_path);
1684 if (pip < 0) {
1685 debug("%s: ERROR: interface %x pip not found in device tree\n",
1686 __func__, xiface);
1687 return -1;
1688 }
1689 snprintf(name_buffer, sizeof(name_buffer), "interface@%d",
1690 xi.interface);
1691 iface = fdt_subnode_offset(fdt_addr, pip, name_buffer);
1692 if (iface < 0)
1693 return 0;
1694 snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", port_index);
1695 eth = fdt_subnode_offset(fdt_addr, iface, name_buffer);
1696 debug("%s: eth subnode offset %d from %s\n", __func__, eth,
1697 name_buffer);
1698
1699 if (eth < 0)
1700 return -1;
1701
1702 cvmx_helper_set_port_fdt_node_offset(xiface, port_index, eth);
1703
1704 phy_node_offset = cvmx_fdt_get_int(fdt_addr, eth, "phy", -1);
1705 cvmx_helper_set_phy_fdt_node_offset(xiface, port_index,
1706 phy_node_offset);
1707
1708 if (fdt_getprop(fdt_addr, eth, "cavium,sgmii-mac-phy-mode", NULL))
1709 cvmx_helper_set_mac_phy_mode(xiface, port_index, true);
1710 else
1711 cvmx_helper_set_mac_phy_mode(xiface, port_index, false);
1712
1713 if (fdt_getprop(fdt_addr, eth, "cavium,force-link-up", NULL))
1714 cvmx_helper_set_port_force_link_up(xiface, port_index, true);
1715 else
1716 cvmx_helper_set_port_force_link_up(xiface, port_index, false);
1717
1718 if (fdt_getprop(fdt_addr, eth, "cavium,sgmii-mac-1000x-mode", NULL))
1719 cvmx_helper_set_1000x_mode(xiface, port_index, true);
1720 else
1721 cvmx_helper_set_1000x_mode(xiface, port_index, false);
1722
1723 if (fdt_getprop(fdt_addr, eth, "cavium,disable-autonegotiation", NULL))
1724 cvmx_helper_set_port_autonegotiation(xiface, port_index, false);
1725 else
1726 cvmx_helper_set_port_autonegotiation(xiface, port_index, true);
1727
1728 if (mode == CVMX_HELPER_INTERFACE_MODE_AGL) {
1729 bool tx_bypass = false;
1730
1731 if (fdt_getprop(fdt_addr, eth, "cavium,rx-clk-delay-bypass",
1732 NULL))
1733 cvmx_helper_set_agl_rx_clock_delay_bypass(
1734 xiface, port_index, true);
1735 else
1736 cvmx_helper_set_agl_rx_clock_delay_bypass(
1737 xiface, port_index, false);
1738
1739 val = cvmx_fdt_get_int(fdt_addr, eth, "cavium,rx-clk-skew", 0);
1740 cvmx_helper_set_agl_rx_clock_skew(xiface, port_index, val);
1741
1742 if (fdt_getprop(fdt_addr, eth, "cavium,tx-clk-delay-bypass",
1743 NULL))
1744 tx_bypass = true;
1745
1746 val = cvmx_fdt_get_int(fdt_addr, eth, "tx-clk-delay", 0);
1747 cvmx_helper_cfg_set_rgmii_tx_clk_delay(xiface, port_index,
1748 tx_bypass, val);
1749
1750 val = cvmx_fdt_get_int(fdt_addr, eth, "cavium,refclk-sel", 0);
1751 cvmx_helper_set_agl_refclk_sel(xiface, port_index, val);
1752 }
1753
1754 return (eth >= 0);
1755}
1756
1757/**
1758 * Given the address of the MDIO registers, output the CPU node and MDIO bus
1759 *
1760 * @param addr 64-bit address of MDIO registers (from device tree)
1761 * @param[out] node CPU node number (78xx)
1762 * @param[out] bus MDIO bus number
1763 */
1764void __cvmx_mdio_addr_to_node_bus(u64 addr, int *node, int *bus)
1765{
1766 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
1767 if (node)
1768 *node = cvmx_csr_addr_to_node(addr);
1769 addr = cvmx_csr_addr_strip_node(addr);
1770 } else {
1771 if (node)
1772 *node = 0;
1773 }
1774 if (OCTEON_IS_MODEL(OCTEON_CN68XX) || OCTEON_IS_MODEL(OCTEON_CN78XX)) {
1775 switch (addr) {
1776 case 0x0001180000003800:
1777 *bus = 0;
1778 break;
1779 case 0x0001180000003880:
1780 *bus = 1;
1781 break;
1782 case 0x0001180000003900:
1783 *bus = 2;
1784 break;
1785 case 0x0001180000003980:
1786 *bus = 3;
1787 break;
1788 default:
1789 *bus = -1;
1790 printf("%s: Invalid SMI bus address 0x%llx\n", __func__,
1791 (unsigned long long)addr);
1792 break;
1793 }
1794 } else if (OCTEON_IS_MODEL(OCTEON_CN73XX) ||
1795 OCTEON_IS_MODEL(OCTEON_CNF75XX)) {
1796 switch (addr) {
1797 case 0x0001180000003800:
1798 *bus = 0;
1799 break;
1800 case 0x0001180000003880:
1801 *bus = 1;
1802 break;
1803 default:
1804 *bus = -1;
1805 printf("%s: Invalid SMI bus address 0x%llx\n", __func__,
1806 (unsigned long long)addr);
1807 break;
1808 }
1809 } else {
1810 switch (addr) {
1811 case 0x0001180000001800:
1812 *bus = 0;
1813 break;
1814 case 0x0001180000001900:
1815 *bus = 1;
1816 break;
1817 default:
1818 *bus = -1;
1819 printf("%s: Invalid SMI bus address 0x%llx\n", __func__,
1820 (unsigned long long)addr);
1821 break;
1822 }
1823 }
1824}