mediatek: Update Airoha EN8811H 2.5G PHY driver to v1.2.5

Change Log:
[2024/03/08] v1.2.5
1. Added surge 5R API.
2. Add CL22 and CL45 command
* MD32 8811_24030702 updated:
1. Fix the issue of external loopback
2. Fix the issue of down-shift
3. Add surge protection to support 0R and 5R mode
4. Enhance cable diag accuracy of cable length
5. Improved IoT performance and stability

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen 2024-05-10 20:45:26 +08:00
parent 4619da9658
commit 0761bea043
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
5 changed files with 5457 additions and 5289 deletions

View File

@ -43,7 +43,7 @@
#define MII_MMD_ADDR_DATA_REG 0x0e
#define MMD_OP_MODE_DATA BIT(14)
#define EN8811H_DRIVER_VERSION "v1.2.4"
#define EN8811H_DRIVER_VERSION "v1.2.5"
#define LED_ON_CTRL(i) (0x024 + ((i)*2))
#define LED_ON_EN (1 << 15)
@ -96,6 +96,7 @@ struct en8811h_priv {
unsigned int dsp_crc32;
char buf[512];
int pol;
int surge;
};
struct air_base_t_led_cfg {

View File

@ -334,6 +334,22 @@ int air_buckpbus_reg_write(struct phy_device *phydev,
}
return ret;
}
int air_surge_5ohm_config(struct phy_device *phydev)
{
int ret = 0;
struct device *dev = phydev_dev(phydev);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x00b0);
if (ret < 0)
return ret;
dev_info(dev, "surge protection mode - 5R\n");
return ret;
}
#if defined(CONFIG_OF)
int en8811h_of_init(struct phy_device *phydev)
{
@ -346,12 +362,12 @@ int en8811h_of_init(struct phy_device *phydev)
if (of_find_property(of_node, "airoha,polarity", NULL)) {
if (of_property_read_u32(of_node, "airoha,polarity",
&val) != 0) {
phydev_err(phydev, "airoha,polarity value is invalid.");
dev_err(dev, "airoha,polarity value is invalid.");
return -EINVAL;
}
if (val < AIR_POL_TX_REV_RX_NOR ||
val > AIR_POL_TX_NOR_RX_REV) {
phydev_err(phydev,
dev_err(dev,
"airoha,polarity value %u out of range.",
val);
return -EINVAL;
@ -360,6 +376,25 @@ int en8811h_of_init(struct phy_device *phydev)
} else
priv->pol = AIR_POL_TX_NOR_RX_NOR;
if (of_find_property(of_node, "airoha,surge", NULL)) {
if (of_property_read_u32(of_node, "airoha,surge",
&val) != 0) {
dev_err(dev, "airoha,surge value is invalid.");
return -EINVAL;
}
if (val < 0 || val > 1) {
dev_err(dev,
"airoha,surge value %u out of range.",
val);
return -EINVAL;
}
if (val)
priv->surge = 1;
else
priv->surge = 0;
} else
priv->surge = 0;
return 0;
}
#else
@ -710,7 +745,7 @@ static int airphy_fcm_counter_show(struct phy_device *phydev,
seq_puts(seq, "| Tx to Line side_T :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0xe0088);
seq_printf(seq, "%010u |\n", pkt_cnt);
ret = air_buckpbus_reg_write(phydev, 0xe0074, 0xf);
ret = air_buckpbus_reg_write(phydev, 0xe0074, 0x3);
if (ret < 0)
return ret;
return 0;
@ -1169,8 +1204,12 @@ static int airphy_temp_show(struct seq_file *seq, void *v)
u32 pbus_value = 0;
seq_puts(seq, "<<AIR EN8811H Temp>>\n");
air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1100);
air_mii_cl45_write(phydev, 0x1e, 0x800f, 0xe5);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1100);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800f, 0xe5);
if (ret < 0) {
pr_notice("\nmii_cl45_write fail\n");
return -EIO;
}
pbus_value = air_buckpbus_reg_read(phydev, 0x3B38);
seq_printf(seq, "| Temperature : %dC |\n",
pbus_value);
@ -1285,6 +1324,114 @@ static int airphy_lp_speed_open(struct inode *inode, struct file *file)
return single_open(file, airphy_lp_speed, inode->i_private);
}
static void airphy_debugfs_mii_cl22_help(void)
{
pr_notice("\nUsage:\n"
"[debugfs] = /sys/kernel/debug/mdio-bus\':[phy_addr]\n"
"Read:\n"
"echo r [phy_register] > /[debugfs]/mii_mgr_op\n"
"Write:\n"
"echo w [phy_register] [value] > /[debugfs]/mii_mgr_op\n");
}
static ssize_t airphy_debugfs_cl22(struct file *file,
const char __user *buffer, size_t count,
loff_t *data)
{
struct phy_device *phydev = file->private_data;
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int addr = phydev_addr(phydev);
char buf[64];
int ret = 0;
unsigned int reg, val;
memset(buf, 0, 64);
if (count > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, buffer, count))
return -EFAULT;
if (buf[0] == 'w') {
if (sscanf(buf, "w %x %x", &reg, &val) == -1)
return -EFAULT;
pr_notice("\nphy=%d, reg=0x%x, val=0x%x\n",
phydev_addr(phydev), reg, val);
ret = air_mii_cl22_write(mbus, addr, reg, val);
if (ret < 0) {
pr_notice("\nmii_cl22_write fail\n");
return -EIO;
}
val = air_mii_cl22_read(mbus, addr, reg);
pr_notice("\nphy=%d, reg=0x%x, val=0x%x confirm..\n",
phydev_addr(phydev), reg, val);
} else if (buf[0] == 'r') {
if (sscanf(buf, "r %x", &reg) == -1)
return -EFAULT;
val = air_mii_cl22_read(mbus, addr, reg);
pr_notice("\nphy=%d, reg=0x%x, val=0x%x\n",
phydev_addr(phydev), reg, val);
} else
airphy_debugfs_mii_cl22_help();
return count;
}
static void airphy_debugfs_mii_cl45_help(void)
{
pr_notice("\nUsage:\n"
"[debugfs] = /sys/kernel/debug/mdio-bus\':[phy_addr]\n"
"Read:\n"
"echo r [device number] [phy_register] > /[debugfs]/mii_mgr_cl45_op\n"
"Write:\n"
"echo w [device number] [phy_register] [value] > /[debugfs]/mii_mgr_cl45_op\n");
}
static ssize_t airphy_debugfs_cl45(struct file *file,
const char __user *buffer, size_t count,
loff_t *data)
{
struct phy_device *phydev = file->private_data;
char buf[64];
int ret = 0;
unsigned int reg, val, devnum;
memset(buf, 0, 64);
if (count > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, buffer, count))
return -EFAULT;
if (buf[0] == 'w') {
if (sscanf(buf, "w %x %x %x", &devnum, &reg, &val) == -1)
return -EFAULT;
pr_notice("\nphy=%d, devnum=0x%x, reg=0x%x, val=0x%x\n",
phydev_addr(phydev), devnum, reg, val);
ret = air_mii_cl45_write(phydev, devnum, reg, val);
if (ret < 0) {
pr_notice("\nmii_cl45_write fail\n");
return -EIO;
}
val = air_mii_cl45_read(phydev, devnum, reg);
pr_notice("\nphy=%d, devnum=0x%x, reg=0x%x, val=0x%x confirm..\n",
phydev_addr(phydev), devnum, reg, val);
} else if (buf[0] == 'r') {
if (sscanf(buf, "r %x %x", &devnum, &reg) == -1)
return -EFAULT;
val = air_mii_cl45_read(phydev, devnum, reg);
pr_notice("\nphy=%d, devnum=0x%x, reg=0x%x, val=0x%x\n",
phydev_addr(phydev), devnum, reg, val);
} else
airphy_debugfs_mii_cl45_help();
return count;
}
static const struct file_operations airphy_lp_speed_fops = {
.owner = THIS_MODULE,
.open = airphy_lp_speed_open,
@ -1361,6 +1508,20 @@ static const struct file_operations airphy_temp_fops = {
.release = single_release,
};
static const struct file_operations airphy_debugfs_cl22_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.write = airphy_debugfs_cl22,
.llseek = noop_llseek,
};
static const struct file_operations airphy_debugfs_cl45_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.write = airphy_debugfs_cl45,
.llseek = noop_llseek,
};
int airphy_debugfs_init(struct phy_device *phydev)
{
int ret = 0;
@ -1404,6 +1565,12 @@ int airphy_debugfs_init(struct phy_device *phydev)
debugfs_create_file(DEBUGFS_LP_SPEED, S_IFREG | 0444,
dir, phydev,
&airphy_lp_speed_fops);
debugfs_create_file(DEBUGFS_MII_CL22_OP, S_IFREG | 0200,
dir, phydev,
&airphy_debugfs_cl22_fops);
debugfs_create_file(DEBUGFS_MII_CL45_OP, S_IFREG | 0200,
dir, phydev,
&airphy_debugfs_cl45_fops);
priv->debugfs_root = dir;
return ret;

View File

@ -31,6 +31,8 @@
#define DEBUGFS_DBG_REG_SHOW "dbg_regs_show"
#define DEBUGFS_TEMPERATURE "temp"
#define DEBUGFS_LP_SPEED "lp_speed"
#define DEBUGFS_MII_CL22_OP "cl22_op"
#define DEBUGFS_MII_CL45_OP "cl45_op"
enum air_port_mode {
AIR_PORT_MODE_FORCE_100,
@ -82,6 +84,7 @@ unsigned int air_buckpbus_reg_read(struct phy_device *phydev,
int air_buckpbus_reg_write(struct phy_device *phydev,
unsigned int pbus_address, unsigned int pbus_data);
int en8811h_of_init(struct phy_device *phydev);
int air_surge_5ohm_config(struct phy_device *phydev);
#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
int airphy_debugfs_init(struct phy_device *phydev);
void airphy_debugfs_remove(struct phy_device *phydev);

File diff suppressed because it is too large Load Diff

View File

@ -51,9 +51,7 @@ static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M;
/***********************************************************
* F U N C T I O N S
***********************************************************/
static int MDIOWriteBuf(struct phy_device *phydev, unsigned long address,
static int air_mdio_write_buf(struct phy_device *phydev, unsigned long address,
unsigned long array_size, const unsigned char *buffer)
{
unsigned int write_data, offset;
@ -125,18 +123,18 @@ static int en8811h_load_firmware(struct phy_device *phydev)
if (ret < 0)
return ret;
/* Download DM */
ret = MDIOWriteBuf(phydev, 0x00000000, EthMD32_dm_size, EthMD32_dm);
ret = air_mdio_write_buf(phydev, 0x00000000, EthMD32_dm_size, EthMD32_dm);
if (ret < 0) {
dev_err(dev,
"MDIOWriteBuf 0x00000000 fail, ret: %d\n", ret);
"air_mdio_write_buf 0x00000000 fail, ret: %d\n", ret);
return ret;
}
/* Download PM */
ret = MDIOWriteBuf(phydev, 0x00100000, EthMD32_pm_size, EthMD32_pm);
ret = air_mdio_write_buf(phydev, 0x00100000, EthMD32_pm_size, EthMD32_pm);
if (ret < 0) {
dev_err(dev,
"MDIOWriteBuf 0x00100000 fail , ret: %d\n", ret);
"air_mdio_write_buf 0x00100000 fail , ret: %d\n", ret);
return ret;
}
pbus_value = air_buckpbus_reg_read(phydev, 0x800000);
@ -358,18 +356,10 @@ static int en8811h_probe(struct phy_device *phydev)
"EN8811H initialize fail!\n");
goto priv_free;
}
/* Mode selection*/
dev_info(dev, "EN8811H Mode 1 !\n");
ret = air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0);
if (ret < 0)
goto priv_free;
ret = air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0);
if (ret < 0)
goto priv_free;
ret = air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101);
if (ret < 0)
goto priv_free;
ret = air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x0002);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x0002);
if (ret < 0)
goto priv_free;
/* Serdes polarity */
@ -390,6 +380,13 @@ static int en8811h_probe(struct phy_device *phydev)
dev_info(dev, "Tx, Rx Polarity : %08x\n", pbus_value);
pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c);
dev_info(dev, "MD32 FW Version : %08x\n", pbus_value);
if (priv->surge) {
ret = air_surge_5ohm_config(phydev);
if (ret < 0)
dev_err(dev,
"air_surge_5ohm_config fail. (ret=%d)\n", ret);
} else
dev_info(dev, "Surge Protection Mode - 0R\n");
#if defined(AIR_LED_SUPPORT)
ret = en8811h_led_init(phydev);
if (ret < 0) {