diff --git a/sys/dev/mii/mcommphy.c b/sys/dev/mii/mcommphy.c --- a/sys/dev/mii/mcommphy.c +++ b/sys/dev/mii/mcommphy.c @@ -76,17 +76,29 @@ #define RXC_DLY_EN (1 << 8) #define YT8531_PAD_DRSTR_CFG 0xa010 -#define PAD_RXC_MASK 0x7 -#define PAD_RXC_SHIFT 13 -#define JH7110_RGMII_RXC_STRENGTH 6 +#define PAD_RXCLK_MASK 0x7 +#define PAD_RXCLK_SHIFT 13 +#define PAD_VOL_DEFAULT 0x3 +#define PAD_VOL_MASK 0x30 +#define PAD_VOL_SHIFT 4 +#define PAD_VOL_1V8_MARKER 0x2 +#define PAD_VOLTABLE_LEN 8 +#define PAD_RXDATA_DRV_PROP_HI_MASK 0x4 +#define PAD_RXDATA_DRV_PROP_LOW_MASK 0x3 +#define PAD_RXDATA_DRV_HI_SHIFT 10 +#define PAD_RXDATA_DRV_LOW_SHIFT 4 +#define PAD_RXDATA_MASK (PAD_RXDATA_DRV_PROP_HI_MASK << \ + PAD_RXDATA_DRV_HI_SHIFT | \ + PAD_RXDATA_DRV_PROP_LOW_MASK << \ + PAD_RXDATA_DRV_LOW_SHIFT) #define YT8531_RGMII_CONFIG1 0xa003 -#define RX_DELAY_SEL_SHIFT 10 +#define RXTX_DELAY_DEFAULT 13 +#define RX_DELAY_MAX 4150 #define RX_DELAY_SEL_MASK 0xf -#define RXC_DLY_THRESH 2250 +#define RX_DELAY_SEL_SHIFT 10 #define RXC_DLY_ADDON 1900 -#define TX_DELAY_SEL_FE_MASK 0xf -#define TX_DELAY_SEL_FE_SHIFT 4 +#define TX_DELAY_MAX 2250 #define TX_DELAY_SEL_MASK 0xf #define TX_DELAY_SEL_SHIFT 0 #define TX_CLK_SEL (1 << 14) @@ -95,6 +107,14 @@ #define YT8531_SYNCE_CFG 0xa012 #define EN_SYNC_E (1 << 6) +#define DEFAULT_PHY_MODE MII_CONTYPE_RGMII_ID + +static const int yt8531_1v8_voltable[] = {1200, 2100, 2700, 2910, 3110, 3600, + 3970, 4350}; + +static const int yt8531_3v3_voltable[] = {3070, 4080, 4370, 4680, 5020, 5450, + 5740, 6140}; + #define LOWEST_SET_BIT(mask) ((((mask) - 1) & (mask)) ^ (mask)) #define SHIFTIN(x, mask) ((x) * LOWEST_SET_BIT(mask)) @@ -107,8 +127,11 @@ struct mcommphy_softc { mii_softc_t mii_sc; device_t dev; + mii_contype_t phy_mode; u_int rx_delay_ps; u_int tx_delay_ps; + u_int rx_clk_drv; + u_int rx_data_drv; bool tx_10_inv; bool tx_100_inv; bool tx_1000_inv; @@ -250,27 +273,58 @@ struct mcommphy_softc *mcomm_sc = (struct mcommphy_softc *)sc; uint16_t reg, oldaddr; int rx_delay = 0, tx_delay = 0; - bool rxc_dly_en_off = false; - - if (mcomm_sc->rx_delay_ps > RXC_DLY_THRESH) { - rx_delay = (mcomm_sc->rx_delay_ps - RXC_DLY_ADDON) / - INTERNAL_DLY_DIV; - } else if (mcomm_sc->rx_delay_ps > 0) { - rx_delay = mcomm_sc->rx_delay_ps / INTERNAL_DLY_DIV; - rxc_dly_en_off = true; + bool rxc_dly_en = true; + + /* The first set of rx_delay values is divisible by three */ + if (mcomm_sc->phy_mode == MII_CONTYPE_RGMII_ID || + mcomm_sc->phy_mode == MII_CONTYPE_RGMII_RXID) { + if (mcomm_sc->rx_delay_ps % 3 == 0) { + rxc_dly_en = false; + rx_delay = mcomm_sc->rx_delay_ps / INTERNAL_DLY_DIV; + } else { + rx_delay = (mcomm_sc->rx_delay_ps - RXC_DLY_ADDON) + / INTERNAL_DLY_DIV; + } + } + + /* Checking that rx_delay value is in either range */ + if ((mcomm_sc->rx_delay_ps % INTERNAL_DLY_DIV != 0 && + (mcomm_sc->rx_delay_ps - RXC_DLY_ADDON) % INTERNAL_DLY_DIV != 0) || + mcomm_sc->rx_delay_ps > RX_DELAY_MAX) { + device_printf(mcomm_sc->dev, + "warning: invalid rx_delay val: %u\n", + mcomm_sc->rx_delay_ps); + rx_delay = RXTX_DELAY_DEFAULT; + } + + if (mcomm_sc->phy_mode == MII_CONTYPE_RGMII_ID || + mcomm_sc->phy_mode == MII_CONTYPE_RGMII_TXID) { + if (mcomm_sc->tx_delay_ps > 0) + tx_delay = mcomm_sc->tx_delay_ps / INTERNAL_DLY_DIV; } - if (mcomm_sc->tx_delay_ps > 0) { - tx_delay = mcomm_sc->tx_delay_ps / INTERNAL_DLY_DIV; + /* Checking that tx_delay value is in the range */ + if ((mcomm_sc->tx_delay_ps % INTERNAL_DLY_DIV != 0) || + mcomm_sc->tx_delay_ps > TX_DELAY_MAX) { + device_printf(mcomm_sc->dev, + "warning: invalid tx_delay val: %u\n", + mcomm_sc->tx_delay_ps); + tx_delay = RXTX_DELAY_DEFAULT; } oldaddr = PHY_READ(sc, EXT_REG_ADDR); + if (mcomm_sc->phy_mode == MII_CONTYPE_RGMII || + mcomm_sc->phy_mode == MII_CONTYPE_RGMII_TXID) + rxc_dly_en = false; + /* Modifying Chip Config register */ PHY_WRITE(sc, EXT_REG_ADDR, YT8531_CHIP_CONFIG); reg = PHY_READ(sc, EXT_REG_DATA); - if (rxc_dly_en_off) - reg &= ~(RXC_DLY_EN); + if (rxc_dly_en == true) + reg |= RXC_DLY_EN; + else + reg &= ~RXC_DLY_EN; PHY_WRITE(sc, EXT_REG_DATA, reg); /* Modifying RGMII Config1 register */ @@ -288,18 +342,50 @@ } #endif +static int +mcommphy_yt8531_fetch_dsvol(struct mcommphy_softc *mcomm_sc, + uint16_t vol, u_int microamp) +{ + if (vol >= PAD_VOL_1V8_MARKER) { + for (int i = 0; i != PAD_VOLTABLE_LEN; i++) { + if (yt8531_1v8_voltable[i] == microamp) + return (i); + } + } else { + for (int i = 0; i != PAD_VOLTABLE_LEN; i++) { + if (yt8531_3v3_voltable[i] == microamp) + return (i); + } + } + device_printf(mcomm_sc->dev, "warning: invalid RX pad strength value"); + + return (PAD_VOL_DEFAULT); +} + static int mcommphy_yt8531_setup(struct mii_softc *sc) { - uint16_t reg, oldaddr; + struct mcommphy_softc *mcomm_sc = (struct mcommphy_softc *)sc; + uint16_t reg, val, vol, oldaddr; oldaddr = PHY_READ(sc, EXT_REG_ADDR); /* Modifying Pad Drive Strength register */ + PHY_WRITE(sc, EXT_REG_ADDR, YT8531_CHIP_CONFIG); + vol = (PHY_READ(sc, EXT_REG_DATA) & PAD_VOL_MASK) >> PAD_VOL_SHIFT; + PHY_WRITE(sc, EXT_REG_ADDR, YT8531_PAD_DRSTR_CFG); reg = PHY_READ(sc, EXT_REG_DATA); - reg &= ~(PAD_RXC_MASK << PAD_RXC_SHIFT); - reg |= (JH7110_RGMII_RXC_STRENGTH << PAD_RXC_SHIFT); + + reg &= ~(PAD_RXCLK_MASK << PAD_RXCLK_SHIFT); + val = mcommphy_yt8531_fetch_dsvol(mcomm_sc, vol, mcomm_sc->rx_clk_drv); + reg |= (val << PAD_RXCLK_SHIFT); + + reg &= ~(PAD_RXDATA_MASK); + val = mcommphy_yt8531_fetch_dsvol(mcomm_sc, vol, mcomm_sc->rx_data_drv); + reg |= (val & PAD_RXDATA_DRV_PROP_HI_MASK) << PAD_RXDATA_DRV_HI_SHIFT | + (val & PAD_RXDATA_DRV_PROP_LOW_MASK) << PAD_RXDATA_DRV_LOW_SHIFT; + PHY_WRITE(sc, EXT_REG_DATA, reg); /* Modifying SyncE Config register */ @@ -327,6 +413,13 @@ cfg = mii_fdt_get_config(sc->dev); + sc->phy_mode = mii_fdt_get_contype(cfg->macnode); + if (sc->phy_mode < MII_CONTYPE_RGMII || + sc->phy_mode > MII_CONTYPE_RGMII_TXID) { + device_printf(sc->dev, "warning: unsupported phy-mode\n"); + sc->phy_mode = DEFAULT_PHY_MODE; + } + if (OF_hasprop(cfg->phynode, "motorcomm,tx-clk-10-inverted")) sc->tx_10_inv = true; if (OF_hasprop(cfg->phynode, "motorcomm,tx-clk-100-inverted")) @@ -344,6 +437,16 @@ sc->tx_delay_ps = val; } + /* Grab data for RGMII drive pad strength (microamperes) */ + if (OF_getencprop(cfg->phynode, "motorcomm,rx-clk-drv-microamp", &val, + sizeof(val)) > 0) { + sc->rx_clk_drv = val; + } + if (OF_getencprop(cfg->phynode, "motorcomm,rx-data-drv-microamp", &val, + sizeof(val)) > 0) { + sc->rx_data_drv = val; + } + mii_fdt_free_config(cfg); } #endif