6f3e57ac9d0b054c3169579f3422080b8ba10105mx/*
47693af92e50a1ad81825eb01b7157a211269613mx * CDDL HEADER START
47693af92e50a1ad81825eb01b7157a211269613mx *
47693af92e50a1ad81825eb01b7157a211269613mx * The contents of this file are subject to the terms of the
47693af92e50a1ad81825eb01b7157a211269613mx * Common Development and Distribution License (the "License").
47693af92e50a1ad81825eb01b7157a211269613mx * You may not use this file except in compliance with the License.
47693af92e50a1ad81825eb01b7157a211269613mx *
47693af92e50a1ad81825eb01b7157a211269613mx * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
47693af92e50a1ad81825eb01b7157a211269613mx * or http://www.opensolaris.org/os/licensing.
47693af92e50a1ad81825eb01b7157a211269613mx * See the License for the specific language governing permissions
47693af92e50a1ad81825eb01b7157a211269613mx * and limitations under the License.
47693af92e50a1ad81825eb01b7157a211269613mx *
47693af92e50a1ad81825eb01b7157a211269613mx * When distributing Covered Code, include this CDDL HEADER in each
47693af92e50a1ad81825eb01b7157a211269613mx * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
47693af92e50a1ad81825eb01b7157a211269613mx * If applicable, add the following below this CDDL HEADER, with the
47693af92e50a1ad81825eb01b7157a211269613mx * fields enclosed by brackets "[]" replaced with your own identifying
47693af92e50a1ad81825eb01b7157a211269613mx * information: Portions Copyright [yyyy] [name of copyright owner]
47693af92e50a1ad81825eb01b7157a211269613mx *
47693af92e50a1ad81825eb01b7157a211269613mx * CDDL HEADER END
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx/*
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
47693af92e50a1ad81825eb01b7157a211269613mx * Use is subject to license terms.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#include "nge.h"
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#undef NGE_DBG
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define NGE_DBG NGE_DBG_MII /* debug flag for this code */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx/*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * The arrays below can be indexed by the MODE bits from the mac2phy
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * register to determine the current speed/duplex settings.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mxstatic const int16_t nge_copper_link_speed[] = {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx 0, /* MII_AUX_STATUS_MODE_NONE */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx 10, /* MII_AUX_STAT0,US_MODE_10 */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx 100, /* MII_AUX_STAT0,US_MODE_100 */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx 1000, /* MII_AUX_STAT0,US_MODE_1000 */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx};
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxstatic const int8_t nge_copper_link_duplex[] = {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx LINK_DUPLEX_UNKNOWN, /* MII_DUPLEX_NONE */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx LINK_DUPLEX_HALF, /* MII_DUPLEX_HALF */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx LINK_DUPLEX_FULL, /* MII_DUPLEX_FULL */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx};
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxstatic uint16_t nge_mii_access(nge_t *ngep, nge_regno_t regno,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t data, uint32_t cmd);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#pragma inline(nge_mii_access)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxstatic uint16_t
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_mii_access(nge_t *ngep, nge_regno_t regno, uint16_t data, uint32_t cmd)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t tries;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t mdio_data;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mdio_adr mdio_adr;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mintr_src intr_src;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx NGE_TRACE(("nge_mii_access($%p, 0x%lx, 0x%x, 0x%x)",
6f3e57ac9d0b054c3169579f3422080b8ba10105mx (void *)ngep, regno, data, cmd));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Clear the privous interrupt event
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx intr_src.src_val = nge_reg_get8(ngep, NGE_MINTR_SRC);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_reg_put8(ngep, NGE_MINTR_SRC, intr_src.src_val);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Check whether the current operation has been finished
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mdio_adr.adr_val = nge_reg_get16(ngep, NGE_MDIO_ADR);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx for (tries = 0; tries < 30; tries ++) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (mdio_adr.adr_bits.mdio_clc == NGE_CLEAR)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx drv_usecwait(10);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mdio_adr.adr_val = nge_reg_get16(ngep, NGE_MDIO_ADR);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * The current operation can not be finished successfully
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * The driver should halt the current operation
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (tries == 30) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mdio_adr.adr_bits.mdio_clc = NGE_SET;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_reg_put16(ngep, NGE_MDIO_ADR, mdio_adr.adr_val);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx drv_usecwait(100);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Assemble the operation cmd
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
a55f711916b9f7718fabc2d1822bf5719aa6140fMiles Xu, Sun Microsystems mdio_adr.adr_bits.phy_reg = (uint16_t)regno;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mdio_adr.adr_bits.phy_adr = ngep->phy_xmii_addr;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mdio_adr.adr_bits.mdio_rw = (cmd == NGE_MDIO_WRITE) ? 1 : 0;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (cmd == NGE_MDIO_WRITE)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_reg_put16(ngep, NGE_MDIO_DATA, data);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_reg_put16(ngep, NGE_MDIO_ADR, mdio_adr.adr_val);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * To check whether the read/write operation is finished
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx for (tries = 0; tries < 300; tries ++) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx drv_usecwait(10);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mdio_adr.adr_val = nge_reg_get16(ngep, NGE_MDIO_ADR);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (mdio_adr.adr_bits.mdio_clc == NGE_CLEAR)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (tries == 300)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return ((uint16_t)~0);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Read the data from MDIO data register
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (cmd == NGE_MDIO_READ)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mdio_data = nge_reg_get16(ngep, NGE_MDIO_DATA);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * To check whether the read/write operation is valid
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx intr_src.src_val = nge_reg_get8(ngep, NGE_MINTR_SRC);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_reg_put8(ngep, NGE_MINTR_SRC, intr_src.src_val);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (intr_src.src_bits.mrei == NGE_SET)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return ((uint16_t)~0);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (mdio_data);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxuint16_t nge_mii_get16(nge_t *ngep, nge_regno_t regno);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#pragma inline(nge_mii_get16)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxuint16_t
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_mii_get16(nge_t *ngep, nge_regno_t regno)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (nge_mii_access(ngep, regno, 0, NGE_MDIO_READ));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxvoid nge_mii_put16(nge_t *ngep, nge_regno_t regno, uint16_t data);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#pragma inline(nge_mii_put16)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxvoid
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_mii_put16(nge_t *ngep, nge_regno_t regno, uint16_t data)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx (void) nge_mii_access(ngep, regno, data, NGE_MDIO_WRITE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx/*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Basic low-level function to probe for a PHY
6f3e57ac9d0b054c3169579f3422080b8ba10105mx *
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Returns TRUE if the PHY responds with valid data, FALSE otherwise
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mxstatic boolean_t
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_phy_probe(nge_t *ngep)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx int i;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t phy_status;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t phyidh;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t phyidl;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx NGE_TRACE(("nge_phy_probe($%p)", (void *)ngep));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Scan the phys to find the right address
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * of the phy
6f3e57ac9d0b054c3169579f3422080b8ba10105mx *
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Probe maximum for 32 phy addresses
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx for (i = 0; i < NGE_PHY_NUMBER; i++) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->phy_xmii_addr = i;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Read the MII_STATUS register twice, in
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * order to clear any sticky bits (but they should
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * have been cleared by the RESET, I think).
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx phy_status = nge_mii_get16(ngep, MII_STATUS);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx phy_status = nge_mii_get16(ngep, MII_STATUS);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (phy_status != 0xffff) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx phyidh = nge_mii_get16(ngep, MII_PHYIDH);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx phyidl = nge_mii_get16(ngep, MII_PHYIDL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->phy_id =
6f3e57ac9d0b054c3169579f3422080b8ba10105mx (((uint32_t)phyidh << 16) |(phyidl & MII_IDL_MASK));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx NGE_DEBUG(("nge_phy_probe: status 0x%x, phy id 0x%x",
6f3e57ac9d0b054c3169579f3422080b8ba10105mx phy_status, ngep->phy_id));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (B_TRUE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (B_FALSE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx/*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Basic low-level function to powerup the phy and remove the isolation
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxstatic boolean_t
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_phy_recover(nge_t *ngep)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t control;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t count;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx NGE_TRACE(("nge_phy_recover($%p)", (void *)ngep));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx control = nge_mii_get16(ngep, MII_CONTROL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx control &= ~(MII_CONTROL_PWRDN | MII_CONTROL_ISOLATE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mii_put16(ngep, MII_CONTROL, control);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx for (count = 0; ++count < 10; ) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx drv_usecwait(5);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx control = nge_mii_get16(ngep, MII_CONTROL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (BIC(control, MII_CONTROL_PWRDN))
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (B_TRUE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (B_FALSE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx/*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Basic low-level function to reset the PHY.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Doesn't incorporate any special-case workarounds.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx *
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Returns TRUE on success, FALSE if the RESET bit doesn't clear
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mxboolean_t
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_phy_reset(nge_t *ngep)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t control;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint_t count;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx NGE_TRACE(("nge_phy_reset($%p)", (void *)ngep));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ASSERT(mutex_owned(ngep->genlock));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Set the PHY RESET bit, then wait up to 5 ms for it to self-clear
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx control = nge_mii_get16(ngep, MII_CONTROL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx control |= MII_CONTROL_RESET;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mii_put16(ngep, MII_CONTROL, control);
c322ff79f6149528aa6dc5018328f071dcf1e50fmx /* We should wait for 500ms. It's defined in the manual */
5164839fa87447c0a1186035041427886a572d29mx delay(drv_usectohz(500000));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx for (count = 0; ++count < 10; ) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx drv_usecwait(5);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx control = nge_mii_get16(ngep, MII_CONTROL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (BIC(control, MII_CONTROL_RESET))
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (B_TRUE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx NGE_DEBUG(("nge_phy_reset: FAILED, control now 0x%x", control));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (B_FALSE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
c322ff79f6149528aa6dc5018328f071dcf1e50fmxstatic boolean_t
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_phy_restart(nge_t *ngep)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t mii_reg;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
c322ff79f6149528aa6dc5018328f071dcf1e50fmx if (!nge_phy_recover(ngep))
c322ff79f6149528aa6dc5018328f071dcf1e50fmx return (B_FALSE);
c322ff79f6149528aa6dc5018328f071dcf1e50fmx if (!nge_phy_reset(ngep))
c322ff79f6149528aa6dc5018328f071dcf1e50fmx return (B_FALSE);
c322ff79f6149528aa6dc5018328f071dcf1e50fmx
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore if (MII_PHY_MFG(ngep->phy_id) == MII_ID_CICADA) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (ngep->phy_mode == RGMII_IN) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_reg = nge_mii_get16(ngep,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx MII_CICADA_EXT_CONTROL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_reg &= ~(MII_CICADA_MODE_SELECT_BITS
6f3e57ac9d0b054c3169579f3422080b8ba10105mx | MII_CICADA_POWER_SUPPLY_BITS);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_reg |= (MII_CICADA_MODE_SELECT_RGMII
6f3e57ac9d0b054c3169579f3422080b8ba10105mx | MII_CICADA_POWER_SUPPLY_2_5V);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mii_put16(ngep, MII_CICADA_EXT_CONTROL, mii_reg);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_reg = nge_mii_get16(ngep,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx MII_CICADA_AUXCTRL_STATUS);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_reg |= MII_CICADA_PIN_PRORITY_SETTING;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mii_put16(ngep, MII_CICADA_AUXCTRL_STATUS,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_reg);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx } else {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_reg = nge_mii_get16(ngep,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx MII_CICADA_10BASET_CONTROL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_reg |= MII_CICADA_DISABLE_ECHO_MODE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mii_put16(ngep,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx MII_CICADA_10BASET_CONTROL, mii_reg);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_reg = nge_mii_get16(ngep,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx MII_CICADA_BYPASS_CONTROL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_reg &= (~CICADA_125MHZ_CLOCK_ENABLE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mii_put16(ngep, MII_CICADA_BYPASS_CONTROL, mii_reg);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
c322ff79f6149528aa6dc5018328f071dcf1e50fmx
c322ff79f6149528aa6dc5018328f071dcf1e50fmx return (B_TRUE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx/*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Synchronise the (copper) PHY's speed/duplex/autonegotiation capabilities
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * and advertisements with the required settings as specified by the various
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * param_* variables that can be poked via the NDD interface.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx *
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * We always reset the PHY and reprogram *all* the relevant registers,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * not just those changed. This should cause the link to go down, and then
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * back up again once the link is stable and autonegotiation (if enabled)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * is complete. We should get a link state change interrupt somewhere along
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * the way ...
6f3e57ac9d0b054c3169579f3422080b8ba10105mx *
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * NOTE: <genlock> must already be held by the caller
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mxstatic void
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_update_copper(nge_t *ngep)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t control;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t gigctrl;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t anar;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx boolean_t adv_autoneg;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx boolean_t adv_pause;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx boolean_t adv_asym_pause;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx boolean_t adv_1000fdx;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx boolean_t adv_100fdx;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx boolean_t adv_100hdx;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx boolean_t adv_10fdx;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx boolean_t adv_10hdx;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx NGE_TRACE(("nge_update_copper($%p)", (void *)ngep));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ASSERT(mutex_owned(ngep->genlock));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx NGE_DEBUG(("nge_update_copper: autoneg %d "
6f3e57ac9d0b054c3169579f3422080b8ba10105mx "pause %d asym_pause %d "
6f3e57ac9d0b054c3169579f3422080b8ba10105mx "1000fdx %d "
6f3e57ac9d0b054c3169579f3422080b8ba10105mx "100fdx %d 100hdx %d "
6f3e57ac9d0b054c3169579f3422080b8ba10105mx "10fdx %d 10hdx %d ",
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_adv_autoneg,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_adv_pause, ngep->param_adv_asym_pause,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_adv_1000fdx,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_adv_100fdx, ngep->param_adv_100hdx,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_adv_10fdx, ngep->param_adv_10hdx));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx control = anar = gigctrl = 0;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * PHY settings are normally based on the param_* variables,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * but if any loopback mode is in effect, that takes precedence.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx *
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * NGE supports MAC-internal loopback, PHY-internal loopback,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * and External loopback at a variety of speeds (with a special
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * cable). In all cases, autoneg is turned OFF, full-duplex
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * is turned ON, and the speed/mastership is forced.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx switch (ngep->param_loop_mode) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case NGE_LOOP_NONE:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx default:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_pause = ngep->param_adv_pause;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_autoneg = ngep->param_adv_autoneg;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_asym_pause = ngep->param_adv_asym_pause;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (ngep->phy_mode == MII_IN) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_1000fdx = ngep->param_adv_1000fdx = B_FALSE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_1000fdx = ngep->param_adv_1000fdx;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_100fdx = ngep->param_adv_100fdx;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_100hdx = ngep->param_adv_100hdx;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_10fdx = ngep->param_adv_10fdx;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_10hdx = ngep->param_adv_10hdx;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case NGE_LOOP_EXTERNAL_100:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case NGE_LOOP_EXTERNAL_10:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case NGE_LOOP_INTERNAL_PHY:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_autoneg = adv_pause = adv_asym_pause = B_FALSE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_1000fdx = adv_100fdx = adv_10fdx = B_FALSE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_100hdx = adv_10hdx = B_FALSE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_link_duplex = LINK_DUPLEX_FULL;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx switch (ngep->param_loop_mode) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case NGE_LOOP_EXTERNAL_100:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_link_speed = 100;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_100fdx = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case NGE_LOOP_EXTERNAL_10:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_link_speed = 10;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_10fdx = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case NGE_LOOP_INTERNAL_PHY:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_link_speed = 1000;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_1000fdx = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx NGE_DEBUG(("nge_update_copper: autoneg %d "
6f3e57ac9d0b054c3169579f3422080b8ba10105mx "pause %d asym_pause %d "
6f3e57ac9d0b054c3169579f3422080b8ba10105mx "1000fdx %d "
6f3e57ac9d0b054c3169579f3422080b8ba10105mx "100fdx %d 100hdx %d "
6f3e57ac9d0b054c3169579f3422080b8ba10105mx "10fdx %d 10hdx %d ",
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_autoneg,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_pause, adv_asym_pause,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_1000fdx,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_100fdx, adv_100hdx,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_10fdx, adv_10hdx));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * We should have at least one technology capability set;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * if not, we select a default of 10Mb/s half-duplex
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (!adv_1000fdx && !adv_100fdx && !adv_10fdx &&
6f3e57ac9d0b054c3169579f3422080b8ba10105mx !adv_100hdx && !adv_10hdx)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx adv_10hdx = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Now transform the adv_* variables into the proper settings
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * of the PHY registers ...
6f3e57ac9d0b054c3169579f3422080b8ba10105mx *
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * If autonegotiation is (now) enabled, we want to trigger
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * a new autonegotiation cycle once the PHY has been
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * programmed with the capabilities to be advertised.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (adv_autoneg)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx control |= MII_CONTROL_ANE|MII_CONTROL_RSAN;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (adv_1000fdx)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx control |= MII_CONTROL_1000MB|MII_CONTROL_FDUPLEX;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx else if (adv_100fdx)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx control |= MII_CONTROL_100MB|MII_CONTROL_FDUPLEX;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx else if (adv_100hdx)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx control |= MII_CONTROL_100MB;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx else if (adv_10fdx)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx control |= MII_CONTROL_FDUPLEX;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx else if (adv_10hdx)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx control |= 0;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx else
6f3e57ac9d0b054c3169579f3422080b8ba10105mx { _NOTE(EMPTY); } /* Can't get here anyway ... */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (adv_1000fdx)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx gigctrl |= MII_1000BT_CTL_ADV_FDX;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (adv_100fdx)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx anar |= MII_ABILITY_100BASE_TX_FD;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (adv_100hdx)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx anar |= MII_ABILITY_100BASE_TX;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (adv_10fdx)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx anar |= MII_ABILITY_10BASE_T_FD;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (adv_10hdx)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx anar |= MII_ABILITY_10BASE_T;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (adv_pause)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx anar |= MII_ABILITY_PAUSE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (adv_asym_pause)
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore anar |= MII_ABILITY_ASMPAUSE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Munge in any other fixed bits we require ...
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx anar |= MII_AN_SELECTOR_8023;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Restart the PHY and write the new values.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mii_put16(ngep, MII_AN_ADVERT, anar);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mii_put16(ngep, MII_CONTROL, control);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mii_put16(ngep, MII_1000BASE_T_CONTROL, gigctrl);
c322ff79f6149528aa6dc5018328f071dcf1e50fmx if (!nge_phy_restart(ngep))
c322ff79f6149528aa6dc5018328f071dcf1e50fmx nge_error(ngep, "nge_update_copper: failed to restart phy");
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Loopback bit in control register is not reset sticky
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * write it after PHY restart.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (ngep->param_loop_mode == NGE_LOOP_INTERNAL_PHY) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx control = nge_mii_get16(ngep, MII_CONTROL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx control |= MII_CONTROL_LOOPBACK;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mii_put16(ngep, MII_CONTROL, control);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxstatic boolean_t
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_check_copper(nge_t *ngep)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t mii_status;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t mii_exstatus;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t mii_excontrol;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t anar;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint16_t lpan;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint_t speed;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint_t duplex;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx boolean_t linkup;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mii_cs mii_cs;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mintr_src mintr_src;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx speed = UNKOWN_SPEED;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx duplex = UNKOWN_DUPLEX;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Read the status from the PHY (which is self-clearing
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * on read!); also read & clear the main (Ethernet) MAC status
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * (the relevant bits of this are write-one-to-clear).
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_status = nge_mii_get16(ngep, MII_STATUS);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_cs.cs_val = nge_reg_get32(ngep, NGE_MII_CS);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mintr_src.src_val = nge_reg_get32(ngep, NGE_MINTR_SRC);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_reg_put32(ngep, NGE_MINTR_SRC, mintr_src.src_val);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx NGE_DEBUG(("nge_check_copper: link %d/%s, MII status 0x%x "
6f3e57ac9d0b054c3169579f3422080b8ba10105mx "(was 0x%x)", ngep->link_state,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx UPORDOWN(ngep->param_link_up), mii_status,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->phy_gen_status));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx do {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * If the PHY status changed, record the time
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx switch (ngep->phy_mode) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx default:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case RGMII_IN:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Judge the giga speed by reading control
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * and status register
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_excontrol = nge_mii_get16(ngep,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx MII_1000BASE_T_CONTROL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_exstatus = nge_mii_get16(ngep,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx MII_1000BASE_T_STATUS);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if ((mii_excontrol & MII_1000BT_CTL_ADV_FDX) &&
6f3e57ac9d0b054c3169579f3422080b8ba10105mx (mii_exstatus & MII_1000BT_STAT_LP_FDX_CAP)) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx speed = NGE_1000M;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx duplex = NGE_FD;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx } else {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx anar = nge_mii_get16(ngep, MII_AN_ADVERT);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx lpan = nge_mii_get16(ngep, MII_AN_LPABLE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (lpan != 0)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx anar = (anar & lpan);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (anar & MII_100BASET_FD) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx speed = NGE_100M;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx duplex = NGE_FD;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx } else if (anar & MII_100BASET_HD) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx speed = NGE_100M;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx duplex = NGE_HD;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx } else if (anar & MII_10BASET_FD) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx speed = NGE_10M;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx duplex = NGE_FD;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx } else if (anar & MII_10BASET_HD) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx speed = NGE_10M;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx duplex = NGE_HD;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case MII_IN:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx anar = nge_mii_get16(ngep, MII_AN_ADVERT);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx lpan = nge_mii_get16(ngep, MII_AN_LPABLE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (lpan != 0)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx anar = (anar & lpan);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (anar & MII_100BASET_FD) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx speed = NGE_100M;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx duplex = NGE_FD;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx } else if (anar & MII_100BASET_HD) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx speed = NGE_100M;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx duplex = NGE_HD;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx } else if (anar & MII_10BASET_FD) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx speed = NGE_10M;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx duplex = NGE_FD;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx } else if (anar & MII_10BASET_HD) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx speed = NGE_10M;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx duplex = NGE_HD;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * We will only consider the link UP if all the readings
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * are consistent and give meaningful results ...
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx linkup = nge_copper_link_speed[speed] > 0;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx linkup &= nge_copper_link_duplex[duplex] != LINK_DUPLEX_UNKNOWN;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx linkup &= BIS(mii_status, MII_STATUS_LINKUP);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx linkup &= BIS(mii_cs.cs_val, MII_STATUS_LINKUP);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Record current register values, then reread status
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * register & loop until it stabilises ...
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->phy_gen_status = mii_status;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_status = nge_mii_get16(ngep, MII_STATUS);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx } while (mii_status != ngep->phy_gen_status);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /* Get the Link Partner Ability */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mii_exstatus = nge_mii_get16(ngep, MII_1000BASE_T_STATUS);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx lpan = nge_mii_get16(ngep, MII_AN_LPABLE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (mii_exstatus & MII_1000BT_STAT_LP_FDX_CAP) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_lp_autoneg = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_link_autoneg = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_lp_1000fdx = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (mii_exstatus & MII_1000BT_STAT_LP_HDX_CAP) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_lp_autoneg = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_link_autoneg = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_lp_1000hdx = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (lpan & MII_100BASET_FD)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_lp_100fdx = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (lpan & MII_100BASET_HD)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_lp_100hdx = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (lpan & MII_10BASET_FD)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_lp_10fdx = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (lpan & MII_10BASET_HD)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_lp_10hdx = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (lpan & MII_LP_ASYM_PAUSE)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_lp_asym_pause = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (lpan & MII_LP_PAUSE)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_lp_pause = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (linkup) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_link_up = linkup;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_link_speed = nge_copper_link_speed[speed];
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_link_duplex = nge_copper_link_duplex[duplex];
6f3e57ac9d0b054c3169579f3422080b8ba10105mx } else {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_link_up = B_FALSE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_link_speed = 0;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_link_duplex = LINK_DUPLEX_UNKNOWN;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx NGE_DEBUG(("nge_check_copper: link now %s speed %d duplex %d",
6f3e57ac9d0b054c3169579f3422080b8ba10105mx UPORDOWN(ngep->param_link_up),
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_link_speed,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_link_duplex));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (B_FALSE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx/*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Because the network chipset embedded in Ck8-04 bridge is only a mac chipset,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * the different vendor can use different media(serdes and copper).
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * To make it easier to extend the driver to support more platforms with ck8-04,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * For example, one platform with serdes support,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * wrapper phy operation functions.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * But now, only supply copper phy operations.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mxstatic const phys_ops_t copper_ops = {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_phy_restart,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_update_copper,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_check_copper
6f3e57ac9d0b054c3169579f3422080b8ba10105mx};
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx/*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Here we have to determine which media we're using (copper or serdes).
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Once that's done, we can initialise the physical layer appropriately.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mxvoid
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_phys_init(nge_t *ngep)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mac2phy m2p;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx NGE_TRACE(("nge_phys_init($%p)", (void *)ngep));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /* Get the phy type from MAC2PHY register */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx m2p.m2p_val = nge_reg_get32(ngep, NGE_MAC2PHY);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->phy_mode = m2p.m2p_bits.in_type;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if ((ngep->phy_mode != RGMII_IN) && (ngep->phy_mode != MII_IN)) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->phy_mode = RGMII_IN;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx m2p.m2p_bits.in_type = RGMII_IN;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_reg_put32(ngep, NGE_MAC2PHY, m2p.m2p_val);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Probe for the type of the PHY.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->phy_xmii_addr = 1;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx (void) nge_phy_probe(ngep);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->chipinfo.flags |= CHIP_FLAG_COPPER;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->physops = &copper_ops;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx (*(ngep->physops->phys_restart))(ngep);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}