已知DP83TC812的608寄存器在值等于0x27a时phy通信正常,但偶发值会突变成0x132,我想知道为何会发生这个变化应该怎么避免这种变化?
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
已知DP83TC812的608寄存器在值等于0x27a时phy通信正常,但偶发值会突变成0x132,我想知道为何会发生这个变化应该怎么避免这种变化?
您好,0x608的寄存器变化来看,像是serdes 的RX数据的顺序发生了变化,导致bit8这里SGMII RX bus invert polarity极性出现相反。
看下这里的配置bit15-14是不是也发生了变化。

您好,从寄存器值的改变来看,就是bit8这里的SGMII极性的交换,而DP83TC812不支持自动极性交换。所以我想是不是这里的原因导致。
0x60A寄存器可以说明SGMII的link状态,当608的值改变之后,看下0x60A的bit 11的SGMII link是否down掉。
您好,这个问题应该是和SGMII协议标准有关,具体要看下协议标准。
我想DP83TC812传输的数据格式应该是遵循协议的,并且不支持自动极性交换。 而和MAC相连的MDI接口是不是自适应极性交换的,所以当传输的数据极性发生改变的时候,DP83TC812侧会报错。
您好,E2E给出回复了,应该是driver的bug,并且给了配置例程,您试试是否可以解决您的问题。
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for the Texas Instruments DP83TC812 PHY
*
* Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/
*
*/
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
#include <linux/kernel.h>
#include <linux/mii.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy.h>
#include <linux/netdevice.h>
#define DP83TC812_CS1_0_PHY_ID 0x2000a270
#define DP83TC812_CS2_0_PHY_ID 0x2000a271
#define DP83TC813_CS2_0_PHY_ID 0x2000a211
#define DP83TC814_CS2_0_PHY_ID 0x2000a261
#define DP83812_DEVADDR 0x1f
#define DP83812_DEVADDR_MMD1 0x1
#define DP83812_STRAP 0x45d
#define MII_DP83812_SGMII_CTRL 0x608
#define SGMII_CONFIG_VAL 0x027B
#define MII_DP83812_RGMII_CTRL 0x600
#define MII_DP83812_INT_STAT1 0x12
#define MII_DP83812_INT_STAT2 0x13
#define MII_DP83812_INT_STAT3 0x18
#define MII_DP83812_RESET_CTRL 0x1f
#define DP83812_HW_RESET BIT(15)
#define DP83812_SW_RESET BIT(14)
/* INT_STAT1 bits */
#define DP83812_RX_ERR_CNT_HALF_FULL_INT_EN BIT(0)
#define DP83812_TX_ERR_CNT_HALF_FULL_INT_EN BIT(1)
#define DP83812_MS_TRAIN_DONE_INT_EN BIT(2)
#define DP83812_ESD_EVENT_INT_EN BIT(3)
#define DP83812_LINK_STAT_INT_EN BIT(5)
#define DP83812_ENERGY_DET_INT_EN BIT(6)
#define DP83812_LINK_QUAL_INT_EN BIT(7)
/* INT_STAT2 bits */
#define DP83812_JABBER_INT_EN BIT(0)
#define DP83812_POL_INT_EN BIT(1)
#define DP83812_SLEEP_MODE_INT_EN BIT(2)
#define DP83812_OVERTEMP_INT_EN BIT(3)
#define DP83812_FIFO_INT_EN BIT(4)
#define DP83812_PAGE_RXD_INT_EN BIT(5)
#define DP83812_OVERVOLTAGE_INT_EN BIT(6)
#define DP83812_UNDERVOLTAGE_INT_EN BIT(7)
/* INT_STAT3 bits */
#define DP83812_LPS_INT_EN BIT(0)
#define DP83812_WUP_INT_EN BIT(1)
#define DP83812_WAKE_REQ_INT_EN BIT(2)
#define DP83811_NO_FRAME_INT_EN BIT(3)
#define DP83811_POR_DONE_INT_EN BIT(4)
#define DP83812_SLEEP_FAIL_INT_EN BIT(5)
/* RGMII_CTRL bits */
#define DP83812_RGMII_EN BIT(3)
/* SGMII CTRL bits */
#define DP83812_SGMII_AUTO_NEG_EN BIT(0)
#define DP83812_SGMII_EN BIT(9)
/* Strap bits */
#define DP83812_MASTER_MODE BIT(9)
#define DP83812_RGMII_IS_EN BIT(7)
/* RGMII ID CTRL */
#define DP83812_RGMII_ID_CTRL 0x602
#define DP83812_RX_CLK_SHIFT BIT(1)
#define DP83812_TX_CLK_SHIFT BIT(0)
enum dp83812_chip_type {
DP83812_CS1 = 0,
DP83812_CS2,
DP83813_CS2,
DP83814_CS2,
};
struct dp83812_init_reg {
int reg;
int val;
};
static const struct dp83812_init_reg dp83812_master_cs1_0_init[] = {
{0x523, 0x0001},
{0x800, 0xf864},
{0x803, 0x1552},
{0x804, 0x1a66},
{0x805, 0x1f7b},
{0x81f, 0x2a88},
{0x825, 0x40e5},
{0x82b, 0x7f3f},
{0x830, 0x0543},
{0x836, 0x5008},
{0x83a, 0x08e0},
{0x83b, 0x0845},
{0x83e, 0x0445},
{0x855, 0x9b9a},
{0x85f, 0x2010},
{0x860, 0x6040},
{0x86c, 0x1333},
{0x86b, 0x3e10},
{0x872, 0x88c0},
{0x873, 0x0003},
{0x879, 0x000f},
{0x87b, 0x0070},
{0x87c, 0x003f},
{0x89e, 0x00aa},
{0x523, 0x0000},
};
static const struct dp83812_init_reg dp83812_master_cs2_0_init[] = {
{0x523, 0x0001},
{0x81C, 0x0fe2},
{0x872, 0x0300},
{0x879, 0x0f00},
{0x806, 0x2952},
{0x807, 0x3361},
{0x808, 0x3D7B},
{0x83E, 0x045F},
{0x834, 0x8000},
{0x862, 0x00E8},
{0x896, 0x32CB},
{0x03E, 0x0009},
{0x01f, 0x4000},
{0x523, 0x0000},
};
static const struct dp83812_init_reg dp83812_slave_cs1_0_init[] = {
{0x523, 0x0001},
{0x803, 0x1b52},
{0x804, 0x216c},
{0x805, 0x277b},
{0x827, 0x3000},
{0x830, 0x0543},
{0x83a, 0x0020},
{0x83c, 0x0001},
{0x855, 0x9b9a},
{0x85f, 0x2010},
{0x860, 0x6040},
{0x86c, 0x0333},
{0x872, 0x88c0},
{0x873, 0x0021},
{0x879, 0x000f},
{0x87b, 0x0070},
{0x87c, 0x0002},
{0x897, 0x003f},
{0x89e, 0x00a2},
{0x510, 0x000f},
{0x523, 0x0000},
};
static const struct dp83812_init_reg dp83812_slave_cs2_0_init[] = {
{0x523, 0x0001},
{0x873, 0x0821},
{0x896, 0x22ff},
{0x89E, 0x0000},
{0x01f, 0x4000},
{0x523, 0x0000},
};
struct dp83812_private {
int chip;
bool is_master;
bool is_rgmii;
bool is_sgmii;
};
static int dp83812_read_straps(struct phy_device *phydev)
{
struct dp83812_private *dp83812 = phydev->priv;
int strap;
strap = phy_read_mmd(phydev, DP83812_DEVADDR, DP83812_STRAP);
if (strap < 0)
return strap;
printk("%s: Strap is 0x%X\n", __func__, strap);
if (strap & DP83812_MASTER_MODE)
dp83812->is_master = true;
if (strap & DP83812_RGMII_IS_EN)
dp83812->is_rgmii = true;
return 0;
};
static int dp83812_reset(struct phy_device *phydev, bool hw_reset)
{
int ret;
if (hw_reset)
ret = phy_write_mmd(phydev, DP83812_DEVADDR, MII_DP83812_RESET_CTRL,
DP83812_HW_RESET);
else
ret = phy_write_mmd(phydev, DP83812_DEVADDR, MII_DP83812_RESET_CTRL,
DP83812_SW_RESET);
if (ret)
return ret;
mdelay(100);
return 0;
}
static int dp83812_phy_reset(struct phy_device *phydev)
{
int err;
int ret;
err = phy_write_mmd(phydev, DP83812_DEVADDR, MII_DP83812_RESET_CTRL, DP83812_HW_RESET);
if (err < 0)
return err;
ret = dp83812_read_straps(phydev);
if (ret)
return ret;
return 0;
}
static int dp83812_write_seq(struct phy_device *phydev, const struct
dp83812_init_reg *init_data, int size)
{
int ret;
int i;
for (i = 0; i < size; i++) {
ret = phy_write_mmd(phydev, DP83812_DEVADDR, init_data[i].reg,
init_data[i].val);
if (ret)
return ret;
}
return 0;
}
static int dp83812_chip_init(struct phy_device *phydev)
{
struct dp83812_private *dp83812 = phydev->priv;
int ret;
ret = dp83812_reset(phydev, true);
if (ret)
return ret;
phydev->autoneg = AUTONEG_DISABLE;
phydev->speed = SPEED_100;
phydev->duplex = DUPLEX_FULL;
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
phydev->supported);
if (dp83812->is_master)
ret = phy_write_mmd(phydev, DP83812_DEVADDR_MMD1, 0x0834, 0xc001);
// ret = phy_write_mmd(phydev, DP83812_DEVADDR, 0x0834, 0xc001);
else
ret = phy_write_mmd(phydev, DP83812_DEVADDR_MMD1, 0x0834, 0x8001);
// ret = phy_write_mmd(phydev, DP83812_DEVADDR, 0x0834, 0x8001);
switch (dp83812->chip) {
case DP83812_CS1:
if (dp83812->is_master)
ret = dp83812_write_seq(phydev,
dp83812_master_cs1_0_init,
ARRAY_SIZE(dp83812_master_cs1_0_init));
else
ret = dp83812_write_seq(phydev,
dp83812_slave_cs1_0_init,
ARRAY_SIZE(dp83812_slave_cs1_0_init));
break;
case DP83812_CS2:
if (dp83812->is_master)
ret = dp83812_write_seq(phydev,
dp83812_master_cs2_0_init,
ARRAY_SIZE(dp83812_master_cs2_0_init));
else
ret = dp83812_write_seq(phydev,
dp83812_slave_cs2_0_init,
ARRAY_SIZE(dp83812_slave_cs2_0_init));
break;
case DP83813_CS2:
if (dp83812->is_master)
ret = dp83812_write_seq(phydev,
dp83812_master_cs2_0_init,
ARRAY_SIZE(dp83812_master_cs2_0_init));
else
ret = dp83812_write_seq(phydev,
dp83812_slave_cs2_0_init,
ARRAY_SIZE(dp83812_slave_cs2_0_init));
break;
case DP83814_CS2:
if (dp83812->is_master)
ret = dp83812_write_seq(phydev,
dp83812_master_cs2_0_init,
ARRAY_SIZE(dp83812_master_cs2_0_init));
else
ret = dp83812_write_seq(phydev,
dp83812_slave_cs2_0_init,
ARRAY_SIZE(dp83812_slave_cs2_0_init));
break;
default:
return -EINVAL;
};
if (ret)
return ret;
mdelay(10);
// phy_write_mmd(phydev, DP83812_DEVADDR, 0x523, 0x00);
/* Do a soft reset to restart the PHY with updated values */
return dp83812_reset(phydev, false);
}
static int dp83812_config_init(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
s32 rx_int_delay;
s32 tx_int_delay;
int rgmii_delay;
int value, ret;
ret = dp83812_chip_init(phydev);
if (ret)
return ret;
if (phy_interface_is_rgmii(phydev)) {
rx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,
true);
if (rx_int_delay <= 0)
rgmii_delay = 0;
else
rgmii_delay = DP83812_RX_CLK_SHIFT;
tx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,
false);
if (tx_int_delay <= 0)
rgmii_delay &= ~DP83812_TX_CLK_SHIFT;
else
rgmii_delay |= DP83812_TX_CLK_SHIFT;
if (rgmii_delay) {
ret = phy_set_bits_mmd(phydev, DP83812_DEVADDR_MMD1,
DP83812_RGMII_ID_CTRL,
rgmii_delay);
if (ret)
return ret;
}
}
if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
value = phy_read(phydev, MII_DP83812_SGMII_CTRL);
ret = phy_write_mmd(phydev, DP83812_DEVADDR, MII_DP83812_SGMII_CTRL,
SGMII_CONFIG_VAL);
if (ret < 0)
return ret;
}
return 0;
}
static int dp83812_ack_interrupt(struct phy_device *phydev)
{
int err;
err = phy_read(phydev, MII_DP83812_INT_STAT1);
if (err < 0)
return err;
err = phy_read(phydev, MII_DP83812_INT_STAT2);
if (err < 0)
return err;
err = phy_read(phydev, MII_DP83812_INT_STAT3);
if (err < 0)
return err;
return 0;
}
static int dp83812_config_intr(struct phy_device *phydev)
{
int misr_status, err;
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
misr_status = phy_read(phydev, MII_DP83812_INT_STAT1);
if (misr_status < 0)
return misr_status;
misr_status |= (DP83812_ESD_EVENT_INT_EN |
DP83812_LINK_STAT_INT_EN |
DP83812_ENERGY_DET_INT_EN |
DP83812_LINK_QUAL_INT_EN);
err = phy_write(phydev, MII_DP83812_INT_STAT1, misr_status);
if (err < 0)
return err;
misr_status = phy_read(phydev, MII_DP83812_INT_STAT2);
if (misr_status < 0)
return misr_status;
misr_status |= (DP83812_SLEEP_MODE_INT_EN |
DP83812_OVERTEMP_INT_EN |
DP83812_OVERVOLTAGE_INT_EN |
DP83812_UNDERVOLTAGE_INT_EN);
err = phy_write(phydev, MII_DP83812_INT_STAT2, misr_status);
if (err < 0)
return err;
misr_status = phy_read(phydev, MII_DP83812_INT_STAT3);
if (misr_status < 0)
return misr_status;
misr_status |= (DP83812_LPS_INT_EN |
DP83812_WAKE_REQ_INT_EN |
DP83811_NO_FRAME_INT_EN |
DP83811_POR_DONE_INT_EN);
err = phy_write(phydev, MII_DP83812_INT_STAT3, misr_status);
} else {
err = phy_write(phydev, MII_DP83812_INT_STAT1, 0);
if (err < 0)
return err;
err = phy_write(phydev, MII_DP83812_INT_STAT2, 0);
if (err < 0)
return err;
err = phy_write(phydev, MII_DP83812_INT_STAT3, 0);
}
return err;
}
#if 0
static irqreturn_t dp83812_handle_interrupt(struct phy_device *phydev)
{
bool trigger_machine = false;
int irq_status;
/* The INT_STAT registers 1, 2 and 3 are holding the interrupt status
* in the upper half (15:8), while the lower half (7:0) is used for
* controlling the interrupt enable state of those individual interrupt
* sources. To determine the possible interrupt sources, just read the
* INT_STAT* register and use it directly to know which interrupts have
* been enabled previously or not.
*/
irq_status = phy_read(phydev, MII_DP83812_INT_STAT1);
if (irq_status < 0) {
phy_error(phydev);
return IRQ_NONE;
}
if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
trigger_machine = true;
irq_status = phy_read(phydev, MII_DP83812_INT_STAT2);
if (irq_status < 0) {
phy_error(phydev);
return IRQ_NONE;
}
if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
trigger_machine = true;
irq_status = phy_read(phydev, MII_DP83812_INT_STAT3);
if (irq_status < 0) {
phy_error(phydev);
return IRQ_NONE;
}
if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
trigger_machine = true;
if (!trigger_machine)
return IRQ_NONE;
phy_trigger_machine(phydev);
return IRQ_HANDLED;
}
#endif
static int dp83812_config_aneg(struct phy_device *phydev)
{
int value, ret;
if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
value = phy_read(phydev, MII_DP83812_SGMII_CTRL);
ret = phy_write_mmd(phydev, DP83812_DEVADDR, MII_DP83812_SGMII_CTRL,
SGMII_CONFIG_VAL);
if (ret < 0)
return ret;
}
return genphy_config_aneg(phydev);
}
static int dp83812_probe(struct phy_device *phydev)
{
struct dp83812_private *dp83812;
int ret;
dp83812 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83812), GFP_KERNEL);
if (!dp83812)
return -ENOMEM;
phydev->priv = dp83812;
ret = dp83812_read_straps(phydev);
if (ret)
return ret;
switch (phydev->phy_id) {
case DP83TC812_CS1_0_PHY_ID:
dp83812->chip = DP83812_CS1;
break;
case DP83TC812_CS2_0_PHY_ID:
dp83812->chip = DP83812_CS2;
break;
case DP83TC813_CS2_0_PHY_ID:
dp83812->chip = DP83813_CS2;
break;
case DP83TC814_CS2_0_PHY_ID:
dp83812->chip = DP83814_CS2;
break;
default:
return -EINVAL;
};
/* vikram : above code added to switch between different phy ids */
return dp83812_config_init(phydev);
}
#define DP83812_PHY_DRIVER(_id, _name) \
{ \
PHY_ID_MATCH_EXACT(_id), \
.name = (_name), \
.probe = dp83812_probe, \
/* PHY_BASIC_FEATURES */ \
.soft_reset = dp83812_phy_reset, \
.config_init = dp83812_config_init, \
.config_aneg = dp83812_config_aneg, \
.ack_interrupt = dp83812_ack_interrupt, \
/*if 0 \
.handle_interrupt = dp83812_handle_interrupt, \
#endif */ \
.config_intr = dp83812_config_intr, \
.suspend = genphy_suspend, \
.resume = genphy_resume, \
}
static struct phy_driver dp83812_driver[] = {
DP83812_PHY_DRIVER(DP83TC812_CS1_0_PHY_ID, "TI DP83TC812CS1.0"),
DP83812_PHY_DRIVER(DP83TC812_CS2_0_PHY_ID, "TI DP83TC812CS2.0"),
DP83812_PHY_DRIVER(DP83TC813_CS2_0_PHY_ID, "TI DP83TC813CS2.0"),
DP83812_PHY_DRIVER(DP83TC814_CS2_0_PHY_ID, "TI DP83TC814CS2.0"),
};
module_phy_driver(dp83812_driver);
static struct mdio_device_id __maybe_unused dp83812_tbl[] = {
{ PHY_ID_MATCH_EXACT(DP83TC812_CS1_0_PHY_ID) },
{ PHY_ID_MATCH_EXACT(DP83TC812_CS2_0_PHY_ID) },
{ PHY_ID_MATCH_EXACT(DP83TC813_CS2_0_PHY_ID) },
{ PHY_ID_MATCH_EXACT(DP83TC814_CS2_0_PHY_ID) },
{ },
};
MODULE_DEVICE_TABLE(mdio, dp83812_tbl);
MODULE_DESCRIPTION("Texas Instruments DP83TC812 PHY driver");
MODULE_AUTHOR("Hari Nagalla <hnagalla@ti.com");
MODULE_LICENSE("GPL");
这个是DP83TC812的driver,您的意思是和您的对比,哪里进行了更改是吗?建议是您直接使用这个driver试试,是否能解决寄存器偶发突变的问题。
抱歉没有对应这版.c的h文件呢,您可以直接在E2E上跟进下。或者我这边帮您确认下也行。
您好,E2E已经给出回复,对应的h文件在包含在linux的SDK里:
The related .h files are included as part of the standard Linux SDK:
https://elixir.bootlin.com/linux/latest/source/include/linux