[Bugfix][T106BUG-616]SPI set to slave mode for read will get stuck start

Only Configure :No
Affected branch: master
Affected module: SPI
Is it affected on both ZXIC and MTK:only ZXIC
Self-test: Yes
Doc Update: No

Change-Id: I7ec80158e6c9fb2dc247009adbf33e1cd9e05697
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 546be32..9d3f781 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
@@ -44,6 +44,10 @@
 
 #include "spi-zx29.h"
 #include "pub_debug_info.h"
+/* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck start */
+#include <linux/wait.h>
+#include <linux/suspend.h>
+/* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck end */
 
 struct zx29_ssp_device_of_data {
 	enum zx29_ssp_device_mode	mode;
@@ -386,6 +390,10 @@
     struct wake_lock        psm_lock;
 #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;
+/* 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
@@ -866,7 +874,16 @@
 {
 	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)));
-    up(&zx29spi->sema_dma);
+        /* 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){
+                wake_up(&zx29spi->wait);
+                zx29spi->trans_done = true;
+        }else
+        {
+                up(&zx29spi->sema_dma);
+        }
+        /* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck end */
 }
 
 /*
@@ -1295,6 +1312,70 @@
 	return;
 }
 
+/* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck start */
+#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) {
+    void __iomem *addr = NULL;
+    ktime_t k_time_start = 0;
+    ktime_t diff_ns = 0;
+    volatile unsigned int val = 0;
+
+    addr = ioremap(SSP1_PARA_BASE_ADDR, 0x1000);
+
+    if (addr) {
+        val = *(volatile unsigned int *)addr;
+        *(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;
+            cpu_relax();
+        } while (val && diff_ns < 100000000); // 100ms
+
+        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);
+        udelay(500);
+    }
+
+    return 0;
+}
+
+static int zx29_slave_ctrl_reinit(struct zx29_spi *zx29spi) {
+    volatile unsigned int regval;
+
+    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));
+
+    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);
+    }
+
+    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);
+
+    dev_info(&zx29spi->pdev->dev, "ssp enabled \n", regval);
+
+    return 0;
+}
+/* yu.dong@20240521 [T106BUG-616] SPI set to slave mode for read will get stuck end */
 
 static int zx29_slave_do_interrupt_dma_transfer(struct zx29_spi *zx29spi)
 {
@@ -1324,6 +1405,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
 		ret = configure_dma(zx29spi);
 		if (ret) {
 			dev_err(&zx29spi->pdev->dev, "configuration of DMA failed, fall back to interrupt mode\n");
@@ -1336,7 +1418,17 @@
 		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);
-		down(&zx29spi->sema_dma);
+                /* 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)));
 
 		
@@ -2819,6 +2911,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 */
 	dev_set_drvdata(&pdev->dev, zx29spi);
 	device_init_wakeup(&pdev->dev, true);
 	/*
@@ -2991,7 +3087,11 @@
 	zx29spi->vendor = &vendor_arm;
 	zx29spi->mode = ZX29_SSP_SLAVE_TYPE;
 	zx29spi->zx29_flush_rxfifo = zx29_flush_rxfifo;
-	sema_init(&zx29spi->sema_dma, 0);
+        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