/************************************************************************** * * Compile-time config * **************************************************************************
*/ #define TXCNAME "TXC43128" /* Total length of time we'll wait for the PHY to come out of reset (ms) */ #define TXC_MAX_RESET_TIME 500 /* Interval between checks (ms) */ #define TXC_RESET_WAIT 10 /* How long to run BIST (us) */ #define TXC_BIST_DURATION 50
/* Signal Quality Control */ #define TXC_GLRGS_GSGQLCTL 0xc01a /* Enable bit */ #define TXC_GSGQLCT_SGQLEN_LBN 15 /* Lane selection */ #define TXC_GSGQLCT_LNSL_LBN 13 #define TXC_GSGQLCT_LNSL_WIDTH 2
/* Analog TX control */ #define TXC_ALRGS_ATXCTL 0xc040 /* Lane power-down */ #define TXC_ATXCTL_TXPD3_LBN 15 #define TXC_ATXCTL_TXPD2_LBN 14 #define TXC_ATXCTL_TXPD1_LBN 13 #define TXC_ATXCTL_TXPD0_LBN 12
/* Amplitude on lanes 0, 1 */ #define TXC_ALRGS_ATXAMP0 0xc041 /* Amplitude on lanes 2, 3 */ #define TXC_ALRGS_ATXAMP1 0xc042 /* Bit position of value for lane 0 (or 2) */ #define TXC_ATXAMP_LANE02_LBN 3 /* Bit position of value for lane 1 (or 3) */ #define TXC_ATXAMP_LANE13_LBN 11
/* Main control */ #define TXC_MRGS_CTL 0xc340 /* Bits in main control */ #define TXC_MCTL_RESET_LBN 15 /* Self clear */ #define TXC_MCTL_TXLED_LBN 14 /* 1 to show align status */ #define TXC_MCTL_RXLED_LBN 13 /* 1 to show align status */
/* The PHY sometimes needs a reset to bring the link back up. So long as * it reports link down, we reset it every 5 seconds.
*/ #define BUG10934_RESET_INTERVAL (5 * HZ)
/* Perform a reset that doesn't clear configuration changes */ staticvoid txc_reset_logic(struct ef4_nic *efx);
/* Set the output value of a gpio */ void falcon_txc_set_gpio_val(struct ef4_nic *efx, int pin, int on)
{
ef4_mdio_set_flag(efx, MDIO_MMD_PHYXS, TXC_GPIO_OUTPUT, 1 << pin, on);
}
/* Set up the GPIO direction register */ void falcon_txc_set_gpio_dir(struct ef4_nic *efx, int pin, int dir)
{
ef4_mdio_set_flag(efx, MDIO_MMD_PHYXS, TXC_GPIO_DIR, 1 << pin, dir);
}
/* Reset the PMA/PMD MMD. The documentation is explicit that this does a
* global reset (it's less clear what reset of other MMDs does).*/ staticint txc_reset_phy(struct ef4_nic *efx)
{ int rc = ef4_mdio_reset_mmd(efx, MDIO_MMD_PMAPMD,
TXC_MAX_RESET_TIME / TXC_RESET_WAIT,
TXC_RESET_WAIT); if (rc < 0) goto fail;
/* Check that all the MMDs we expect are present and responding. */
rc = ef4_mdio_check_mmds(efx, TXC_REQUIRED_DEVS); if (rc < 0) goto fail;
/* Run a single BIST on one MMD */ staticint txc_bist_one(struct ef4_nic *efx, int mmd, int test)
{ int ctrl, bctl; int lane; int rc = 0;
/* Set PMA to test into loopback using Mt Diablo reg as per app note */
ctrl = ef4_mdio_read(efx, MDIO_MMD_PCS, TXC_MTDIABLO_CTRL);
ctrl |= (1 << TXC_MTDIABLO_CTRL_PMA_LOOP_LBN);
ef4_mdio_write(efx, MDIO_MMD_PCS, TXC_MTDIABLO_CTRL, ctrl);
/* The BIST app. note lists these as 3 distinct steps. */ /* Set the BIST type */
bctl = (test << TXC_BIST_CTRL_TYPE_LBN);
ef4_mdio_write(efx, mmd, TXC_BIST_CTL, bctl);
/* Set the BSTEN bit in the BIST Control register to enable */
bctl |= (1 << TXC_BIST_CTRL_ENAB_LBN);
ef4_mdio_write(efx, mmd, TXC_BIST_CTL, bctl);
/* Set the BSTRT bit in the BIST Control register */
ef4_mdio_write(efx, mmd, TXC_BIST_CTL,
bctl | (1 << TXC_BIST_CTRL_STRT_LBN));
/* Wait. */
udelay(TXC_BIST_DURATION);
/* Set the BSTOP bit in the BIST Control register */
bctl |= (1 << TXC_BIST_CTRL_STOP_LBN);
ef4_mdio_write(efx, mmd, TXC_BIST_CTL, bctl);
/* The STOP bit should go off when things have stopped */ while (bctl & (1 << TXC_BIST_CTRL_STOP_LBN))
bctl = ef4_mdio_read(efx, mmd, TXC_BIST_CTL);
/* Check all the error counts are 0 and all the frame counts are
non-zero */ for (lane = 0; lane < 4; lane++) { int count = ef4_mdio_read(efx, mmd, TXC_BIST_RX0ERRCNT + lane); if (count != 0) {
netif_err(efx, hw, efx->net_dev, TXCNAME": BIST error. " "Lane %d had %d errs\n", lane, count);
rc = -EIO;
}
count = ef4_mdio_read(efx, mmd, TXC_BIST_RX0FRMCNT + lane); if (count == 0) {
netif_err(efx, hw, efx->net_dev, TXCNAME": BIST error. " "Lane %d got 0 frames\n", lane);
rc = -EIO;
}
}
if (rc == 0)
netif_info(efx, hw, efx->net_dev, TXCNAME": BIST pass\n");
/* Push the non-configurable defaults into the PHY. This must be
* done after every full reset */ staticvoid txc_apply_defaults(struct ef4_nic *efx)
{ int mctrl;
/* Turn amplitude down and preemphasis off on the host side * (PHY<->MAC) as this is believed less likely to upset Falcon * and no adverse effects have been noted. It probably also
* saves a picowatt or two */
/* Turn down the amplitude */
ef4_mdio_write(efx, MDIO_MMD_PHYXS,
TXC_ALRGS_ATXAMP0, TXC_ATXAMP_0820_BOTH);
ef4_mdio_write(efx, MDIO_MMD_PHYXS,
TXC_ALRGS_ATXAMP1, TXC_ATXAMP_0820_BOTH);
/* Set the line side amplitude and preemphasis to the databook * defaults as an erratum causes them to be 0 on at least some
* PHY rev.s */
ef4_mdio_write(efx, MDIO_MMD_PMAPMD,
TXC_ALRGS_ATXPRE0, TXC_ATXPRE_DEFAULT);
ef4_mdio_write(efx, MDIO_MMD_PMAPMD,
TXC_ALRGS_ATXPRE1, TXC_ATXPRE_DEFAULT);
ef4_mdio_write(efx, MDIO_MMD_PMAPMD,
TXC_ALRGS_ATXAMP0, TXC_ATXAMP_DEFAULT);
ef4_mdio_write(efx, MDIO_MMD_PMAPMD,
TXC_ALRGS_ATXAMP1, TXC_ATXAMP_DEFAULT);
/* Set up the LEDs */
mctrl = ef4_mdio_read(efx, MDIO_MMD_PHYXS, TXC_MRGS_CTL);
/* Set the Green and Red LEDs to their default modes */
mctrl &= ~((1 << TXC_MCTL_TXLED_LBN) | (1 << TXC_MCTL_RXLED_LBN));
ef4_mdio_write(efx, MDIO_MMD_PHYXS, TXC_MRGS_CTL, mctrl);
/* Databook recommends doing this after configuration changes */
txc_reset_logic(efx);
/* Initialisation entry point for this PHY driver */ staticint txc43128_phy_init(struct ef4_nic *efx)
{ int rc;
rc = txc_reset_phy(efx); if (rc < 0) return rc;
rc = txc_bist(efx); if (rc < 0) return rc;
txc_apply_defaults(efx);
return 0;
}
/* Set the lane power down state in the global registers */ staticvoid txc_glrgs_lane_power(struct ef4_nic *efx, int mmd)
{ int pd = (1 << TXC_GLCMD_L01PD_LBN) | (1 << TXC_GLCMD_L23PD_LBN); int ctl = ef4_mdio_read(efx, mmd, TXC_GLRGS_GLCMD);
/* Set the lane power down state in the analog control registers */ staticvoid txc_analog_lane_power(struct ef4_nic *efx, int mmd)
{ int txpd = (1 << TXC_ATXCTL_TXPD3_LBN) | (1 << TXC_ATXCTL_TXPD2_LBN)
| (1 << TXC_ATXCTL_TXPD1_LBN) | (1 << TXC_ATXCTL_TXPD0_LBN); int rxpd = (1 << TXC_ARXCTL_RXPD3_LBN) | (1 << TXC_ARXCTL_RXPD2_LBN)
| (1 << TXC_ARXCTL_RXPD1_LBN) | (1 << TXC_ARXCTL_RXPD0_LBN); int txctl = ef4_mdio_read(efx, mmd, TXC_ALRGS_ATXCTL); int rxctl = ef4_mdio_read(efx, mmd, TXC_ALRGS_ARXCTL);
staticvoid txc_set_power(struct ef4_nic *efx)
{ /* According to the data book, all the MMDs can do low power */
ef4_mdio_set_mmds_lpower(efx,
!!(efx->phy_mode & PHY_MODE_LOW_POWER),
TXC_REQUIRED_DEVS);
/* Global register bank is in PCS, PHY XS. These control the host
* side and line side settings respectively. */
txc_glrgs_lane_power(efx, MDIO_MMD_PCS);
txc_glrgs_lane_power(efx, MDIO_MMD_PHYXS);
/* Analog register bank in PMA/PMD, PHY XS */
txc_analog_lane_power(efx, MDIO_MMD_PMAPMD);
txc_analog_lane_power(efx, MDIO_MMD_PHYXS);
}
staticvoid txc_reset_logic_mmd(struct ef4_nic *efx, int mmd)
{ int val = ef4_mdio_read(efx, mmd, TXC_GLRGS_GLCMD); int tries = 50;
val |= (1 << TXC_GLCMD_LMTSWRST_LBN);
ef4_mdio_write(efx, mmd, TXC_GLRGS_GLCMD, val); while (--tries) {
val = ef4_mdio_read(efx, mmd, TXC_GLRGS_GLCMD); if (!(val & (1 << TXC_GLCMD_LMTSWRST_LBN))) break;
udelay(1);
} if (!tries)
netif_info(efx, hw, efx->net_dev,
TXCNAME " Logic reset timed out!\n");
}
/* Perform a logic reset. This preserves the configuration registers
* and is needed for some configuration changes to take effect */ staticvoid txc_reset_logic(struct ef4_nic *efx)
{ /* The data sheet claims we can do the logic reset on either the * PCS or the PHYXS and the result is a reset of both host- and
* line-side logic. */
txc_reset_logic_mmd(efx, MDIO_MMD_PCS);
}
ef4_mdio_transmit_disable(efx);
ef4_mdio_phy_reconfigure(efx); if (mode_change & PHY_MODE_LOW_POWER)
txc_set_power(efx);
/* The data sheet claims this is required after every reconfiguration * (note at end of 7.1), but we mustn't do it when nothing changes as * it glitches the link, and reconfigure gets called on link change,
* so we get an IRQ storm on link up. */ if (loop_change || mode_change)
txc_reset_logic(efx);
/* Periodic callback: this exists mainly to poll link status as we
* don't use LASI interrupts */ staticbool txc43128_phy_poll(struct ef4_nic *efx)
{ struct txc43128_data *data = efx->phy_data; bool was_up = efx->link_state.up;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.