18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
58c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
118c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
128c2ecf20Sopenharmony_ci *     conditions are met:
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
158c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
168c2ecf20Sopenharmony_ci *        disclaimer.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
198c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
208c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
218c2ecf20Sopenharmony_ci *        provided with the distribution.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
308c2ecf20Sopenharmony_ci * SOFTWARE.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include "common.h"
348c2ecf20Sopenharmony_ci#include "regs.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cienum {
378c2ecf20Sopenharmony_ci	/* MDIO_DEV_PMA_PMD registers */
388c2ecf20Sopenharmony_ci	AQ_LINK_STAT	= 0xe800,
398c2ecf20Sopenharmony_ci	AQ_IMASK_PMA	= 0xf000,
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	/* MDIO_DEV_XGXS registers */
428c2ecf20Sopenharmony_ci	AQ_XAUI_RX_CFG	= 0xc400,
438c2ecf20Sopenharmony_ci	AQ_XAUI_TX_CFG	= 0xe400,
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	/* MDIO_DEV_ANEG registers */
468c2ecf20Sopenharmony_ci	AQ_1G_CTRL	= 0xc400,
478c2ecf20Sopenharmony_ci	AQ_ANEG_STAT	= 0xc800,
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	/* MDIO_DEV_VEND1 registers */
508c2ecf20Sopenharmony_ci	AQ_FW_VERSION	= 0x0020,
518c2ecf20Sopenharmony_ci	AQ_IFLAG_GLOBAL	= 0xfc00,
528c2ecf20Sopenharmony_ci	AQ_IMASK_GLOBAL	= 0xff00,
538c2ecf20Sopenharmony_ci};
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cienum {
568c2ecf20Sopenharmony_ci	IMASK_PMA	= 1 << 2,
578c2ecf20Sopenharmony_ci	IMASK_GLOBAL	= 1 << 15,
588c2ecf20Sopenharmony_ci	ADV_1G_FULL	= 1 << 15,
598c2ecf20Sopenharmony_ci	ADV_1G_HALF	= 1 << 14,
608c2ecf20Sopenharmony_ci	ADV_10G_FULL	= 1 << 12,
618c2ecf20Sopenharmony_ci	AQ_RESET	= (1 << 14) | (1 << 15),
628c2ecf20Sopenharmony_ci	AQ_LOWPOWER	= 1 << 12,
638c2ecf20Sopenharmony_ci};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic int aq100x_reset(struct cphy *phy, int wait)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	/*
688c2ecf20Sopenharmony_ci	 * Ignore the caller specified wait time; always wait for the reset to
698c2ecf20Sopenharmony_ci	 * complete. Can take up to 3s.
708c2ecf20Sopenharmony_ci	 */
718c2ecf20Sopenharmony_ci	int err = t3_phy_reset(phy, MDIO_MMD_VEND1, 3000);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	if (err)
748c2ecf20Sopenharmony_ci		CH_WARN(phy->adapter, "PHY%d: reset failed (0x%x).\n",
758c2ecf20Sopenharmony_ci			phy->mdio.prtad, err);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return err;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic int aq100x_intr_enable(struct cphy *phy)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AQ_IMASK_PMA, IMASK_PMA);
838c2ecf20Sopenharmony_ci	if (err)
848c2ecf20Sopenharmony_ci		return err;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	err = t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, IMASK_GLOBAL);
878c2ecf20Sopenharmony_ci	return err;
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int aq100x_intr_disable(struct cphy *phy)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	return t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, 0);
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic int aq100x_intr_clear(struct cphy *phy)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	unsigned int v;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &v);
1008c2ecf20Sopenharmony_ci	t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	return 0;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic int aq100x_intr_handler(struct cphy *phy)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	int err;
1088c2ecf20Sopenharmony_ci	unsigned int cause, v;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	err = t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &cause);
1118c2ecf20Sopenharmony_ci	if (err)
1128c2ecf20Sopenharmony_ci		return err;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	/* Read (and reset) the latching version of the status */
1158c2ecf20Sopenharmony_ci	t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return cphy_cause_link_change;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic int aq100x_power_down(struct cphy *phy, int off)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	return mdio_set_flag(&phy->mdio, phy->mdio.prtad,
1238c2ecf20Sopenharmony_ci			     MDIO_MMD_PMAPMD, MDIO_CTRL1,
1248c2ecf20Sopenharmony_ci			     MDIO_CTRL1_LPOWER, off);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic int aq100x_autoneg_enable(struct cphy *phy)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	int err;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	err = aq100x_power_down(phy, 0);
1328c2ecf20Sopenharmony_ci	if (!err)
1338c2ecf20Sopenharmony_ci		err = mdio_set_flag(&phy->mdio, phy->mdio.prtad,
1348c2ecf20Sopenharmony_ci				    MDIO_MMD_AN, MDIO_CTRL1,
1358c2ecf20Sopenharmony_ci				    BMCR_ANENABLE | BMCR_ANRESTART, 1);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	return err;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic int aq100x_autoneg_restart(struct cphy *phy)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	int err;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	err = aq100x_power_down(phy, 0);
1458c2ecf20Sopenharmony_ci	if (!err)
1468c2ecf20Sopenharmony_ci		err = mdio_set_flag(&phy->mdio, phy->mdio.prtad,
1478c2ecf20Sopenharmony_ci				    MDIO_MMD_AN, MDIO_CTRL1,
1488c2ecf20Sopenharmony_ci				    BMCR_ANENABLE | BMCR_ANRESTART, 1);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return err;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic int aq100x_advertise(struct cphy *phy, unsigned int advertise_map)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	unsigned int adv;
1568c2ecf20Sopenharmony_ci	int err;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/* 10G advertisement */
1598c2ecf20Sopenharmony_ci	adv = 0;
1608c2ecf20Sopenharmony_ci	if (advertise_map & ADVERTISED_10000baseT_Full)
1618c2ecf20Sopenharmony_ci		adv |= ADV_10G_FULL;
1628c2ecf20Sopenharmony_ci	err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
1638c2ecf20Sopenharmony_ci				  ADV_10G_FULL, adv);
1648c2ecf20Sopenharmony_ci	if (err)
1658c2ecf20Sopenharmony_ci		return err;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	/* 1G advertisement */
1688c2ecf20Sopenharmony_ci	adv = 0;
1698c2ecf20Sopenharmony_ci	if (advertise_map & ADVERTISED_1000baseT_Full)
1708c2ecf20Sopenharmony_ci		adv |= ADV_1G_FULL;
1718c2ecf20Sopenharmony_ci	if (advertise_map & ADVERTISED_1000baseT_Half)
1728c2ecf20Sopenharmony_ci		adv |= ADV_1G_HALF;
1738c2ecf20Sopenharmony_ci	err = t3_mdio_change_bits(phy, MDIO_MMD_AN, AQ_1G_CTRL,
1748c2ecf20Sopenharmony_ci				  ADV_1G_FULL | ADV_1G_HALF, adv);
1758c2ecf20Sopenharmony_ci	if (err)
1768c2ecf20Sopenharmony_ci		return err;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	/* 100M, pause advertisement */
1798c2ecf20Sopenharmony_ci	adv = 0;
1808c2ecf20Sopenharmony_ci	if (advertise_map & ADVERTISED_100baseT_Half)
1818c2ecf20Sopenharmony_ci		adv |= ADVERTISE_100HALF;
1828c2ecf20Sopenharmony_ci	if (advertise_map & ADVERTISED_100baseT_Full)
1838c2ecf20Sopenharmony_ci		adv |= ADVERTISE_100FULL;
1848c2ecf20Sopenharmony_ci	if (advertise_map & ADVERTISED_Pause)
1858c2ecf20Sopenharmony_ci		adv |= ADVERTISE_PAUSE_CAP;
1868c2ecf20Sopenharmony_ci	if (advertise_map & ADVERTISED_Asym_Pause)
1878c2ecf20Sopenharmony_ci		adv |= ADVERTISE_PAUSE_ASYM;
1888c2ecf20Sopenharmony_ci	err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_ADVERTISE,
1898c2ecf20Sopenharmony_ci				  0xfe0, adv);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	return err;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic int aq100x_set_loopback(struct cphy *phy, int mmd, int dir, int enable)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	return mdio_set_flag(&phy->mdio, phy->mdio.prtad,
1978c2ecf20Sopenharmony_ci			     MDIO_MMD_PMAPMD, MDIO_CTRL1,
1988c2ecf20Sopenharmony_ci			     BMCR_LOOPBACK, enable);
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic int aq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	/* no can do */
2048c2ecf20Sopenharmony_ci	return -1;
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic int aq100x_get_link_status(struct cphy *phy, int *link_ok,
2088c2ecf20Sopenharmony_ci				  int *speed, int *duplex, int *fc)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	int err;
2118c2ecf20Sopenharmony_ci	unsigned int v;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (link_ok) {
2148c2ecf20Sopenharmony_ci		err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AQ_LINK_STAT, &v);
2158c2ecf20Sopenharmony_ci		if (err)
2168c2ecf20Sopenharmony_ci			return err;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci		*link_ok = v & 1;
2198c2ecf20Sopenharmony_ci		if (!*link_ok)
2208c2ecf20Sopenharmony_ci			return 0;
2218c2ecf20Sopenharmony_ci	}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	err = t3_mdio_read(phy, MDIO_MMD_AN, AQ_ANEG_STAT, &v);
2248c2ecf20Sopenharmony_ci	if (err)
2258c2ecf20Sopenharmony_ci		return err;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	if (speed) {
2288c2ecf20Sopenharmony_ci		switch (v & 0x6) {
2298c2ecf20Sopenharmony_ci		case 0x6:
2308c2ecf20Sopenharmony_ci			*speed = SPEED_10000;
2318c2ecf20Sopenharmony_ci			break;
2328c2ecf20Sopenharmony_ci		case 0x4:
2338c2ecf20Sopenharmony_ci			*speed = SPEED_1000;
2348c2ecf20Sopenharmony_ci			break;
2358c2ecf20Sopenharmony_ci		case 0x2:
2368c2ecf20Sopenharmony_ci			*speed = SPEED_100;
2378c2ecf20Sopenharmony_ci			break;
2388c2ecf20Sopenharmony_ci		case 0x0:
2398c2ecf20Sopenharmony_ci			*speed = SPEED_10;
2408c2ecf20Sopenharmony_ci			break;
2418c2ecf20Sopenharmony_ci		}
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (duplex)
2458c2ecf20Sopenharmony_ci		*duplex = v & 1 ? DUPLEX_FULL : DUPLEX_HALF;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return 0;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic const struct cphy_ops aq100x_ops = {
2518c2ecf20Sopenharmony_ci	.reset             = aq100x_reset,
2528c2ecf20Sopenharmony_ci	.intr_enable       = aq100x_intr_enable,
2538c2ecf20Sopenharmony_ci	.intr_disable      = aq100x_intr_disable,
2548c2ecf20Sopenharmony_ci	.intr_clear        = aq100x_intr_clear,
2558c2ecf20Sopenharmony_ci	.intr_handler      = aq100x_intr_handler,
2568c2ecf20Sopenharmony_ci	.autoneg_enable    = aq100x_autoneg_enable,
2578c2ecf20Sopenharmony_ci	.autoneg_restart   = aq100x_autoneg_restart,
2588c2ecf20Sopenharmony_ci	.advertise         = aq100x_advertise,
2598c2ecf20Sopenharmony_ci	.set_loopback      = aq100x_set_loopback,
2608c2ecf20Sopenharmony_ci	.set_speed_duplex  = aq100x_set_speed_duplex,
2618c2ecf20Sopenharmony_ci	.get_link_status   = aq100x_get_link_status,
2628c2ecf20Sopenharmony_ci	.power_down        = aq100x_power_down,
2638c2ecf20Sopenharmony_ci	.mmds 		   = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
2648c2ecf20Sopenharmony_ci};
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ciint t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
2678c2ecf20Sopenharmony_ci		       const struct mdio_ops *mdio_ops)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	unsigned int v, v2, gpio, wait;
2708c2ecf20Sopenharmony_ci	int err;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	cphy_init(phy, adapter, phy_addr, &aq100x_ops, mdio_ops,
2738c2ecf20Sopenharmony_ci		  SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full |
2748c2ecf20Sopenharmony_ci		  SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI,
2758c2ecf20Sopenharmony_ci		  "1000/10GBASE-T");
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	/*
2788c2ecf20Sopenharmony_ci	 * The PHY has been out of reset ever since the system powered up.  So
2798c2ecf20Sopenharmony_ci	 * we do a hard reset over here.
2808c2ecf20Sopenharmony_ci	 */
2818c2ecf20Sopenharmony_ci	gpio = phy_addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL;
2828c2ecf20Sopenharmony_ci	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, 0);
2838c2ecf20Sopenharmony_ci	msleep(1);
2848c2ecf20Sopenharmony_ci	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, gpio);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	/*
2878c2ecf20Sopenharmony_ci	 * Give it enough time to load the firmware and get ready for mdio.
2888c2ecf20Sopenharmony_ci	 */
2898c2ecf20Sopenharmony_ci	msleep(1000);
2908c2ecf20Sopenharmony_ci	wait = 500; /* in 10ms increments */
2918c2ecf20Sopenharmony_ci	do {
2928c2ecf20Sopenharmony_ci		err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v);
2938c2ecf20Sopenharmony_ci		if (err || v == 0xffff) {
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci			/* Allow prep_adapter to succeed when ffff is read */
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci			CH_WARN(adapter, "PHY%d: reset failed (0x%x, 0x%x).\n",
2988c2ecf20Sopenharmony_ci				phy_addr, err, v);
2998c2ecf20Sopenharmony_ci			goto done;
3008c2ecf20Sopenharmony_ci		}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci		v &= AQ_RESET;
3038c2ecf20Sopenharmony_ci		if (v)
3048c2ecf20Sopenharmony_ci			msleep(10);
3058c2ecf20Sopenharmony_ci	} while (v && --wait);
3068c2ecf20Sopenharmony_ci	if (v) {
3078c2ecf20Sopenharmony_ci		CH_WARN(adapter, "PHY%d: reset timed out (0x%x).\n",
3088c2ecf20Sopenharmony_ci			phy_addr, v);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci		goto done; /* let prep_adapter succeed */
3118c2ecf20Sopenharmony_ci	}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	/* Datasheet says 3s max but this has been observed */
3148c2ecf20Sopenharmony_ci	wait = (500 - wait) * 10 + 1000;
3158c2ecf20Sopenharmony_ci	if (wait > 3000)
3168c2ecf20Sopenharmony_ci		CH_WARN(adapter, "PHY%d: reset took %ums\n", phy_addr, wait);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	/* Firmware version check. */
3198c2ecf20Sopenharmony_ci	t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_FW_VERSION, &v);
3208c2ecf20Sopenharmony_ci	if (v != 101)
3218c2ecf20Sopenharmony_ci		CH_WARN(adapter, "PHY%d: unsupported firmware %d\n",
3228c2ecf20Sopenharmony_ci			phy_addr, v);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	/*
3258c2ecf20Sopenharmony_ci	 * The PHY should start in really-low-power mode.  Prepare it for normal
3268c2ecf20Sopenharmony_ci	 * operations.
3278c2ecf20Sopenharmony_ci	 */
3288c2ecf20Sopenharmony_ci	err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v);
3298c2ecf20Sopenharmony_ci	if (err)
3308c2ecf20Sopenharmony_ci		return err;
3318c2ecf20Sopenharmony_ci	if (v & AQ_LOWPOWER) {
3328c2ecf20Sopenharmony_ci		err = t3_mdio_change_bits(phy, MDIO_MMD_VEND1, MDIO_CTRL1,
3338c2ecf20Sopenharmony_ci					  AQ_LOWPOWER, 0);
3348c2ecf20Sopenharmony_ci		if (err)
3358c2ecf20Sopenharmony_ci			return err;
3368c2ecf20Sopenharmony_ci		msleep(10);
3378c2ecf20Sopenharmony_ci	} else
3388c2ecf20Sopenharmony_ci		CH_WARN(adapter, "PHY%d does not start in low power mode.\n",
3398c2ecf20Sopenharmony_ci			phy_addr);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	/*
3428c2ecf20Sopenharmony_ci	 * Verify XAUI settings, but let prep succeed no matter what.
3438c2ecf20Sopenharmony_ci	 */
3448c2ecf20Sopenharmony_ci	v = v2 = 0;
3458c2ecf20Sopenharmony_ci	t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_RX_CFG, &v);
3468c2ecf20Sopenharmony_ci	t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_TX_CFG, &v2);
3478c2ecf20Sopenharmony_ci	if (v != 0x1b || v2 != 0x1b)
3488c2ecf20Sopenharmony_ci		CH_WARN(adapter,
3498c2ecf20Sopenharmony_ci			"PHY%d: incorrect XAUI settings (0x%x, 0x%x).\n",
3508c2ecf20Sopenharmony_ci			phy_addr, v, v2);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cidone:
3538c2ecf20Sopenharmony_ci	return err;
3548c2ecf20Sopenharmony_ci}
355