Merge "[Feature][T106]version update to T106-V2.01.01.02P56U06.AP.15.05_CAP.15.05"
diff --git a/ap/app/Script/scripts/nat.sh b/ap/app/Script/scripts/nat.sh
old mode 100644
new mode 100755
index 1c9b82e..db36140
--- a/ap/app/Script/scripts/nat.sh
+++ b/ap/app/Script/scripts/nat.sh
@@ -6,6 +6,7 @@
 #
 
 path_sh=`nv get path_sh`
+rndis_ip_map=`cat /sys/class/lynq_nv_cfg/cdev_lynq_nv_cfg/rndis_ip_map`
 . $path_sh/global.sh
 echo "Info: nat.sh start " >> $test_log
 
@@ -18,7 +19,9 @@
 iptables -P FORWARD ACCEPT
 
 #clear nat
-iptables -t nat -F
+if [ "$rndis_ip_map" != "1" ];then
+	iptables -t nat -F
+fi
 iptables -t nat -X $ZTE_FORWARD_CHAIN
 iptables -t nat -X $ZTE_DMZ_CHAIN
 iptables -t nat -X $ZTE_MAPPING_CHAIN
@@ -29,6 +32,12 @@
 iptables -t nat -N $ZTE_DMZ_CHAIN
 iptables -t nat -N $ZTE_MAPPING_CHAIN
 
+if [ "$rndis_ip_map" == "1" ];then
+	iptables -t nat -D PREROUTING -j $ZTE_FORWARD_CHAIN
+	iptables -t nat -D PREROUTING -j $ZTE_DMZ_CHAIN
+	iptables -t nat -D PREROUTING -j $ZTE_MAPPING_CHAIN
+fi
+
 iptables -t nat -I PREROUTING 1 -j $ZTE_FORWARD_CHAIN
 iptables -t nat -I PREROUTING 1 -j $ZTE_DMZ_CHAIN
 iptables -t nat -I PREROUTING 1 -j $ZTE_MAPPING_CHAIN
diff --git a/ap/app/zte_comm/zte_mainctrl/netdev_proc.c b/ap/app/zte_comm/zte_mainctrl/netdev_proc.c
index a24b64c..367298f 100755
--- a/ap/app/zte_comm/zte_mainctrl/netdev_proc.c
+++ b/ap/app/zte_comm/zte_mainctrl/netdev_proc.c
@@ -871,16 +871,24 @@
 		{
 			char nat_enable[4] = {0};
 			
+			int rndis_ip_map = !system("cat /sys/class/lynq_nv_cfg/cdev_lynq_nv_cfg/rndis_ip_map | grep 1");
 			system_cmd_ex("iptables -P INPUT ACCEPT");
 			system_cmd_ex("iptables -P OUTPUT ACCEPT");
 			system_cmd_ex("iptables -P FORWARD ACCEPT");
-			system_cmd_ex("iptables -t nat -F");
+			if (rndis_ip_map == 0)
+				system_cmd_ex("iptables -t nat -F");
 			system_cmd_ex("iptables -t nat -X port_forward");
 			system_cmd_ex("iptables -t nat -X DMZ");
 			system_cmd_ex("iptables -t nat -X port_mapping");
 			system_cmd_ex("iptables -t nat -N port_forward");
 			system_cmd_ex("iptables -t nat -N DMZ");
 			system_cmd_ex("iptables -t nat -N port_mapping");
+			if (rndis_ip_map == 1)
+			{
+				system_cmd_ex("iptables -t nat -D PREROUTING -j port_forward");
+				system_cmd_ex("iptables -t nat -D PREROUTING -j DMZ");
+				system_cmd_ex("iptables -t nat -D PREROUTING -j port_mapping");
+			}
 			system_cmd_ex("iptables -t nat -I PREROUTING 1 -j port_forward");
 			system_cmd_ex("iptables -t nat -I PREROUTING 1 -j DMZ");
 			system_cmd_ex("iptables -t nat -I PREROUTING 1 -j port_mapping");
diff --git a/ap/app/zte_mdl/zte_mdl.c b/ap/app/zte_mdl/zte_mdl.c
index 38bb203..b883b2a 100755
--- a/ap/app/zte_mdl/zte_mdl.c
+++ b/ap/app/zte_mdl/zte_mdl.c
@@ -93,8 +93,13 @@
 }
 void wlan_entry(char *arg)
 {
-#if (defined _USE_VEHICLE_DC_REF)&&(defined _USE_VEHICLE_DC_REF_MMC0) //jb.qi add for wifi config on 20240301
-	wlan_main(0,NULL);
+#if (defined _USE_VEHICLE_DC_REF) //jb.qi add for wifi config on 20240301
+	if (system("cat /sys/class/lynq_nv_cfg/cdev_lynq_nv_cfg/wifi_enable | grep 1") == 0) {
+		wlan_main(0,NULL);
+	}
+	else{
+		printf("not need to start wifi\n");
+	}
 #endif
 	return;
 }
diff --git a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/Makefile b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/Makefile
index 1d079c1..89aebac 100755
--- a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/Makefile
+++ b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/Makefile
@@ -10,7 +10,7 @@
 
 # CPU-specific support
 obj-$(CONFIG_ARCH_ZX297520V3)	+= io.o  irq.o board-zx297520v3.o spinlock.o pcu.o \
-                               		gpio.o debug.o reset.o pwr_ctrl.o 
+                               		gpio.o debug.o reset.o pwr_ctrl.o lynq_ap_nv_cfg.o
 obj-$(CONFIG_ARCH_ZX297520V3_EVB) += zx297520v3-evb-devices.o
 obj-$(CONFIG_ARCH_ZX297520V3_MDL) += zx297520v3-mdl-devices.o
 obj-$(CONFIG_ARCH_ZX297520V3_WATCH) += zx297520v3-watch-devices.o
diff --git a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/board-zx297520v3.c b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/board-zx297520v3.c
index 929e125..2601f6e 100755
--- a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/board-zx297520v3.c
+++ b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/board-zx297520v3.c
@@ -669,6 +669,9 @@
 	pwr_buck3v3_on(POWER_WIFI);
 	printk("buck3v3 on, wifi power up.\n");
 #endif
+	//youchen@2024-06-20 add for lynq nv config begin
+	modify_zx29_device_table();
+	//youchen@2024-06-20 add for lynq nv config end
 	platform_add_devices(zx29_device_table, zx29_device_table_num);
 
 #if (defined CONFIG_SPI_ZX29) || (defined CONFIG_SPI_GPIO)
diff --git a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/include/mach/board.h b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/include/mach/board.h
index 060569c..d6b6a32 100644
--- a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/include/mach/board.h
+++ b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/include/mach/board.h
@@ -75,6 +75,9 @@
 
 extern struct platform_device *zx29_device_table[];
 extern unsigned int zx29_device_table_num;
+//youchen@2024-06-20 add for lynq nv config begin
+extern void modify_zx29_device_table();
+//youchen@2024-06-20 add for lynq nv config end
 
 void __init zx29_map_io(void);
 void __init zx29_clock_init(void);
diff --git a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/include/mach/iomap.h b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/include/mach/iomap.h
index c721782..fe908c7 100755
--- a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/include/mach/iomap.h
+++ b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/include/mach/iomap.h
@@ -247,7 +247,12 @@
 

 #define SECURE_PUK_BASE						(POWERON_TYPE_BASE + 0xc)/*secure pub key 256byte*/

 #define WDT_IRAM_BASE						(SECURE_PUK_BASE + 0x100)/*wdt iram flag 36byte*/

-#define MMC_CFG_BASE						(WDT_IRAM_BASE+0x34)/*mmc flag 4Byte*/

+//youchen@2024-06-20 add for lynq nv config begin
+//#define MMC_CFG_BASE						(WDT_IRAM_BASE+0x34)/*mmc flag 4Byte*/

+#define MMC_LYNQ_NV_CFG_ADDR				(WDT_IRAM_BASE+0x34)/*mmc flag 1024Byte*/

+#define MMC_LYNQ_NV_CFG_SIZE				(0x100UL)
+//youchen@2024-06-20 add for lynq nv config end
+//
 /**************************************************************************************

  *                        iram: tsc

  **************************************************************************************/

diff --git a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/lynq_ap_nv_cfg.c b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/lynq_ap_nv_cfg.c
new file mode 100755
index 0000000..7fae817
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/lynq_ap_nv_cfg.c
@@ -0,0 +1,232 @@
+#include <linux/module.h>

+#include <linux/kernel.h>

+#include <linux/types.h>

+#include <linux/init.h>

+#include <linux/slab.h>

+#include <linux/device.h>

+#include <lynq/lynq_ap_nv_cfg.h>

+#include <linux/crc16.h>

+#include <mach/iomap.h>

+#include <linux/cdev.h>

+//#include <asm-generic/iomap.h>

+#include "lynq_default_nv_cfg.h"

+

+static struct nv_cfg_info * g_nv_cfg_info = NULL;

+

+static struct nv_cfg_info * get_valid_nv_cfg(unsigned char * buff, unsigned int len)

+{

+    int content_len, pos, crc;

+    unsigned char * p_cfg_body = NULL;

+    struct lynq_nv_cfg_header *p_tail;

+    struct version_info * p_versions;

+    struct lynq_nv_cfg * p_nv_cfg = (struct lynq_nv_cfg *)buff;

+    if (p_nv_cfg == NULL)

+        return NULL;

+    if (p_nv_cfg->head.magic_flag != 0xaa55 || p_nv_cfg->head.valid_flag != 1 ||

+            len < (p_nv_cfg->head.content_len + sizeof(struct lynq_nv_cfg_header)*2))

+    {

+        printk("got bad header\n");

+        return NULL;

+    }

+    content_len = (char*)&p_nv_cfg->tail - (char*)&p_nv_cfg->head - sizeof(struct lynq_nv_cfg_header);

+    //actual content len less than default request len, maybe a lower version protocol, ignore

+    if (content_len > p_nv_cfg->head.content_len || content_len != sizeof(lynq_nv_cfg_bitmap))

+    {

+        printk("got bad content len\n");

+        return NULL;

+    }

+    else if ( content_len == p_nv_cfg->head.content_len)

+    {

+        if (p_nv_cfg->tail.magic_flag != 0x55aa || p_nv_cfg->tail.valid_flag != 1

+                || p_nv_cfg->tail.content_len != p_nv_cfg->head.content_len)

+        {

+            printk("got bad tail %d\n", __LINE__);

+            return NULL;

+        }

+        p_cfg_body = (unsigned char*)kzalloc(p_nv_cfg->head.content_len, GFP_KERNEL);

+        memcpy(p_cfg_body, &p_nv_cfg->content, p_nv_cfg->head.content_len);

+        p_versions = p_nv_cfg->versions;

+    }

+    else // maybe a newer protocol, need backward compatible

+    {

+        p_cfg_body = (unsigned char*)&p_nv_cfg->content;

+        p_tail = (struct lynq_nv_cfg_header *)(p_cfg_body+p_nv_cfg->head.content_len);

+        if (p_tail->magic_flag != 0x55aa || p_tail->valid_flag != 1

+                || p_tail->content_len != p_nv_cfg->head.content_len)

+        {

+            printk("got bad tail %d\n", __LINE__);

+            return NULL;

+        }

+        p_versions = (struct version_info *)(p_cfg_body+p_nv_cfg->head.content_len + sizeof (struct lynq_nv_cfg_header));

+        p_cfg_body = (unsigned char*)kzalloc(p_nv_cfg->head.content_len, GFP_KERNEL);

+        memcpy(p_cfg_body, &p_nv_cfg->content, p_nv_cfg->head.content_len);

+    }

+

+    while(p_versions->soft_ver != 0 && p_versions->crc != 0)

+    {

+        if (p_versions->soft_ver != lynq_default_soft_version)

+        {

+            p_versions++;

+            continue;

+        }

+

+        //

+        for(pos = 0; pos < content_len; pos ++)

+        {

+            p_cfg_body[pos] &= lynq_nv_cfg_bitmap[pos];

+        }

+

+        crc = crc16(0, p_cfg_body, content_len);

+        printk("crc is %d\n", crc);

+

+        if (crc != p_versions->crc)

+        {

+            printk("got bad crc\n");

+            break;

+        }

+

+        return (struct nv_cfg_info *)p_cfg_body;

+    }

+

+    printk("no valid protocal version found\n");

+

+    if (p_cfg_body != NULL)

+    {

+        kfree(p_cfg_body);

+    }

+    return NULL;

+}

+

+static int read_from_uboot_memory(unsigned char * buff)

+{

+    int len, total_read_cnt, min_read_cnt, zero_cnt, ret;

+    int * curr_pos;

+    struct lynq_nv_cfg_header * head = (struct lynq_nv_cfg_header *)buff;

+    curr_pos = (int*)buff;

+    *curr_pos = ioread32(MMC_LYNQ_NV_CFG_ADDR);

+    printk("read data is %08x\n", *curr_pos);

+    curr_pos++;

+    if (head->magic_flag != 0xaa55 || head->valid_flag != 1

+            || head->content_len > (MMC_LYNQ_NV_CFG_SIZE - sizeof(struct lynq_nv_cfg_header)*2))

+    {

+        printk("got bad header len %d\n",head->content_len);

+        printk("magic %04x-need %04x\n", head->magic_flag, 0xaa55);

+        return 0;

+    }

+    min_read_cnt = head->content_len + sizeof(struct lynq_nv_cfg_header) + sizeof (struct version_info) + sizeof(int);

+    if (min_read_cnt > MMC_LYNQ_NV_CFG_SIZE)

+    {

+        total_read_cnt = MMC_LYNQ_NV_CFG_SIZE;

+        min_read_cnt = MMC_LYNQ_NV_CFG_SIZE;

+    }

+

+    total_read_cnt = total_read_cnt / sizeof (int);

+    min_read_cnt = min_read_cnt / sizeof (int);

+

+    len = 1;

+    zero_cnt = 0;

+    while(len < total_read_cnt && zero_cnt < 4)

+    {

+        ret = ioread32(MMC_LYNQ_NV_CFG_ADDR + len * sizeof(int));

+        printk("read data %08x\n", ret);

+        *curr_pos++ = ret;

+        if (ret != 0) {

+            zero_cnt = 0;

+        }

+        else{

+            zero_cnt ++;

+        }

+        len ++;

+    }

+

+    return len * sizeof(int);

+}

+

+struct nv_cfg_info *get_ap_nv_cfg_info()

+{

+

+    int len;

+    unsigned char * buff;

+    struct nv_cfg_info * ret;

+    printk("enter get_ap_nv_cfg_info\n");

+    if (g_nv_cfg_info != NULL)

+        return g_nv_cfg_info;

+

+    printk("[%s] start init!\n", __func__);

+

+    ret = NULL;

+    buff = kzalloc(MMC_LYNQ_NV_CFG_SIZE, GFP_KERNEL);

+    printk("enter read_from_uboot_memory\n");

+    len = read_from_uboot_memory(buff);

+    if (len > 0)

+    {

+        printk("enter check cfg from uboot\n");

+        ret = get_valid_nv_cfg(buff, len);

+    }

+    // read default in head file

+    if (ret == NULL)

+    {

+        printk("enter check lynq_default_nv_cfg_value\n");

+        ret = get_valid_nv_cfg(lynq_default_nv_cfg_value, sizeof (lynq_default_nv_cfg_value));

+    }

+

+    // use local default values

+    if (ret == NULL){

+        printk("enter use local default values\n");

+        ret = (struct nv_cfg_info *)kzalloc(sizeof (struct nv_cfg_info), GFP_KERNEL);

+        memset(ret, 0, sizeof(struct nv_cfg_info));

+        ret->mmc0_enable = 1;

+        ret->mmc1_enable = 1;

+    }

+

+    g_nv_cfg_info = ret;

+

+    return ret;

+}

+

+#define DECLARE_NV_CFG_ATTR(name) \

+static ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf) \

+{ \

+    return sprintf(buf, "%d", get_##name()); \

+}\

+\

+static DEVICE_ATTR(name, 0664, name##_show, NULL); \

+

+

+DECLARE_NV_CFG_ATTR(wifi_enable)

+DECLARE_NV_CFG_ATTR(rndis_ip_map)

+/*

+static struct attribute * lynq_nv_cfg_attrs[] = {

+    &dev_attr_wifi_enable.attr,

+    NULL,

+};

+

+static const struct attribute_group lynq_nv_cfg_attr_grp = {

+    .attrs = lynq_nv_cfg_attrs,

+};

+*/

+static struct class * lynq_nv_cfg_class;

+static struct class_device * lynq_nv_cfg_device;

+static int __init lynq_nv_cfg_init(void)

+{

+    printk("[%s] start init!\n", __func__);

+    lynq_nv_cfg_class =  class_create(THIS_MODULE, "lynq_nv_cfg");

+    if (lynq_nv_cfg_class == NULL)

+        return -1;

+    lynq_nv_cfg_device = device_create(lynq_nv_cfg_class, NULL, MKDEV(1,0), NULL, "cdev_lynq_nv_cfg");

+    if (lynq_nv_cfg_device == NULL)

+        return -1;

+    //sysfs_create_group(&lynq_nv_cfg_device->kobj, &lynq_nv_cfg_attr_grp);

+    device_create_file(lynq_nv_cfg_device, &dev_attr_wifi_enable);

+    device_create_file(lynq_nv_cfg_device, &dev_attr_rndis_ip_map);

+    return 0;

+}

+

+static void __exit lynq_nv_cfg_exit(void)

+{

+    printk("[%s] start exit!\n", __func__);

+    //platform_driver_unregister(&lynq_nv_cfg_device);

+}

+

+module_init(lynq_nv_cfg_init);

+module_exit(lynq_nv_cfg_exit);

diff --git a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/lynq_default_nv_cfg.h b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/lynq_default_nv_cfg.h
new file mode 100755
index 0000000..85ebb80
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/lynq_default_nv_cfg.h
@@ -0,0 +1,18 @@
+#ifndef LYNQ_DEFAULT_NV_CFG_H

+#define LYNQ_DEFAULT_NV_CFG_H

+

+static const char lynq_default_nv_cfg_value1[] = {

+    '\x55', '\xaa', '\x0b', '\x00', '\xff', '\xff', '\xff', '\xff', '\x00', '\xaa', '\x55', '\x0b', '\x00', '\x05', '\x10', '\x0c', '\x03'

+};

+

+static const char lynq_default_nv_cfg_value[] = {

+    '\x55', '\xaa', '\x09', '\x00', '\xc0', '\x80', '\x80', '\x00', '\xaa', '\x55', '\x09', '\x00', '\x05', '\x10', '\x0c', '\x03'

+};

+

+static const char lynq_nv_cfg_bitmap[] = {

+    '\xC0', '\x80', '\x80', '\x80'

+};

+

+static int lynq_default_soft_version = 1;

+

+#endif // LYNQ_DEFAULT_NV_CFG_H

diff --git a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/pwr_ctrl.c b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/pwr_ctrl.c
index e5ec161..0ba80af 100755
--- a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/pwr_ctrl.c
+++ b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/pwr_ctrl.c
@@ -29,6 +29,10 @@
 //++yuwei 20160719
 #include <mach/gpio_cfg.h>
 //++
+//youchen@2024-06-20 add for lynq nv config begin
+#include <lynq/lynq_ap_nv_cfg.h>
+//youchen@2024-06-20 add for lynq nv config end
+
 
 static unsigned int pwr_buck3v3_init_flag	= 0;
 static unsigned int pwr_buck3v3_status  		= 0;
@@ -287,7 +291,7 @@
 	   }
 
 	   // zw.wang The WiFi-related control pins gpio132 and gpio91 are still affected after the uboot removes mmc0 on 20240531 on start
-	   if ((ioread32(MMC_CFG_BASE) & (1 << 0)))
+	   if (get_mmc0_enable() == 1)
 	   {
 		   gpio_direction_output(ZX29_GPIO_132, 1);
 		   gpio_direction_output(ZX29_GPIO_91, 1);
diff --git a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/zx297520v3-mdl-devices.c b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/zx297520v3-mdl-devices.c
index 485d8f2..74cba0d 100755
--- a/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/zx297520v3-mdl-devices.c
+++ b/ap/os/linux/linux-3.4.x/arch/arm/mach-zx297520v3/zx297520v3-mdl-devices.c
@@ -64,6 +64,9 @@
 #endif
 #include <mach/gpio_cfg.h>
 
+//youchen@2024-06-20 add for lynq nv config begin
+#include <lynq/lynq_ap_nv_cfg.h>
+//youchen@2024-06-20 add for lynq nv config end
 
 struct zx29_uart_platdata  zx29_uart0_platdata= {
 		.uart_use = 1,
@@ -1149,7 +1152,7 @@
 #endif
 
 #ifdef CONFIG_MMC_ZX29
-#if (defined _USE_VEHICLE_DC_REF)&&(defined _USE_VEHICLE_DC_REF_MMC0) //jb.qi add for wifi config on 20240221
+#if (defined _USE_VEHICLE_DC_REF) //jb.qi add for wifi config on 20240221
     &zx29_sdmmc0_device,
 #endif
     &zx29_sdmmc1_device,
@@ -1232,6 +1235,37 @@
 
 unsigned int zx29_device_table_num=ARRAY_SIZE(zx29_device_table);
 
+//youchen@2024-06-20 add for lynq nv config begin
+void modify_zx29_device_table()
+{
+#if (defined _USE_VEHICLE_DC_REF) 
+	int i, last;
+
+	last = 0;
+	for( i=0; i<zx29_device_table_num;i++ )
+	{
+		if (zx29_device_table[i] == &zx29_sdmmc0_device && get_mmc0_enable() == 0)
+		{
+			continue;
+		}
+		else if (zx29_device_table[i] == &zx29_sdmmc1_device && get_mmc1_enable() == 0)
+		{
+			continue;
+		}
+		else if (i != last)
+		{
+			zx29_device_table[last++] = zx29_device_table[i];
+		}
+		else
+		{
+			last++;
+		}
+	}
+	zx29_device_table_num -= (i - last);
+#endif
+}
+//youchen@2024-06-20 add for lynq nv config end
+
 #if (defined CONFIG_SPI_ZX29) || (defined CONFIG_SPI_GPIO)
 struct zx29_lcd_platform_data lead_lcd_platform = {
 	.spi_dcx_gpio = PIN_SPI_DCX,
diff --git a/ap/os/linux/linux-3.4.x/drivers/mmc/host/zx29_mmc-pltfm.c b/ap/os/linux/linux-3.4.x/drivers/mmc/host/zx29_mmc-pltfm.c
index 0cf0d7f..1100d88 100755
--- a/ap/os/linux/linux-3.4.x/drivers/mmc/host/zx29_mmc-pltfm.c
+++ b/ap/os/linux/linux-3.4.x/drivers/mmc/host/zx29_mmc-pltfm.c
@@ -44,6 +44,11 @@
 static struct dw_mci *dw_mci_host_ptr[2];
 volatile u8 mmc0_data1_flag = 0xff;
 //zw.wang The sdio0 pin is configured in gpio mode before and after wifi uninstallation on 20240521 on end
+
+//youchen@2024-06-20 add for lynq nv config begin
+#include <lynq/lynq_ap_nv_cfg.h>
+//youchen@2024-06-20 add for lynq nv config end
+
 static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
 {
 	*cmdr |= SDMMC_CMD_USE_HOLD_REG;
@@ -551,7 +556,8 @@
 #endif
 
 #ifdef _USE_VEHICLE_DC
-	if(ioread32(MMC_CFG_BASE)&(1<<pdev->id)){
+	//youchen@2024-06-20 add for lynq nv config
+	if((0 == pdev->id && get_mmc0_enable() == 1) || (1 == pdev->id && get_mmc1_enable() == 1)){
 		return dw_mci_pltfm_register(pdev, drv_data);
 	}else
 	{
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800d80l/wifi_dev_aic88.c b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800d80l/wifi_dev_aic88.c
index a020bbc..18b3a9c 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800d80l/wifi_dev_aic88.c
+++ b/ap/os/linux/linux-3.4.x/drivers/net/wireless/aic8800d80l/wifi_dev_aic88.c
@@ -6,7 +6,7 @@
 #include <asm/uaccess.h>
 #include <linux/slab.h>
 //zw.wang The WiFi-related control pins gpio132 and gpio91 are still affected after the uboot removes mmc0 on 20240531 on start
-#include <mach/iomap.h>
+#include <lynq/lynq_ap_nv_cfg.h>
 //zw.wang The WiFi-related control pins gpio132 and gpio91 are still affected after the uboot removes mmc0 on 20240531 on end
 
 #define WIFI_IOCTL_STOP   0x0
@@ -51,7 +51,7 @@
 	int ret = 0;
 	void __user *argp = (void __user *) arg;
 	//zw.wang The WiFi-related control pins gpio132 and gpio91 are still affected after the uboot removes mmc0 on 20240531 on start
-	if(!(ioread32(MMC_CFG_BASE)&(1<<0)))
+	if(!get_mmc0_enable() || !get_wifi_enable())
         return -ENODEV;
 	//zw.wang The WiFi-related control pins gpio132 and gpio91 are still affected after the uboot removes mmc0 on 20240531 on end
 	switch (cmd) {
diff --git a/ap/os/linux/linux-3.4.x/drivers/usb/gadget/u_ether.c b/ap/os/linux/linux-3.4.x/drivers/usb/gadget/u_ether.c
index 5f9d709..16cf5dc 100755
--- a/ap/os/linux/linux-3.4.x/drivers/usb/gadget/u_ether.c
+++ b/ap/os/linux/linux-3.4.x/drivers/usb/gadget/u_ether.c
@@ -26,6 +26,10 @@
 #include "multi_packet.h"
 #include <mach/highspeed_debug.h>
 #include <linux/nvro_comm.h>
+//youchen@2024-06-20 add for lynq nv config begin
+#include <lynq/lynq_ap_nv_cfg.h>
+//youchen@2024-06-20 add for lynq nv config end
+
 /*
  * This component encapsulates the Ethernet link glue needed to provide
  * one (!) network link through the USB gadget stack, normally "usb0".
@@ -1007,6 +1011,13 @@
 	{0x34,0x4b,0x50,0x00,0x00,0x0a},
 	{0x34,0x4b,0x50,0x00,0x00,0x0b},
 	{0x34,0x4b,0x50,0x00,0x00,0x0c}};
+//youchen@2024-06-20 add for lynq nv config begin
+static u8 eth_addrs2[ETH_MAX_NUM][ETH_ALEN] = {
+	{0x3a,0x4b,0x50,0x00,0x00,0x00},
+	{0x34,0x4b,0x50,0x00,0x00,0x0a},
+	{0x34,0x4b,0x50,0x00,0x00,0x0b},
+	{0x34,0x4b,0x50,0x00,0x00,0x0c}};
+//youchen@2024-06-20 add for lynq nv config end
 #define NVUSB_MAC_LEN 6
 
 
@@ -1323,7 +1334,17 @@
     {
     	random_ether_addr(net->dev_addr);
 	usb_printk("random_ether_addr ok\n");
-	host_addr = &eth_addrs[num][0];
+	//youchen@2024-06-20 add for lynq nv config begin
+	if (get_rndis_mac_convert() == 1)
+	{
+		host_addr = &eth_addrs2[num][0];
+		printk("rndis_mac_convert finish\n");
+	}
+	else
+	{
+		host_addr = &eth_addrs[num][0];
+	}
+	//youchen@2024-06-20 add for lynq nv config end
 	memcpy(dev->host_mac, host_addr, ETH_ALEN);
 
 	if (ethaddr)
diff --git a/ap/os/linux/linux-3.4.x/include/lynq/lynq_ap_nv_cfg.h b/ap/os/linux/linux-3.4.x/include/lynq/lynq_ap_nv_cfg.h
new file mode 100755
index 0000000..e13fb05
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/include/lynq/lynq_ap_nv_cfg.h
@@ -0,0 +1,61 @@
+#ifndef LYNQ_AP_NV_CFG_H

+#define LYNQ_AP_NV_CFG_H

+

+#pragma pack(1)

+struct lynq_nv_cfg_header

+{

+    unsigned short magic_flag;

+    unsigned short valid_flag:1;

+    unsigned short content_len:15;

+};

+struct nv_cfg_info{

+    unsigned char reserved_0:6;

+    unsigned char mmc1_enable:1;

+    unsigned char mmc0_enable:1;

+    unsigned char reserved_1:7;

+    unsigned char wifi_enable:1;

+    unsigned char reserved_2:7;

+    unsigned char rndis_mac_convert:1;

+    unsigned char reserved_3:7;

+    unsigned char rndis_ip_map:1;

+};

+

+struct version_info{

+    unsigned short soft_ver:12;

+    unsigned short hard_ver:4;

+    unsigned short crc;

+};

+

+struct lynq_nv_cfg

+{

+    struct lynq_nv_cfg_header head;

+    struct nv_cfg_info content;

+    struct lynq_nv_cfg_header tail;

+    struct version_info versions[0];

+};

+

+#pragma pack()

+

+extern struct nv_cfg_info *get_ap_nv_cfg_info();

+

+static inline int get_mmc0_enable() {

+    return get_ap_nv_cfg_info()->mmc0_enable;

+}

+

+static inline int get_mmc1_enable() {

+    return get_ap_nv_cfg_info()->mmc1_enable;

+}

+

+static inline int get_wifi_enable() {

+    return get_ap_nv_cfg_info()->wifi_enable;

+}

+

+static inline int get_rndis_mac_convert() {

+    return get_ap_nv_cfg_info()->rndis_mac_convert;

+}

+

+static inline int get_rndis_ip_map() {

+    return get_ap_nv_cfg_info()->rndis_ip_map;

+}

+

+#endif // LYNQ_AP_NV_CFG_H

diff --git a/boot/common/src/uboot/drivers/peripheral/Makefile b/boot/common/src/uboot/drivers/peripheral/Makefile
index 103b373..2f058a9 100755
--- a/boot/common/src/uboot/drivers/peripheral/Makefile
+++ b/boot/common/src/uboot/drivers/peripheral/Makefile
@@ -42,6 +42,8 @@
 COBJS-$(CONFIG_ZX297520V3E_MDL_AB)	+= peripheral.o
 COBJS-$(CONFIG_ZX297520V3E_VEHICLE_DC)	+= peripheral.o
 COBJS-$(CONFIG_ZX297520V3E_VEHICLE_DC_REF)	+= peripheral.o
+COBJS-$(CONFIG_ZX297520V3E_VEHICLE_DC_REF)	+= lynq_uboot_nv_cfg.o
+COBJS-$(CONFIG_ZX297520V3E_VEHICLE_DC_REF)	+= oem_nv_cfg.o
 
 COBJS	:= $(sort $(COBJS-y))
 SRCS	:= $(COBJS:.o=.c)
diff --git a/boot/common/src/uboot/drivers/peripheral/lynq_uboot_nv_cfg.c b/boot/common/src/uboot/drivers/peripheral/lynq_uboot_nv_cfg.c
new file mode 100755
index 0000000..36fe651
--- /dev/null
+++ b/boot/common/src/uboot/drivers/peripheral/lynq_uboot_nv_cfg.c
@@ -0,0 +1,194 @@
+#include <dma_cfg.h>
+
+#ifdef LYNQ_NV_CFG_SUPPORT
+
+#include "../rsa/drv_rsa.h"
+#include "../hash/drv_hash.h"
+#include "lynq_uboot_nv_cfg.h"
+
+#define LYNQ_ERROR(t) do{BOOT_PRINTF(UBOOT_NOTICE, t);}while(0)
+
+#define DEBUG_LYNQ_NV_CFG 1
+
+#ifdef DEBUG_LYNQ_NV_CFG
+void lynq_hex_display(u32 * buff, int len)
+{
+    int i, pos;
+    char * txt_buffer = malloc(4096);
+    memset(txt_buffer, 0, 4096);
+    pos = 0;
+    BOOT_PRINTF(UBOOT_NOTICE, "display data begin:\n");
+    for(i=0;i<len;i++)
+    {
+        pos += sprintf(txt_buffer+pos, "%08x", buff[i]);
+        //BOOT_PRINTF(UBOOT_NOTICE, "%08x ", buff[i]);
+        if (i % 8 == 7 )
+        {
+            BOOT_PRINTF(UBOOT_NOTICE, "%s\n", txt_buffer);
+            memset(txt_buffer, 0, 4096);
+            pos = 0;
+        }
+    }
+    BOOT_PRINTF(UBOOT_NOTICE, "%s\n", txt_buffer);
+    free(txt_buffer);
+}
+#define LYNQ_DEBUG(t) do{BOOT_PRINTF(UBOOT_NOTICE, t);}while(0)
+#else
+#define lynq_hex_display(...) do{}while(0)
+#define LYNQ_DEBUG(t) do{}while(0)
+#endif
+
+int check_lynq_nv_cfg(void)
+{
+    struct lynq_nv_cfg * tmp_cfg;
+    int content_len, pos, len, x;
+    T_Rsa_Paramter sRSAInput;
+    u32 uiRet = -1;
+    u32 uiHashResArr[4] = {0};
+    u32 uiHashResLen = 0;
+    u32 uiRsaResArr[RSA_U32_LEN] = {0};
+    u32 puiArrPubKey[RSA_U32_LEN*2] = {0};
+    u32 *puiRsaResAddr = NULL;
+    char * tmp_buffer = malloc(MMC_LYNQ_NV_CFG_SIZE*3);
+    memset(tmp_buffer, 0 , MMC_LYNQ_NV_CFG_SIZE*3);
+    tmp_cfg = (struct lynq_nv_cfg *)tmp_buffer;
+    if (sizeof (lynq_nv_cfg_bitmap) <= 0 || sizeof (lynq_nv_cfg_bitmap) != sizeof (oem_nv_cfg_bitmap))
+    {
+        LYNQ_ERROR("got bad bitmap\n");
+        goto fail_exit;
+    }
+    if (sizeof (lynq_nv_cfg_publickey) != LYNQ_NV_CFG_PUBLICKEY_LEN)
+    {
+        LYNQ_ERROR("got bad public key\n");
+        goto fail_exit;
+    }
+    if (sizeof (lynq_nv_cfg_sign) != LYNQ_NV_CFG_SIGN_LEN )
+    {
+        LYNQ_ERROR("got bad sign\n");
+        goto fail_exit;
+    }
+    if (sizeof(lynq_nv_cfg_value) == sizeof(struct lynq_nv_cfg))
+    {
+        pos = 0;
+        len = sizeof(lynq_nv_cfg_value);
+        memcpy(tmp_cfg, lynq_nv_cfg_value, len);
+        pos += len;
+        content_len = ((char*)&tmp_cfg->tail - (char*)&tmp_cfg->head) - sizeof(struct lynq_nv_cfg_header);
+
+        if (tmp_cfg->head.magic_flag == 0xaa55 && tmp_cfg->tail.magic_flag == 0x55aa
+                && tmp_cfg->head.content_len == content_len  && tmp_cfg->tail.content_len == content_len
+                && tmp_cfg->head.valid_flag == 1 && tmp_cfg->tail.valid_flag == 1)
+        {
+            len = sizeof (lynq_nv_cfg_version);
+            memcpy(tmp_buffer+pos, lynq_nv_cfg_version, len);
+            pos += len;
+
+            len = sizeof (lynq_nv_cfg_bitmap);
+            memcpy(tmp_buffer+pos, lynq_nv_cfg_bitmap, len);
+            pos += len;
+
+            len = sizeof (oem_nv_cfg_bitmap);
+            memcpy(tmp_buffer+pos, oem_nv_cfg_bitmap, len);
+            pos += len;
+
+            for(x=0; x < sizeof(lynq_nv_cfg_bitmap); x++)
+            {
+                tmp_cfg->content[x] &= lynq_nv_cfg_bitmap[x];
+            }
+
+            memcpy(puiArrPubKey, lynq_nv_cfg_publickey, RSA_BYTE_LEN);
+            memcpy((puiArrPubKey+(RSA_U32_LEN*2 -1)), lynq_nv_cfg_publickey + RSA_BYTE_LEN, sizeof(u32));
+            sRSAInput.udCalMode = RSA_MOD_EXPO_WITH_INIT;
+            sRSAInput.udNbitLen = RAS_BIT_LEN;
+            sRSAInput.udEbitLen = RAS_BIT_LEN;
+            sRSAInput.pudInputM = (u32*)lynq_nv_cfg_sign;
+            sRSAInput.pudInputE = (u32*)puiArrPubKey + RSA_U32_LEN;
+            sRSAInput.pudInputN = ((u32*)puiArrPubKey);
+            sRSAInput.pudOutputP = uiRsaResArr;
+
+            lynq_hex_display(sRSAInput.pudInputE, RSA_U32_LEN);
+            lynq_hex_display(sRSAInput.pudInputN, RSA_U32_LEN);
+            lynq_hex_display(sRSAInput.pudInputM, RSA_U32_LEN);
+
+            uiRet = Rsa_Calculate(sRSAInput);
+            if(uiRet != 0)
+            {
+                LYNQ_ERROR("calc rsa fail\n");
+                goto fail_exit;
+            }
+
+            lynq_hex_display(uiRsaResArr, RSA_U32_LEN);
+
+            uiRet = Hash_Calculate(HASH_MODE_MD5,
+                                   HASH_SMALL_ENDIAN,
+                                   (u32*)tmp_buffer,
+                                   pos,
+                                   NULL,
+                                   0,
+                                   uiHashResArr,
+                                   &uiHashResLen);
+            if(uiRet != 0)
+            {
+                LYNQ_ERROR("calc hash fail\n");
+                goto fail_exit;
+            }
+            lynq_hex_display(uiHashResArr, uiHashResLen);
+
+            puiRsaResAddr = sRSAInput.pudOutputP + (RSA_U32_LEN - uiHashResLen);
+
+            if (memcmp(puiRsaResAddr, uiHashResArr, uiHashResLen*sizeof (u32)) != 0)
+            {
+                LYNQ_ERROR("not valid sign\n");
+                goto fail_exit;
+            }
+        }
+        else
+        {
+            LYNQ_ERROR("not valid head\n");
+            goto fail_exit;
+        }
+    }
+    else
+    {
+        LYNQ_ERROR("not valid cfg\n");
+        goto fail_exit;
+    }
+
+    free(tmp_buffer);
+//    for (x=0;x<10;x++)
+//        udelay (600000);
+//    LYNQ_ERROR("cy: lynq_setup_nv_cfg\n");
+    return 0;
+fail_exit:
+    free(tmp_buffer);
+    return -1;
+}
+
+extern char* get_oem_nv_cfg(void);
+void lynq_setup_nv_cfg(void)
+{
+    char * oem_cfg_buff;
+    memset((void*)MMC_LYNQ_NV_CFG_ADDR, 0, MMC_LYNQ_NV_CFG_SIZE);
+    if (sizeof(lynq_nv_cfg_value) <= MMC_LYNQ_NV_CFG_SIZE && check_lynq_nv_cfg() == 0)
+    {
+        oem_cfg_buff = get_oem_nv_cfg();
+        if (oem_cfg_buff != NULL)
+        {
+            memcpy((void*)MMC_LYNQ_NV_CFG_ADDR, oem_cfg_buff, sizeof(lynq_nv_cfg_value));
+            free(oem_cfg_buff);
+            LYNQ_DEBUG("using oem nv cfg\n");
+        }
+        else
+        {
+            memcpy((void*)MMC_LYNQ_NV_CFG_ADDR, lynq_nv_cfg_value, sizeof(lynq_nv_cfg_value));
+            LYNQ_DEBUG("using lynq nv cfg\n");
+        }
+    }
+    else
+    {
+        LYNQ_ERROR("lynq_setup_nv_cfg no valid nv config\n");
+    }
+}
+
+#endif
+
diff --git a/boot/common/src/uboot/drivers/peripheral/lynq_uboot_nv_cfg.h b/boot/common/src/uboot/drivers/peripheral/lynq_uboot_nv_cfg.h
new file mode 100755
index 0000000..d2f0da9
--- /dev/null
+++ b/boot/common/src/uboot/drivers/peripheral/lynq_uboot_nv_cfg.h
@@ -0,0 +1,60 @@
+#ifndef __LYNQ_UBOOT_NV_CFG__H__
+#define __LYNQ_UBOOT_NV_CFG__H__
+
+#define RAS_BIT_LEN 1024
+#define RSA_BYTE_LEN (RAS_BIT_LEN / 8)
+#define RSA_U32_LEN (RSA_BYTE_LEN / sizeof(u32))
+#define LYNQ_NV_CFG_SIGN_LEN RSA_BYTE_LEN
+#define LYNQ_NV_CFG_PUBLICKEY_LEN (RSA_BYTE_LEN + sizeof(u32))
+
+#pragma pack(1)
+
+struct lynq_nv_cfg_header
+{
+    unsigned short magic_flag;
+    unsigned short valid_flag:1;
+    unsigned short content_len:15;
+};
+struct lynq_nv_cfg
+{
+    struct lynq_nv_cfg_header head;
+    unsigned char content[4];
+    struct lynq_nv_cfg_header tail;
+    unsigned int lynq_reserved[1];
+};
+#pragma pack()
+
+static const char lynq_nv_cfg_version[] = "T106_CN_20240617";
+static const char lynq_nv_cfg_value[] = {
+   '\x55', '\xaa', '\x09', '\x00', '\xc0', '\x00', '\x00', '\x00', '\xaa', '\x55', '\x09', '\x00', '\x01', '\x00', '\x3c', '\x00'
+};
+
+static const char lynq_nv_cfg_bitmap[] = {
+    '\xC0', '\x80', '\x80', '\x80'
+};
+static const char oem_nv_cfg_bitmap[] = {
+    '\x40', '\x80', '\x80', '\x80'
+};
+static const char lynq_nv_cfg_publickey[] = {
+    '\x92', '\x95', '\xf0', '\xc7', '\x36', '\x68', '\xad', '\xd0', '\x0f', '\xdb', '\x5c', '\xfd', '\x58', '\xf0', '\xc0', '\xa0',
+    '\x0b', '\x89', '\x6b', '\xa0', '\x05', '\x93', '\xa9', '\xb3', '\x54', '\x0f', '\x68', '\x24', '\x3e', '\x2d', '\xfd', '\x02',
+    '\x05', '\xf7', '\xe7', '\x48', '\xad', '\x39', '\x13', '\x6f', '\x71', '\xef', '\x6e', '\xcf', '\xc6', '\xcf', '\x5f', '\xc9',
+    '\x24', '\xa2', '\xd8', '\x2d', '\x17', '\xd6', '\x2b', '\x96', '\x7b', '\x48', '\x98', '\x12', '\xd5', '\x28', '\x4c', '\x72',
+    '\xcd', '\x34', '\xd5', '\xdb', '\x89', '\x87', '\x34', '\xe2', '\xab', '\x29', '\xe4', '\x56', '\x40', '\xe5', '\x92', '\x76',
+    '\xa5', '\xee', '\xb4', '\xbc', '\x37', '\x93', '\xb7', '\xe4', '\x30', '\x4d', '\x92', '\x7b', '\x2c', '\x11', '\x94', '\xd9',
+    '\x8b', '\xe8', '\x0d', '\x96', '\xed', '\x64', '\xd1', '\x0a', '\x7d', '\x4a', '\xd8', '\x1b', '\xf5', '\x0f', '\x4c', '\xfb',
+    '\x07', '\xde', '\xfa', '\xf9', '\xae', '\x42', '\x68', '\x6d', '\xe9', '\xe4', '\x58', '\x80', '\xdb', '\x0b', '\x84', '\xab',
+    '\x01', '\x00', '\x01', '\x00'
+};
+static const char lynq_nv_cfg_sign[] = {
+    '\xef', '\x87', '\xd6', '\x86', '\xea', '\xe6', '\x7f', '\xbd', '\x01', '\x57', '\xe4', '\x94', '\xfa', '\x86', '\xcd', '\xdb',
+    '\x75', '\xe2', '\xc0', '\x94', '\xe0', '\x3f', '\x30', '\x90', '\x9d', '\x24', '\x6e', '\x29', '\x8f', '\x90', '\x52', '\x86',
+    '\x19', '\xfc', '\x83', '\x7f', '\x1d', '\x9f', '\x32', '\x4b', '\xb9', '\x01', '\x5d', '\xb3', '\xf3', '\xcd', '\x30', '\xc5',
+    '\xf6', '\x2f', '\xc5', '\x68', '\x7e', '\x87', '\xae', '\xf2', '\x70', '\x54', '\xff', '\xe6', '\x60', '\xcb', '\xfe', '\xec',
+    '\x68', '\xaa', '\x01', '\x49', '\xd2', '\x93', '\x7b', '\x6e', '\x31', '\x0f', '\x91', '\xad', '\xdf', '\x81', '\x62', '\x04',
+    '\x36', '\x21', '\x22', '\xb6', '\x79', '\xfd', '\x61', '\xcf', '\x3a', '\xb9', '\x40', '\xba', '\x7c', '\xdf', '\x6e', '\xba',
+    '\x1e', '\xc2', '\x27', '\xb9', '\x49', '\x35', '\xd6', '\x5d', '\xc9', '\xe5', '\xed', '\x27', '\xa4', '\x70', '\x59', '\x41',
+    '\x4c', '\x84', '\x72', '\x7a', '\x06', '\xc7', '\x16', '\xcb', '\x56', '\x6a', '\x39', '\xeb', '\x0f', '\xa9', '\x59', '\xcc'
+};
+
+#endif
diff --git a/boot/common/src/uboot/drivers/peripheral/oem_nv_cfg.c b/boot/common/src/uboot/drivers/peripheral/oem_nv_cfg.c
new file mode 100755
index 0000000..0893035
--- /dev/null
+++ b/boot/common/src/uboot/drivers/peripheral/oem_nv_cfg.c
@@ -0,0 +1,141 @@
+#include <dma_cfg.h>
+
+
+#ifdef LYNQ_NV_CFG_SUPPORT
+#include "../rsa/drv_rsa.h"
+#include "../hash/drv_hash.h"
+#include "lynq_uboot_nv_cfg.h"
+#include "oem_nv_cfg.h"
+
+#define LYNQ_ERROR(t) do{BOOT_PRINTF(UBOOT_NOTICE, t);}while(0)
+
+#define DEBUG_LYNQ_NV_CFG 1
+
+#ifdef DEBUG_LYNQ_NV_CFG
+#define LYNQ_DEBUG(t) do{BOOT_PRINTF(UBOOT_NOTICE, t);}while(0)
+extern void lynq_hex_display(u32 * buff, int len);
+#else
+#define lynq_hex_display(...) do{}while(0)
+#define LYNQ_DEBUG(t) do{}while(0)
+#endif
+
+char* get_oem_nv_cfg(void)
+{
+    struct lynq_nv_cfg * oem_cfg, *lynq_cfg;
+    int content_len, pos, len, x;
+    T_Rsa_Paramter sRSAInput;
+    u32 uiRet = -1;
+    u32 uiHashResArr[4] = {0};
+    u32 uiHashResLen = 0;
+    u32 uiRsaResArr[RSA_U32_LEN] = {0};
+    u32 puiArrPubKey[RSA_U32_LEN*2] = {0};
+    u32 *puiRsaResAddr = NULL;
+    char * tmp_buffer = malloc(MMC_LYNQ_NV_CFG_SIZE*3);
+    memset(tmp_buffer, 0 , MMC_LYNQ_NV_CFG_SIZE*3);
+    oem_cfg = (struct lynq_nv_cfg *)tmp_buffer;
+    lynq_cfg = (struct lynq_nv_cfg *)lynq_nv_cfg_value;
+    if (sizeof (oem_nv_cfg_publickey) != LYNQ_NV_CFG_PUBLICKEY_LEN)
+    {
+        LYNQ_ERROR("got bad oem public key\n");
+        goto fail_exit;
+    }
+    if (sizeof (oem_nv_cfg_sign) != LYNQ_NV_CFG_SIGN_LEN )
+    {
+        LYNQ_ERROR("got bad oem sign\n");
+        goto fail_exit;
+    }
+    if (sizeof(oem_nv_cfg_value) == sizeof(struct lynq_nv_cfg))
+    {
+        pos = 0;
+        len = sizeof(oem_nv_cfg_value);
+        memcpy(oem_cfg, oem_nv_cfg_value, len);
+        pos += len;
+        content_len = ((char*)&oem_cfg->tail - (char*)&oem_cfg->head) - sizeof (struct lynq_nv_cfg_header);
+        if (oem_cfg->head.magic_flag == 0xaa55 && oem_cfg->tail.magic_flag == 0x55aa
+                && oem_cfg->head.content_len == content_len  && oem_cfg->tail.content_len == content_len
+                && oem_cfg->head.valid_flag == 1 && oem_cfg->tail.valid_flag == 1)
+        {
+            len = sizeof (oem_nv_cfg_version);
+            memcpy(tmp_buffer+pos, oem_nv_cfg_version, len);
+            pos += len;
+
+            len = sizeof (lynq_nv_cfg_bitmap);
+            memcpy(tmp_buffer+pos, lynq_nv_cfg_bitmap, len);
+            pos += len;
+
+            len = sizeof (oem_nv_cfg_bitmap);
+            memcpy(tmp_buffer+pos, oem_nv_cfg_bitmap, len);
+            pos += len;
+
+            for(x=0; x < sizeof(lynq_nv_cfg_bitmap); x++)
+            {
+                oem_cfg->content[x] &= oem_nv_cfg_bitmap[x];
+                oem_cfg->content[x] |= (lynq_cfg->content[x] & (~lynq_nv_cfg_bitmap[x]));
+            }
+
+            memcpy(puiArrPubKey, oem_nv_cfg_publickey, RSA_BYTE_LEN);
+            memcpy((puiArrPubKey+(RSA_U32_LEN*2 -1)), oem_nv_cfg_publickey + RSA_BYTE_LEN, sizeof(u32));
+            sRSAInput.udCalMode = RSA_MOD_EXPO_WITH_INIT;
+            sRSAInput.udNbitLen = RAS_BIT_LEN;
+            sRSAInput.udEbitLen = RAS_BIT_LEN;
+            sRSAInput.pudInputM = (u32*)oem_nv_cfg_sign;
+            sRSAInput.pudInputE = (u32*)puiArrPubKey + RSA_U32_LEN;
+            sRSAInput.pudInputN = ((u32*)puiArrPubKey);
+            sRSAInput.pudOutputP = uiRsaResArr;
+
+            lynq_hex_display(sRSAInput.pudInputE, RSA_U32_LEN);
+            lynq_hex_display(sRSAInput.pudInputN, RSA_U32_LEN);
+            lynq_hex_display(sRSAInput.pudInputM, RSA_U32_LEN);
+
+            uiRet = Rsa_Calculate(sRSAInput);
+            if(uiRet != 0)
+            {
+                LYNQ_ERROR("oem calc rsa fail\n");
+                goto fail_exit;
+            }
+
+            lynq_hex_display(uiRsaResArr, RSA_U32_LEN);
+
+            uiRet = Hash_Calculate(HASH_MODE_MD5,
+                                   HASH_SMALL_ENDIAN,
+                                   (u32*)tmp_buffer,
+                                   pos,
+                                   NULL,
+                                   0,
+                                   uiHashResArr,
+                                   &uiHashResLen);
+            if(uiRet != 0)
+            {
+                LYNQ_ERROR("oem calc hash fail\n");
+                goto fail_exit;
+            }
+            lynq_hex_display(uiHashResArr, uiHashResLen);
+
+            puiRsaResAddr = sRSAInput.pudOutputP + (RSA_U32_LEN - uiHashResLen);
+
+            if (memcmp(puiRsaResAddr, uiHashResArr, uiHashResLen*sizeof (u32)) != 0)
+            {
+                LYNQ_ERROR("not valid oem sign\n");
+                goto fail_exit;
+            }
+        }
+        else
+        {
+            LYNQ_ERROR("not valid oem head\n");
+            goto fail_exit;
+        }
+    }
+    else
+    {
+        LYNQ_ERROR("not valid oem cfg\n");
+        goto fail_exit;
+    }
+
+    return tmp_buffer;
+fail_exit:
+    free(tmp_buffer);
+    return NULL;
+}
+
+#endif
+
diff --git a/boot/common/src/uboot/drivers/peripheral/oem_nv_cfg.h b/boot/common/src/uboot/drivers/peripheral/oem_nv_cfg.h
new file mode 100755
index 0000000..82d0a91
--- /dev/null
+++ b/boot/common/src/uboot/drivers/peripheral/oem_nv_cfg.h
@@ -0,0 +1,32 @@
+#ifndef __OEM_NV_CFG__H__
+#define __OEM_NV_CFG__H__
+
+static const char oem_nv_cfg_version[] = "oem_20240617";
+static const char oem_nv_cfg_value[] = {
+    '\x55', '\xaa', '\x19', '\x00', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', '\x38', '\x39', '\x30', '\x31', '\x32',
+    '\xaa', '\x55', '\x19', '\x00', '\x10', '\x00', '\x00', '\x00'
+};
+
+static const char oem_nv_cfg_publickey[] = {
+    '\x85', '\xb2', '\x39', '\x98', '\x5d', '\x46', '\xb4', '\xc0', '\x7d', '\x30', '\x47', '\x7e', '\xa8', '\x1a', '\x8c', '\xdf',
+    '\x2c', '\x02', '\xdf', '\xb0', '\xeb', '\x95', '\x2b', '\xf0', '\xde', '\x04', '\xe8', '\xcd', '\x4c', '\x94', '\x49', '\x2d',
+    '\xe8', '\xa0', '\xcc', '\x91', '\x6e', '\xb3', '\xba', '\x53', '\x31', '\x21', '\x88', '\xbf', '\xd8', '\x7f', '\xab', '\x24',
+    '\xd4', '\x07', '\x76', '\xb6', '\x23', '\x6c', '\x43', '\x9e', '\x15', '\x4c', '\xc2', '\x67', '\x49', '\x47', '\x02', '\x8b',
+    '\x19', '\x52', '\x29', '\xd2', '\xd7', '\xdb', '\x7e', '\x48', '\xa3', '\x53', '\x03', '\xb9', '\xd6', '\x10', '\xb8', '\x52',
+    '\x18', '\x92', '\xf0', '\x4d', '\x96', '\x62', '\xc0', '\x65', '\x17', '\x51', '\xc0', '\x4c', '\xa1', '\x5c', '\x92', '\xeb',
+    '\x83', '\xc5', '\x61', '\xbe', '\x85', '\x1f', '\x21', '\x16', '\xf1', '\xbc', '\x17', '\xa0', '\xfe', '\x15', '\x03', '\xcf',
+    '\x82', '\x2b', '\xd6', '\x7e', '\x82', '\xdb', '\xfc', '\xd5', '\xe3', '\xc5', '\x9d', '\x73', '\x5d', '\xb1', '\x51', '\xbf',
+    '\x01', '\x00', '\x01', '\x00'
+};
+static const char oem_nv_cfg_sign[] = {
+    '\xc8', '\x48', '\x27', '\x16','\x8e', '\x43', '\x5d', '\xb2', '\x00', '\xac', '\x49', '\x8f','\x0c', '\xef', '\xf0', '\xdb',
+    '\x7d', '\x5c', '\xa9', '\x30','\xe3', '\x7e', '\xbe', '\xbd', '\xe9', '\xa4', '\x20', '\x9f','\x49', '\x65', '\xed', '\x3e',
+    '\x63', '\xfa', '\xeb', '\xbf','\xb9', '\xa6', '\x7f', '\x7e', '\x6e', '\x65', '\xfb', '\x84','\xf5', '\x6b', '\xc8', '\xe0',
+    '\x62', '\x3a', '\x55', '\xc9','\xa9', '\xc1', '\x64', '\x3a', '\xdf', '\x2e', '\xc6', '\xf2','\x5d', '\xcc', '\xa5', '\x28',
+    '\xfd', '\xaa', '\x33', '\x55','\x41', '\x8d', '\x26', '\xc8', '\x8a', '\xba', '\x73', '\x57','\x5c', '\xd5', '\x54', '\xbd',
+    '\x22', '\x7f', '\xcd', '\x04','\x28', '\x1d', '\x94', '\xdf', '\x40', '\x17', '\x89', '\x53','\xf2', '\xef', '\x6c', '\x22',
+    '\x19', '\x49', '\xd8', '\xbd','\xb4', '\xf7', '\x8f', '\x08', '\xd2', '\x08', '\x76', '\xa2','\xc8', '\xc3', '\x96', '\xc4',
+    '\x6d', '\x60', '\x10', '\x3f','\xb6', '\x87', '\x63', '\xec', '\x82', '\x81', '\x19', '\x63','\xac', '\x42', '\xf4', '\xc6'
+};
+
+#endif
diff --git a/boot/common/src/uboot/drivers/peripheral/peripheral.c b/boot/common/src/uboot/drivers/peripheral/peripheral.c
index fe410a9..3898062 100755
--- a/boot/common/src/uboot/drivers/peripheral/peripheral.c
+++ b/boot/common/src/uboot/drivers/peripheral/peripheral.c
@@ -28,6 +28,11 @@
 #include <drvs_gpio.h>

 #include "common.h"

 #include <dma_cfg.h>

+#include "../rsa/drv_rsa.h"

+

+#ifdef LYNQ_NV_CFG_SUPPORT

+extern void lynq_setup_nv_cfg(void);

+#endif

 

 //#include <gpio.h>

 

@@ -67,9 +72,16 @@
 	int ret = 0;

 	ret = power_init();

 	

+	BOOT_PRINTF(UBOOT_NOTICE, "cy: peripheral_init 2\n");

+

+#ifndef LYNQ_NV_CFG_SUPPORT

 /*mmc config*/

-	REG32(MMC_FLAG_ADDR) &=~0x3;//clear bit0~1	

+   	REG32(MMC_FLAG_ADDR) &=~0x3;//clear bit0~1	

 	REG32(MMC_FLAG_ADDR) |=((MMC0_USED_EN<<0)|(MMC1_USED_EN<<1));

+#else

+	lynq_setup_nv_cfg();

+#endif

+

 /*led*/

 /*lcd*/

 

diff --git a/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-autosuspend/files/autosuspend_wakeup_count.c b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-autosuspend/files/autosuspend_wakeup_count.c
index ca823c2..c7cc274 100755
--- a/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-autosuspend/files/autosuspend_wakeup_count.c
+++ b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-autosuspend/files/autosuspend_wakeup_count.c
@@ -236,11 +236,29 @@
 #endif
 
 #ifdef MOBILETEK_TARGET_PLATFORM_T106
+int t106_set_lowpwr(int state)
+{
+    int ret;
+    char rsp[128];
+    char cmdstr[32];
+    if(state == 0)
+    {
+        strcpy(cmdstr, "AT+ZLOWPWR=0\r\n");
+    }
+    else
+    {
+        strcpy(cmdstr, "AT+ZLOWPWR=1\r\n");
+    }
+    ret = sc_at_send(1,cmdstr,rsp,sizeof(rsp));
+    printf("AT+ZLOWPWR result:%d %s\n",ret,rsp);
+    return ret;
+}
+
 int t106_set_blacklist(int blacklist_state)
 {
     int ret;
     char rsp[128];
-    char cmdstr[256];
+    char cmdstr[128];
     if(blacklist_state == 0)
     {
         strcpy(cmdstr, "AT+SHELL=echo \"+CREG:+CGREG:+CEREG:^MODE:\" > /sys/module/at_io/parameters/at_psm_filter\r\n");
@@ -249,9 +267,8 @@
     {
         strcpy(cmdstr, "AT+SHELL=echo \"\" > /sys/module/at_io/parameters/at_psm_filter\r\n");
     }
-    printf("cmd:%s\n",cmdstr);
     ret = sc_at_send(1,cmdstr,rsp,sizeof(rsp));
-    printf("sc_at_send result:%d %s\n",ret,rsp);
+    printf("AT+SHELL=echo result:%d %s\n",ret,rsp);
     return ret;
 
 }
@@ -318,7 +335,8 @@
     RLOGD("t106_early_suspend start\n");
     ret=lynq_sleep_status(0);
     RLOGD("lynq_get_sleep_status ret=%d\n", ret);
-
+    ret = t106_set_lowpwr(1);
+    RLOGD("t106_set_lowpwr status ret=%d\n", ret);
     system("zlog_nvctrl -m 1");
     ret = t106_set_whitelist();
     if(ret)
@@ -350,7 +368,8 @@
         RLOGD("sc_mnet_whitelist_clear ret=%d\n", ret);
     }
     system("zlog_nvctrl -m 0");
-
+    ret = t106_set_lowpwr(0);
+    RLOGD("t106_set_lowpwr status ret=%d\n", ret);
     ret=lynq_sleep_status(1);
     RLOGD("lynq_get_sleep_status ret=%d\n", ret);
 
diff --git a/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/files/lynq-wifi-demo.cpp b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/files/lynq-wifi-demo.cpp
index c289c0f..c116e65 100755
--- a/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/files/lynq-wifi-demo.cpp
+++ b/cap/zx297520v3/sources/meta-zxic-custom/recipes-lynq/lynq-wifi-demo/files/lynq-wifi-demo.cpp
@@ -35,6 +35,20 @@
     }
 }
 
+static void print_lynq_lanhost_t(lynq_lanhost_ts lynq_arrays) 
+{
+	int i = 0;
+	for (i = 0; i < lynq_arrays.array_len; i++) {
+		printf("Element %d:\n", i);
+		printf("addr: %s\n", lynq_arrays.array[i].addr);
+		printf("macaddr: %s\n", lynq_arrays.array[i].macaddr);
+		printf("name: %s\n", lynq_arrays.array[i].name);
+		printf("ifname: %s\n", lynq_arrays.array[i].ifname);
+		printf("uptime: %d\n", lynq_arrays.array[i].uptime);
+		printf("\n");
+	}
+}
+
 int main(int argc, char *argv[])
 {
     lynq_wifi_ap_index_e type;
@@ -94,6 +108,7 @@
             lynq_wifi_work_mode_e work_type;
             lynq_wifi_ap_status_t stat = {0};
             lynq_wifi_sta_status_t status_stat = {0};
+            lynq_wifi_pkt_stats_t pkt_stat = {0};
             lynq_wifi_bandwidth_type_e bandwidth;
             int ret = -1;
             qser_wifi_enable();                      // enable wifi
@@ -120,18 +135,47 @@
             ret = qser_wifi_sta_get_status(&status_stat); // Gets the status value associated with sta
             printf("[lynq-wifi-demo]  status = %d ifname = %s ap_bssid = %s signal_level = %d reason_code = %d\n", status_stat.status, status_stat.ifname, status_stat.ap_bssid, status_stat.signal_level, status_stat.reason_code);
             if (status_stat.has_addr == 1)
-                printf("[lynq-wifi-demo]addr inet_ntop: %s\n", status_stat.addr);
+                printf("[lynq-wifi-demo]addr ip:%s, netmask:%s, subnet_bits:%d, gateway:%s, dnsp:%s, dnss:%s\n",
+                       status_stat.addr.addr, status_stat.addr.netmask, status_stat.addr.subnet_bits,
+                       status_stat.addr.gateway, status_stat.addr.dnsp, status_stat.addr.dnss);
             if (status_stat.has_addr6 == 1)
-                printf("[lynq-wifi-demo]addr6 inet_ntop: %s\n", status_stat.addr6);
+                printf("[lynq-wifi-demo]addr6 ip:%s, prefix:%s, prefix_bits:%d, gateway:%s, dnsp:%s, dnss:%s\n",
+                       status_stat.addr6.addr, status_stat.addr6.prefix, status_stat.addr6.prefix_bits,
+                       status_stat.addr6.gateway, status_stat.addr6.dnsp, status_stat.addr6.dnss);
+            ret = qser_wifi_get_ap_pkt_stats(type, &pkt_stat); // Obtain data packets sent and received by ap
+            printf("[lynq-wifi-demo]ap_pkt_get rx[%llu, %llu, %llu, %llu] tx[%llu, %llu, %llu, %llu] ret=%d\n",
+                   pkt_stat.rx_packets, pkt_stat.rx_bytes, pkt_stat.rx_errors, pkt_stat.rx_dropped,
+                   pkt_stat.tx_packets, pkt_stat.tx_bytes, pkt_stat.tx_errors, pkt_stat.tx_dropped, ret);
         }
         else if (strcmp(argv[1], "3") == 0) //Enable the callback query only when WiFi is used as an ap
         {
+            int ret = -1;
+            int args = 3;       // enable ap_sta callback
             qser_wifi_enable(); // enable wifi
-            int args = 3; //enable ap_sta callback
             qser_wifi_register_handle(lynq_wifi_event_handle_demo, NULL, (void *)&args);
             while (1)
             {
-                sleep(1);
+                char cmdstr[128] = {0};
+                printf("[lynq-wifi-demo]Get sta device information received as an ap :ap_lanhost\n");
+                if (NULL != fgets(cmdstr, sizeof(cmdstr) - 1, stdin))
+                {
+                    if (1 >= strlen(cmdstr))
+                    {
+                        continue;
+                    }
+                    if (0 == strncmp(cmdstr, "ap_lanhost", strlen(cmdstr) - 1))
+                    {
+                        lynq_lanhost_ts ap_lanhost = {0};
+                        ret = qser_wifi_lanhost_get_list(&ap_lanhost);
+                        printf("[lynq-wifi-demo]ret = %d\n",ret);
+                        print_lynq_lanhost_t(ap_lanhost);
+                        continue;
+                    }
+                }
+                else
+                {
+                    printf("  [lynq-wifi-demo]Parameter error, please re-enter\n");
+                }
             }
         }
         else if (strcmp(argv[1], "4") == 0) //Overlay WiFi callback as ap and scan callback as sta
@@ -154,7 +198,7 @@
 
             while (1)
             {
-                printf("[lynq-wifi-demo]Enter the ssid and password as shown in the following example:ssid auth paris pw ||sta_param_get || sta_scan ||sta_stop\n");
+                printf("[lynq-wifi-demo]Enter the ssid and password as shown in the following example:ssid auth paris pw ||sta_pkt_get ||sta_param_get || sta_scan ||sta_stop\n");
                 if (NULL != fgets(cmdstr, sizeof(cmdstr) - 1, stdin))
                 {
                     if (1 >= strlen(cmdstr))
@@ -167,6 +211,15 @@
                         printf("[lynq-wifi-demo]sta_param_get[%s, %d, %d, %s] ret=%d\n", stat.ssid, stat.auth, stat.pairwise, stat.passwd, ret);
                         continue;
                     }
+                    if (0 == strncmp(cmdstr, "sta_pkt_get", strlen(cmdstr) - 1))
+                    {
+                        lynq_wifi_pkt_stats_t pkt_stat = {0};
+                        ret = qser_wifi_get_sta_pkt_stats(&pkt_stat); // Obtain data packets sent and received by ap
+                        printf("[lynq-wifi-demo]sta_pkt_get rx[%llu, %llu, %llu, %llu] tx[%llu, %llu, %llu, %llu] ret=%d\n",
+                               pkt_stat.rx_packets, pkt_stat.rx_bytes, pkt_stat.rx_errors, pkt_stat.rx_dropped,
+                               pkt_stat.tx_packets, pkt_stat.tx_bytes, pkt_stat.tx_errors, pkt_stat.tx_dropped, ret);
+                        continue;
+                    }
                     else if (0 == strncmp(cmdstr, "sta_scan", strlen(cmdstr) - 1))
                     {
                         qser_wifi_sta_start_scan(); // When this function is executed once, sta's scan is called once
diff --git a/cap/zx297520v3/src/lynq/lib/liblynq-data/lynq_data.cpp b/cap/zx297520v3/src/lynq/lib/liblynq-data/lynq_data.cpp
index fc6c6a8..7b29791 100755
--- a/cap/zx297520v3/src/lynq/lib/liblynq-data/lynq_data.cpp
+++ b/cap/zx297520v3/src/lynq/lib/liblynq-data/lynq_data.cpp
@@ -730,7 +730,7 @@
                         break;
                     }
                 }
-                if(j == num)
+                if(j == num && lynq_apn_table[i].cid != 0)
                 {
                     LYINFLOG("need delete lynq_apn_table[%d]\n", i);
                     bzero(lynq_apn_table[i].apnType,LYNQ_APN_TYPE_MAX_LEN);//async clean
@@ -1219,11 +1219,17 @@
 
     char *tmp_msg = NULL;
     int len = 0;
+    int unlock_flag = 0;
 
     LYINFLOG("[data_thread_rc_recv]: in thread_rc_recv");
     while(module_rc_status)
     {
         pthread_mutex_lock(&s_lynq_rc_vector_mutex);
+        if(unlock_flag == 1)
+        {
+            pthread_mutex_unlock(&g_lynq_data_sendto_mutex);
+        }
+        unlock_flag=1;
         pthread_cond_wait(&s_lynq_rc_vector_cond,&s_lynq_rc_vector_mutex);
         pthread_mutex_unlock(&s_lynq_rc_vector_mutex);
         LYINFLOG("[data_thread_rc_recv]: pthread_mutex_unlock");
@@ -1255,7 +1261,7 @@
             }
             continue;
         }
-        pthread_mutex_unlock(&g_lynq_data_sendto_mutex);
+
 
         bzero(type,LYNQ_TYPE_MAX_LEN);
         bzero(ifaceName,LYNQ_IFACE_NAME_MAX_LEN);
diff --git a/cap/zx297520v3/src/lynq/lib/liblynq-qser-data/lynq-qser-data.cpp b/cap/zx297520v3/src/lynq/lib/liblynq-qser-data/lynq-qser-data.cpp
index 786428f..995b7e4 100755
--- a/cap/zx297520v3/src/lynq/lib/liblynq-qser-data/lynq-qser-data.cpp
+++ b/cap/zx297520v3/src/lynq/lib/liblynq-qser-data/lynq-qser-data.cpp
@@ -29,6 +29,7 @@
 static pthread_t s_cb_tid = -1;
 static int s_qser_data_cb_thread_status = 0;
 static pthread_mutex_t s_qser_data_cb_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t s_qser_data_database_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t s_qser_data_cb_cond = PTHREAD_COND_INITIALIZER;
 
 
@@ -453,10 +454,12 @@
     int idx = 0;
 
     /* Open database */
+    pthread_mutex_lock(&s_qser_data_database_mutex);
     rc = sqlite3_open(APN_DB_PATH, &apnDb);
     if( rc )
     {
         LYERRLOG("[%s] Can't open database: %s\n", __FUNCTION__,sqlite3_errmsg(apnDb));
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
 
@@ -471,11 +474,13 @@
         LYERRLOG("SQL error: %s\n", zErrMsg);
         sqlite3_free(zErrMsg);
         sqlite3_close(apnDb);
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     };
     *profile_idx = (unsigned char)idx;
     LYINFLOG("get idx %d successfully\n", *profile_idx);
     sqlite3_close(apnDb);
+    pthread_mutex_unlock(&s_qser_data_database_mutex);
     return 0;
 }
 static int lynq_apn_callback(void *data, int argc, char **argv, char **azColName){
@@ -505,10 +510,12 @@
     int rc;
     char sql[128]={0};
     /* Open database */
+    pthread_mutex_lock(&s_qser_data_database_mutex);
     rc = sqlite3_open(APN_DB_PATH, &apnDb);
     if( rc )
     {
         LYERRLOG("[%s] Can't open database: %s\n", __FUNCTION__,sqlite3_errmsg(apnDb));
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
     sprintf(sql,"%s", "SELECT * from LYNQAPN");
@@ -518,6 +525,7 @@
         LYERRLOG("SQL error: %s\n", zErrMsg);
         sqlite3_free(zErrMsg);
         sqlite3_close(apnDb);
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
     //for(int cnt = 0; cnt < next_index;cnt++)
@@ -527,11 +535,14 @@
         {
             LYINFLOG("index = apn_index\n");
             sqlite3_close(apnDb);
+            pthread_mutex_unlock(&s_qser_data_database_mutex);
             return 1;
         }
     }
     LYINFLOG("cant find the index %d\n", index);
     sqlite3_close(apnDb);
+    pthread_mutex_unlock(&s_qser_data_database_mutex);
+
     return 0;
 }
 
@@ -545,11 +556,12 @@
         return LYNQ_E_APN_DB_FAIL;
     }
     /* Open database */
-
+    pthread_mutex_lock(&s_qser_data_database_mutex);
     rc = sqlite3_open(APN_DB_PATH, &apnDb);
     if( rc )
     {
         LYERRLOG("[%s] Can't open database: %s\n", __FUNCTION__,sqlite3_errmsg(apnDb));
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
 
@@ -565,10 +577,12 @@
         LYERRLOG("SQL error: %s\n", zErrMsg);
         sqlite3_free(zErrMsg);
         sqlite3_close(apnDb);
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
     LYINFLOG("update apn %d successfully\n", profile_idx);
     sqlite3_close(apnDb);
+    pthread_mutex_unlock(&s_qser_data_database_mutex);
     return 0;
 }
 static int apn_db_handle_get_cb(void *data, int argc, char **argv, char **azColName)
@@ -596,10 +610,12 @@
         return LYNQ_E_APN_DB_FAIL;
     }
     /* Open database */
+    pthread_mutex_lock(&s_qser_data_database_mutex);
     rc = sqlite3_open(APN_DB_PATH, &apnDb);
     if( rc )
     {
         LYERRLOG("[%s] Can't open database: %s\n", __FUNCTION__,sqlite3_errmsg(apnDb));
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
 
@@ -614,10 +630,12 @@
         LYERRLOG("SQL error: %s\n", zErrMsg);
         sqlite3_free(zErrMsg);
         sqlite3_close(apnDb);
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
     LYINFLOG("get idx %d successfully\n", *handle);
     sqlite3_close(apnDb);
+    pthread_mutex_unlock(&s_qser_data_database_mutex);
     return 0;
 }
 
@@ -669,10 +687,12 @@
     char *sql;
 
     /* Open database */
+    pthread_mutex_lock(&s_qser_data_database_mutex);
     rc = sqlite3_open(path, &apnDb);
     if( rc )
     {
         LYERRLOG("[%s] Can't open database: %s\n", __FUNCTION__,sqlite3_errmsg(apnDb));
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return 1;
     }
     LYINFLOG("[%s] Opened database successfully\n",__FUNCTION__);
@@ -693,16 +713,21 @@
         LYERRLOG("SQL error: %s\n", zErrMsg);
         sqlite3_free(zErrMsg);
         sqlite3_close(apnDb);
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return 1;
     }
     LYINFLOG("Table LYNQAPN created successfully\n");
     sqlite3_close(apnDb);
+    pthread_mutex_unlock(&s_qser_data_database_mutex);
     return 0;
 }
 static int init_apn_db()
 {
     int db_ret=0;
     int table_ret=0;
+
+    pthread_mutex_init(&s_qser_data_database_mutex, NULL);   
+
     db_ret = create_apn_db(APN_DB_PATH);
     if(db_ret==APN_DB_CREATE)
     {
@@ -732,10 +757,12 @@
     int default_handle = LYNQ_APN_CHANNEL_MAX + 1;
 
     /* Open database */
+    pthread_mutex_lock(&s_qser_data_database_mutex);
     rc = sqlite3_open(APN_DB_PATH, &apnDb);
     if( rc )
     {
         LYERRLOG("[%s] Can't open database: %s\n", __FUNCTION__,sqlite3_errmsg(apnDb));
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
 
@@ -750,10 +777,12 @@
         LYERRLOG("SQL error: %s\n", zErrMsg);
         sqlite3_free(zErrMsg);
         sqlite3_close(apnDb);
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
     LYINFLOG("clean apn table successfully\n");
     sqlite3_close(apnDb);
+    pthread_mutex_unlock(&s_qser_data_database_mutex);
     return RESULT_OK;
 }
 
@@ -769,10 +798,12 @@
     next_index = 0;
     LYINFLOG("index = %p",apn_indexs);
     /* Open database */
+    pthread_mutex_lock(&s_qser_data_database_mutex);
     rc = sqlite3_open(APN_DB_PATH, &apnDb);
     if( rc )
     {
        LYERRLOG("Can't open database: %s\n", sqlite3_errmsg(apnDb));
+       pthread_mutex_unlock(&s_qser_data_database_mutex);
        return -1;
     }
     else
@@ -789,6 +820,7 @@
         LYERRLOG("SQL error: %s\n", zErrMsg);
         sqlite3_free(zErrMsg);
         sqlite3_close(apnDb);
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return -1;
     }
     else
@@ -808,6 +840,7 @@
         }
     }
     sqlite3_close(apnDb);
+    pthread_mutex_unlock(&s_qser_data_database_mutex);
     LYINFLOG("count is %d\n", count);
     return count;
 }
@@ -818,10 +851,12 @@
     int rc;
     int default_handle = LYNQ_APN_CHANNEL_MAX + 1;
     /* Open database */
+    pthread_mutex_lock(&s_qser_data_database_mutex);
     rc = sqlite3_open(APN_DB_PATH, &apnDb);
     if( rc )
     {
         LYERRLOG("[%s] Can't open database: %s",__FUNCTION__,sqlite3_errmsg(apnDb));
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return 1;
     }
     LYINFLOG("[%s] Opened database successfully",__FUNCTION__);
@@ -835,10 +870,12 @@
         LYERRLOG( "SQL error: %s", zErrMsg);
         sqlite3_free(zErrMsg);
         sqlite3_close(apnDb);
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return 1;
     }
     LYINFLOG("write apn to apn db successfully");
     sqlite3_close(apnDb);
+    pthread_mutex_unlock(&s_qser_data_database_mutex);
     return 0;
 }
 
@@ -852,18 +889,19 @@
         return LYNQ_E_APN_DB_FAIL;
     }
     /* Open database */
-
+    pthread_mutex_lock(&s_qser_data_database_mutex);
     rc = sqlite3_open(APN_DB_PATH, &apnDb);
     if( rc )
     {
         LYERRLOG("[%s] Can't open database: %s\n", __FUNCTION__,sqlite3_errmsg(apnDb));
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
 
     LYINFLOG("[%s] Opened database successfully\n",__FUNCTION__);
     /* Create SQL statement */
     //sql = "SELECT * from LYNQAPN";
-    char *sql = sqlite3_mprintf("DELETE  from LYNQAPN WHERE ID=%d",(int)profile_idx);
+    char *sql = sqlite3_mprintf("DELETE from LYNQAPN WHERE ID=%d",(int)profile_idx);
     LYINFLOG("sql: %s\n", sql);
     /* Execute SQL statement */
     rc = sqlite3_exec(apnDb, sql, NULL, NULL, &zErrMsg);
@@ -872,10 +910,12 @@
         LYERRLOG("SQL error: %s\n", zErrMsg);
         sqlite3_free(zErrMsg);
         sqlite3_close(apnDb);
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
     LYINFLOG("delete apn %d successfully\n", profile_idx);
     sqlite3_close(apnDb);
+    pthread_mutex_unlock(&s_qser_data_database_mutex);
     return 0;
 }
 
@@ -889,11 +929,12 @@
         return LYNQ_E_APN_DB_FAIL;
     }
     /* Open database */
-
+    pthread_mutex_lock(&s_qser_data_database_mutex);
     rc = sqlite3_open(APN_DB_PATH, &apnDb);
     if( rc )
     {
         LYERRLOG("[%s] Can't open database: %s\n", __FUNCTION__,sqlite3_errmsg(apnDb));
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
 
@@ -908,10 +949,12 @@
         LYERRLOG("SQL error: %s\n", zErrMsg);
         sqlite3_free(zErrMsg);
         sqlite3_close(apnDb);
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
     LYINFLOG("set apn %d successfully\n",apn->profile_idx);
     sqlite3_close(apnDb);
+    pthread_mutex_unlock(&s_qser_data_database_mutex);
     return 0;
 }
 
@@ -945,11 +988,12 @@
         return LYNQ_E_APN_DB_FAIL;
     }
     /* Open database */
-
+    pthread_mutex_lock(&s_qser_data_database_mutex);
     rc = sqlite3_open(APN_DB_PATH, &apnDb);
     if( rc )
     {
         LYERRLOG("[%s] Can't open database: %s\n", __FUNCTION__,sqlite3_errmsg(apnDb));
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
 
@@ -964,10 +1008,12 @@
         LYERRLOG("SQL error: %s\n", zErrMsg);
         sqlite3_free(zErrMsg);
         sqlite3_close(apnDb);
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
     LYINFLOG("set apn %d successfully\n",apn->profile_idx);
     sqlite3_close(apnDb);
+    pthread_mutex_unlock(&s_qser_data_database_mutex);
     return 0;
 }
 static int apn_db_query_list_cb(void *data, int argc, char **argv, char **azColName)
@@ -999,10 +1045,12 @@
     /* Open database */
     apn_count = 0;
     apn_list->cnt = 0;
+    pthread_mutex_lock(&s_qser_data_database_mutex);
     rc = sqlite3_open(APN_DB_PATH, &apnDb);
     if( rc )
     {
         LYERRLOG("[%s] Can't open database: %s\n", __FUNCTION__,sqlite3_errmsg(apnDb));
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
 
@@ -1017,9 +1065,11 @@
         LYERRLOG("SQL error: %s\n", zErrMsg);
         sqlite3_free(zErrMsg);
         sqlite3_close(apnDb);
+        pthread_mutex_unlock(&s_qser_data_database_mutex);
         return LYNQ_E_APN_DB_FAIL;
     }
     sqlite3_close(apnDb);
+    pthread_mutex_unlock(&s_qser_data_database_mutex);
     return 0;
 }
 // **************apn DB end****************************
@@ -1159,6 +1209,7 @@
         /*compare paramter*/
         //data_cb_state.profile_idx = (char)handle;
         apn_db_handle_get_profile(handle, &data_cb_state.profile_idx);
+        LYINFLOG("[thread_wait_cb_status]: callback profile_idx is %d\n", data_cb_state.profile_idx);
         LYINFLOG("[thread_wait_cb_status]: status=%d, suggestedRetryTime=%d, cid=%d, active=%d, type=%s, ifname=%s, addresses=%s, dnses=%s, gateways=%s, pcscf=%s, mtu=%d\n",
         data_urc_info.status, data_urc_info.suggestedRetryTime, data_urc_info.cid, data_urc_info.active, 
         data_urc_info.type, data_urc_info.ifname, data_urc_info.addresses, data_urc_info.dnses, data_urc_info.gateways, data_urc_info.pcscf, 
@@ -1729,6 +1780,10 @@
 
 int qser_apn_del(unsigned char profile_idx)
 {
+    int ret = 0;
+    int handle = -1;
+
+    LYINFLOG("[%s] entry\n",__FUNCTION__);
     if(g_lynq_qser_data_init_flag == 0)
     {
         return LYNQ_E_NO_INIT;
@@ -1738,8 +1793,7 @@
         LYERRLOG("apn del incoming paramters error");
         return RESULT_ERROR;
     }
-    int ret = 0;
-    int handle = -1;
+
     ret = apn_db_handle_get(profile_idx, &handle);
     if(ret != 0)
     {
diff --git a/cap/zx297520v3/src/lynq/lib/liblynq-qser-fota/lynq-qser-fota.cpp b/cap/zx297520v3/src/lynq/lib/liblynq-qser-fota/lynq-qser-fota.cpp
index 10f967a..1589c5f 100755
--- a/cap/zx297520v3/src/lynq/lib/liblynq-qser-fota/lynq-qser-fota.cpp
+++ b/cap/zx297520v3/src/lynq/lib/liblynq-qser-fota/lynq-qser-fota.cpp
@@ -537,14 +537,15 @@
     if(ret != 0)

     {

         LYINFLOG("fota update fail!\n");

+        qser_wakelock_unlock(lock_fd);

+        tmp = qser_wakelock_destroy(lock_fd);

+        if(tmp < 0)

+        {

+            LYERRLOG("Destroy fota wakelock failed");

+        }

     }

 

-    qser_wakelock_unlock(lock_fd);

-    tmp = qser_wakelock_destroy(lock_fd);

-    if(tmp < 0)

-    {

-        LYERRLOG("Destroy fota wakelock failed");

-    }

+    

     return ret;

 

 }

diff --git a/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/include/lynq_qser_gnss.h b/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/include/lynq_qser_gnss.h
index 9eead07..ed70d21 100755
--- a/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/include/lynq_qser_gnss.h
+++ b/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/include/lynq_qser_gnss.h
@@ -128,6 +128,7 @@
 int qser_firmware_update(uint32_t h_gnss);
 int qser_Gnss_injectEphemeris(uint32_t h_gnss);
 int qser_Gnss_download_tle();
+int qser_Gnss_injectEphemeris_withpath(uint32_t h_gnss, char *path);
 #ifdef __cplusplus
 }
 #endif
diff --git a/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/include/mbtk_gnss_internal.h b/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/include/mbtk_gnss_internal.h
index c6486d8..50cc58a 100755
--- a/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/include/mbtk_gnss_internal.h
+++ b/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/include/mbtk_gnss_internal.h
@@ -343,7 +343,7 @@
 int set_baudrate(int fd, int baudrate);
 int mopen_gnss_dev_reset(uint32 h_gnss, int type, int mode);
 int lynq_open_gps(int state);
-int lynq_gnss_Injection_ephemeris(uint32 h_gnss);
+int lynq_gnss_Injection_ephemeris(uint32 h_gnss, char *ephemeris_path);
 int exec_cmd(const char *cmd, char *result);
 int lynq_gnss_get_aidinfo(uint32 h_gnss);
 int lynq_gnss_get_device_info(uint32 h_gnss);
diff --git a/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/src/lynq_qser_gnss.cpp b/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/src/lynq_qser_gnss.cpp
index 7360f71..4fe61db 100755
--- a/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/src/lynq_qser_gnss.cpp
+++ b/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/src/lynq_qser_gnss.cpp
@@ -129,7 +129,6 @@
         return -1;
     }
     struct mbtk_gnss_handle_t *gnss_handle = (struct mbtk_gnss_handle_t *)h_gnss;
-    printf("type in\n");
     switch(type)
     {
 
@@ -452,18 +451,34 @@
         return -1;
     }
 #if defined(HD_GNSS)
-        ret = hd_gnss_injects_aidpos(h_gnss);
-        if(ret < 0)
-        {
-            return -1;
-        }
+    ret = hd_gnss_injects_aidpos(h_gnss);
+    if(ret < 0)
+    {
+         return -1;
+    }
 #elif defined(HX_GNSS)
-        ret = mopen_gnss_injects_aidpos(h_gnss);
-        if(ret < 0)
-        {
-            return -1;
-        }
+    ret = mopen_gnss_injects_aidpos(h_gnss);
+    if(ret < 0)
+    {
+        return -1;
+    }
 #endif
+    return 0;
+}
+
+int qser_Gnss_injectEphemeris_withpath(uint32_t h_gnss, char *path)
+{
+    int ret;
+    if(!inited)
+    {
+        ALOGE("has not been initiated\n");
+        return -1;
+    }
+    ret = lynq_gnss_Injection_ephemeris(h_gnss,path);
+    if(ret < 0)
+    {
+        return -1;
+    }
 
     return 0;
 }
diff --git a/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/src/mbtk_gnss.cpp b/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/src/mbtk_gnss.cpp
index ab4cf73..5087a82 100755
--- a/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/src/mbtk_gnss.cpp
+++ b/cap/zx297520v3/src/lynq/lib/liblynq-qser-gnss/src/mbtk_gnss.cpp
@@ -1607,7 +1607,7 @@
 }
 
 /*Injection ephemeris AGNSS_TLE_FILE*/
-int lynq_gnss_Injection_ephemeris(uint32 h_gnss)
+int lynq_gnss_Injection_ephemeris(uint32 h_gnss, char *ephemeris_path)
 {
     int ret;
     int agnss_fd = 0;
@@ -1619,7 +1619,7 @@
         return -1;
     }
 
-    agnss_fd = open(AGNSS_TLE_FILE, O_RDWR);
+    agnss_fd = open(ephemeris_path, O_RDWR);
     if (agnss_fd <= 0)
     {
         printf("%s open file FAIL. errno:%d\n", __FUNCTION__, errno);
diff --git a/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/include/lynq-qser-wifi.h b/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/include/lynq-qser-wifi.h
index 8b839fd..9f97c14 100644
--- a/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/include/lynq-qser-wifi.h
+++ b/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/include/lynq-qser-wifi.h
@@ -174,15 +174,35 @@
 
 typedef struct
 {
+	char addr[16];
+	char netmask[16];
+	unsigned char subnet_bits; //255.255.255.0 is 24
+	char gateway[16];
+	char dnsp[16]; //primary DNS
+	char dnss[16]; //secondary DNS
+} lynq_wifi_net_addr_t;
+
+typedef struct
+{
+	char addr[48];
+	char prefix[48];
+	unsigned char prefix_bits;
+	char gateway[48];
+	char dnsp[48]; //primary DNS
+	char dnss[48]; //secondary DNS
+} lynq_wifi_net_addr6_t;
+
+typedef struct
+{
 	lynq_wifi_sta_status_e status;
 	char ifname[32];
 	char ap_bssid[18]; //cur ap mac
 	//int rssi;
 	unsigned char signal_level;
 	unsigned char has_addr;
-	char addr[48]; //(addr.s_addr)
+	lynq_wifi_net_addr_t addr; //(addr.s_addr)
 	unsigned char has_addr6;
-	char addr6[48]; //
+	lynq_wifi_net_addr6_t addr6; //
 	lynq_wifi_reason_code_e reason_code;
 } lynq_wifi_sta_status_t;
 
@@ -204,6 +224,32 @@
 	lynq_wifi_sta_scan_info_t info[LYNQ_WIFI_MAX_SCAN_INFO_CNT];
 }lynq_wifi_sta_scan_list_t;
 
+typedef struct {
+	unsigned long long	rx_packets;
+	unsigned long long	rx_bytes;
+	unsigned long long	rx_errors;
+	unsigned long long	rx_dropped;
+	unsigned long long	tx_packets;
+	unsigned long long	tx_bytes;
+	unsigned long long	tx_errors;
+	unsigned long long	tx_dropped;
+} lynq_wifi_pkt_stats_t;
+
+typedef struct
+{
+    char addr[16]; 		/**< IPV4 address format string */
+    char macaddr[18]; 	/**< MAC address, format: XX:XX:XX:XX:XX:XX */
+    char name[20]; 		/**< hostname */
+    char ifname[18]; 	/**< device name */
+    int  uptime; 		/**< online time in sec */
+} lynq_lanhost_t;
+
+typedef struct
+{
+	int array_len;
+    lynq_lanhost_t array[32];
+} lynq_lanhost_ts;
+
 typedef void (*lynq_wifi_event_handle)(lynq_wifi_event_s *event, void *arg);
 typedef void (*lynq_wifi_event_handle_sta)(lynq_wifi_sta_scan_list_t *event);
 
@@ -229,6 +275,8 @@
 int  qser_wifi_ap_auth_get_s(lynq_wifi_ap_index_e idx, lynq_wifi_ap_auth_t *auth_mode);
 int  qser_wifi_ap_max_sta_set(lynq_wifi_ap_index_e idx, int max_sta_num);
 int  qser_wifi_ap_max_sta_get(lynq_wifi_ap_index_e idx, int *max_sta_num);
+int  qser_wifi_lanhost_get_list(lynq_lanhost_ts *lynq_arrays);
+int  qser_wifi_get_ap_pkt_stats(lynq_wifi_ap_index_e idx, lynq_wifi_pkt_stats_t *pkt_stat);
 int  qser_wifi_ap_start(lynq_wifi_ap_index_e idx);
 int  qser_wifi_ap_stop(lynq_wifi_ap_index_e idx);
 int  qser_wifi_ap_restart(lynq_wifi_ap_index_e idx);
@@ -236,6 +284,7 @@
 int  qser_wifi_sta_param_set(lynq_wifi_sta_param_t *param_stat);
 int  qser_wifi_sta_param_get(lynq_wifi_sta_param_t *param_stat);
 int  qser_wifi_sta_get_status(lynq_wifi_sta_status_t *status_stat);
+int  qser_wifi_get_sta_pkt_stats(lynq_wifi_pkt_stats_t *pkt_stat);
 int  qser_wifi_sta_start_scan(void);
 int  qser_wifi_sta_start(void);
 int  qser_wifi_sta_stop(void);
diff --git a/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/lynq-qser-wifi.cpp b/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/lynq-qser-wifi.cpp
index da282c8..2b23394 100644
--- a/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/lynq-qser-wifi.cpp
+++ b/cap/zx297520v3/src/lynq/lib/liblynq-qser-wifi/lynq-qser-wifi.cpp
@@ -251,34 +251,26 @@
 * @see: NA
 * @warning: NA
 *********************************************************************/
-/*
 static void print_sta_status(sc_wifi_sta_status_t *p_msg)
 {
-	LYINFLOG("%s: %d, %s, %s, %d, %d\n", __func__, p_msg->status, p_msg->ifname, p_msg->ap_bssid, 
-	p_msg->signal_level, p_msg->reason_code);
+    LYINFLOG("%s: %d, %s, %s, %d, %d\n", __func__, p_msg->status, p_msg->ifname, p_msg->ap_bssid,
+             p_msg->signal_level, p_msg->reason_code);
 
-	if (p_msg->has_addr == 1) {
-		char addrtxt[48] = {0};
-		inet_ntop(AF_INET, &p_msg->addr, addrtxt, sizeof(addrtxt));
-		LYINFLOG("%s : addr inet_ntop: %s\n", __func__, addrtxt);
+    if (p_msg->has_addr == 1)
+    {
+        LYINFLOG("[%s]addr ip:%s, netmask:%s, subnet_bits:%d, gateway:%s, dnsp:%s, dnss:%s\n", __func__,
+                 p_msg->addr.addr, p_msg->addr.netmask, p_msg->addr.subnet_bits,
+                 p_msg->addr.gateway, p_msg->addr.dnsp, p_msg->addr.dnss);
+    }
 
-		LYINFLOG("%s : addr: %08X\n", __func__, p_msg->addr.s_addr);
-	}
-
-	if (p_msg->has_addr6 == 1) {
-		char addrtxt[48] = {0};
-		inet_ntop(AF_INET6, &p_msg->addr6, addrtxt, sizeof(addrtxt));
-		LYINFLOG("%s : addr6 inet_ntop: %s\n", __func__, addrtxt);
-
-		LYINFLOG("%s : addr6: %02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X\n",__func__, 
-		p_msg->addr6.s6_addr[0], p_msg->addr6.s6_addr[1], p_msg->addr6.s6_addr[2], p_msg->addr6.s6_addr[3], 
-		p_msg->addr6.s6_addr[4], p_msg->addr6.s6_addr[5], p_msg->addr6.s6_addr[6], p_msg->addr6.s6_addr[7], 
-		p_msg->addr6.s6_addr[8], p_msg->addr6.s6_addr[9], p_msg->addr6.s6_addr[10], p_msg->addr6.s6_addr[11], 
-		p_msg->addr6.s6_addr[12], p_msg->addr6.s6_addr[13], p_msg->addr6.s6_addr[14], p_msg->addr6.s6_addr[15]);
-	}
-	LYINFLOG("%s : sta_status end\n",__func__);
+    if (p_msg->has_addr6 == 1)
+    {
+        LYINFLOG("[%s]addr6 ip:%s, prefix:%s, prefix_bits:%d, gateway:%s, dnsp:%s, dnss:%s\n", __func__,
+                 p_msg->addr6.addr, p_msg->addr6.prefix, p_msg->addr6.prefix_bits,
+                 p_msg->addr6.gateway, p_msg->addr6.dnsp, p_msg->addr6.dnss);
+    }
+    LYINFLOG("%s : sta_status end\n", __func__);
 }
-*/
 
 /********************************************************************
 * @brief: lynq_user_sta_status_ind, wifi gets the status callback in sta mode
@@ -291,7 +283,7 @@
   sc_wifi_sta_status_t *p_msg)
 {	 
 	 LYINFLOG("%s : user_sta_status_ind_cb pre:%d, cur:%d\n", __func__, pre_status, p_msg->status);
-	 //print_sta_status(p_msg);
+	 print_sta_status(p_msg);
 }
 
 /********************************************************************
@@ -1013,6 +1005,84 @@
 }
 
 /********************************************************************
+* @brief: qser_wifi_lanhost_get_list, Get sta device information received as an ap for 2.4G or 5G
+* @param lynq_arrays [OUT]: lynq_lanhost_ts *, Get sta device information received as an ap
+* @return : int, If equal to 0 succeeds, others fail
+* @todo: NA
+* @see: NA
+* @warning: NA
+*********************************************************************/
+int qser_wifi_lanhost_get_list(lynq_lanhost_ts *lynq_arrays)
+{
+    int ret = -1;
+    int i = 0;
+    sc_lanhost_t array[32] = {0};
+    if (lynq_arrays == NULL)
+    {
+        LYERRLOG("[%s ] Null pointer lynq_arrays = 0x%p\n", __func__, lynq_arrays);
+        return ret;
+    }
+    lynq_arrays->array_len = 32;
+    ret = ret = sc_wifi_lanhost_get_list(array, &lynq_arrays->array_len);
+    if (0 != ret)
+    {
+        LYERRLOG("[%s ] ret = %d\n", __func__, ret);
+        return ret;
+    }
+    LYINFLOG("[%s]ap_lanhost len[%d]\n", __func__, lynq_arrays->array_len);
+    for (i = 0; i < lynq_arrays->array_len; i++)
+    {
+        LYINFLOG("[%s]Element : [%d] ifname = %s  macaddr = %s addr = %s name = %s uptime = %d\n", __func__, i,
+                 array[i].ifname, array[i].macaddr, array[i].addr, array[i].name, array[i].uptime);
+        strncpy(lynq_arrays->array[i].ifname, array[i].ifname, sizeof(lynq_arrays->array[i].ifname) - 1);
+        strncpy(lynq_arrays->array[i].macaddr, array[i].macaddr, sizeof(lynq_arrays->array[i].macaddr) - 1);
+        strncpy(lynq_arrays->array[i].addr, array[i].addr, sizeof(lynq_arrays->array[i].addr) - 1);
+        strncpy(lynq_arrays->array[i].name, array[i].name, sizeof(lynq_arrays->array[i].name) - 1);
+        lynq_arrays->array[i].uptime = array[i].uptime;
+    }
+    return 0;
+}
+
+/********************************************************************
+* @brief: qser_wifi_get_ap_pkt_stats, Obtain data packets sent and received by ap for 2.4G or 5G
+* @param idx [IN]: int, Set 2.4G or 5G
+* @param pkt_stat [OUT]: lynq_wifi_pkt_stats_t *, Obtain data packets sent and received by ap
+* @return : int, If equal to 0 succeeds, others fail
+* @todo: NA
+* @see: NA
+* @warning: NA
+*********************************************************************/
+int qser_wifi_get_ap_pkt_stats(lynq_wifi_ap_index_e idx, lynq_wifi_pkt_stats_t *pkt_stat)
+{
+    int ret = -1;
+    sc_wifi_pkt_stats_t stat = {0};
+    if (pkt_stat == NULL)
+    {
+        LYERRLOG("[%s ] Null pointer pkt_stat = 0x%p\n", __func__, pkt_stat);
+        return ret;
+    }
+    idx = LYNQ_WIFI_AP_INDEX_AP0;
+    ret = sc_wifi_get_ap_pkt_stats((sc_wifi_ap_index_e)idx, &stat);
+    if (0 != ret)
+    {
+        LYERRLOG("[%s ] ret = %d\n", __func__, ret);
+        return ret;
+    }
+    LYINFLOG("[%s ]ap_pkt_get[%d] rx[%llu, %llu, %llu, %llu] tx[%llu, %llu, %llu, %llu]\n", __func__, idx,
+             stat.rx_packets, stat.rx_bytes, stat.rx_errors, stat.rx_dropped,
+             stat.tx_packets, stat.tx_bytes, stat.tx_errors, stat.tx_dropped);
+    pkt_stat->rx_packets = stat.rx_packets;
+    pkt_stat->rx_bytes = stat.rx_bytes;
+    pkt_stat->rx_errors = stat.rx_errors;
+    pkt_stat->rx_dropped = stat.rx_dropped;
+    pkt_stat->tx_packets = stat.tx_packets;
+    pkt_stat->tx_bytes = stat.tx_bytes;
+    pkt_stat->tx_errors = stat.tx_errors;
+    pkt_stat->tx_dropped = stat.tx_dropped;
+    return 0;
+}
+
+/********************************************************************
 * @brief: qser_wifi_ap_start, Set the ap mode of 2.4G or 5G to enable
 * @param idx [IN]: int, Set 2.4G or 5G
 * @return : int, If equal to 0 succeeds, others fail
@@ -1141,17 +1211,17 @@
 * @see: NA
 * @warning: NA
 *********************************************************************/
-int  qser_wifi_sta_get_status(lynq_wifi_sta_status_t *status_stat)
+int qser_wifi_sta_get_status(lynq_wifi_sta_status_t *status_stat)
 {
     int ret = -1;
     sc_wifi_sta_status_t stat;
     ret = sc_wifi_sta_get_status(&stat);
     if (0 != ret)
     {
-        LYERRLOG("[%s ] sta_param_get ret = %d\n", __func__,ret);
+        LYERRLOG("[%s ] sta_param_get ret = %d\n", __func__, ret);
         return ret;
     }
-    //print_sta_status(&stat);
+    print_sta_status(&stat);
     status_stat->status = (lynq_wifi_sta_status_e)stat.status;
     status_stat->signal_level = stat.signal_level;
     status_stat->has_addr = stat.has_addr;
@@ -1161,17 +1231,64 @@
     strncpy(status_stat->ap_bssid, stat.ap_bssid, sizeof(stat.ap_bssid) - 1);
     if (status_stat->has_addr == 1)
     {
-        //inet_ntop(AF_INET, &stat.addr, status_stat->addr, sizeof(status_stat->addr));
+        strncpy(status_stat->addr.addr, stat.addr.addr, sizeof(status_stat->addr.addr) - 1);
+        strncpy(status_stat->addr.netmask, stat.addr.netmask, sizeof(status_stat->addr.netmask) - 1);
+        status_stat->addr.subnet_bits = stat.addr.subnet_bits;
+        strncpy(status_stat->addr.gateway, stat.addr.gateway, sizeof(status_stat->addr.gateway) - 1);
+        strncpy(status_stat->addr.dnsp, stat.addr.dnsp, sizeof(status_stat->addr.dnsp) - 1);
+        strncpy(status_stat->addr.dnss, stat.addr.dnss, sizeof(status_stat->addr.dnss) - 1);
     }
     if (status_stat->has_addr6 == 1)
     {
-        //inet_ntop(AF_INET6, &stat.addr6, status_stat->addr6, sizeof(status_stat->addr6));
+        strncpy(status_stat->addr6.addr, stat.addr6.addr, sizeof(status_stat->addr6.addr) - 1);
+        strncpy(status_stat->addr6.prefix, stat.addr6.prefix, sizeof(status_stat->addr6.prefix) - 1);
+        status_stat->addr6.prefix_bits = stat.addr6.prefix_bits;
+        strncpy(status_stat->addr6.gateway, stat.addr6.gateway, sizeof(status_stat->addr6.gateway) - 1);
+        strncpy(status_stat->addr6.dnsp, stat.addr6.dnsp, sizeof(status_stat->addr6.dnsp) - 1);
+        strncpy(status_stat->addr6.dnss, stat.addr6.dnss, sizeof(status_stat->addr6.dnss) - 1);
     }
     LYINFLOG("[%s ] ret = %d \n", __func__, ret);
     return 0;
 }
 
 /********************************************************************
+* @brief: qser_wifi_get_sta_pkt_stats, Obtain data packets sent and received by sta for 2.4G or 5G
+* @param pkt_stat [OUT]: lynq_wifi_pkt_stats_t *, Obtain data packets sent and received by sta
+* @return : int, If equal to 0 succeeds, others fail
+* @todo: NA
+* @see: NA
+* @warning: NA
+*********************************************************************/
+int qser_wifi_get_sta_pkt_stats(lynq_wifi_pkt_stats_t *pkt_stat)
+{
+    int ret = -1;
+    sc_wifi_pkt_stats_t stat = {0};
+    if (pkt_stat == NULL)
+    {
+        LYERRLOG("[%s ] Null pointer pkt_stat = 0x%p\n", __func__, pkt_stat);
+        return ret;
+    }
+    ret = sc_wifi_get_sta_pkt_stats(&stat);
+    if (0 != ret)
+    {
+        LYERRLOG("[%s ] ret = %d\n", __func__, ret);
+        return ret;
+    }
+    LYINFLOG("[%s ]sta_pkt_get rx[%llu, %llu, %llu, %llu] tx[%llu, %llu, %llu, %llu]\n", __func__, 
+             stat.rx_packets, stat.rx_bytes, stat.rx_errors, stat.rx_dropped,
+             stat.tx_packets, stat.tx_bytes, stat.tx_errors, stat.tx_dropped);
+    pkt_stat->rx_packets = stat.rx_packets;
+    pkt_stat->rx_bytes = stat.rx_bytes;
+    pkt_stat->rx_errors = stat.rx_errors;
+    pkt_stat->rx_dropped = stat.rx_dropped;
+    pkt_stat->tx_packets = stat.tx_packets;
+    pkt_stat->tx_bytes = stat.tx_bytes;
+    pkt_stat->tx_errors = stat.tx_errors;
+    pkt_stat->tx_dropped = stat.tx_dropped;
+    return 0;
+}
+
+/********************************************************************
 * @brief: qser_wifi_sta_start_scan, Scan for ap nodes and return them through callback
 * @return : int, If equal to 0 succeeds, others fail
 * @todo: NA
diff --git a/cap/zx297520v3/src/lynq/lib/libpoweralarm/libpoweralarm.cpp b/cap/zx297520v3/src/lynq/lib/libpoweralarm/libpoweralarm.cpp
index 26f57be..af24cd9 100755
--- a/cap/zx297520v3/src/lynq/lib/libpoweralarm/libpoweralarm.cpp
+++ b/cap/zx297520v3/src/lynq/lib/libpoweralarm/libpoweralarm.cpp
@@ -24,15 +24,18 @@
 extern "C" {

 #endif

 

+#include "sc_rtc_timer.h"

+

 #define USER_LOG_TAG "LYNQ_POWERALARM"

 

 #define MIN_TIME    1

 #define MAX_TIME    268435456

 

 

-typedef int (*sc_rtc_timer_exp_cb)(unsigned int src_id, int rtc_id);

+//typedef int (*sc_rtc_timer_exp_cb)(unsigned int src_id, int rtc_id);

 typedef int (*lynq_wakealarm_add_cb)(unsigned int src_id, int rtc_id);

 

+/*

 extern int sc_rtc_timer_init(void);

 extern int sc_rtc_timer_uninit(void );

 extern int sc_rtc_timer_add(int srcid, int rtc_id, unsigned long ulSec, sc_rtc_timer_exp_cb rtc_notify);

@@ -44,6 +47,7 @@
 

 extern int sc_rtc_add_poweroff_alarm(int srcid, int alarm_modid, int rtc_id, struct tm *utc_sec, sc_rtc_timer_exp_cb rtc_notify);

 

+*/

 

 /*****************************************

 * @brief:lynq_rtc_service_init

diff --git a/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/drivers/dma/sc/zx297520v3_dma.c b/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/drivers/dma/sc/zx297520v3_dma.c
index a1ebb94..6ef00d8 100644
--- a/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/drivers/dma/sc/zx297520v3_dma.c
+++ b/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/drivers/dma/sc/zx297520v3_dma.c
@@ -117,7 +117,7 @@
 
 #define MAX(a,b) ((a) > (b) ? (a) : (b))
 
-/* Ò»¸öÁ´±íÖÐ×î´óµÄÁ´±íÏî¸öÊý */
+/* һ��������������������� */
 #define MAX_LLI_PARA_CNT						(32)
 
 
@@ -1088,13 +1088,15 @@
 						dmac_ptr->dma_chan[channel_id].desc.callback(dmac_ptr->dma_chan[channel_id].desc.callback_param);
 #else
 					/* schedule tasklet on this channel */
-			#ifdef _USE_VEHICLE_DC
-					if((channel_id == DMA_CH_UART0_RX) || (channel_id == DMA_CH_UART2_RX)){
+			/* yu.dong@20240617 [T106BUG-641] SPI packet loss issue, increase kernel buffer and read all cached data away, no data loss start */
+			#ifdef _USE_VEHICLE_DC || _USE_VEHICLE_DC_REF
+					if((channel_id == DMA_CH_UART0_RX) || (channel_id == DMA_CH_UART2_RX) || (channel_id == DMA_CH_SSP0_RX)){
 						if (dmac_ptr->dma_chan[channel_id].desc.callback)
 							dmac_ptr->dma_chan[channel_id].desc.callback(dmac_ptr->dma_chan[channel_id].desc.callback_param);
 					}else
 						tasklet_schedule(&dmac_ptr->dma_chan[channel_id].tasklet);
 			#else
+			/* yu.dong@20240617 [T106BUG-641] SPI packet loss issue, increase kernel buffer and read all cached data away, no data loss end */
 					tasklet_schedule(&dmac_ptr->dma_chan[channel_id].tasklet);
 			#endif
 #endif
diff --git a/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/drivers/spi/spi-zx29.c b/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/drivers/spi/spi-zx29.c
index 9d3f781..d570db1 100755
--- a/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/drivers/spi/spi-zx29.c
+++ b/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/drivers/spi/spi-zx29.c
@@ -158,6 +158,8 @@
 #define SPI_INTR_EN_MASK_TX_EMPTY_IE  		(0x1UL << 3)
 #define SPI_INTR_EN_MASK_RX_THRES_IE  		(0x1UL << 4)
 #define SPI_INTR_EN_MASK_TX_THRES_IE  		(0x1UL << 5)
+//yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme.
+#define SPI_INTR_EN_MASK_MST_EOT_IE  		(0x1UL << 6)
 
 /*
  * SPI Interrupt Status Register OR Interrupt Clear Register - SPI_INTR_SR_SCLR
@@ -391,9 +393,10 @@
 #endif
 	struct semaphore 	sema_dma;
 /* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck start */
-        wait_queue_head_t	wait;
-        int trans_done;
+	wait_queue_head_t	wait;
+	int 			trans_done;
 /* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck end */
+
 	u8 iface_mode;
 #define	SPI_MOTO_FORMAT	0x00
 #define	SPI_TI_FORMAT	0x01
@@ -875,14 +878,13 @@
 	struct zx29_spi *zx29spi = (struct zx29_spi *)data;
 	//printk(KERN_INFO "spi:dma transfer complete. %X-%X-%x\n", zx29spi->dma_running, readl((SPI_INTR_SR_OFFSET+zx29spi->virtbase)),readl((SPI_FIFO_SR_OFFSET+zx29spi->virtbase)));
         /* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck start */
-        //up(&zx29spi->sema_dma);
-        if(zx29spi->master->slave == true){
+	//up(&zx29spi->sema_dma);
+	if(zx29spi->master->slave == true){
                 wake_up(&zx29spi->wait);
                 zx29spi->trans_done = true;
-        }else
-        {
+	}else{
                 up(&zx29spi->sema_dma);
-        }
+	}
         /* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck end */
 }
 
@@ -1207,6 +1209,7 @@
 		for(i = 0;i <= (len-8);i+=8) {
 			printk("%02x %02x %02x %02x %02x %02x %02x %02x \r\n",p[i],p[i+1],p[i+2],p[i+3],p[i+4],p[i+5],p[i+6],p[i+7]);
 		}
+		printk("\n");
 	}
 	
 }
@@ -1313,65 +1316,84 @@
 }
 
 /* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck start */
+#define SSP0_PARA_BASE_ADDR 0x1400030
 #define SSP1_PARA_BASE_ADDR 0x1400048
-
-#define SSP_MASK_SW_WRST    (0x1L << 9)
-#define SSP_MASK_SW_PRST    (0x1L << 8)
-
-static int zx29_slave_ctrl_reset(struct zx29_spi *zx29spi) {
+#define SSP_MASK_SW_WRST	(0x1L << 9)
+#define SSP_MASK_SW_PRST	(0x1L << 8)
+static int zx29_slave_ctrl_reset(struct zx29_spi *zx29spi)
+{
     void __iomem *addr = NULL;
     ktime_t k_time_start = 0;
     ktime_t diff_ns = 0;
     volatile unsigned int val = 0;
 
+	if(!strcmp(zx29spi->pdev->name,"1410000.ssp")) {
     addr = ioremap(SSP1_PARA_BASE_ADDR, 0x1000);
+	}else{
+		addr = ioremap(SSP0_PARA_BASE_ADDR, 0x1000);
+	}
 
-    if (addr) {
+	if(addr){
         val = *(volatile unsigned int *)addr;
-        *(volatile unsigned int *)addr = val & (~(SSP_MASK_SW_WRST | SSP_MASK_SW_PRST));
+		//dev_info(&zx29spi->pdev->dev, "val = 0x%x 0x%x\n",val,(~(SSP_MASK_SW_WRST|SSP_MASK_SW_PRST)));
+		*(volatile unsigned int *)addr =  val & (~(SSP_MASK_SW_WRST|SSP_MASK_SW_PRST));
 
         k_time_start = ktime_get();
         do {
-            diff_ns = ktime_sub(ktime_get(), k_time_start);
-            val = readl((SPI_COM_CTRL_OFFSET + zx29spi->virtbase)) >> 1 & 0x1;
+			diff_ns = ktime_sub(ktime_get(),k_time_start);
+			val = readl((SPI_COM_CTRL_OFFSET+zx29spi->virtbase))>> 1 & 0x1;
             cpu_relax();
-        } while (val && diff_ns < 100000000); // 100ms
+		}while(val && diff_ns < 100000000); //100ms
 
-        if (diff_ns >= 100000000)
+		if(diff_ns >= 100000000)
             dev_info(&zx29spi->pdev->dev, "zx29_slave_assert_ctrl failed!!! \n");
         else
             dev_info(&zx29spi->pdev->dev, "zx29_slave_assert_ctrl success! \n");
 
+
         val = *(volatile unsigned int *)addr;
-        *(volatile unsigned int *)addr = val | (SSP_MASK_SW_WRST | SSP_MASK_SW_PRST);
+		*(volatile unsigned int *)addr = val|(SSP_MASK_SW_WRST|SSP_MASK_SW_PRST);
         udelay(500);
+
+		iounmap(addr);
     }
 
     return 0;
 }
 
-static int zx29_slave_ctrl_reinit(struct zx29_spi *zx29spi) {
+static int zx29_slave_ctrl_reinit(struct zx29_spi *zx29spi)
+{
     volatile unsigned int regval;
+		ktime_t k_time_start = 0;
+		ktime_t diff_ns = 0;
 
     zx29_slave_ctrl_reset(zx29spi);
 
     /* Disable SPI */
-    regval = readl((SPI_COM_CTRL_OFFSET + zx29spi->virtbase)) & (~SPI_COM_CTRL_MASK_SSPE);
-    writel(regval, (SPI_COM_CTRL_OFFSET + zx29spi->virtbase));
+		regval = readl((SPI_COM_CTRL_OFFSET+zx29spi->virtbase)) & (~SPI_COM_CTRL_MASK_SSPE);
+		writel(regval, (SPI_COM_CTRL_OFFSET+zx29spi->virtbase));
 
     load_spi_default_config(zx29spi);
     writel(0, (SPI_TIMING_OFFSET + zx29spi->virtbase));
 
-    if (!strcmp(zx29spi->pdev->name, "1410000.ssp")) {
-        regval = readl((SPI_FMT_CTRL_OFFSET + zx29spi->virtbase)) & (~(0x1 << 12));
-        writel(regval, (SPI_FMT_CTRL_OFFSET + zx29spi->virtbase));
-        dev_info(&zx29spi->pdev->dev, "%s set non-camera mode regval:0x%x \n", zx29spi->pdev->name, regval);
+		if(!strcmp(zx29spi->pdev->name,"1410000.ssp")) {
+			regval = readl((SPI_FMT_CTRL_OFFSET+zx29spi->virtbase))&(~(0x1<<12));
+			writel(regval, (SPI_FMT_CTRL_OFFSET+zx29spi->virtbase));
+			dev_info(&zx29spi->pdev->dev," %s set non-camera mode regval:0x%x \n",zx29spi->pdev->name,regval);
     }
 
-    writel(readl((SPI_COM_CTRL_OFFSET + zx29spi->virtbase)) | SPI_COM_CTRL_MASK_SSPE, (SPI_COM_CTRL_OFFSET + zx29spi->virtbase));
-    while (((readl((SPI_COM_CTRL_OFFSET + zx29spi->virtbase)) >> 4) & 0x1) == 0);
+		writel(readl((SPI_COM_CTRL_OFFSET+zx29spi->virtbase)) | SPI_COM_CTRL_MASK_SSPE,  (SPI_COM_CTRL_OFFSET+zx29spi->virtbase));
+		k_time_start = ktime_get();
+		do{
+			diff_ns = ktime_sub(ktime_get(),k_time_start);
+			regval = ((readl((SPI_COM_CTRL_OFFSET+zx29spi->virtbase))>> 4)&0x1);
+			cpu_relax();
+		}while((regval == 0) && diff_ns < 100000000);
 
-    dev_info(&zx29spi->pdev->dev, "ssp enabled \n", regval);
+		if(diff_ns >= 100000000)
+			dev_info(&zx29spi->pdev->dev, "wait sspen timeout!!! \n");
+		else
+			dev_info(&zx29spi->pdev->dev,"ssp enabled \n",regval);
 
     return 0;
 }
@@ -1405,7 +1427,7 @@
 	/* If we're using DMA, set up DMA here */
 	if (zx29spi->cur_chip->enable_dma) {
 		/* Configure DMA transfer */
-                zx29spi->trans_done = false; //yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck
+		zx29spi->trans_done = false; //yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck
 		ret = configure_dma(zx29spi);
 		if (ret) {
 			dev_err(&zx29spi->pdev->dev, "configuration of DMA failed, fall back to interrupt mode\n");
@@ -1418,17 +1440,18 @@
 		extern void spi_dev_send_dma_cfg_down(struct spi_device *spi);
 		struct spi_device *spi = zx29spi->cur_msg->spi;
 		spi_dev_send_dma_cfg_down(spi);
-                /* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck start */
-                //down(&zx29spi->sema_dma);
-                ret = wait_event_freezable(zx29spi->wait, zx29spi->trans_done);
-                if(ret){
-                        terminate_dma(zx29spi);
-                        disable_irq_nosync(zx29spi->irq);
-                        zx29spi->dma_running = 0;
-                        zx29_slave_ctrl_reinit(zx29spi);
-                        goto err_config_dma;
-                }
-                /* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck end */
+		/* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck start */
+		//down(&zx29spi->sema_dma);
+		ret = wait_event_freezable(zx29spi->wait, zx29spi->trans_done);
+		if(ret){
+			terminate_dma(zx29spi);
+			disable_irq_nosync(zx29spi->irq);
+			zx29spi->dma_running = 0;
+			zx29_slave_ctrl_reinit(zx29spi);
+			goto err_config_dma;
+
+		}
+		/* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck end */
 		//printk("COM=0x%x,FMT=0x%x,FIFO_CTL=0x%x,FIFO_SR=0x%x\n",readl((SPI_COM_CTRL_OFFSET+zx29spi->virtbase)),readl((SPI_FMT_CTRL_OFFSET+zx29spi->virtbase)),readl((SPI_FIFO_CTRL_OFFSET+zx29spi->virtbase)),readl((SPI_FIFO_SR_OFFSET+zx29spi->virtbase)));
 
 		
@@ -1961,8 +1984,252 @@
 	return ret;
 }
 
+/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme start */
+#define SPI_SLVAE_RX_BUFF_SIZE        4096
+#define SPI_SLVAE_RX_MAX_PACK_NUM     15
+#define SPI_SLVAE_RX_PACK_LEN         146
+#define SPI_SLVAE_RX_LIST_BUFF_LEN    (SPI_SLVAE_RX_MAX_PACK_NUM*SPI_SLVAE_RX_PACK_LEN)
+static dma_channel_def slave_rx_conf[SPI_SLVAE_RX_MAX_PACK_NUM] = {0};
+//yu.dong@20240617 [T106BUG-641] SPI packet loss issue, increase kernel buffer and read all cached data away, no data loss.
+#define SPI_MAGIC 0x55555555
+static bool rxbuf_is_free_space(struct spi_device *spi)
+{
+	if (spi->recv_pos < spi->rd_pos) {
+        if ((spi->rd_pos - spi->recv_pos) > SPI_SLVAE_RX_PACK_LEN)
+			return 1;
+		else
+			return 0;
+	}
+	else {
+		if ((SPI_SLVAE_RX_BUFF_SIZE - spi->recv_pos + spi->rd_pos ) > SPI_SLVAE_RX_PACK_LEN)
+			return 1;
+		else
+			return 0;
+	}
+}
 
+/* yu.dong@20240617 [T106BUG-641] SPI packet loss issue, increase kernel buffer and read all cached data away, no data loss start */
+static void dma_cyclic_callback(void *data)
+{
+	struct spi_device *spi = (struct spi_device *)data;
+	struct zx29_spi *zx29spi = NULL;
+	int index = 0;
+	unsigned int end = 0;
 
+	zx29spi = spi_master_get_devdata(spi->master);
+	zx29spi->spi_poll_cnt++;
+	end = *(volatile unsigned int *)(spi->cyc_buf +spi->cyc_index * SPI_SLVAE_RX_PACK_LEN + SPI_SLVAE_RX_PACK_LEN - 4);
+	while((end != SPI_MAGIC) && index < SPI_SLVAE_RX_MAX_PACK_NUM) {
+		if(!rxbuf_is_free_space(spi)) {
+			printk("rx_buff not enough space!!!!!");
+			zx29spi->spi_dma_cnt++;
+			break;
+		}else {
+			if((spi->recv_pos + SPI_SLVAE_RX_PACK_LEN) <= SPI_SLVAE_RX_BUFF_SIZE) {
+				memcpy(spi->rx_buf + spi->recv_pos,spi->cyc_buf + spi->cyc_index * SPI_SLVAE_RX_PACK_LEN,SPI_SLVAE_RX_PACK_LEN);
+			}else {
+				memcpy(spi->rx_buf + spi->recv_pos,spi->cyc_buf + spi->cyc_index * SPI_SLVAE_RX_PACK_LEN,SPI_SLVAE_RX_BUFF_SIZE - spi->recv_pos);
+				memcpy(spi->rx_buf,spi->cyc_buf + spi->cyc_index * SPI_SLVAE_RX_PACK_LEN + (SPI_SLVAE_RX_BUFF_SIZE - spi->recv_pos),SPI_SLVAE_RX_PACK_LEN-(SPI_SLVAE_RX_BUFF_SIZE-spi->recv_pos));
+			}
+			*(volatile unsigned int *)(spi->cyc_buf +spi->cyc_index * SPI_SLVAE_RX_PACK_LEN + SPI_SLVAE_RX_PACK_LEN - 4) = SPI_MAGIC;
+			spi->recv_pos = (spi->recv_pos + SPI_SLVAE_RX_PACK_LEN)%SPI_SLVAE_RX_BUFF_SIZE;
+			spi->cyc_index = (spi->cyc_index + 1)%SPI_SLVAE_RX_MAX_PACK_NUM;
+
+			zx29spi->spi_dma_cnt++;
+			index++;
+			end = *(volatile unsigned int *)(spi->cyc_buf +spi->cyc_index * SPI_SLVAE_RX_PACK_LEN + SPI_SLVAE_RX_PACK_LEN - 4);
+		}
+
+		if(spi->is_rd_waiting == true && spi->recv_done == 0) {
+			wake_up(&spi->rd_wait);
+			spi->recv_done = 1;
+		}
+	}
+	if((end != SPI_MAGIC) && index == SPI_SLVAE_RX_MAX_PACK_NUM)
+		printk("cyc_buf be covered!!!!!");
+	return;
+}
+/* yu.dong@20240617 [T106BUG-641] SPI packet loss issue, increase kernel buffer and read all cached data away, no data loss end */
+
+static int zx29_slave_config_dma(struct zx29_spi *zx29spi,struct spi_device *spi)
+{
+	struct chip_data *chip = NULL;
+	struct dma_chan *rxchan = NULL;
+	struct dma_async_tx_descriptor *rxdesc;
+	unsigned short transfer_len = SPI_SLVAE_RX_PACK_LEN;
+	int i;
+
+	chip = zx29spi->cur_chip = spi->controller_state;
+
+	if (spi->rx_dma)
+		flush(zx29spi);
+	writel(CLEAR_ALL_INTERRUPTS, (SPI_INTR_SR_OFFSET+zx29spi->virtbase));
+	writel((chip->fifo_ctrl | SPI_FIFO_CTRL_MASK_RX_DMA_EN), (SPI_FIFO_CTRL_OFFSET+zx29spi->virtbase));
+
+	zx29spi->write = zx29spi->tx ? zx29spi->cur_chip->write : WRITING_NULL;
+	zx29spi->read = zx29spi->rx ? zx29spi->cur_chip->read : READING_NULL;
+	rxchan = zx29spi->dma_rx_channel;
+	/* Check that the channels are available */
+	if (!rxchan)
+		return -ENODEV;
+
+	/*
+	 * If supplied, the DMA burstsize should equal the FIFO trigger level.
+	 * Notice that the DMA engine uses one-to-one mapping. Since we can
+	 * not trigger on 2 elements this needs explicit mapping rather than
+	 * calculation.
+	 */
+	for(i = 0;i < SPI_SLVAE_RX_MAX_PACK_NUM;i++) {
+		switch (zx29spi->rx_lev_trig) {
+		case SPI_RX_1_OR_MORE_ELEM:
+			slave_rx_conf[i].dma_control.src_burst_len = DMA_BURST_LEN_1;
+			slave_rx_conf[i].dma_control.dest_burst_len = DMA_BURST_LEN_1;
+			break;
+		case SPI_RX_4_OR_MORE_ELEM:
+			slave_rx_conf[i].dma_control.src_burst_len = DMA_BURST_LEN_4;
+			slave_rx_conf[i].dma_control.dest_burst_len = DMA_BURST_LEN_4;
+			break;
+		case SPI_RX_8_OR_MORE_ELEM:
+			slave_rx_conf[i].dma_control.src_burst_len = DMA_BURST_LEN_8;
+			slave_rx_conf[i].dma_control.dest_burst_len = DMA_BURST_LEN_8;
+			break;
+		case SPI_RX_16_OR_MORE_ELEM:
+			slave_rx_conf[i].dma_control.src_burst_len = DMA_BURST_LEN_16;
+			slave_rx_conf[i].dma_control.dest_burst_len = DMA_BURST_LEN_16;
+			break;
+		case SPI_RX_32_OR_MORE_ELEM:
+			slave_rx_conf[i].dma_control.src_burst_len = DMA_BURST_LEN_ALL;
+			slave_rx_conf[i].dma_control.dest_burst_len = DMA_BURST_LEN_ALL;
+			break;
+		default:
+			slave_rx_conf[i].dma_control.src_burst_len = zx29spi->vendor->fifodepth >> 1;
+			slave_rx_conf[i].dma_control.dest_burst_len = zx29spi->vendor->fifodepth >> 1;
+			break;
+		}
+
+		switch (zx29spi->read) {
+		case READING_NULL:
+			/* Use the same as for writing */
+			slave_rx_conf[i].dma_control.src_burst_size = DMA_BURST_SIZE_8BIT;
+			slave_rx_conf[i].dma_control.dest_burst_size = DMA_BURST_SIZE_8BIT;
+			slave_rx_conf[i].count	  = transfer_len;
+			break;
+		case READING_U8:
+			slave_rx_conf[i].dma_control.src_burst_size = DMA_BURST_SIZE_8BIT;
+			slave_rx_conf[i].dma_control.dest_burst_size = DMA_BURST_SIZE_8BIT;
+			slave_rx_conf[i].count	  = transfer_len;
+			break;
+		case READING_U16:
+			slave_rx_conf[i].dma_control.src_burst_size = DMA_BURST_SIZE_16BIT;
+			slave_rx_conf[i].dma_control.dest_burst_size = DMA_BURST_SIZE_16BIT;
+			slave_rx_conf[i].count	  = transfer_len;
+			break;
+		case READING_U32:
+			slave_rx_conf[i].dma_control.src_burst_size = DMA_BURST_SIZE_32BIT;
+			slave_rx_conf[i].dma_control.dest_burst_size = DMA_BURST_SIZE_32BIT;
+			slave_rx_conf[i].count	  = transfer_len;
+			break;
+		}
+
+		slave_rx_conf[i].src_addr  = (SPI_DR_OFFSET+zx29spi->phybase);
+		slave_rx_conf[i].dma_control.tran_mode = TRAN_PERI_TO_MEM;
+		slave_rx_conf[i].dma_control.irq_mode  = DMA_ALL_IRQ_ENABLE;
+		slave_rx_conf[i].dest_addr = (unsigned int)spi->rx_dma + transfer_len*i;
+		slave_rx_conf[i].link_addr = 1;
+		//yu.dong@20240617 [T106BUG-641] SPI packet loss issue, increase kernel buffer and read all cached data away, no data loss.
+		*(volatile unsigned int *)(spi->cyc_buf + transfer_len*i + transfer_len -4) = SPI_MAGIC;
+	}
+
+	dmaengine_slave_config(rxchan,(struct dma_slave_config*)&slave_rx_conf[0]);
+
+	/* Submit and fire RX and TX with TX last so we're ready to read! */
+	if (spi->rx_dma) {
+		rxdesc = rxchan->device->device_prep_dma_cyclic(rxchan,NULL,SPI_SLVAE_RX_MAX_PACK_NUM * SPI_SLVAE_RX_PACK_LEN, SPI_SLVAE_RX_PACK_LEN,0,0);
+		if (!rxdesc) {
+			printk(KERN_INFO "!!ERROR DESC !!![%s][%d]\n",__func__,__LINE__);
+			dmaengine_terminate_all(rxchan);
+			return -EBUSY;
+		}
+		/* Put the callback on the RX transfer only, that should finish last */
+		rxdesc->callback = dma_cyclic_callback;
+		rxdesc->callback_param = spi;
+		dmaengine_submit(rxdesc);
+		dma_async_issue_pending(rxchan);
+		zx29spi->dma_running = RX_TRANSFER;
+	}
+	return 0;
+}
+
+static int zx29_slave_rd_start(struct spi_device *spi)
+{
+	struct zx29_spi *zx29spi = NULL;
+	struct device *dev;
+	int status = 0;
+	static int wd_wait_queue_init = 0;
+
+	printk("zx29_slave_rd_start...\r\n");
+
+	zx29spi = spi_master_get_devdata(spi->master);
+	dev = &zx29spi->pdev->dev;
+	if (!zx29spi)
+		return -EINVAL;
+
+	spi->cyc_index = 0;
+	spi->rd_pos = spi->recv_pos = 0;
+
+	spi->cyc_buf = dma_alloc_coherent(dev, SPI_SLVAE_RX_BUFF_SIZE, &spi->rx_dma, GFP_KERNEL);
+	if (dma_mapping_error(dev, spi->rx_dma)) {
+		dev_err(dev, "dma_map_single spi rx failed\n");
+		return -ENOMEM;
+	}
+
+	if(wd_wait_queue_init == 0) {
+		init_waitqueue_head(&spi->rd_wait);
+		spi->recv_done = false;
+		spi->is_rd_waiting = false;
+		wd_wait_queue_init = 1;
+	}
+	status = zx29_slave_config_dma(zx29spi,spi);
+
+	return status;
+}
+
+static int zx29_slave_rd_stop(struct spi_device *spi)
+{
+	struct zx29_spi *zx29spi = NULL;
+	struct device *dev;
+	int status = 0;
+	struct chip_data *chip = NULL;
+	struct dma_chan *rxchan = NULL;
+
+	zx29spi = spi_master_get_devdata(spi->master);
+	dev = &zx29spi->pdev->dev;
+	if (!zx29spi)
+		return -EINVAL;
+
+	chip = zx29spi->cur_chip= spi->controller_state;
+	writel(chip->fifo_ctrl, (SPI_FIFO_CTRL_OFFSET+zx29spi->virtbase));
+	rxchan = zx29spi->dma_rx_channel;
+	/* Submit and fire RX and TX with TX last so we're ready to read! */
+	if(spi->rx_dma) {
+		dmaengine_terminate_all(rxchan);
+		zx29spi->dma_running = 0;
+	}
+
+	if(spi->cyc_buf != NULL && spi->rx_dma) {
+		dma_free_coherent(dev, SPI_SLVAE_RX_BUFF_SIZE, spi->cyc_buf, spi->rx_dma);
+		spi->cyc_buf = NULL;
+	}
+
+	spi->cyc_index = 0;
+	spi->rd_pos = spi->recv_pos = 0;
+	spi->recv_done = false;
+	spi->is_rd_waiting = false;
+	printk("zx29_slave_rd_stop...\r\n");
+
+	return status;
+}
+/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme end */
 
 static int zx29_prepare_transfer_hardware(struct spi_master *master)
 {
@@ -2085,7 +2352,7 @@
 };
 
 /*
-*    spi ʹÓÃGPIOģʽ¶ÁÈ¡LCD µÄID Begin
+
 */
 static void spi_set_gpio_function(int dev_id)
 {
@@ -2344,14 +2611,13 @@
 	ktime_t k_time_start = 0;
 	ktime_t k_time_end = 0;
 	ktime_t diff_ns = 0;
-
-	if(false == zx29spi->master->slave)
-		pm_stay_awake(&zx29spi->pdev->dev);
+        /* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme start */
 	regval = readl((SPI_COM_CTRL_OFFSET+zx29spi->virtbase)) & (~SPI_COM_CTRL_MASK_SSPE);
 	writel(regval, (SPI_COM_CTRL_OFFSET+zx29spi->virtbase));
 	
 	writel(chip->fmt_ctrl, (SPI_FMT_CTRL_OFFSET+zx29spi->virtbase));
-	writel(chip->fifo_ctrl, (SPI_FIFO_CTRL_OFFSET+zx29spi->virtbase));
+	//writel(chip->fifo_ctrl, (SPI_FIFO_CTRL_OFFSET+zx29spi->virtbase));
+        /* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme end */
 	writel(chip->com_ctrl, (SPI_COM_CTRL_OFFSET + zx29spi->virtbase));
 	//writel(chip->timing, (SPI_TIMING_OFFSET + zx29spi->virtbase));
 
@@ -2369,9 +2635,6 @@
 	if(diff_ns >= 10000000) {
 		dev_info(&zx29spi->pdev->dev, " zx29_setup_to_regs failed! diff_ns=%lld \n",diff_ns);
 	}
-
-	if(false == zx29spi->master->slave)
-		pm_relax(&zx29spi->pdev->dev);
 	
 }
 /**
@@ -2557,11 +2820,9 @@
 		SPI_WRITE_BITS(chip->com_ctrl, SPI_SLAVE_MODE, SPI_COM_CTRL_MASK_MS, 2);
 		zx29_setup_to_regs(chip,zx29spi);
 	}
-	
-	if(zx29spi->mode == ZX29_SSP_MASTER_TYPE) {
-		if(spi->setup_immediately == 1)
-			zx29_setup_to_regs(chip,zx29spi);
-	}	
+
+        //yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme.
+
 	return status;
  err_config_params:
 	spi_set_ctldata(spi, NULL);
@@ -2911,10 +3172,10 @@
 	zx29spi->mode = ZX29_SSP_MASTER_TYPE;
 	zx29spi->zx29_flush_rxfifo = zx29_flush_rxfifo;
 	sema_init(&zx29spi->sema_dma, 0);
-        /* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck start */
-        init_waitqueue_head(&zx29spi->wait);
-        zx29spi->trans_done = false;
-        /* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck end */
+	/* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck start */
+	init_waitqueue_head(&zx29spi->wait);
+	zx29spi->trans_done = false;
+	/* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck end */
 	dev_set_drvdata(&pdev->dev, zx29spi);
 	device_init_wakeup(&pdev->dev, true);
 	/*
@@ -3087,11 +3348,11 @@
 	zx29spi->vendor = &vendor_arm;
 	zx29spi->mode = ZX29_SSP_SLAVE_TYPE;
 	zx29spi->zx29_flush_rxfifo = zx29_flush_rxfifo;
-        sema_init(&zx29spi->sema_dma, 0);
-        /* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck start */
-        init_waitqueue_head(&zx29spi->wait);
-        zx29spi->trans_done = false;
-        /* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck end */
+	sema_init(&zx29spi->sema_dma, 0);
+	/* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck start */
+	init_waitqueue_head(&zx29spi->wait);
+	zx29spi->trans_done = false;
+	/* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck end */
 	dev_set_drvdata(&pdev->dev, zx29spi);
 	/*
 	 * Bus Number Which has been Assigned to this SSP controller
@@ -3104,6 +3365,10 @@
 	master->prepare_transfer_hardware = zx29_prepare_transfer_hardware;
 	master->transfer_one_message = zx29_slave_transfer_one_message;
 	master->unprepare_transfer_hardware = zx29_unprepare_transfer_hardware;
+	/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme start */
+	master->spi_slave_rd_start = zx29_slave_rd_start;
+	master->spi_slave_rd_stop = zx29_slave_rd_stop;
+	/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme end */
 	//master->rt = platform_info->rt;
 
 	/*
diff --git a/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/drivers/spi/spidev.c b/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/drivers/spi/spidev.c
index 53ea041..1522a21 100755
--- a/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/drivers/spi/spidev.c
+++ b/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/drivers/spi/spidev.c
@@ -31,9 +31,12 @@
 #include <linux/of_irq.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme start*/
+#include <linux/wait.h>
+#include <linux/suspend.h>
 
-
-
+#define SPI_SLAVE_FOR_YK
+/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme end */
 /*
  * This supports access to SPI devices using normal userspace I/O calls.
  * Note that while traditional UNIX/POSIX I/O semantics are half duplex,
@@ -201,29 +204,100 @@
 
 
 /*-------------------------------------------------------------------------*/
-
+/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme start*/
 /* Read-only message with current device setup */
 static ssize_t
 spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
 {
 	struct spidev_data	*spidev;
 	ssize_t			status;
-
+	unsigned long	missing;
 	/* chipselect only toggles at start or end of operation */
 	if (count > bufsiz)
 		return -EMSGSIZE;
 
 	spidev = filp->private_data;
 
+
+
+	#ifdef SPI_SLAVE_FOR_YK
+	size_t total = 0;
+
+	if (spidev->spi->rd_pos == spidev->spi->recv_pos) {
+
+		status = 0;
+		spidev->spi->is_rd_waiting = true;
+		if(0 != wait_event_freezable(spidev->spi->rd_wait, spidev->spi->recv_done)) {
+			if(spidev->spi->controller->spi_slave_rd_stop)
+				spidev->spi->controller->spi_slave_rd_stop(spidev->spi);
+			spidev->spi->is_rd_waiting = false;
+			return 	status;
+		}else {
+			spidev->spi->recv_done = false;
+			spidev->spi->is_rd_waiting = false;
+		}
+	}
 	mutex_lock(&spidev->buf_lock);
+	if(spidev->spi->rd_pos < spidev->spi->recv_pos) {
+
+		total = spidev->spi->recv_pos - spidev->spi->rd_pos;
+		status = (total > count) ? count : total;
 	
+		missing = copy_to_user(buf, spidev->rx_buffer+spidev->spi->rd_pos, status);
+		if (missing == status) {
+			status = -EFAULT;
+		}
+		else {
+			status = status - missing;
+			spidev->spi->rd_pos += status;
+		}
+
+	}else if(spidev->spi->rd_pos > spidev->spi->recv_pos) {
+
+		total = bufsiz - (spidev->spi->rd_pos - spidev->spi->recv_pos);
+		status = (total > count) ? count : total;
+
+		if((spidev->spi->rd_pos + status) <= bufsiz) {
+
+			missing = copy_to_user(buf, spidev->rx_buffer+spidev->spi->rd_pos, status);
+			if (missing == status) {
+				status = -EFAULT;
+			}
+			else {
+				status = status - missing;
+				spidev->spi->rd_pos += status;
+				spidev->spi->rd_pos = spidev->spi->rd_pos%bufsiz;
+			}
+		}else {
+
+			unsigned long first,rest;
+
+			first = bufsiz - spidev->spi->rd_pos;
+			missing = copy_to_user(buf, spidev->rx_buffer+spidev->spi->rd_pos, first);
+			if (missing == first) {
+				status = -EFAULT;
+			} else {
+				status = status - missing;
+			}
+
+			rest = status-first;
+			missing = copy_to_user(buf+first, spidev->rx_buffer, rest);
+			if (missing == rest) {
+				status = -EFAULT;
+			} else {
+				status = status - missing;
+			}
+			spidev->spi->rd_pos = rest;
+		}
+	}
+	#else
+	mutex_lock(&spidev->buf_lock);
 	if(spidev->rd_from_rx_buffer) 
 		status = count;
 	else 
 		status = spidev_sync_read(spidev, count);
 	
 	if (status > 0) {
-		unsigned long	missing;
 
 		missing = copy_to_user(buf, spidev->rx_buffer, status);
 		if (missing == status)
@@ -231,10 +305,12 @@
 		else
 			status = status - missing;
 	}
+	#endif
 	mutex_unlock(&spidev->buf_lock);
 
 	return status;
 }
+/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme end*/
 
 /* Write-only message with current device setup */
 static ssize_t
@@ -556,6 +632,16 @@
 					spidev->rd_from_rx_buffer ? "RX_BUFFER":"DEVICE");
 		}
 		break;
+/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme start */
+#ifdef SPI_SLAVE_FOR_YK
+	case SPI_IOC_RD_BLOCK_RELEASE:
+		if(spidev->spi->is_rd_waiting == true) {
+				wake_up(&spidev->spi->rd_wait);
+                                spidev->spi->recv_done = 1;
+		}
+		break;
+#endif
+/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme end */
 #ifdef TEST_SWAP_KERNEL_AND_USER
 	case SPI_IOC_WR_SIG_PID:
 		retval = get_user(tmp, (__u32 __user *)arg);
@@ -697,6 +783,15 @@
 		}
 	}
 
+        /* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme start */
+	#ifdef SPI_SLAVE_FOR_YK
+	if(spidev->rx_buffer) {
+		spidev->spi->rx_buf = spidev->rx_buffer;
+		if(spidev->spi->controller->spi_slave_rd_start)
+			spidev->spi->controller->spi_slave_rd_start(spidev->spi);
+	}
+	#endif
+        /* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme end */
 	spidev->users++;
 	filp->private_data = spidev;
 	stream_open(inode, filp);
@@ -742,6 +837,15 @@
 		spin_lock_irq(&spidev->spi_lock);
 		spi = spi_dev_get(spidev->spi);
 		spin_unlock_irq(&spidev->spi_lock);
+
+                /* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme start */
+		#ifdef SPI_SLAVE_FOR_YK
+		if(spidev->rx_buffer) {
+			if(spi->controller->spi_slave_rd_stop)
+				spi->controller->spi_slave_rd_stop(spi);
+		}
+		#endif

+                /* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme end */
 		if(spi && spi->master->slave) 
 			pm_relax(&spi->dev);
 		kfree(spidev->tx_buffer);
@@ -2153,14 +2257,7 @@
 		dev_info(&spi->dev,"trans_gap_num = 0x%x",val);
 	}
 
-	if (device_property_read_u32(&spi->dev, "setup-immediately",&val)) {
-		spi->setup_immediately = 0;
-		dev_err(&spi->dev,"setup-immediately get failed");
-	}
-	else {
-		spi->setup_immediately = val;
-		dev_info(&spi->dev,"setup-immediately = 0x%x",val);
-	}
+	// yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme.
 
 	/* If we can allocate a minor number, hook up this device.
 	 * Reusing minors is fine so long as udev or mdev is working.
diff --git a/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/include/linux/spi/spi.h b/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/include/linux/spi/spi.h
index e308466..569ba92 100755
--- a/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/include/linux/spi/spi.h
+++ b/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/include/linux/spi/spi.h
@@ -209,7 +209,17 @@
 	u8		dma_used;
 	u8 		trans_gaped;
 	u8 		trans_gap_num;
-	u8      setup_immediately;
+	/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme start */
+	u32		rd_pos;
+	u32     recv_pos;
+	u8 *    rx_buf;
+	u8 *    cyc_buf;
+	u8      cyc_index;
+	dma_addr_t rx_dma;
+	wait_queue_head_t	rd_wait;
+	int 	recv_done;
+	bool 	is_rd_waiting;
+	/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme end */
 };
 
 static inline struct spi_device *to_spi_device(struct device *dev)
@@ -675,6 +685,11 @@
 
 	/* Interrupt enable state during PTP system timestamping */
 	unsigned long		irq_flags;
+
+	/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme start */
+	int (*spi_slave_rd_start)(struct spi_device *spi);
+	int (*spi_slave_rd_stop)(struct spi_device *spi);
+	/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme end */
 };
 
 static inline void *spi_controller_get_devdata(struct spi_controller *ctlr)
diff --git a/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/include/uapi/linux/spi/spidev.h b/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/include/uapi/linux/spi/spidev.h
index f930a8e..d69bab6 100755
--- a/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/include/uapi/linux/spi/spidev.h
+++ b/cap/zx297520v3/zxic_code/zxic_source/linux-5.10/include/uapi/linux/spi/spidev.h
@@ -158,5 +158,10 @@
 #define SPI_IOC_RD_INT_ST		_IOR(SPI_IOC_MAGIC, 8, __u32)
 #define SPI_IOC_WR_INT_ST	    _IOW(SPI_IOC_MAGIC, 8, __u32)
 
+/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme start*/
+/* release from rd/wr block */
+#define SPI_IOC_RD_BLOCK_RELEASE	_IOR(SPI_IOC_MAGIC, 9, __u32)
+//#define SPI_IOC_WR_INT_ST	    _IOW(SPI_IOC_MAGIC, 9, __u32)
+/* yu.dong@20240617 [T106BUG-641] SPI packet loss problem, add kernel buffer scheme end*/
 
 #endif /* SPIDEV_H */
diff --git a/pub/project/zx297520v3/include/drv/dma_cfg.h b/pub/project/zx297520v3/include/drv/dma_cfg.h
index b83ca2b..5cd218e 100755
--- a/pub/project/zx297520v3/include/drv/dma_cfg.h
+++ b/pub/project/zx297520v3/include/drv/dma_cfg.h
@@ -204,11 +204,24 @@
 #define EXCEPT_FLAG_ADDR         (BOOT_FLAG_ADDR + BOOT_FLAG_SIZE)

 #define EXCEPT_FLAG_SIZE         (0x4UL)

 

+//youchen@2024-06-20 add for lynq nv config begin

+#define LYNQ_NV_CFG_SUPPORT 1

+

+#ifndef LYNQ_NV_CFG_SUPPORT

+

 #define MMC_FLAG_ADDR         (EXCEPT_FLAG_ADDR + EXCEPT_FLAG_SIZE)

 #define MMC_FLAG_SIZE         (0x4UL)/*bit 0: mmc0 exit,bit1 mmc1 exit*/

-

 #define RAM_CONFIG_END (MMC_FLAG_ADDR+MMC_FLAG_SIZE)

 

+#else

+

+#define MMC_LYNQ_NV_CFG_ADDR         (EXCEPT_FLAG_ADDR + EXCEPT_FLAG_SIZE)

+#define MMC_LYNQ_NV_CFG_SIZE         (0x100UL)

+#define RAM_CONFIG_END (MMC_LYNQ_NV_CFG_ADDR+MMC_LYNQ_NV_CFG_SIZE)

+

+#endif 

+//youchen@2024-06-20 add for lynq nv config end

+

 //#if RAM_CONFIG_END > (IRAM_BASE_ADDR_DRV+IRAM_BASE_LEN_DRV)

 //#error error drv_ram_cfg !!!!!!!!!!!!!!!

 //#endif