[Feature][T108] [task-view-1618] optimize the PHY initialization process and provide r/w phy registers interfaces and test demo
Only Configure: No
Affected branch: GSW_V1453
Affected module: PHY
Self-test: yes
Doc Update: no
Change-Id: I43a2fd10a51a4f2e5b6b63038a080a3447663752
diff --git a/marvell/linux/arch/arm/boot/dts/asr1806-p301.dts b/marvell/linux/arch/arm/boot/dts/asr1806-p301.dts
index b12c88c..1aba992 100755
--- a/marvell/linux/arch/arm/boot/dts/asr1806-p301.dts
+++ b/marvell/linux/arch/arm/boot/dts/asr1806-p301.dts
@@ -63,9 +63,10 @@
ptp-clk-rate = <100000000>;
status = "okay";
enable-suspend;
- reset-gpio = <&gpio 42 0>;
- reset-active-low;
- reset-delays-us = <100000 100000 100000>;
+ // reset-gpio = <&gpio 42 0>;
+ // reset-active-low;
+ // reset-delays-us = <100000 100000 100000>;
+ local-mac-address = [02 00 00 00 10 01];
//ldo-gpio = <&gpio 40 0>;
//ldo-active-low;
// ldo-delays-us = <0 100000 100000>;
@@ -115,6 +116,7 @@
compatible = "ethernet-phy-ieee802.3-c22";
device_type = "ethernet-phy";
reg = <0x0>; /* set phy address*/
+ rst-gpio = <&gpio 42 0>;
phy-mode = "rgmii";
// tx_rx_delay = <0xb 0x0>; /* 150ps per step*/
};
diff --git a/marvell/linux/drivers/net/phy/realtek.c b/marvell/linux/drivers/net/phy/realtek.c
old mode 100644
new mode 100755
index 2b797a2..4531775
--- a/marvell/linux/drivers/net/phy/realtek.c
+++ b/marvell/linux/drivers/net/phy/realtek.c
@@ -12,6 +12,35 @@
#include <linux/phy.h>
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_gpio.h>
+//#LYNQ_MODFIY modify for task-1618 2025/6/10 start
+
+#define DEVICE_NAME "mdio_misc"
+
+struct rtl9000bf_mdio_dev {
+ struct phy_device *phydev;
+ struct mutex lock;
+ int rst_gpio;
+};
+struct mdio_reg_op {
+ uint32_t reg;
+ uint32_t val;
+};
+static struct rtl9000bf_mdio_dev *s_rtl9000bf_mdio_dev;
+static u16 param_check[27] = {0, 0x8017, 0xFB03, 0, 0x8092, 0x6000, 0, 0x80AF, 0x6000, \
+ 0, 0x807D, 0x4443, 0, 0x809A, 0x4443, \
+ 0, 0x81A3, 0x0F00, 0x0A81, 0x12, 0x0004, 0, \
+ 0x83C8, 0x0005, 0x0A5C, 0x12, 0x0003};
+
+static u16 param_check2[5] = {0x401C, 0xA610, 0x8520, 0xA510, 0x21F4};
+static u16 param_check3[3] = {0, 0xA000, 0x11EF};
+
+#define RTL9000BF_INIT_TIMES_OUT 10
+#define RTL9000BF_ACCESS_TIMES_OUT 10
+//#LYNQ_MODFIY modify for task-1618 2025/6/10 end
#define RTL821x_PHYSR 0x11
#define RTL821x_PHYSR_DUPLEX BIT(13)
@@ -702,123 +731,388 @@
return ret;
}
+//#LYNQ_MODFIY modify for task-1618 2025/6/10 start
+
+static int mdio_misc_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static ssize_t mdio_misc_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+{
+ struct rtl9000bf_mdio_dev *dev = s_rtl9000bf_mdio_dev;
+ struct mdio_reg_op reg_op;
+
+ if (count < sizeof(struct mdio_reg_op))
+ return -EINVAL;
+
+ if (copy_from_user(®_op, buf, sizeof(struct mdio_reg_op)))
+ return -EFAULT;
+
+
+ mutex_lock(&dev->lock);
+ reg_op.val = __phy_read(dev->phydev, reg_op.reg);
+ mutex_unlock(&dev->lock);
+
+ if (copy_to_user(buf, ®_op, sizeof(struct mdio_reg_op)))
+ return -EFAULT;
+
+ return sizeof(reg_op);
+}
+
+static ssize_t mdio_misc_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
+{
+ struct rtl9000bf_mdio_dev *dev = s_rtl9000bf_mdio_dev;
+ struct mdio_reg_op reg_op;
+ int ret;
+
+ if (count < sizeof(struct mdio_reg_op))
+ return -EINVAL;
+
+ if (copy_from_user(®_op, buf, sizeof(struct mdio_reg_op)))
+ return -EFAULT;
+
+
+ mutex_lock(&dev->lock);
+ ret = __phy_write(dev->phydev, reg_op.reg, reg_op.val);
+ mutex_unlock(&dev->lock);
+
+ *f_pos += count;
+ return ret ? ret : count;
+
+}
+
+static const struct file_operations mdio_misc_fops = {
+ .owner = THIS_MODULE,
+ .open = mdio_misc_open,
+ .read = mdio_misc_read,
+ .write = mdio_misc_write,
+};
+
+static struct miscdevice mdio_misc_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = DEVICE_NAME,
+ .fops = &mdio_misc_fops,
+};
+
+static int mdio_misc_init(struct phy_device *phydev)
+{
+ s_rtl9000bf_mdio_dev->phydev = phydev;
+ mutex_init(&s_rtl9000bf_mdio_dev->lock);
+ return misc_register(&mdio_misc_device);
+}
+
+static s16 RTL9000Bx_Initial_Configuration(struct phy_device *phydev)
+{
+ u16 reg_data = 0;
+ u32 timer = 2000; // set a 2ms timer
+
+ //power down
+ __phy_write(phydev, 0, 0x800);
+ mdelay(10);
+
+ __phy_write(phydev, 27, 0x8017);
+ __phy_write(phydev, 28, 0xFB03);
+ __phy_write(phydev, 27, 0x8092);
+ __phy_write(phydev, 28, 0x6000);
+ __phy_write(phydev, 27, 0x80AF);
+ __phy_write(phydev, 28, 0x6000);
+ __phy_write(phydev, 27, 0x807D);
+ __phy_write(phydev, 28, 0x4443);
+ __phy_write(phydev, 27, 0x809A);
+ __phy_write(phydev, 28, 0x4443);
+ __phy_write(phydev, 27, 0x81A3);
+ __phy_write(phydev, 28, 0x0F00);
+ __phy_write(phydev, 31, 0x0a81);
+ __phy_write(phydev, 18, 0x0004);
+ __phy_write(phydev, 27, 0x83c8);
+ __phy_write(phydev, 28, 0x0005);
+ __phy_write(phydev, 31, 0x0a5c);
+ __phy_write(phydev, 18, 0x0003);
+ __phy_write(phydev, 27, 0xB820);
+ __phy_write(phydev, 28, 0x0010);
+ __phy_write(phydev, 27, 0xB830);
+ __phy_write(phydev, 28, 0x8000);
+
+ __phy_write(phydev, 27, 0xB800);
+ do {
+ reg_data = ((u16)__phy_read(phydev, 28) & 0x0040);
+ timer--;
+ if (timer == 0)
+ {
+ return -1;
+ }
+ } while (reg_data != 0x0040);
+
+ __phy_write(phydev, 27, 0x8020);
+ __phy_write(phydev, 28, 0x3300);
+ __phy_write(phydev, 27, 0xb82e);
+ __phy_write(phydev, 28, 0x0001);
+ __phy_write(phydev, 27, 0xb820);
+ __phy_write(phydev, 28, 0x0290);
+ __phy_write(phydev, 27, 0xa012);
+ __phy_write(phydev, 28, 0x0000);
+ __phy_write(phydev, 27, 0xa014);
+ __phy_write(phydev, 28, 0x401c);
+ __phy_write(phydev, 28, 0xa610);
+ __phy_write(phydev, 28, 0x8520);
+ __phy_write(phydev, 28, 0xa510);
+ __phy_write(phydev, 28, 0x21f4);
+ __phy_write(phydev, 27, 0xa01a);
+ __phy_write(phydev, 28, 0x0000);
+ __phy_write(phydev, 27, 0xa000);
+ __phy_write(phydev, 28, 0x11ef);
+ __phy_write(phydev, 27, 0xb820);
+ __phy_write(phydev, 28, 0x0210);
+ __phy_write(phydev, 27, 0xb82e);
+ __phy_write(phydev, 28, 0x0000);
+ __phy_write(phydev, 27, 0x8020);
+ __phy_write(phydev, 28, 0x0000);
+ __phy_write(phydev, 27, 0xb820);
+ __phy_write(phydev, 28, 0x0000);
+
+ __phy_write(phydev, 27, 0xb800);
+ timer = 2000; // set a 2ms timer
+ do {
+ reg_data = ((u16)__phy_read(phydev, 28) & 0x0040);
+ timer--;
+ if (timer == 0) {
+ return -1;
+ }
+ } while (reg_data != 0x0000);
+
+ __phy_write(phydev, 0, 0x2100); //power on
+
+ return 0;
+}
+
+static s16 RTL9000Bx_Initial_Configuration_Check(struct phy_device *phydev)
+{
+ u16 reg_data = 0, reg_data_temp;
+ u16 reg_data_chk = 0;
+ u32 timer = 2000; // set a 2ms timer
+
+ u16 page;
+ u16 reg, i, param_address;
+
+ for (i = 0; i < 27; i = i + 3) {
+ page = param_check[i];
+ reg = param_check[i + 1];
+ reg_data_chk = param_check[i + 2];
+
+ if (page == 0) {
+ __phy_write(phydev, 27, reg);
+ reg_data = __phy_read(phydev, 28);
+ }
+ else {
+ __phy_write(phydev, 31, page);
+ reg_data = __phy_read(phydev, reg);
+ }
+ if (reg_data_chk != reg_data) {
+ printk(KERN_ERR "%dth param error page=0x%04X reg=0x%04X data=0x%04X\r\n", i / 3, page, reg, reg_data);
+ return -1;
+ }
+ }
+
+ __phy_write(phydev, 27, 0xB820);
+ __phy_write(phydev, 28, 0x0010);
+ __phy_write(phydev, 27, 0xB830);
+ __phy_write(phydev, 28, 0x8000);
+
+ __phy_write(phydev, 27, 0xB800);
+ do {
+ reg_data = ((u16)__phy_read(phydev, 28) & 0x0040);
+ timer--;
+ if (timer == 0){
+ return -1;
+ }
+ } while (reg_data != 0x0040);
+
+ __phy_write(phydev, 27, 0x8020);
+ __phy_write(phydev, 28, 0x3300);
+ __phy_write(phydev, 27, 0xB82E);
+ __phy_write(phydev, 28, 0x0001);
+
+ param_address = 0;
+ for (i = 0; i < 5; i++) {
+ __phy_write(phydev, 31, 0xA01);
+ reg_data_temp = __phy_read(phydev, 17);
+ reg_data_temp &= ~(0x1ff);
+ param_address &= 0x1FF;
+ __phy_write(phydev, 17, (reg_data_temp | param_address));
+ __phy_write(phydev, 31, 0xA01);
+ reg_data = __phy_read(phydev, 18);
+ reg_data_chk = param_check2[i];
+ if (reg_data_chk != reg_data){
+ printk(KERN_ERR "%dth param error data=0x%04X expected_data=0x%04X\r\n", i, reg_data, reg_data_chk);
+ return -1;
+ }
+ param_address++;
+ }
+ for (i = 0; i < 3; i = i + 3) {
+ page = param_check3[i];
+ reg = param_check3[i + 1];
+ reg_data_chk = param_check3[i + 2];
+
+ if (page == 0) {
+ __phy_write(phydev, 27, reg);
+ reg_data = __phy_read(phydev, 28);
+ }
+ else {
+ __phy_write(phydev, 31, page);
+ reg_data = __phy_read(phydev, reg);
+ }
+ if (reg_data_chk != reg_data) {
+ printk(KERN_ERR "%dth param error page=0x%04X reg=0x%04X data=0x%04X\r\n", i / 3, page, reg, reg_data);
+ return -1;
+ }
+ }
+ __phy_write(phydev, 27, 0xB82E);
+ __phy_write(phydev, 28, 0x0000);
+ __phy_write(phydev, 27, 0x8020);
+ __phy_write(phydev, 28, 0x0000);
+ __phy_write(phydev, 27, 0xB820);
+ __phy_write(phydev, 28, 0x0000);
+
+ __phy_write(phydev, 27, 0xB800);
+ timer = 2000; // set a 2ms timer
+ do {
+ reg_data = ((u16)__phy_read(phydev, 28) & 0x0040);
+ timer--;
+ if (timer == 0){
+ return -1;
+ }
+ } while (reg_data != 0x0000);
+
+ return 0;
+}
static int rtl9000Bf_config_init(struct phy_device *phydev)
{
- printk("phy_debug:func:%s,line:%d\n", __FUNCTION__, __LINE__);
u32 mdio_data = 0;
- u32 io_data = 0;
- int timer = 2000;
+ u32 ret;
+ int times= 1;
+ struct device_node *np;
+
+ np = phydev->mdio.dev.of_node;
+ if (!np) {
+ dev_err(&phydev->mdio.dev, "No device tree node found\n");
+ return -ENODEV;
+ }
+
+ if (!s_rtl9000bf_mdio_dev) {
+ s_rtl9000bf_mdio_dev = kzalloc(sizeof(*s_rtl9000bf_mdio_dev), GFP_KERNEL);
+ if (!s_rtl9000bf_mdio_dev)
+ return -ENOMEM;
- __phy_write(phydev, 0, 0x8000); // PHY soft-reset
- mdelay(30);
-#if 0
- //phy power down
- phy_write(phydev, 0, 0x800);
- mdelay(10);
-#endif
- //sample_code 04
- //phy_write(phydev, 0x1F, 0x0A43);
- __phy_write(phydev, 0x1B, 0x8017);
- __phy_write(phydev, 0x1C, 0xFB03); // PHY patch request
- __phy_write(phydev, 0x1B, 0x8092);
- __phy_write(phydev, 0x1C, 0x6000);
- __phy_write(phydev, 0x1B, 0x80AF);
- __phy_write(phydev, 0x1C, 0x6000);
- __phy_write(phydev, 0x1B, 0x807D);
- __phy_write(phydev, 0x1C, 0x4443);
- __phy_write(phydev, 0x1B, 0x809A);
- __phy_write(phydev, 0x1C, 0x4443);
- __phy_write(phydev, 0x1B, 0x81A3);
- __phy_write(phydev, 0x1C, 0x0F00);
- __phy_write(phydev, 0x1F, 0x0A81);
- __phy_write(phydev, 0x12, 0x0004);
- __phy_write(phydev, 0x1B, 0x83C8);
- __phy_write(phydev, 0x1C, 0x0005);
- __phy_write(phydev, 0x1F, 0x0A5C);
- __phy_write(phydev, 0x12, 0x0003);
- __phy_write(phydev, 0x1B, 0xB820);
- __phy_write(phydev, 0x1C, 0x0010);
- __phy_write(phydev, 0x1B, 0xB830);
- __phy_write(phydev, 0x1C, 0x8000);
- //__phy_write(phydev, 0x1B, 0xB800);
- do {
- __phy_write(phydev, 0x1B, 0xB800);
- io_data = (__phy_read(phydev, 0x1C)) & 0x40;
- timer--;
- if (timer == 0) {
- timer = 2000;
- printk("phy_debug: phy init error func:%s,line:%d\n", __FUNCTION__, __LINE__);
-
- break;
+ s_rtl9000bf_mdio_dev->rst_gpio = of_get_named_gpio(np, "rst-gpio", 0);
+ if (s_rtl9000bf_mdio_dev->rst_gpio < 0) {
+ dev_err(&phydev->mdio.dev, "Failed to get reset gpio: %d\n", s_rtl9000bf_mdio_dev->rst_gpio);
+ kfree(s_rtl9000bf_mdio_dev);
+ s_rtl9000bf_mdio_dev = NULL;
+ return s_rtl9000bf_mdio_dev->rst_gpio;
}
- } while (io_data == 0);
-
- __phy_write(phydev, 0x1B, 0x8020);
- __phy_write(phydev, 0x1C, 0x3300);
- __phy_write(phydev, 0x1B, 0xB82E);
- __phy_write(phydev, 0x1C, 0x0001);
- __phy_write(phydev, 0x1B, 0xB820);
- __phy_write(phydev, 0x1C, 0x0290);
- __phy_write(phydev, 0x1B, 0xA012);
- __phy_write(phydev, 0x1C, 0x0000);
- __phy_write(phydev, 0x1B, 0xA014);
- __phy_write(phydev, 0x1C, 0x401C);
- __phy_write(phydev, 0x1C, 0xA610);
- __phy_write(phydev, 0x1C, 0x8520);
- __phy_write(phydev, 0x1C, 0xA510);
- __phy_write(phydev, 0x1C, 0x21F4);
- __phy_write(phydev, 0x1B, 0xA01A);
- __phy_write(phydev, 0x1C, 0x0000);
- __phy_write(phydev, 0x1B, 0xA000);
- __phy_write(phydev, 0x1C, 0x11EF);
- __phy_write(phydev, 0x1B, 0xB820);
- __phy_write(phydev, 0x1C, 0x0210);
- __phy_write(phydev, 0x1B, 0xB82E);
- __phy_write(phydev, 0x1C, 0x0000);
- __phy_write(phydev, 0x1B, 0x8020);
- __phy_write(phydev, 0x1C, 0x0000);
- __phy_write(phydev, 0x1B, 0xB820);
- __phy_write(phydev, 0x1C, 0x0000);
- //__phy_write(phydev, 0x1B, 0xB800);
- do {
- __phy_write(phydev, 0x1B, 0xB800);
- io_data = (__phy_read(phydev, 0x1C)) & 0x40;
- timer--;
- if (timer == 0) {
- printk("phy_debug: phy init error func:%s,line:%d\n", __FUNCTION__, __LINE__);
-
- break;
+ ret = mdio_misc_init(phydev);
+ if(ret){
+ goto err;
}
- } while (io_data != 0);
+ }
+
+ gpio_request(s_rtl9000bf_mdio_dev->rst_gpio, "phy-reset");
+ gpio_direction_output(s_rtl9000bf_mdio_dev->rst_gpio, 0);
+ mdelay(20);
+ gpio_set_value(s_rtl9000bf_mdio_dev->rst_gpio, 1);
+ mdelay(20);
- printk("phy_debug phy init success\n");
-
+ //check PHY accessible
+ while(times <= RTL9000BF_ACCESS_TIMES_OUT) {
+ mdio_data = phy_read(phydev, 0x10);
+ mdio_data = mdio_data & 0x0007;
+ if(mdio_data == 0x0003) {
+ printk(KERN_INFO "phy_info: phy is accessible \n");
+ break;
+ } else {
+ printk(KERN_INFO "phy_info: phy is not accessible times:%d \n", times);
+ gpio_direction_output(s_rtl9000bf_mdio_dev->rst_gpio, 0);
+ mdelay(30);
+ gpio_set_value(s_rtl9000bf_mdio_dev->rst_gpio, 1);
+ mdelay(20);
+ }
+ times++;
+ mdelay(1000);
+ }
+
+ if(times >= RTL9000BF_ACCESS_TIMES_OUT) {
+ printk(KERN_ERR "phy_info: phy init error times:%d \n", times);
+ ret = -1;
+ goto err;
+ }
+
+ times = 1;
+
+ //init phy init and check phy init
+ while(times <= RTL9000BF_INIT_TIMES_OUT) {
+ ret = RTL9000Bx_Initial_Configuration(phydev);
+ if(0 == ret) {
+ printk(KERN_INFO "phy_info: phy init success times:%d \n", times);
+ ret = RTL9000Bx_Initial_Configuration_Check(phydev);
+ if(0 == ret) {
+ printk(KERN_INFO "phy_info: phy init_check success times:%d \n", times);
+ break;
+ } else {
+ printk(KERN_INFO "phy_info: phy init_check error times:%d \n", times);
+ }
+ } else {
+ printk(KERN_INFO "phy_info: phy init error times:%d \n", times);
+ //phy hard reset
+ gpio_set_value(s_rtl9000bf_mdio_dev->rst_gpio, 0);
+ mdelay(30);
+ gpio_set_value(s_rtl9000bf_mdio_dev->rst_gpio, 1);
+ mdelay(20);
+ }
+ times++;
+ }
+
+ if(times >= RTL9000BF_INIT_TIMES_OUT) {
+ printk(KERN_ERR "phy_info: phy init error times:%d \n", times);
+ ret = -1;
+ goto err;
+ }
+
/* I/O Power Sllection */
- __phy_write(phydev, 0x1F, 0x0A4C);//change page to default value
+ //change page to default value
+ __phy_write(phydev, 0x1F, 0x0A4C);
mdio_data = __phy_read(phydev, 0x12);
mdio_data &= 0xC7FF;
mdio_data |= 4 << 11;
__phy_write(phydev, 0x12, mdio_data);
-
-
- printk("phy_debug set rgmii driving strengths is 1.8v\n");
+ printk(KERN_INFO "phy_info: set rgmii driving strengths is 1.8v \n");
phydev->autoneg = AUTONEG_DISABLE;
phydev->duplex = DUPLEX_FULL;
-#if 0
-//phy power on
- __phy_write(phydev, 0, 0x2100);
-#endif
- //mdio_misc_init(phydev);
return 0;
+
+err:
+ gpio_free(s_rtl9000bf_mdio_dev->rst_gpio);
+ kfree(s_rtl9000bf_mdio_dev);
+ s_rtl9000bf_mdio_dev = NULL;
+ return ret;
+}
+
+static void rtl9000Bf_remove(struct phy_device *phydev)
+{
+ if (s_rtl9000bf_mdio_dev && s_rtl9000bf_mdio_dev->phydev == phydev) {
+ misc_deregister(&mdio_misc_device);
+ gpio_free(s_rtl9000bf_mdio_dev->rst_gpio);
+ kfree(s_rtl9000bf_mdio_dev);
+ s_rtl9000bf_mdio_dev = NULL;
+ }
+
}
static int rtl9000Bf_read_status(struct phy_device *phydev)
{
- //printk("phy_debug:func:%s,line:%d\n", __FUNCTION__, __LINE__);
-
phydev->duplex = DUPLEX_FULL;
phydev->speed = SPEED_100;
phydev->pause = 0;
@@ -827,6 +1121,12 @@
return 0;
}
+static int rtl9000Bf_soft_reset(struct phy_device *phydev)
+{
+ return 0;
+}
+
+//#LYNQ_MODFIY modify for task-1618 2025/6/10 end
static struct phy_driver realtek_drvs[] = {
{
@@ -966,15 +1266,19 @@
.write_page = rtl821x_write_page,
.read_mmd = rtl822x_read_mmd,
.write_mmd = rtl822x_write_mmd,
- }, {
+ },
+//#LYNQ_MODFIY modify for task-1618 2025/6/10 start
+ {
PHY_ID_MATCH_EXACT(0x001ccb00),
.name = "RTL90000Bf PHY",
.config_init = &rtl9000Bf_config_init,
-// .remove = &rtl900Bf_remove,
+ .remove = &rtl9000Bf_remove,
.read_status = rtl9000Bf_read_status,
.suspend = genphy_suspend,
.resume = rtlgen_resume,
+ .soft_reset = rtl9000Bf_soft_reset,
},
+//#LYNQ_MODFIY modify for task-1618 2025/6/10 end
};
@@ -984,8 +1288,13 @@
static const struct mdio_device_id __maybe_unused realtek_tbl[] = {
{ PHY_ID_MATCH_VENDOR(0x001cc800) },
+//#LYNQ_MODFIY modify for task-1618 2025/6/10 start
+
{ 0x001ccb00, 0x001fffff },
+
+//#LYNQ_MODFIY modify for task-1618 2025/6/10 end
{ }
};
MODULE_DEVICE_TABLE(mdio, realtek_tbl);
+