[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/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(&reg_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, &reg_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(&reg_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);
+