Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/mii/mcommphy.c
| Show First 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | |||||
| #define PHY_SLEEP_CONTROL1_REG 0x27 | #define PHY_SLEEP_CONTROL1_REG 0x27 | ||||
| #define PLLON_IN_SLP 0x4000 | #define PLLON_IN_SLP 0x4000 | ||||
| /* Registers and values for YT8531 */ | /* Registers and values for YT8531 */ | ||||
| #define YT8531_CHIP_CONFIG 0xa001 | #define YT8531_CHIP_CONFIG 0xa001 | ||||
| #define RXC_DLY_EN (1 << 8) | #define RXC_DLY_EN (1 << 8) | ||||
| #define YT8531_PAD_DRSTR_CFG 0xa010 | #define YT8531_PAD_DRSTR_CFG 0xa010 | ||||
| #define PAD_RXC_MASK 0x7 | #define PAD_RXCLK_MASK 0x7 | ||||
| #define PAD_RXC_SHIFT 13 | #define PAD_RXCLK_SHIFT 13 | ||||
| #define JH7110_RGMII_RXC_STRENGTH 6 | #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 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 RX_DELAY_SEL_MASK 0xf | ||||
| #define RXC_DLY_THRESH 2250 | #define RX_DELAY_SEL_SHIFT 10 | ||||
| #define RXC_DLY_ADDON 1900 | #define RXC_DLY_ADDON 1900 | ||||
| #define TX_DELAY_SEL_FE_MASK 0xf | #define TX_DELAY_MAX 2250 | ||||
| #define TX_DELAY_SEL_FE_SHIFT 4 | |||||
| #define TX_DELAY_SEL_MASK 0xf | #define TX_DELAY_SEL_MASK 0xf | ||||
| #define TX_DELAY_SEL_SHIFT 0 | #define TX_DELAY_SEL_SHIFT 0 | ||||
| #define TX_CLK_SEL (1 << 14) | #define TX_CLK_SEL (1 << 14) | ||||
| #define INTERNAL_DLY_DIV 150 | #define INTERNAL_DLY_DIV 150 | ||||
| #define YT8531_SYNCE_CFG 0xa012 | #define YT8531_SYNCE_CFG 0xa012 | ||||
| #define EN_SYNC_E (1 << 6) | #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 LOWEST_SET_BIT(mask) ((((mask) - 1) & (mask)) ^ (mask)) | ||||
| #define SHIFTIN(x, mask) ((x) * LOWEST_SET_BIT(mask)) | #define SHIFTIN(x, mask) ((x) * LOWEST_SET_BIT(mask)) | ||||
| static const struct mii_phydesc mcommphys[] = { | static const struct mii_phydesc mcommphys[] = { | ||||
| MII_PHY_DESC(MOTORCOMM, YT8511), | MII_PHY_DESC(MOTORCOMM, YT8511), | ||||
| MII_PHY_DESC(MOTORCOMM2, YT8531), | MII_PHY_DESC(MOTORCOMM2, YT8531), | ||||
| MII_PHY_END | MII_PHY_END | ||||
| }; | }; | ||||
| struct mcommphy_softc { | struct mcommphy_softc { | ||||
| mii_softc_t mii_sc; | mii_softc_t mii_sc; | ||||
| device_t dev; | device_t dev; | ||||
| mii_contype_t phy_mode; | |||||
| u_int rx_delay_ps; | u_int rx_delay_ps; | ||||
| u_int tx_delay_ps; | u_int tx_delay_ps; | ||||
| u_int rx_clk_drv; | |||||
| u_int rx_data_drv; | |||||
| bool tx_10_inv; | bool tx_10_inv; | ||||
| bool tx_100_inv; | bool tx_100_inv; | ||||
| bool tx_1000_inv; | bool tx_1000_inv; | ||||
| }; | }; | ||||
| static void mcommphy_yt8531_speed_adjustment(struct mii_softc *sc); | static void mcommphy_yt8531_speed_adjustment(struct mii_softc *sc); | ||||
| static int | static int | ||||
| ▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | |||||
| #ifdef FDT | #ifdef FDT | ||||
| static int | static int | ||||
| mcommphy_yt8531_setup_delay(struct mii_softc *sc) | mcommphy_yt8531_setup_delay(struct mii_softc *sc) | ||||
| { | { | ||||
| struct mcommphy_softc *mcomm_sc = (struct mcommphy_softc *)sc; | struct mcommphy_softc *mcomm_sc = (struct mcommphy_softc *)sc; | ||||
| uint16_t reg, oldaddr; | uint16_t reg, oldaddr; | ||||
| int rx_delay = 0, tx_delay = 0; | int rx_delay = 0, tx_delay = 0; | ||||
| bool rxc_dly_en_off = false; | bool rxc_dly_en = true; | ||||
| if (mcomm_sc->rx_delay_ps > RXC_DLY_THRESH) { | /* The first set of rx_delay values is divisible by three */ | ||||
| rx_delay = (mcomm_sc->rx_delay_ps - RXC_DLY_ADDON) / | if (mcomm_sc->phy_mode == MII_CONTYPE_RGMII_ID || | ||||
| INTERNAL_DLY_DIV; | mcomm_sc->phy_mode == MII_CONTYPE_RGMII_RXID) { | ||||
| } else if (mcomm_sc->rx_delay_ps > 0) { | if (mcomm_sc->rx_delay_ps % 3 == 0) { | ||||
| rxc_dly_en = false; | |||||
| rx_delay = mcomm_sc->rx_delay_ps / INTERNAL_DLY_DIV; | rx_delay = mcomm_sc->rx_delay_ps / INTERNAL_DLY_DIV; | ||||
| rxc_dly_en_off = true; | } else { | ||||
| rx_delay = (mcomm_sc->rx_delay_ps - RXC_DLY_ADDON) | |||||
| / INTERNAL_DLY_DIV; | |||||
| } | } | ||||
| } | |||||
| if (mcomm_sc->tx_delay_ps > 0) { | /* 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; | 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); | 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 */ | /* Modifying Chip Config register */ | ||||
| PHY_WRITE(sc, EXT_REG_ADDR, YT8531_CHIP_CONFIG); | PHY_WRITE(sc, EXT_REG_ADDR, YT8531_CHIP_CONFIG); | ||||
| reg = PHY_READ(sc, EXT_REG_DATA); | reg = PHY_READ(sc, EXT_REG_DATA); | ||||
| if (rxc_dly_en_off) | if (rxc_dly_en == true) | ||||
| reg &= ~(RXC_DLY_EN); | reg |= RXC_DLY_EN; | ||||
| else | |||||
| reg &= ~RXC_DLY_EN; | |||||
| PHY_WRITE(sc, EXT_REG_DATA, reg); | PHY_WRITE(sc, EXT_REG_DATA, reg); | ||||
| /* Modifying RGMII Config1 register */ | /* Modifying RGMII Config1 register */ | ||||
| PHY_WRITE(sc, EXT_REG_ADDR, YT8531_RGMII_CONFIG1); | PHY_WRITE(sc, EXT_REG_ADDR, YT8531_RGMII_CONFIG1); | ||||
| reg = PHY_READ(sc, EXT_REG_DATA); | reg = PHY_READ(sc, EXT_REG_DATA); | ||||
| reg &= ~(RX_DELAY_SEL_MASK << RX_DELAY_SEL_SHIFT); | reg &= ~(RX_DELAY_SEL_MASK << RX_DELAY_SEL_SHIFT); | ||||
| reg |= rx_delay << RX_DELAY_SEL_SHIFT; | reg |= rx_delay << RX_DELAY_SEL_SHIFT; | ||||
| reg &= ~(TX_DELAY_SEL_MASK << TX_DELAY_SEL_SHIFT); | reg &= ~(TX_DELAY_SEL_MASK << TX_DELAY_SEL_SHIFT); | ||||
| reg |= tx_delay << TX_DELAY_SEL_SHIFT; | reg |= tx_delay << TX_DELAY_SEL_SHIFT; | ||||
| PHY_WRITE(sc, EXT_REG_DATA, reg); | PHY_WRITE(sc, EXT_REG_DATA, reg); | ||||
| PHY_WRITE(sc, EXT_REG_ADDR, oldaddr); | PHY_WRITE(sc, EXT_REG_ADDR, oldaddr); | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| #endif | #endif | ||||
| static int | 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) | 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); | oldaddr = PHY_READ(sc, EXT_REG_ADDR); | ||||
| /* Modifying Pad Drive Strength register */ | /* 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); | PHY_WRITE(sc, EXT_REG_ADDR, YT8531_PAD_DRSTR_CFG); | ||||
| reg = PHY_READ(sc, EXT_REG_DATA); | 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); | PHY_WRITE(sc, EXT_REG_DATA, reg); | ||||
| /* Modifying SyncE Config register */ | /* Modifying SyncE Config register */ | ||||
| PHY_WRITE(sc, EXT_REG_ADDR, YT8531_SYNCE_CFG); | PHY_WRITE(sc, EXT_REG_ADDR, YT8531_SYNCE_CFG); | ||||
| reg = PHY_READ(sc, EXT_REG_DATA); | reg = PHY_READ(sc, EXT_REG_DATA); | ||||
| reg &= ~(EN_SYNC_E); | reg &= ~(EN_SYNC_E); | ||||
| PHY_WRITE(sc, EXT_REG_DATA, reg); | PHY_WRITE(sc, EXT_REG_DATA, reg); | ||||
| Show All 11 Lines | |||||
| static void | static void | ||||
| mcommphy_fdt_get_config(struct mcommphy_softc *sc) | mcommphy_fdt_get_config(struct mcommphy_softc *sc) | ||||
| { | { | ||||
| mii_fdt_phy_config_t *cfg; | mii_fdt_phy_config_t *cfg; | ||||
| pcell_t val; | pcell_t val; | ||||
| cfg = mii_fdt_get_config(sc->dev); | 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")) | if (OF_hasprop(cfg->phynode, "motorcomm,tx-clk-10-inverted")) | ||||
| sc->tx_10_inv = true; | sc->tx_10_inv = true; | ||||
| if (OF_hasprop(cfg->phynode, "motorcomm,tx-clk-100-inverted")) | if (OF_hasprop(cfg->phynode, "motorcomm,tx-clk-100-inverted")) | ||||
| sc->tx_100_inv = true; | sc->tx_100_inv = true; | ||||
| if (OF_hasprop(cfg->phynode, "motorcomm,tx-clk-1000-inverted")) | if (OF_hasprop(cfg->phynode, "motorcomm,tx-clk-1000-inverted")) | ||||
| sc->tx_1000_inv = true; | sc->tx_1000_inv = true; | ||||
| /* Grab raw delay values (picoseconds); adjusted later. */ | /* Grab raw delay values (picoseconds); adjusted later. */ | ||||
| if (OF_getencprop(cfg->phynode, "rx-internal-delay-ps", &val, | if (OF_getencprop(cfg->phynode, "rx-internal-delay-ps", &val, | ||||
| sizeof(val)) > 0) { | sizeof(val)) > 0) { | ||||
| sc->rx_delay_ps = val; | sc->rx_delay_ps = val; | ||||
| } | } | ||||
| if (OF_getencprop(cfg->phynode, "tx-internal-delay-ps", &val, | if (OF_getencprop(cfg->phynode, "tx-internal-delay-ps", &val, | ||||
| sizeof(val)) > 0) { | sizeof(val)) > 0) { | ||||
| sc->tx_delay_ps = val; | 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); | mii_fdt_free_config(cfg); | ||||
| } | } | ||||
| #endif | #endif | ||||
| static int | static int | ||||
| mcommphy_attach(device_t dev) | mcommphy_attach(device_t dev) | ||||
| ▲ Show 20 Lines • Show All 57 Lines • Show Last 20 Lines | |||||