1// 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}
1825