Merge branch 'master' of git://git.denx.de/u-boot-net

- Various PHY fixes / enhancements.
- TI K2G fixes
This commit is contained in:
Tom Rini 2019-05-08 22:46:31 -04:00
commit eb511984e9
18 changed files with 287 additions and 187 deletions

View File

@ -44,28 +44,28 @@
reg = <0x1>;
interrupt-parent = <&pioB>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
txen-skew-ps = <800>;
txc-skew-ps = <3000>;
rxdv-skew-ps = <400>;
rxc-skew-ps = <3000>;
rxd0-skew-ps = <400>;
rxd1-skew-ps = <400>;
rxd2-skew-ps = <400>;
rxd3-skew-ps = <400>;
txen-skew-ps = <480>;
txc-skew-ps = <1800>;
rxdv-skew-ps = <240>;
rxc-skew-ps = <1800>;
rxd0-skew-ps = <240>;
rxd1-skew-ps = <240>;
rxd2-skew-ps = <240>;
rxd3-skew-ps = <240>;
};
ethernet-phy@7 {
reg = <0x7>;
interrupt-parent = <&pioB>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
txen-skew-ps = <800>;
txc-skew-ps = <3000>;
rxdv-skew-ps = <400>;
rxc-skew-ps = <3000>;
rxd0-skew-ps = <400>;
rxd1-skew-ps = <400>;
rxd2-skew-ps = <400>;
rxd3-skew-ps = <400>;
txen-skew-ps = <480>;
txc-skew-ps = <1800>;
rxdv-skew-ps = <240>;
rxc-skew-ps = <1800>;
rxd0-skew-ps = <240>;
rxd1-skew-ps = <240>;
rxd2-skew-ps = <240>;
rxd3-skew-ps = <240>;
};
};
};

View File

@ -43,28 +43,28 @@
reg = <0x1>;
interrupt-parent = <&pioB>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
txen-skew-ps = <800>;
txc-skew-ps = <3000>;
rxdv-skew-ps = <400>;
rxc-skew-ps = <3000>;
rxd0-skew-ps = <400>;
rxd1-skew-ps = <400>;
rxd2-skew-ps = <400>;
rxd3-skew-ps = <400>;
txen-skew-ps = <480>;
txc-skew-ps = <1800>;
rxdv-skew-ps = <240>;
rxc-skew-ps = <1800>;
rxd0-skew-ps = <240>;
rxd1-skew-ps = <240>;
rxd2-skew-ps = <240>;
rxd3-skew-ps = <240>;
};
ethernet-phy@7 {
reg = <0x7>;
interrupt-parent = <&pioB>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
txen-skew-ps = <800>;
txc-skew-ps = <3000>;
rxdv-skew-ps = <400>;
rxc-skew-ps = <3000>;
rxd0-skew-ps = <400>;
rxd1-skew-ps = <400>;
rxd2-skew-ps = <400>;
rxd3-skew-ps = <400>;
txen-skew-ps = <480>;
txc-skew-ps = <1800>;
rxdv-skew-ps = <240>;
rxc-skew-ps = <1800>;
rxd0-skew-ps = <240>;
rxd1-skew-ps = <240>;
rxd2-skew-ps = <240>;
rxd3-skew-ps = <240>;
};
};

View File

@ -67,9 +67,9 @@
rxd2-skew-ps = <0>;
rxd3-skew-ps = <0>;
txen-skew-ps = <0>;
txc-skew-ps = <2600>;
txc-skew-ps = <1560>;
rxdv-skew-ps = <0>;
rxc-skew-ps = <2000>;
rxc-skew-ps = <1200>;
};
&gpio0 {

View File

@ -43,9 +43,9 @@
rxd2-skew-ps = <0>;
rxd3-skew-ps = <0>;
txen-skew-ps = <0>;
txc-skew-ps = <2600>;
txc-skew-ps = <1560>;
rxdv-skew-ps = <0>;
rxc-skew-ps = <2000>;
rxc-skew-ps = <1200>;
};
&gpio1 {

View File

@ -71,9 +71,9 @@
rxd2-skew-ps = <0>;
rxd3-skew-ps = <0>;
txen-skew-ps = <0>;
txc-skew-ps = <2600>;
txc-skew-ps = <1560>;
rxdv-skew-ps = <0>;
rxc-skew-ps = <2000>;
rxc-skew-ps = <1200>;
};
&gpio0 {

View File

@ -128,9 +128,9 @@
rxd2-skew-ps = <0>;
rxd3-skew-ps = <0>;
txen-skew-ps = <0>;
txc-skew-ps = <2600>;
txc-skew-ps = <1560>;
rxdv-skew-ps = <0>;
rxc-skew-ps = <2000>;
rxc-skew-ps = <1200>;
};
&gpio0 { /* GPIO 0..29 */

View File

@ -85,9 +85,9 @@
rxd2-skew-ps = <0>;
rxd3-skew-ps = <0>;
txen-skew-ps = <0>;
txc-skew-ps = <2600>;
txc-skew-ps = <1560>;
rxdv-skew-ps = <0>;
rxc-skew-ps = <2000>;
rxc-skew-ps = <1200>;
};
};
};

View File

@ -126,22 +126,22 @@ struct pin_cfg k2g_evm_pin_cfg[] = {
{ 71, MODE(0) }, /* MMC1POW TP124 */
/* EMAC */
{ 79, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD1 */
{ 78, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD2 */
{ 77, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD3 */
{ 80, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD0 */
{ 94, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD0 */
{ 93, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD1 */
{ 92, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD2 */
{ 91, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD3 */
{ 85, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXC */
{ 95, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXCTL */
{ 72, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXC */
{ 77, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD3 */
{ 78, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD2 */
{ 79, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD1 */
{ 80, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD0 */
{ 81, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXCTL */
{ 85, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXC */
{ 91, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD3 */
{ 92, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD2 */
{ 93, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD1 */
{ 94, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD0 */
{ 95, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXCTL */
/* MDIO */
{ 99, BUFFER_CLASS_B | PIN_PDIS | MODE(0) }, /* MDIO_CLK */
{ 98, BUFFER_CLASS_B | PIN_PDIS | MODE(0) }, /* MDIO_DATA */
{ 99, BUFFER_CLASS_B | PIN_PDIS | MODE(0) }, /* MDIO_CLK */
/* PWM */
{ 73, MODE(4) }, /* SOC_EHRPWM3A */
@ -350,22 +350,22 @@ struct pin_cfg k2g_ice_evm_pin_cfg[] = {
{ 135, MODE(0) }, /* SOC_QSPI_CSN0 */
/* EMAC */
{ 79, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD1 */
{ 78, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD2 */
{ 77, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD3 */
{ 80, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD0 */
{ 94, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD0 */
{ 93, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD1 */
{ 92, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD2 */
{ 91, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD3 */
{ 85, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXC */
{ 95, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXCTL */
{ 72, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXC */
{ 77, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD3 */
{ 78, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD2 */
{ 79, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD1 */
{ 80, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXD0 */
{ 81, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_RXCTL */
{ 85, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXC */
{ 91, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD3 */
{ 92, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD2 */
{ 93, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD1 */
{ 94, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXD0 */
{ 95, BUFFER_CLASS_D | PIN_PDIS | MODE(1) }, /* RGMII_TXCTL */
/* MDIO */
{ 99, BUFFER_CLASS_B | PIN_PDIS | MODE(0) }, /* MDIO_CLK */
{ 98, BUFFER_CLASS_B | PIN_PDIS | MODE(0) }, /* MDIO_DATA */
{ 99, BUFFER_CLASS_B | PIN_PDIS | MODE(0) }, /* MDIO_CLK */
{ MAX_PIN_N, }
};

View File

@ -39,21 +39,24 @@ static int extract_range(char *input, int *plo, int *phi)
return 0;
}
static int mdio_write_ranges(struct phy_device *phydev, struct mii_dev *bus,
static int mdio_write_ranges(struct mii_dev *bus,
int addrlo,
int addrhi, int devadlo, int devadhi,
int reglo, int reghi, unsigned short data,
int extended)
{
struct phy_device *phydev;
int addr, devad, reg;
int err = 0;
for (addr = addrlo; addr <= addrhi; addr++) {
phydev = bus->phymap[addr];
for (devad = devadlo; devad <= devadhi; devad++) {
for (reg = reglo; reg <= reghi; reg++) {
if (!extended)
err = bus->write(bus, addr, devad,
reg, data);
err = phy_write_mmd(phydev, devad,
reg, data);
else
err = phydev->drv->writeext(phydev,
addr, devad, reg, data);
@ -68,15 +71,17 @@ err_out:
return err;
}
static int mdio_read_ranges(struct phy_device *phydev, struct mii_dev *bus,
static int mdio_read_ranges(struct mii_dev *bus,
int addrlo,
int addrhi, int devadlo, int devadhi,
int reglo, int reghi, int extended)
{
int addr, devad, reg;
struct phy_device *phydev;
printf("Reading from bus %s\n", bus->name);
for (addr = addrlo; addr <= addrhi; addr++) {
phydev = bus->phymap[addr];
printf("PHY at address %x:\n", addr);
for (devad = devadlo; devad <= devadhi; devad++) {
@ -84,7 +89,7 @@ static int mdio_read_ranges(struct phy_device *phydev, struct mii_dev *bus,
int val;
if (!extended)
val = bus->read(bus, addr, devad, reg);
val = phy_read_mmd(phydev, devad, reg);
else
val = phydev->drv->readext(phydev, addr,
devad, reg);
@ -222,14 +227,14 @@ static int do_mdio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
bus = phydev->bus;
extended = 1;
} else {
return -1;
return CMD_RET_FAILURE;
}
if (!phydev->drv ||
(!phydev->drv->writeext && (op[0] == 'w')) ||
(!phydev->drv->readext && (op[0] == 'r'))) {
puts("PHY does not have extended functions\n");
return -1;
return CMD_RET_FAILURE;
}
}
}
@ -242,13 +247,13 @@ static int do_mdio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
if (pos > 1)
if (extract_reg_range(argv[pos--], &devadlo, &devadhi,
&reglo, &reghi))
return -1;
return CMD_RET_FAILURE;
default:
if (pos > 1)
if (extract_phy_range(&argv[2], pos - 1, &bus,
&phydev, &addrlo, &addrhi))
return -1;
return CMD_RET_FAILURE;
break;
}
@ -264,12 +269,12 @@ static int do_mdio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
switch (op[0]) {
case 'w':
mdio_write_ranges(phydev, bus, addrlo, addrhi, devadlo, devadhi,
mdio_write_ranges(bus, addrlo, addrhi, devadlo, devadhi,
reglo, reghi, data, extended);
break;
case 'r':
mdio_read_ranges(phydev, bus, addrlo, addrhi, devadlo, devadhi,
mdio_read_ranges(bus, addrlo, addrhi, devadlo, devadhi,
reglo, reghi, extended);
break;
}

View File

@ -14,6 +14,33 @@ KSZ9021:
value is 0, the maximum value is 1800, and it is incremented by 120ps
steps.
The KSZ9021 hardware supports a range of skew values from negative to
positive, where the specific range is property dependent. All values
specified in the devicetree are offset by the minimum value so they
can be represented as positive integers in the devicetree since it's
difficult to represent a negative number in the devictree.
The following 4-bit values table applies to all the skew properties:
Pad Skew Value Delay (ps) Devicetree Value
------------------------------------------------------
0000 -840ps 0
0001 -720ps 120
0010 -600ps 240
0011 -480ps 360
0100 -360ps 480
0101 -240ps 600
0110 -120ps 720
0111 0ps 840
1000 120ps 960
1001 240ps 1080
1010 360ps 1200
1011 480ps 1320
1100 600ps 1440
1101 720ps 1560
1110 840ps 1680
1111 960ps 1800
Optional properties:
- rxc-skew-ps : Skew control of RXC pad

View File

@ -1074,6 +1074,7 @@ int ldpaa_eth_init(int dpmac_id, phy_interface_t enet_if)
priv = (struct ldpaa_eth_priv *)malloc(sizeof(struct ldpaa_eth_priv));
if (!priv) {
printf("ldpaa_eth_priv malloc() failed\n");
free(net_dev);
return -ENOMEM;
}
memset(priv, 0, sizeof(struct ldpaa_eth_priv));

View File

@ -202,6 +202,26 @@ config RTL8211X_PHY_FORCE_MASTER
If unsure, say N.
config RTL8211F_PHY_FORCE_EEE_RXC_ON
bool "Ethernet PHY RTL8211F: do not stop receiving the xMII clock during LPI"
depends on PHY_REALTEK
default n
help
The IEEE 802.3az-2010 (EEE) standard provides a protocol to coordinate
transitions to/from a lower power consumption level (Low Power Idle
mode) based on link utilization. When no packets are being
transmitted, the system goes to Low Power Idle mode to save power.
Under particular circumstances this setting can cause issues where
the PHY is unable to transmit or receive any packet when in LPI mode.
The problem is caused when the PHY is configured to stop receiving
the xMII clock while it is signaling LPI. For some PHYs the bit
configuring this behavior is set by the Linux kernel, causing the
issue in U-Boot on reboot if the PHY retains the register value.
Default n, which means that the PHY state is not changed. To work
around the issues, change this setting to y.
config PHY_SMSC
bool "Microchip(SMSC) Ethernet PHYs support"

View File

@ -303,9 +303,14 @@ int aquantia_config(struct phy_device *phydev)
AQUANTIA_SYSTEM_INTERFACE_SR);
/* If SI is USXGMII then start USXGMII autoneg */
if ((val & AQUANTIA_SI_IN_USE_MASK) == AQUANTIA_SI_USXGMII) {
reg_val1 = phy_read(phydev, MDIO_MMD_PHYXS,
AQUANTIA_VENDOR_PROVISIONING_REG);
reg_val1 |= AQUANTIA_USX_AUTONEG_CONTROL_ENA;
phy_write(phydev, MDIO_MMD_PHYXS,
AQUANTIA_VENDOR_PROVISIONING_REG,
AQUANTIA_USX_AUTONEG_CONTROL_ENA);
reg_val1);
printf("%s: system interface USXGMII\n",
phydev->dev->name);
} else {

View File

@ -33,10 +33,14 @@
#define CTRL1000_CONFIG_MASTER (1 << 11)
#define CTRL1000_MANUAL_CONFIG (1 << 12)
#define KSZ9021_PS_TO_REG 120
/* KSZ9031 PHY Registers */
#define MII_KSZ9031_MMD_ACCES_CTRL 0x0d
#define MII_KSZ9031_MMD_REG_DATA 0x0e
#define KSZ9031_PS_TO_REG 60
static int ksz90xx_startup(struct phy_device *phydev)
{
unsigned phy_ctl;
@ -102,20 +106,28 @@ static const struct ksz90x1_reg_field ksz9031_clk_grp[] = {
};
static int ksz90x1_of_config_group(struct phy_device *phydev,
struct ksz90x1_ofcfg *ofcfg)
struct ksz90x1_ofcfg *ofcfg,
int ps_to_regval)
{
struct udevice *dev = phydev->dev;
struct phy_driver *drv = phydev->drv;
const int ps_to_regval = 60;
int val[4];
int i, changed = 0, offset, max;
u16 regval = 0;
ofnode node;
if (!drv || !drv->writeext)
return -EOPNOTSUPP;
/* Look for a PHY node under the Ethernet node */
node = dev_read_subnode(dev, "ethernet-phy");
if (!ofnode_valid(node)) {
/* No node found, look in the Ethernet node */
node = dev_ofnode(dev);
}
for (i = 0; i < ofcfg->grpsz; i++) {
val[i] = dev_read_u32_default(dev, ofcfg->grp[i].name, ~0);
val[i] = ofnode_read_u32_default(node, ofcfg->grp[i].name, ~0);
offset = ofcfg->grp[i].off;
if (val[i] == -1) {
/* Default register value for KSZ9021 */
@ -148,7 +160,8 @@ static int ksz9021_of_config(struct phy_device *phydev)
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(ofcfg); i++) {
ret = ksz90x1_of_config_group(phydev, &(ofcfg[i]));
ret = ksz90x1_of_config_group(phydev, &ofcfg[i],
KSZ9021_PS_TO_REG);
if (ret)
return ret;
}
@ -167,7 +180,8 @@ static int ksz9031_of_config(struct phy_device *phydev)
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(ofcfg); i++) {
ret = ksz90x1_of_config_group(phydev, &(ofcfg[i]));
ret = ksz90x1_of_config_group(phydev, &ofcfg[i],
KSZ9031_PS_TO_REG);
if (ret)
return ret;
}

View File

@ -462,6 +462,18 @@ static LIST_HEAD(phy_drivers);
int phy_init(void)
{
#ifdef CONFIG_NEEDS_MANUAL_RELOC
/*
* The pointers inside phy_drivers also needs to be updated incase of
* manual reloc, without which these points to some invalid
* pre reloc address and leads to invalid accesses, hangs.
*/
struct list_head *head = &phy_drivers;
head->next = (void *)head->next + gd->reloc_off;
head->prev = (void *)head->prev + gd->reloc_off;
#endif
#ifdef CONFIG_B53_SWITCH
phy_b53_init();
#endif
@ -549,6 +561,10 @@ int phy_register(struct phy_driver *drv)
drv->readext += gd->reloc_off;
if (drv->writeext)
drv->writeext += gd->reloc_off;
if (drv->read_mmd)
drv->read_mmd += gd->reloc_off;
if (drv->write_mmd)
drv->write_mmd += gd->reloc_off;
#endif
return 0;
}
@ -655,7 +671,10 @@ static struct phy_device *phy_device_create(struct mii_dev *bus, int addr,
dev->drv = get_phy_driver(dev, interface);
phy_probe(dev);
if (phy_probe(dev)) {
printf("%s, PHY probe failed\n", __func__);
return NULL;
}
if (addr >= 0 && addr < PHY_MAX_ADDR)
bus->phymap[addr] = dev;

View File

@ -12,6 +12,7 @@
#define PHY_RTL8211x_FORCE_MASTER BIT(1)
#define PHY_RTL8211E_PINE64_GIGABIT_FIX BIT(2)
#define PHY_RTL8211F_FORCE_EEE_RXC_ON BIT(3)
#define PHY_AUTONEGOTIATE_TIMEOUT 5000
@ -102,6 +103,15 @@ static int rtl8211e_probe(struct phy_device *phydev)
return 0;
}
static int rtl8211f_probe(struct phy_device *phydev)
{
#ifdef CONFIG_RTL8211F_PHY_FORCE_EEE_RXC_ON
phydev->flags |= PHY_RTL8211F_FORCE_EEE_RXC_ON;
#endif
return 0;
}
/* RealTek RTL8211x */
static int rtl8211x_config(struct phy_device *phydev)
{
@ -151,6 +161,14 @@ static int rtl8211f_config(struct phy_device *phydev)
{
u16 reg;
if (phydev->flags & PHY_RTL8211F_FORCE_EEE_RXC_ON) {
unsigned int reg;
reg = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
reg &= ~MDIO_PCS_CTRL1_CLKSTOP_EN;
phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, reg);
}
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
phy_write(phydev, MDIO_DEVAD_NONE,
@ -360,6 +378,7 @@ static struct phy_driver RTL8211F_driver = {
.uid = 0x1cc916,
.mask = 0xffffff,
.features = PHY_GBIT_FEATURES,
.probe = &rtl8211f_probe,
.config = &rtl8211f_config,
.startup = &rtl8211f_startup,
.shutdown = &genphy_shutdown,

View File

@ -73,16 +73,6 @@
#define MII_DP83867_CFG2_SPEEDOPT_INTLOW 0x2000
#define MII_DP83867_CFG2_MASK 0x003F
#define MII_MMD_CTRL 0x0d /* MMD Access Control Register */
#define MII_MMD_DATA 0x0e /* MMD Access Data Register */
/* MMD Access Control register fields */
#define MII_MMD_CTRL_DEVAD_MASK 0x1f /* Mask MMD DEVAD*/
#define MII_MMD_CTRL_ADDR 0x0000 /* Address */
#define MII_MMD_CTRL_NOINCR 0x4000 /* no post increment */
#define MII_MMD_CTRL_INCR_RDWT 0x8000 /* post increment on reads & writes */
#define MII_MMD_CTRL_INCR_ON_WT 0xC000 /* post increment on writes only */
/* User setting - can be taken from DTS */
#define DEFAULT_RX_ID_DELAY DP83867_RGMIIDCTL_2_25_NS
#define DEFAULT_TX_ID_DELAY DP83867_RGMIIDCTL_2_75_NS
@ -116,88 +106,20 @@ struct dp83867_private {
int clk_output_sel;
};
/**
* phy_read_mmd_indirect - reads data from the MMD registers
* @phydev: The PHY device bus
* @prtad: MMD Address
* @devad: MMD DEVAD
* @addr: PHY address on the MII bus
*
* Description: it reads data from the MMD registers (clause 22 to access to
* clause 45) of the specified phy address.
* To read these registers we have:
* 1) Write reg 13 // DEVAD
* 2) Write reg 14 // MMD Address
* 3) Write reg 13 // MMD Data Command for MMD DEVAD
* 3) Read reg 14 // Read MMD data
*/
int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
int devad, int addr)
{
int value = -1;
/* Write the desired MMD Devad */
phy_write(phydev, addr, MII_MMD_CTRL, devad);
/* Write the desired MMD register address */
phy_write(phydev, addr, MII_MMD_DATA, prtad);
/* Select the Function : DATA with no post increment */
phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
/* Read the content of the MMD's selected register */
value = phy_read(phydev, addr, MII_MMD_DATA);
return value;
}
/**
* phy_write_mmd_indirect - writes data to the MMD registers
* @phydev: The PHY device
* @prtad: MMD Address
* @devad: MMD DEVAD
* @addr: PHY address on the MII bus
* @data: data to write in the MMD register
*
* Description: Write data from the MMD registers of the specified
* phy address.
* To write these registers we have:
* 1) Write reg 13 // DEVAD
* 2) Write reg 14 // MMD Address
* 3) Write reg 13 // MMD Data Command for MMD DEVAD
* 3) Write reg 14 // Write MMD data
*/
void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
int devad, int addr, u32 data)
{
/* Write the desired MMD Devad */
phy_write(phydev, addr, MII_MMD_CTRL, devad);
/* Write the desired MMD register address */
phy_write(phydev, addr, MII_MMD_DATA, prtad);
/* Select the Function : DATA with no post increment */
phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
/* Write the data into MMD's selected register */
phy_write(phydev, addr, MII_MMD_DATA, data);
}
static int dp83867_config_port_mirroring(struct phy_device *phydev)
{
struct dp83867_private *dp83867 =
(struct dp83867_private *)phydev->priv;
u16 val;
val = phy_read_mmd_indirect(phydev, DP83867_CFG4, DP83867_DEVADDR,
phydev->addr);
val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4);
if (dp83867->port_mirroring == DP83867_PORT_MIRRORING_EN)
val |= DP83867_CFG4_PORT_MIRROR_EN;
else
val &= ~DP83867_CFG4_PORT_MIRROR_EN;
phy_write_mmd_indirect(phydev, DP83867_CFG4, DP83867_DEVADDR,
phydev->addr, val);
phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4, val);
return 0;
}
@ -257,13 +179,13 @@ static int dp83867_of_init(struct phy_device *phydev)
/* Clock output selection if muxing property is set */
if (dp83867->clk_output_sel != DP83867_CLK_O_SEL_REF_CLK) {
val = phy_read_mmd_indirect(phydev, DP83867_IO_MUX_CFG,
DP83867_DEVADDR, phydev->addr);
val = phy_read_mmd(phydev, DP83867_DEVADDR,
DP83867_IO_MUX_CFG);
val &= ~DP83867_IO_MUX_CFG_CLK_O_SEL_MASK;
val |= (dp83867->clk_output_sel <<
DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT);
phy_write_mmd_indirect(phydev, DP83867_IO_MUX_CFG,
DP83867_DEVADDR, phydev->addr, val);
phy_write_mmd(phydev, DP83867_DEVADDR,
DP83867_IO_MUX_CFG, val);
}
return 0;
@ -308,11 +230,11 @@ static int dp83867_config(struct phy_device *phydev)
/* Mode 1 or 2 workaround */
if (dp83867->rxctrl_strap_quirk) {
val = phy_read_mmd_indirect(phydev, DP83867_CFG4,
DP83867_DEVADDR, phydev->addr);
val = phy_read_mmd(phydev, DP83867_DEVADDR,
DP83867_CFG4);
val &= ~BIT(7);
phy_write_mmd_indirect(phydev, DP83867_CFG4,
DP83867_DEVADDR, phydev->addr, val);
phy_write_mmd(phydev, DP83867_DEVADDR,
DP83867_CFG4, val);
}
if (phy_interface_is_rgmii(phydev)) {
@ -332,8 +254,8 @@ static int dp83867_config(struct phy_device *phydev)
* register's bit 11 (marked as RESERVED).
*/
bs = phy_read_mmd_indirect(phydev, DP83867_STRAP_STS1,
DP83867_DEVADDR, phydev->addr);
bs = phy_read_mmd(phydev, DP83867_DEVADDR,
DP83867_STRAP_STS1);
val = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL);
if (bs & DP83867_STRAP_STS1_RESERVED) {
val &= ~DP83867_PHYCR_RESERVED_MASK;
@ -354,8 +276,8 @@ static int dp83867_config(struct phy_device *phydev)
MII_DP83867_CFG2_SPEEDOPT_INTLOW);
phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_CFG2, cfg2);
phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
DP83867_DEVADDR, phydev->addr, 0x0);
phy_write_mmd(phydev, DP83867_DEVADDR,
DP83867_RGMIICTL, 0x0);
phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL,
DP83867_PHYCTRL_SGMIIEN |
@ -367,8 +289,8 @@ static int dp83867_config(struct phy_device *phydev)
}
if (phy_interface_is_rgmii(phydev)) {
val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL,
DP83867_DEVADDR, phydev->addr);
val = phy_read_mmd(phydev, DP83867_DEVADDR,
DP83867_RGMIICTL);
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
val |= (DP83867_RGMII_TX_CLK_DELAY_EN |
@ -380,26 +302,24 @@ static int dp83867_config(struct phy_device *phydev)
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
val |= DP83867_RGMII_RX_CLK_DELAY_EN;
phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
DP83867_DEVADDR, phydev->addr, val);
phy_write_mmd(phydev, DP83867_DEVADDR,
DP83867_RGMIICTL, val);
delay = (dp83867->rx_id_delay |
(dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT));
phy_write_mmd_indirect(phydev, DP83867_RGMIIDCTL,
DP83867_DEVADDR, phydev->addr, delay);
phy_write_mmd(phydev, DP83867_DEVADDR,
DP83867_RGMIIDCTL, delay);
if (dp83867->io_impedance >= 0) {
val = phy_read_mmd_indirect(phydev,
DP83867_IO_MUX_CFG,
DP83867_DEVADDR,
phydev->addr);
val = phy_read_mmd(phydev,
DP83867_DEVADDR,
DP83867_IO_MUX_CFG);
val &= ~DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL;
val |= dp83867->io_impedance &
DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL;
phy_write_mmd_indirect(phydev, DP83867_IO_MUX_CFG,
DP83867_DEVADDR, phydev->addr,
val);
phy_write_mmd(phydev, DP83867_DEVADDR,
DP83867_IO_MUX_CFG, val);
}
}

View File

@ -101,6 +101,14 @@ struct phy_driver {
int (*readext)(struct phy_device *phydev, int addr, int devad, int reg);
int (*writeext)(struct phy_device *phydev, int addr, int devad, int reg,
u16 val);
/* Phy specific driver override for reading a MMD register */
int (*read_mmd)(struct phy_device *phydev, int devad, int reg);
/* Phy specific driver override for writing a MMD register */
int (*write_mmd)(struct phy_device *phydev, int devad, int reg,
u16 val);
struct list_head list;
};
@ -165,6 +173,68 @@ static inline int phy_write(struct phy_device *phydev, int devad, int regnum,
return bus->write(bus, phydev->addr, devad, regnum, val);
}
static inline void phy_mmd_start_indirect(struct phy_device *phydev, int devad,
int regnum)
{
/* Write the desired MMD Devad */
phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_CTRL, devad);
/* Write the desired MMD register address */
phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA, regnum);
/* Select the Function : DATA with no post increment */
phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_CTRL,
(devad | MII_MMD_CTRL_NOINCR));
}
static inline int phy_read_mmd(struct phy_device *phydev, int devad,
int regnum)
{
struct phy_driver *drv = phydev->drv;
if (regnum > (u16)~0 || devad > 32)
return -EINVAL;
/* driver-specific access */
if (drv->read_mmd)
return drv->read_mmd(phydev, devad, regnum);
/* direct C45 / C22 access */
if ((drv->features & PHY_10G_FEATURES) == PHY_10G_FEATURES ||
devad == MDIO_DEVAD_NONE || !devad)
return phy_read(phydev, devad, regnum);
/* indirect C22 access */
phy_mmd_start_indirect(phydev, devad, regnum);
/* Read the content of the MMD's selected register */
return phy_read(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA);
}
static inline int phy_write_mmd(struct phy_device *phydev, int devad,
int regnum, u16 val)
{
struct phy_driver *drv = phydev->drv;
if (regnum > (u16)~0 || devad > 32)
return -EINVAL;
/* driver-specific access */
if (drv->write_mmd)
return drv->write_mmd(phydev, devad, regnum, val);
/* direct C45 / C22 access */
if ((drv->features & PHY_10G_FEATURES) == PHY_10G_FEATURES ||
devad == MDIO_DEVAD_NONE || !devad)
return phy_write(phydev, devad, regnum, val);
/* indirect C22 access */
phy_mmd_start_indirect(phydev, devad, regnum);
/* Write the data into MMD's selected register */
return phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA, val);
}
#ifdef CONFIG_PHYLIB_10G
extern struct phy_driver gen10g_driver;