From b38dd76a4f14dbe4ec37ac92ab8267805e365b08 Mon Sep 17 00:00:00 2001
From: Gokul S <g-s@ti.com>
Date: Thu, 30 Apr 2026 13:27:16 +0530
Subject: [PATCH] virtual context implementation for csitx

Signed-off-by: Gokul S <g-s@ti.com>
---
 source/drivers/csitx/v0/csitx.h               |  14 +
 .../drivers/csitx/v0/include/csitx_drvPriv.h  |  51 +-
 .../drivers/csitx/v0/include/csitx_drvUdma.h  |   5 +-
 source/drivers/csitx/v0/soc/V0/csitx_soc.h    |   3 +
 source/drivers/csitx/v0/src/csitx_drv.c       | 647 +++++++++++-------
 source/drivers/csitx/v0/src/csitx_drvInit.c   |  42 +-
 source/drivers/csitx/v0/src/csitx_drvUdma.c   | 180 +++--
 7 files changed, 600 insertions(+), 342 deletions(-)

diff --git a/source/drivers/csitx/v0/csitx.h b/source/drivers/csitx/v0/csitx.h
index 6d7313a..5f33a0a 100755
--- a/source/drivers/csitx/v0/csitx.h
+++ b/source/drivers/csitx/v0/csitx.h
@@ -144,6 +144,20 @@ extern "C" {
  *
  */
 #define IOCTL_CSITX_PRINT_DEBUG_LOGS    (FVID2_CSITX_DRV_IOCTL_BASE + 0x0100U)
+
+/**
+ *  \brief Get the context id
+ *
+ *  This IOCTL can be used to get the context id for an instance
+ *  Note:
+ *
+ *  \param cmdArgs       [OUT] NULL
+ *  \param cmdArgsStatus [OUT] NULL
+ *
+ *  \return FVID2_SOK on success, else failure
+ *
+ */
+#define IOCTL_CSITX_GET_INST_CONTEXT_ID  (FVID2_CSITX_DRV_IOCTL_BASE + 0x0200U)
 /* @} */
 
 /**
diff --git a/source/drivers/csitx/v0/include/csitx_drvPriv.h b/source/drivers/csitx/v0/include/csitx_drvPriv.h
index 863c434..c9a1393 100755
--- a/source/drivers/csitx/v0/include/csitx_drvPriv.h
+++ b/source/drivers/csitx/v0/include/csitx_drvPriv.h
@@ -205,6 +205,8 @@ extern "C" {
 /* ========================================================================== */
 typedef struct CsitxDrv_ChObj CsitxDrv_ChObj;
 typedef struct CsitxDrv_InstObj CsitxDrv_InstObj;
+typedef struct CsitxDrv_VirtContext_t CsitxDrv_VirtContext;
+typedef struct CsitxDrv_CommonObj_t CsitxDrv_CommonObj;
 
 /**
  *  \brief This structure contains information about data type and bpp.
@@ -344,6 +346,32 @@ typedef struct
     Fvid2UtilsLinkListObj doneLlObj;
     /**< Linked List object for doneQ for all channels of each stream. */
 } CsitxDrv_InstBufManObj;
+/*
+ * struct CsitxDrv_VirtContext_t
+ * \brief CSITX driver global/common driver object.
+ */
+struct CsitxDrv_VirtContext_t
+{
+    uint32_t contextId;
+    /**< Context ID */
+    uint32_t state;
+    /**< Instance state.
+      *  See \ref CSITX_DrvState for details */
+    CsitxDrv_InstObj *instObj;
+    /**< Reference to instance object. */
+    uint32_t inUse;
+    /**< Current is being used or not.
+      *   See \ref CSITX_DrvUsageStatus for details */
+    uint32_t chId[CSITX_NUM_CH];
+    /**< Array containing channel for this context */
+    uint32_t numCh;
+    /**< Number of channels registered on this context */
+    Csitx_CreateParams createParams;
+    /**< CSI Rx module create configurations.
+      *  See \ref Csitx_CreateParams for details */
+    Fvid2_DrvCbParams fdmCbParams;
+    /**< FVID2 driver manager callback function parameters. */
+};
 
 /**
  *  \brief CSITX Driver Channel Object.
@@ -354,6 +382,11 @@ struct CsitxDrv_ChObj
     /**< CSI Tx Channel configuration passed down by application. */
     CsitxDrv_InstObj *instObj;
     /**< Reference to instance object. */
+    CsitxDrv_VirtContext *virtContext;
+    uint32_t chId;
+    /**< Channel ID */
+    uint32_t numCh;
+    /**< Number of channels registered on this context */
     uint32_t status;
     /**< Channel status
       *  See \ref CSITXDRV_ChState for details */
@@ -420,9 +453,7 @@ struct CsitxDrv_InstObj
     uint32_t inUse;
     /**< Current is being used or not.
       *   See \ref CSITX_DrvUsageStatus for details */
-    uint32_t state;
-    /**< Instance state.
-      *  See \ref CSITX_DrvState for details */
+    CsitxDrv_CommonObj *commonObjRef;
     Csitx_CreateParams createParams;
     /**< CSI Tx module create configurations.
       *  See \ref Csitx_CreateParams for details */
@@ -460,13 +491,19 @@ struct CsitxDrv_InstObj
     /**< CSITX D-PHY configurations. */
     CsitxDrv_EventObj eventObj[CSITX_EVENT_GROUP_MAX];
     /**< Event object for event management. */
+    uint32_t dpyCfgDone;
+    /**< DPHY configuration done. 0: Not done 1: Done */
+    Csitx_EventPrms eventParams;
+    /**< CSITX Event configurations. */
+    uint32_t eventRegDone;
+    /**< Error Event configuration done. 0: Not done 1: Done */
 };
 
 /*
  * struct CsitxDrv_CommonObj
  * \brief Transmit driver global/common driver object.
  */
-typedef struct
+struct CsitxDrv_CommonObj_t
 {
     Fvid2_DrvOps fvidDrvOps;
     /**< FVID2 driver ops. */
@@ -474,6 +511,10 @@ typedef struct
     /**< FVID2 registration complete flag. */
     uint32_t numInst;
     /**< Number of valid instance. */
+    uint32_t numVirtContUsed[CSITX_INSTANCE_ID_MAX];
+    /**< Number of virtual context used */
+    CsitxDrv_VirtContext virtContext[CSITX_INSTANCE_ID_MAX][CSITX_NUM_VIRTUAL_CONTEXT];
+    /**< Virtual context objects. */
     CsitxDrv_InstObj instObj[CSITX_INSTANCE_ID_MAX];
     /**< Transmit instance objects pointer. */
     Csitx_PlatformData platData;
@@ -504,7 +545,7 @@ typedef struct
     /**< Get timestamp function. */
     Udma_EventObject masterEvent;
     /**< UDMA Master event handle. */
-} CsitxDrv_CommonObj;
+};
 /* ========================================================================== */
 /*                            Global Variables                                */
 /* ========================================================================== */
diff --git a/source/drivers/csitx/v0/include/csitx_drvUdma.h b/source/drivers/csitx/v0/include/csitx_drvUdma.h
index 49756ae..1653f62 100755
--- a/source/drivers/csitx/v0/include/csitx_drvUdma.h
+++ b/source/drivers/csitx/v0/include/csitx_drvUdma.h
@@ -85,10 +85,9 @@ extern "C" {
 /* ========================================================================== */
 int32_t CsitxDrv_setDMACfgParams(CsitxDrv_ChObj *chObj);
 
-int32_t CsitxDrv_setUdmaParams(CsitxDrv_CommonObj *txObj,
-                               CsitxDrv_InstObj *instObj);
+int32_t CsitxDrv_setChUdmaParams(CsitxDrv_ChObj *chObj);
 
-int32_t CsitxDrv_clearUdmaParams(CsitxDrv_InstObj *instObj);
+int32_t CsitxDrv_clearUdmaParams(CsitxDrv_ChObj *chObj);
 
 int32_t CsitxDrv_udmaTxTrpdInit(Udma_ChHandle txChHandle,
                                 uint8_t *pTrpdMem,
diff --git a/source/drivers/csitx/v0/soc/V0/csitx_soc.h b/source/drivers/csitx/v0/soc/V0/csitx_soc.h
index ef1d961..b2e1ba4 100755
--- a/source/drivers/csitx/v0/soc/V0/csitx_soc.h
+++ b/source/drivers/csitx/v0/soc/V0/csitx_soc.h
@@ -229,6 +229,9 @@ extern "C" {
 /** \brief CSITX DRV Numbers: Number of stream per CSI TX module */
 #define CSITX_NUM_STREAM                             (1U)
 
+/** \brief CSITX DRV Virtual Context: Number of virtual contexts per CSI TX port */
+#define CSITX_NUM_VIRTUAL_CONTEXT                   (8U)
+
 /**
  *  \anchor CSITX_CoreIntrNum
  *  \name   CSITX Module Core Interrupts Numbers
diff --git a/source/drivers/csitx/v0/src/csitx_drv.c b/source/drivers/csitx/v0/src/csitx_drv.c
index 792bcfb..b66a551 100755
--- a/source/drivers/csitx/v0/src/csitx_drv.c
+++ b/source/drivers/csitx/v0/src/csitx_drv.c
@@ -126,7 +126,9 @@ uint32_t gTxTrOutCnt = 0U;
 static int32_t CsitxDrv_setInstCfgParams(CsitxDrv_InstObj *instObj,
                                          Csitx_CreateParams *createParams);
 
-static int32_t CsitxDrv_createChQueues(CsitxDrv_InstObj *instObj);
+static int32_t CsitxDrv_createChQueues(CsitxDrv_ChObj *chObj);
+
+static int32_t CsitxDrv_setChCfgParams(CsitxDrv_ChObj *chObj, Csitx_ChCfg *chCfg);
 
 static int32_t CsitxDrv_setCslCfgParams(CsitxDrv_CommonObj *txObj,
                                         CsitxDrv_InstObj *instObj,
@@ -135,19 +137,24 @@ static int32_t CsitxDrv_setCslCfgParams(CsitxDrv_CommonObj *txObj,
 static int32_t CsitxDrv_configShim(CsitxDrv_CommonObj *txObj,
                                    CsitxDrv_InstObj *instObj);
 
-int32_t Csitx_setDphyCfg(Csitx_DPhyCfg *dphyCfg);
+static int32_t CsitxDrv_chConfigShim(CsitxDrv_ChObj *chObj);
+
+static int32_t CsitxDrv_getFreeChNumIoctl(CsitxDrv_InstObj *instObj,
+                                          uint32_t *chNum);
 
-static void CsitxDrv_deleteChObj(CsitxDrv_InstObj *instObj);
+int32_t Csitx_setDphyCfg(CsitxDrv_VirtContext *virtContext, Csitx_DPhyCfg *dphyCfg);
+
+static void CsitxDrv_deleteChObj(CsitxDrv_ChObj *chObj);
 
 static void CsitxDrv_deleteChQueues(CsitxDrv_ChObj *chObj);
 
-static int32_t CsitxDrv_startIoctl(CsitxDrv_InstObj *instObj);
+static int32_t CsitxDrv_startIoctl(CsitxDrv_VirtContext *virtContext);
 
-static int32_t CsitxDrv_stopIoctl(CsitxDrv_InstObj *instObj);
+static int32_t CsitxDrv_stopIoctl(CsitxDrv_VirtContext *virtContext);
 
 void Csitx_printLogs(void);
 
-static int32_t CsitxDrv_getStatusIoctl(CsitxDrv_InstObj *instObj,
+static int32_t CsitxDrv_getStatusIoctl(const CsitxDrv_VirtContext *virtContext,
                                        Csitx_InstStatus *txStat);
 
 /* This function returns the size aligned to wordSize boundary
@@ -169,7 +176,8 @@ Fdrv_Handle CsitxDrv_create(uint32_t drvId,
     CsitxDrv_InstObj *instObj = NULL;
     Csitx_CreateParams *createParams;
     Csitx_CreateStatus *status;
-    uint32_t eventIdx;
+    uint32_t eventIdx, virtContextId, chId, chIdx;
+    CsitxDrv_VirtContext *virtContext;
 
     /* Check for NULL pointers and invalid arguments */
     if ((createArgs == NULL) ||
@@ -185,24 +193,39 @@ Fdrv_Handle CsitxDrv_create(uint32_t drvId,
         txObj = &gCsitxCommonObj;
         status = (Csitx_CreateStatus *)createStatusArgs;
         createParams = (Csitx_CreateParams *)createArgs;
-        /* check if provided instance is free */
-        if (txObj->instObj[instId].inUse !=
-                                (uint32_t)CSITX_DRV_USAGE_STATUS_NOT_USED)
+
+	/* Get free virtual context */
+        for (virtContextId = 0U ;
+             virtContextId < CSITX_NUM_VIRTUAL_CONTEXT ;
+             virtContextId++)
+        {
+            if (CSITX_DRV_USAGE_STATUS_NOT_USED ==
+                txObj->virtContext[instId][virtContextId].inUse)
+            {
+                virtContext = &txObj->virtContext[instId][virtContextId];
+                /* Get the instance object for this instance */
+                instObj = virtContext->instObj;
+                /* Copy createParams to instance object */
+                Fvid2Utils_memcpy(&virtContext->createParams,
+                          createParams,
+                          sizeof (virtContext->createParams));
+                Fvid2Utils_memcpy(&virtContext->fdmCbParams,
+                          fdmCbParams,
+                          sizeof (virtContext->fdmCbParams));
+                break;
+            }
+        }
+
+        if (CSITX_NUM_VIRTUAL_CONTEXT <= virtContextId)
         {
             GT_0trace(CsitxTrace,
                       GT_ERR,
                       "Provided instance is already in use\r\n");
-            retVal = FVID2_EINVALID_PARAMS;
-        }
-        else
-        {
-            /* Get the instance object for this instance */
-            instObj = &txObj->instObj[instId];
-            GT_assert(CsitxTrace, (instObj != NULL));
+            retVal = FVID2_EDEVICE_INUSE;
         }
     }
     /* If the selected instance is IDLE or not */
-    if ((retVal == FVID2_SOK) && (instObj->state != CSITX_DRV_STATE_IDLE))
+    if ((retVal == FVID2_SOK) && (virtContext->state != CSITX_DRV_STATE_IDLE))
     {
         retVal = FVID2_EFAIL;
         GT_0trace(CsitxTrace,
@@ -210,17 +233,22 @@ Fdrv_Handle CsitxDrv_create(uint32_t drvId,
                   "Selected instance is not in IDLE state\r\n");
     }
 
-    if (instObj != NULL)
+    if (NULL != instObj)
     {
         /* Pend on the instance semaphore */
         (void)SemaphoreP_pend(&instObj->lockSem, SystemP_WAIT_FOREVER);
-        /* Assert reset to pixel interface */
-        CSL_csitxAssertPixelIfReset((CSL_csi_tx_ifRegs *)instObj->shimBaseAddr,
-                                    TRUE);
+    }
+    else
+    {
+        retVal = FVID2_EFAIL;
     }
 
-    if (retVal == FVID2_SOK)
+    if ((retVal == FVID2_SOK) &&
+    (CSITX_DRV_USAGE_STATUS_NOT_USED == instObj->inUse))
     {
+        /* De-assert reset to pixel interface in case of failure. */
+        CSL_csitxAssertPixelIfReset((CSL_csi_tx_ifRegs *)instObj->shimBaseAddr,
+                                    TRUE);
         /* Copy createParams to instance object */
         Fvid2Utils_memcpy(&instObj->createParams,
                           createParams,
@@ -228,9 +256,14 @@ Fdrv_Handle CsitxDrv_create(uint32_t drvId,
         /* Initialize instance configuration parameters */
         instObj->drvInstId = instId;
         instObj->inUse = (uint32_t)CSITX_DRV_USAGE_STATUS_IN_USE;
-        Fvid2Utils_memcpy(&instObj->fdmCbParams,
-                          fdmCbParams,
-                          sizeof (instObj->fdmCbParams));
+        /* Set CSITX Module configuration parameters */
+        retVal = CsitxDrv_setCslCfgParams(txObj,
+                                          instObj,
+                                          &instObj->createParams);
+        /* Assert reset to pixel interface */
+        CSL_csitxAssertPixelIfReset((CSL_csi_tx_ifRegs *)instObj->shimBaseAddr,
+                                    UFALSE);
+
         /* Create done Queue */
         retVal = Fvid2Utils_constructQ(&instObj->bufManObj.doneLlObj);
         GT_assert(CsitxTrace, (retVal == FVID2_SOK));
@@ -244,51 +277,63 @@ Fdrv_Handle CsitxDrv_create(uint32_t drvId,
             instObj->bufManObj.waitQ = &instObj->bufManObj.waitLlObj;
         }
     }
-    /* Call this API before configuration of SHIM/UDMA as some of variables are
-       set in this function which will be used in 'CsitxDrv_setUdmaParams()' */
-    if (retVal == FVID2_SOK)
-    {
-        /* Set CSITX Module configuration parameters */
-        retVal = CsitxDrv_setCslCfgParams(txObj,
-                                          instObj,
-                                          &instObj->createParams);
-    }
-    if (retVal == FVID2_SOK)
-    {
-        /* Set SHIL/PSIL, UDMA configuration parameters */
-        retVal = CsitxDrv_setInstCfgParams(instObj, &instObj->createParams);
-    }
-    if (retVal == FVID2_SOK)
-    {
-        /* Configure UDMA */
-        retVal = CsitxDrv_setUdmaParams(txObj, instObj);
-    }
-    if (retVal == FVID2_SOK)
+
+    /* Do channels configurations here, these has to be done per context */
+    if ((FVID2_SOK == retVal) &&
+        (CSITX_DRV_USAGE_STATUS_IN_USE == instObj->inUse))
     {
-        /* Set CSITX Module configuration parameters */
-        retVal = CsitxDrv_createChQueues(instObj);
+        for (chIdx = 0U ; chIdx < createParams->numCh ; chIdx++)
+        {
+            if (FVID2_SOK == CsitxDrv_getFreeChNumIoctl(instObj, &chId))
+            {
+                 retVal = CsitxDrv_setChCfgParams(&instObj->chObj[chId],
+                                                 &createParams->chCfg[chIdx]);
+                if (FVID2_SOK == retVal)
+                {
+                    /* Configure UDMA */
+                    retVal = CsitxDrv_setChUdmaParams(
+                                            &instObj->chObj[chId]);
+                }
+                if (FVID2_SOK == retVal)
+                {
+                    /* Set CSITX Module configuration parameters */
+                    retVal = CsitxDrv_createChQueues(
+                                            &instObj->chObj[chId]);
+                }
+                if (FVID2_SOK == retVal)
+                {
+                    /* Set SHIM- CSITX Module configuration parameters */
+                    retVal = CsitxDrv_chConfigShim(&instObj->chObj[chId]);
+                }
+                if (FVID2_SOK != retVal)
+                {
+                    break;
+                }
+                else
+                {
+                    instObj->chObj[chId].virtContext = virtContext;
+                    virtContext->chId[virtContext->numCh] = chId;
+                    virtContext->numCh++;
+                }
+            }
+        }
     }
-    if (retVal == FVID2_SOK)
+
+    if (FVID2_SOK == retVal)
     {
         /* Copy Csitx_DPhyCfg to instance object */
         Fvid2Utils_memcpy(&instObj->dphyCfg,
                           &createParams->instCfg.dphyCfg,
                           sizeof (instObj->dphyCfg));
         /* Configure DPHY */
-        retVal = Csitx_setDphyCfg(&instObj->dphyCfg);
-    }
-    if (retVal == FVID2_SOK)
-    {
-        /* Set SHIM- CSITX Module configuration parameters */
-        retVal = CsitxDrv_configShim(txObj, instObj);
+        retVal = Csitx_setDphyCfg(virtContext, &instObj->dphyCfg);
     }
 
-    if (retVal == FVID2_SOK)
+    if (FVID2_SOK == retVal)
     {
         for (eventIdx = 0U ;
              eventIdx < CSITX_EVENT_GROUP_MAX;
              eventIdx++)
-
         {
             /* Initialize event configuration parameters */
             retVal = CsitxDrv_eventGroupRegister(instObj,
@@ -296,25 +341,22 @@ Fdrv_Handle CsitxDrv_create(uint32_t drvId,
         }
     }
 
-    if (retVal != FVID2_SOK)
+    if (FVID2_SOK != retVal)
     {
-        if (instObj != NULL)
+        if (NULL != instObj)
         {
-            /* De-assert reset to pixel interface in case of failure.
-               In normal scenario, this will de-asserted in Fvid_start() call */
-            CSL_csitxAssertPixelIfReset((CSL_csi_tx_ifRegs *)instObj->shimBaseAddr,
-                                        FALSE);
             GT_0trace(CsitxTrace,
                       GT_ERR,
                       "Instance create failed!!!\r\n");
         }
     }
 
-    if (retVal == FVID2_SOK)
+    if (FVID2_SOK == retVal)
     {
-        instObj->state = CSITX_DRV_STATE_CREATED;
-        drvHandle = instObj;
-        status->retVal = retVal;
+        drvHandle = virtContext;
+        virtContext->state = CSITX_DRV_STATE_CREATED;
+        virtContext->inUse = CSITX_DRV_USAGE_STATUS_IN_USE;
+        txObj->numVirtContUsed[instId]++;
     }
     else
     {
@@ -323,16 +365,22 @@ Fdrv_Handle CsitxDrv_create(uint32_t drvId,
             status = (Csitx_CreateStatus *)createStatusArgs;
             status->retVal = retVal;
         }
-        if (instObj != NULL)
+        if (NULL != instObj)
         {
             /* Deallocate if error occurs */
-            CsitxDrv_deleteChObj(instObj);
+            for (chIdx = 0U ; chIdx < createParams->numCh ; chIdx++)
+            {
+                chId = virtContext->chId[chIdx];
+                    /* Deallocate if error occurs */
+                CsitxDrv_deleteChObj(&instObj->chObj[chId]);
+	    }
         }
+
         GT_0trace(CsitxTrace,
                   GT_ERR,
                   "Create failed for given configuration\r\n");
     }
-    if (instObj != NULL)
+    if (NULL != instObj)
     {
         /* Post the instance semaphore */
         SemaphoreP_post(&instObj->lockSem);
@@ -367,7 +415,7 @@ int32_t CsitxDrv_control(Fdrv_Handle handle,
                          void *cmdStatusArgs)
 {
     int32_t retVal = FVID2_SOK;
-    CsitxDrv_InstObj *instObj;
+    CsitxDrv_VirtContext *virtContext;
     Fvid2_TimeStampParams *tsParams;
 
     /* Check for NULL pointers */
@@ -378,18 +426,18 @@ int32_t CsitxDrv_control(Fdrv_Handle handle,
     }
     else
     {
-        instObj = (CsitxDrv_InstObj *) handle;
+        virtContext = (CsitxDrv_VirtContext *) handle;
         switch (cmd)
         {
             case FVID2_START:
-                retVal = CsitxDrv_startIoctl(instObj);
+                retVal = CsitxDrv_startIoctl(virtContext);
             break;
             case FVID2_STOP:
-                retVal = CsitxDrv_stopIoctl(instObj);
+                retVal = CsitxDrv_stopIoctl(virtContext);
             break;
             case IOCTL_CSITX_GET_INST_STATUS:
                 retVal = CsitxDrv_getStatusIoctl(
-                                    instObj,
+                                    virtContext,
                                     (Csitx_InstStatus *)cmdArgs);
             break;
             case IOCTL_CSITX_PRINT_DEBUG_LOGS:
@@ -400,6 +448,9 @@ int32_t CsitxDrv_control(Fdrv_Handle handle,
                 tsParams = (Fvid2_TimeStampParams *)cmdArgs;
                 gCsitxCommonObj.getTimeStamp = tsParams->timeStampFxn;
             break;
+            case IOCTL_CSITX_GET_INST_CONTEXT_ID:
+                (*(uint32_t *)cmdArgs) = (uint32_t)virtContext->contextId;
+            break;
             default:
             {
                 GT_0trace(CsitxTrace, GT_ERR,
@@ -416,7 +467,9 @@ int32_t CsitxDrv_delete(Fdrv_Handle handle, void *reserved)
 {
     int32_t retVal = FVID2_SOK;
     CsitxDrv_InstObj *instObj = NULL;
-    uint32_t eventIdx;
+    CsitxDrv_VirtContext *virtContext = NULL;
+    CsitxDrv_CommonObj *txObj = &gCsitxCommonObj;
+    uint32_t eventIdx, chIdx;
 
     /* Check for NULL pointers and invalid arguments */
     if (handle == NULL)
@@ -426,59 +479,77 @@ int32_t CsitxDrv_delete(Fdrv_Handle handle, void *reserved)
     }
     else
     {
-        instObj = (CsitxDrv_InstObj *) handle;
+        virtContext = (CsitxDrv_VirtContext *) handle;
+        instObj = virtContext->instObj;
     }
 
-    if (instObj != NULL)
+    if (NULL != instObj)
     {
         /* Pend on the instance semaphore */
         (void)SemaphoreP_pend(&instObj->lockSem, SystemP_WAIT_FOREVER);
 
         /* Check if the instance is already opened and in a stopped state */
-        if ((instObj->state == CSITX_DRV_STATE_STOPPED) ||
-            (instObj->state == CSITX_DRV_STATE_CREATED))
+        if ((virtContext->state == CSITX_DRV_STATE_STOPPED) ||
+            (virtContext->state == CSITX_DRV_STATE_CREATED))
         {
-            /* Un-register events if any */
-            if (retVal == FVID2_SOK)
-            {
-                for (eventIdx = 0U ;
-                     eventIdx < CSITX_EVENT_GROUP_MAX;
-                     eventIdx++)
+                /* Un-register events if any */
+                if (retVal == FVID2_SOK)
                 {
-                    /* Initialize event configuration parameters */
-                    retVal = CsitxDrv_eventGroupUnRegister(instObj,
-                            instObj->createParams.instCfg.eventParams[eventIdx].eventGroup);
+                    for (eventIdx = 0U ;
+                        eventIdx < CSITX_EVENT_GROUP_MAX;
+                        eventIdx++)
+                    {
+                        /* Initialize event configuration parameters */
+                        retVal = CsitxDrv_eventGroupUnRegister(instObj,
+                                instObj->createParams.instCfg.eventParams[eventIdx].eventGroup);
+                    }
                 }
-            }
-            CsitxDrv_deleteChObj(instObj);
 
-            if (instObj->bufManObj.doneQ !=  NULL)
+            /* Clean up virtual context */
+            for (chIdx = 0U ; chIdx < virtContext->numCh ; chIdx++)
             {
-                /* Delete the done Q */
-                Fvid2Utils_destructQ(instObj->bufManObj.doneQ);
-                instObj->bufManObj.doneQ = NULL;
-            }
-            if (gCsitxCommonObj.platData.serialMultiChanEnable ==
-                    CSITX_ENABLE_SERIAL_TRANS_ENABLE)
-            {
-                if (instObj->bufManObj.waitQ !=  NULL)
+                if (CSITX_DRV_CH_STATE_STOPPED ==
+                    instObj->chObj[virtContext->chId[chIdx]].status)
                 {
-                    /* Delete the free Q */
-                    Fvid2Utils_destructQ(instObj->bufManObj.waitQ);
-                    instObj->bufManObj.waitQ = NULL;
+                    CsitxDrv_deleteChObj(&instObj->chObj[virtContext->chId[chIdx]]);
+                    instObj->chObj[virtContext->chId[chIdx]].status =
+                                        CSITX_DRV_CH_STATE_IDLE;
                 }
             }
 
-            /* Mark state as idle */
-            instObj->state = CSITX_DRV_STATE_IDLE;
-
-            /* Mark as not in use */
-            instObj->inUse = (uint32_t)CSITX_DRV_USAGE_STATUS_NOT_USED;
+            /* Set configuration parameter to '0' */
+            Fvid2Utils_memset(&virtContext->createParams,
+                        0U,
+                        sizeof (Csitx_CreateParams));
+            Fvid2Utils_memset(&virtContext->fdmCbParams,
+                        0U,
+                        sizeof (Fvid2_DrvCbParams));
+            virtContext->state = CSITX_DRV_STATE_IDLE;
+            virtContext->numCh = 0U;
+
+            virtContext->inUse = (uint32_t)CSITX_DRV_USAGE_STATUS_NOT_USED;
+            if(1U == txObj->numVirtContUsed[instObj->drvInstId])
+            {
+                instObj->inUse = (uint32_t)CSITX_DRV_USAGE_STATUS_NOT_USED;
 
-            /* Reset all channel numbers */
-            instObj->numTxCh        = 0U;
-            instObj->numColorbarCh  = 0U;
-            instObj->numLpbkCh      = 0U;
+                if (NULL != instObj->bufManObj.doneQ)
+                {
+                    /* Delete the done Q */
+                    Fvid2Utils_destructQ(instObj->bufManObj.doneQ);
+                    instObj->bufManObj.doneQ = NULL;
+                }
+                if (CSITX_ENABLE_SERIAL_TRANS_ENABLE ==
+                        gCsitxCommonObj.platData.serialMultiChanEnable)
+                {
+                    if (NULL != instObj->bufManObj.waitQ)
+                    {
+                        /* Delete the free Q */
+                        Fvid2Utils_destructQ(instObj->bufManObj.waitQ);
+                        instObj->bufManObj.waitQ = NULL;
+                    }
+                }
+            }
+            txObj->numVirtContUsed[instObj->drvInstId]--;
         }
         else
         {
@@ -505,6 +576,7 @@ int32_t CsitxDrv_queue(Fdrv_Handle handle,
     Fvid2_Frame *frm;
     CSL_UdmapTR1 *pTr;
     CsitxDrv_QueObj *qObj;
+    CsitxDrv_VirtContext *virtContext;
     /* Check for NULL pointers */
     if((NULL == handle) || (NULL == frmList))
     {
@@ -513,13 +585,14 @@ int32_t CsitxDrv_queue(Fdrv_Handle handle,
     }
     if(retVal == FVID2_SOK)
     {
-        instObj = (CsitxDrv_InstObj *)handle;
+        virtContext = (CsitxDrv_VirtContext *)handle;
+        instObj = virtContext->instObj;
         retVal = Fvid2_checkFrameList(frmList, (uint32_t) FVID2_MAX_FRAME_PTR);
         if (retVal != FVID2_SOK)
         {
             GT_0trace(CsitxTrace, GT_ERR, "Check frame list error\n");
         }
-        if (instObj->state == CSITX_DRV_STATE_IDLE)
+        if (virtContext->state == CSITX_DRV_STATE_IDLE)
         {
             /* If driver handle is not open then skip this frame queue */
             GT_0trace(
@@ -538,8 +611,8 @@ int32_t CsitxDrv_queue(Fdrv_Handle handle,
             /* Get FVID2 frame pointer - NULL check is already done in
              * check frame list function */
             frm = frmList->frames[frmCnt];
-            chIdx = frm->chNum;
-            if (chIdx >= instObj->createParams.numCh)
+            chIdx = virtContext->chId[frm->chNum];
+            if (frm->chNum >= virtContext->numCh)
             {
                 /* invalid stream ID skip this frame queue */
                 GT_0trace(CsitxTrace, GT_ERR, "Invalid Channel ID\r\n");
@@ -715,6 +788,7 @@ int32_t CsitxDrv_dequeue(Fdrv_Handle handle,
     volatile uint32_t loopBreakFlag = 1U;
     CsitxDrv_QueObj *qObj;
     uint64_t pDesc;
+    CsitxDrv_VirtContext *virtContext;
 
     /* Check for NULL pointers */
     if((handle == NULL) ||
@@ -725,8 +799,9 @@ int32_t CsitxDrv_dequeue(Fdrv_Handle handle,
     }
     if(retVal == FVID2_SOK)
     {
-        instObj = (CsitxDrv_InstObj *) handle;
-        if (instObj->state == CSITX_DRV_STATE_IDLE)
+        virtContext = (CsitxDrv_VirtContext *) handle;
+        instObj = virtContext->instObj;
+        if (virtContext->state == CSITX_DRV_STATE_IDLE)
         {
             GT_0trace(
                 CsitxTrace, GT_ERR,
@@ -755,7 +830,7 @@ int32_t CsitxDrv_dequeue(Fdrv_Handle handle,
                 GT_assert(CsitxTrace, (qObj->frm != NULL));
                 frmList->frames[frmList->numFrames] = qObj->frm;
                 frmList->numFrames++;
-                instObj->status.dequeueCount[chObj->chCfg->chId]++;
+                instObj->status.dequeueCount[chObj->chId]++;
 
                 /* Give back the queue object back to the free pool */
                 qObj->frm = NULL;
@@ -778,11 +853,11 @@ int32_t CsitxDrv_dequeue(Fdrv_Handle handle,
         /* When an instance is stopped, return all the request in
          * channel's current queue as well. */
         GT_assert(CsitxTrace, (instObj != NULL));
-        if (instObj->state == CSITX_DRV_STATE_STOPPED)
+        if (virtContext->state == CSITX_DRV_STATE_STOPPED)
         {
-            for (chIdx = 0U ; chIdx < instObj->createParams.numCh ; chIdx++)
+            for (chIdx = 0U ; chIdx < virtContext->numCh ; chIdx++)
             {
-                chObj = &instObj->chObj[chIdx];
+                chObj = &instObj->chObj[(virtContext->chId[chIdx])];
                 if (chObj->chCfg->chType == CSITX_CH_TYPE_TX)
                 {
                     /* Extract frames from queue till the queue
@@ -805,7 +880,7 @@ int32_t CsitxDrv_dequeue(Fdrv_Handle handle,
                                Fvid2Utils_dequeue(chObj->bufManObj.curQ);
                         GT_assert(CsitxTrace, (qObj != NULL));
                         GT_assert(CsitxTrace,
-                            (chObj->chCfg->chId == qObj->chObj->chCfg->chId));
+                            (chObj->chId == qObj->chObj->chId));
                         /* Check returned descriptor pointer */
                         GT_assert(CsitxTrace,
                                   (pDesc == ((uint64_t) qObj->trpd)));
@@ -814,7 +889,7 @@ int32_t CsitxDrv_dequeue(Fdrv_Handle handle,
                         qObj->frm->status = FVID2_FRAME_STATUS_ABORTED;
                         frmList->frames[frmList->numFrames] = qObj->frm;
                         frmList->numFrames++;
-                        instObj->status.dequeueCount[chObj->chCfg->chId]++;
+                        instObj->status.dequeueCount[chObj->chId]++;
                         /* Give back the queue object back to the free pool */
                         qObj->frm = NULL;
                         GT_assert(CsitxTrace, (chObj == qObj->chObj));
@@ -854,7 +929,7 @@ int32_t CsitxDrv_dequeue(Fdrv_Handle handle,
                         GT_assert(CsitxTrace, (qObj->frm != NULL));
                         frmList->frames[frmList->numFrames] = qObj->frm;
                         frmList->numFrames++;
-                        instObj->status.dequeueCount[chObj->chCfg->chId]++;
+                        instObj->status.dequeueCount[chObj->chId]++;
 
                         qObj->frm = NULL;
 
@@ -882,8 +957,8 @@ int32_t CsitxDrv_dequeue(Fdrv_Handle handle,
         /* If no frame is dequeued, then return appropriate error */
         if (frmList->numFrames == 0U)
         {
-            if ((instObj->state == CSITX_DRV_STATE_CREATED) ||
-                (instObj->state == CSITX_DRV_STATE_STOPPED))
+            if ((virtContext->state == CSITX_DRV_STATE_CREATED) ||
+                (virtContext->state == CSITX_DRV_STATE_STOPPED))
             {
                 GT_0trace(
                     CsitxTrace, GT_DEBUG,
@@ -993,82 +1068,143 @@ static int32_t CsitxDrv_setInstCfgParams(CsitxDrv_InstObj *instObj,
     return retVal;
 }
 
-static int32_t CsitxDrv_createChQueues(CsitxDrv_InstObj *instObj)
+static int32_t CsitxDrv_setChCfgParams(CsitxDrv_ChObj *chObj, Csitx_ChCfg *chCfg)
+{
+    int32_t retVal = FVID2_SOK;
+    CsitxDrv_InstObj *instObj;
+
+    instObj = chObj->instObj;
+    chObj->chCfg = chCfg;
+
+    if (CSITX_CH_TYPE_TX == chCfg->chType)
+    {
+        if (instObj->numTxCh < CSITX_NUM_CH_TX)
+        {
+            instObj->numTxCh++;
+            retVal = CsitxDrv_setDMACfgParams(chObj);
+        }
+        else
+        {
+            GT_0trace(
+                CsitxTrace,
+                GT_ERR,
+                "More Capture channels are provided than HW "
+                "can process\r\n");
+            retVal = FVID2_EINVALID_PARAMS;
+        }
+    }
+    if (CSITX_CH_TYPE_COLORBAR == chCfg->chType)
+    {
+        if (instObj->numColorbarCh < CSITX_NUM_CH_COLORBAR_MAX)
+        {
+            instObj->colorbarChId[instObj->numColorbarCh] = chObj->chId;
+            instObj->numColorbarCh++;
+            /* Only capture channel will have 'psilThreadId' other than
+               'CSITX_DRV_DEF_PSIL_THREAD_ID' */
+            chObj->psilThreadId = CSITX_DRV_DEF_PSIL_THREAD_ID;
+        }
+        else
+        {
+            GT_0trace(
+                CsitxTrace,
+                GT_ERR,
+                "More OTF channels are provided than HW can "
+                "process\r\n");
+            retVal = FVID2_EINVALID_PARAMS;
+        }
+    }
+    if (CSITX_CH_TYPE_LPBK == chCfg->chType)
+    {
+        if (instObj->numLpbkCh < CSITX_NUM_CH_LPBK_MAX)
+        {
+            instObj->lpbkChId[instObj->numLpbkCh] = chObj->chId;
+            instObj->numLpbkCh++;
+            /* Only capture channel will have 'psilThreadId' other than
+               'CSITX_DRV_DEF_PSIL_THREAD_ID' */
+            chObj->psilThreadId = CSITX_DRV_DEF_PSIL_THREAD_ID;
+            CSL_csitxRetransCfg((CSL_csi_tx_ifRegs *)instObj->shimBaseAddr,
+                                &instObj->createParams.instCfg.retransCfg);
+            retVal = CsirtxDrv_lpbkSel(instObj->drvInstId, instObj->createParams.instCfg.lpbkCsiRxInst);
+        }
+        else
+        {
+            GT_0trace(
+                CsitxTrace,
+                GT_ERR,
+                "More Loop-back channels are provided than "
+                "HW can process\r\n");
+            retVal = FVID2_EINVALID_PARAMS;
+        }
+    }
+
+    return retVal;
+}
+
+static int32_t CsitxDrv_createChQueues(CsitxDrv_ChObj *chObj)
 {
     int32_t  retVal = FVID2_SOK, tempRetVal;
     uint32_t chIdx = 0U;
     uint32_t qCnt = 0U;
     CsitxDrv_QueObj *qObj;
-    CsitxDrv_ChObj *chObj;
     CsitxDrv_ChBufManObj *bmObj;
     CsitxDrv_InstBufManObj *instBmObj;
+    CsitxDrv_InstObj *instObj;
 
-    /* NULL pointer check */
-    GT_assert(CsitxTrace, (NULL != instObj));
-    for (chIdx = 0U ; chIdx < instObj->createParams.numCh ; chIdx++)
+    instObj = chObj->instObj;
+    chIdx = chObj->chId;
+    /* Do configuration for CSITX_CH_TYPE_TX type of channel */
+    if (CSITX_CH_TYPE_TX == chObj->chCfg->chType)
     {
-        chObj = &instObj->chObj[chIdx];
-        /* Do configuration for CSITX_CH_TYPE_TX type of channel */
-        if (chObj->chCfg->chType == CSITX_CH_TYPE_TX)
+        bmObj = &chObj->bufManObj;
+
+        bmObj->freeQ         = NULL;
+        /* Create Queues */
+        retVal = Fvid2Utils_constructQ(&bmObj->freeLlObj);
+        GT_assert(CsitxTrace, (FVID2_SOK == retVal));
+        bmObj->freeQ = &bmObj->freeLlObj;
+
+        bmObj->curQ          = NULL;
+        retVal = Fvid2Utils_constructQ(&bmObj->curLlObj);
+        GT_assert(CsitxTrace, (FVID2_SOK == retVal));
+        bmObj->curQ = &bmObj->curLlObj;
+        instBmObj = &instObj->bufManObj;
+        /* Initialize and queue the allocate queue object to free Q */
+        for (qCnt = 0U; qCnt < CSITX_TX_QUEUE_DEPTH_PER_CH ; qCnt++)
         {
-            bmObj = &chObj->bufManObj;
-
-            bmObj->freeQ         = NULL;
-            /* Create Queues */
-            retVal = Fvid2Utils_constructQ(&bmObj->freeLlObj);
-            GT_assert(CsitxTrace, (retVal == FVID2_SOK));
-            bmObj->freeQ = &bmObj->freeLlObj;
-
-            bmObj->curQ          = NULL;
-            retVal = Fvid2Utils_constructQ(&bmObj->curLlObj);
-            GT_assert(CsitxTrace, (retVal == FVID2_SOK));
-            bmObj->curQ = &bmObj->curLlObj;
-            instBmObj = &instObj->bufManObj;
-            /* Initialize and queue the allocate queue object to free Q */
-            for (qCnt = 0U; qCnt < CSITX_TX_QUEUE_DEPTH_PER_CH ; qCnt++)
+            if (CSITX_ENABLE_SERIAL_TRANS_DISABLE ==
+                gCsitxCommonObj.platData.serialMultiChanEnable)
             {
-                if (gCsitxCommonObj.platData.serialMultiChanEnable ==
-                                CSITX_ENABLE_SERIAL_TRANS_DISABLE)
-                {
-                    qObj = &bmObj->txQObj[qCnt];
-                }
-                else
-                {
-                    qObj = &instBmObj->txQObj[((chIdx * CSITX_TX_QUEUE_DEPTH_PER_CH) + qCnt)];
-                }
-                qObj->inUse = CSITX_DRV_USAGE_STATUS_NOT_USED;
-                qObj->chObj = &instObj->chObj[chIdx];
-                qObj->frm   = NULL;
-                qObj->trpd =
-                        (CSL_UdmapCppi5TRPD *)CsitxDrv_getTrpdMemAddr(chIdx,
-                                                                      qCnt);
-                tempRetVal = CsitxDrv_udmaTxTrpdInit(
-                                    &instObj->chObj[chIdx].txChObj,
-                                    (uint8_t *)qObj->trpd,
-                                    NULL,
-                                    instObj->chObj[chIdx].chCfg,
-                                    chIdx);
-                if (tempRetVal != FVID2_SOK)
-                {
-                    retVal = FVID2_EINVALID_PARAMS;
-                    break;
-                }
-                Fvid2Utils_queue(bmObj->freeQ, &qObj->qElem, qObj);
+                qObj = &bmObj->txQObj[qCnt];
             }
-            if (retVal != FVID2_SOK)
+            else
             {
+                qObj = &instBmObj->txQObj[((chIdx * CSITX_TX_QUEUE_DEPTH_PER_CH) + qCnt)];
+            }
+            qObj->inUse = CSITX_DRV_USAGE_STATUS_NOT_USED;
+            qObj->chObj = chObj;
+            qObj->frm   = NULL;
+            qObj->trpd =
+                    (CSL_UdmapCppi5TRPD *)CsitxDrv_getTrpdMemAddr(chIdx,
+                                                                  qCnt);
+            tempRetVal = CsitxDrv_udmaTxTrpdInit(
+                                &chObj->txChObj,
+                                (uint8_t *)qObj->trpd,
+                                NULL,
+                                chObj->chCfg,
+                                chObj->chId);
+            if (FVID2_SOK != tempRetVal)
+            {
+                retVal = FVID2_EINVALID_PARAMS;
                 break;
             }
+            Fvid2Utils_queue(bmObj->freeQ, &qObj->qElem, qObj);
         }
     }
 
     /* Deallocate if error occurs */
-    if (retVal != FVID2_SOK)
+    if (FVID2_SOK != retVal)
     {
-        for (chIdx = 0U ; chIdx < CSITX_NUM_CH; chIdx++)
-        {
-            CsitxDrv_deleteChQueues(&instObj->chObj[chIdx]);
-        }
+        CsitxDrv_deleteChQueues(chObj);
     }
 
     return retVal;
@@ -1308,27 +1444,49 @@ static int32_t CsitxDrv_configShim(CsitxDrv_CommonObj *txObj,
     return retVal;
 }
 
-int32_t Csitx_setDphyCfg(Csitx_DPhyCfg *dphyCfg)
+static int32_t CsitxDrv_chConfigShim(CsitxDrv_ChObj *chObj)
+{
+    int32_t retVal = FVID2_SOK, status = CSL_PASS;
+
+    if (chObj->psilThreadId != CSITX_DRV_DEF_PSIL_THREAD_ID)
+    {
+        /* Do following for Capture channels only */
+        status+= CSL_csitxConfigDMA(
+                        (CSL_csi_tx_ifRegs *)chObj->instObj->shimBaseAddr,
+                        &chObj->dmaCfgParams);
+        if (CSL_PASS != status)
+        {
+            GT_0trace(CsitxTrace,
+                      GT_ERR,
+                      "Invalid SHIM Capture config arguments\r\n");
+            retVal = FVID2_EBADARGS;
+        }
+    }
+
+    return retVal;
+}
+
+int32_t Csitx_setDphyCfg(CsitxDrv_VirtContext *virtContext, Csitx_DPhyCfg *dphyCfg)
 {
     int32_t retVal = FVID2_SOK;
     CsitxDrv_InstObj *instObj;
 
-    if (dphyCfg == NULL)
+    if (NULL == dphyCfg)
     {
         retVal = FVID2_EBADARGS;
     }
-    if (retVal == FVID2_SOK)
+    if (FVID2_SOK == retVal)
     {
         instObj = &gCsitxCommonObj.instObj[dphyCfg->inst];
         retVal = Csitx_dphyConfig(instObj);
     }
     /* put lanes into LP state if clock mode is non continuous */
-    if ((retVal == FVID2_SOK) &&
-        (dphyCfg->clkMode == CSITX_CLK_MODE_NON_CONTINUOUS))
+    if ((FVID2_SOK == retVal) &&
+        (CSITX_CLK_MODE_NON_CONTINUOUS == dphyCfg->clkMode))
     {
         retVal = CsitxDrv_dphytxSetLaneState(instObj, CSITX_DPHY_MODE_LOW_POWER);
     }
-    if (retVal != FVID2_SOK)
+    if (FVID2_SOK != retVal)
     {
         GT_0trace(CsitxTrace,
                   GT_ERR,
@@ -1338,30 +1496,20 @@ int32_t Csitx_setDphyCfg(Csitx_DPhyCfg *dphyCfg)
     return retVal;
 }
 
-static void CsitxDrv_deleteChObj(CsitxDrv_InstObj *instObj)
+static void CsitxDrv_deleteChObj(CsitxDrv_ChObj *chObj)
 {
     int32_t retVal = FVID2_SOK;
-    uint32_t chIdx;
-    CsitxDrv_ChObj *chObj;
 
-    GT_assert(CsitxTrace, (instObj != NULL));
-    GT_assert(CsitxTrace,
-              (instObj->createParams.numCh <= CSITX_NUM_CH));
     /* Close sequence for UDMA DRV */
-    retVal = CsitxDrv_clearUdmaParams(instObj);
-    if (retVal != UDMA_SOK)
+    retVal = CsitxDrv_clearUdmaParams(chObj);
+    if (UDMA_SOK != retVal)
     {
         GT_0trace(CsitxTrace,
                   GT_ERR,
                   "[ERROR]UDMA channel close FAILED!!!\r\n");
     }
-    for (chIdx = 0U; chIdx < instObj->createParams.numCh; chIdx++)
-    {
-        /* Get channel object */
-        chObj = &instObj->chObj[chIdx];
-        /* Delete channel queues */
-        CsitxDrv_deleteChQueues(chObj);
-    }
+    /* Delete channel queues */
+    CsitxDrv_deleteChQueues(chObj);
 }
 
 static void CsitxDrv_deleteChQueues(CsitxDrv_ChObj *chObj)
@@ -1399,35 +1547,37 @@ static void CsitxDrv_deleteChQueues(CsitxDrv_ChObj *chObj)
     }
 }
 
-static int32_t CsitxDrv_startIoctl(CsitxDrv_InstObj *instObj)
+static int32_t CsitxDrv_startIoctl(CsitxDrv_VirtContext *virtContext)
 {
     int32_t retVal = FVID2_SOK, tempRetVal = UDMA_SOK;
     uint32_t chIdx = 0U;
     CsitxDrv_ChObj *chObj;
+    CsitxDrv_InstObj *instObj;
 
     /* Check for NULL pointers */
-    GT_assert(CsitxTrace, (instObj != NULL));
+    GT_assert(CsitxTrace, (NULL != virtContext));
     GT_assert(CsitxTrace,
-              (instObj->createParams.numCh <= CSITX_NUM_CH));
+              (CSITX_NUM_CH >= virtContext->numCh));
+    instObj = virtContext->instObj;
     /* Pend the instance semaphore */
     (void)SemaphoreP_pend(&instObj->lockSem, SystemP_WAIT_FOREVER);
 
-    for (chIdx = 0U ; chIdx < instObj->createParams.numCh ; chIdx++)
+    for (chIdx = 0U ; chIdx < virtContext->numCh ; chIdx++)
     {
         /* Get channel object */
-        chObj = &instObj->chObj[chIdx];
+        chObj = &instObj->chObj[(virtContext->chId[chIdx])];
         /* Enable channel only if it is created */
         if (chObj->status == CSITX_DRV_CH_STATE_CREATED)
         {
             /* Enable DMA context for PSIL threads and UDMA channels only
                for capture channels */
-            if (chObj->chCfg->chType == CSITX_CH_TYPE_TX)
+            if (CSITX_CH_TYPE_TX == chObj->chCfg->chType)
             {
-                if (retVal == FVID2_SOK)
+                if (FVID2_SOK == retVal)
                 {
                     /* Enable UDMA channel */
                     tempRetVal = Udma_chEnable(&chObj->txChObj);
-                    if(tempRetVal != UDMA_SOK)
+                    if (UDMA_SOK != tempRetVal)
                     {
                         retVal = FVID2_EFAIL;
                         GT_0trace(
@@ -1437,7 +1587,7 @@ static int32_t CsitxDrv_startIoctl(CsitxDrv_InstObj *instObj)
                     }
                 }
             }
-            if (retVal == FVID2_SOK)
+            if (FVID2_SOK == retVal)
             {
                 /* set channel state to running */
                 chObj->status = CSITX_DRV_CH_STATE_RUNNING;
@@ -1447,7 +1597,7 @@ static int32_t CsitxDrv_startIoctl(CsitxDrv_InstObj *instObj)
     if (retVal == FVID2_SOK)
     {
         /* change driver instance to started/running state */
-        instObj->state = CSITX_DRV_STATE_RUNNING;
+        virtContext->state = CSITX_DRV_STATE_RUNNING;
         /* release pixel reset */
         CSL_csitxAssertPixelIfReset((CSL_csi_tx_ifRegs *)instObj->shimBaseAddr,
                                     FALSE);
@@ -1458,38 +1608,38 @@ static int32_t CsitxDrv_startIoctl(CsitxDrv_InstObj *instObj)
     return retVal;
 }
 
-static int32_t CsitxDrv_stopIoctl(CsitxDrv_InstObj *instObj)
+static int32_t CsitxDrv_stopIoctl(CsitxDrv_VirtContext *virtContext)
 {
     int32_t retVal = FVID2_SOK, tempRetVal = UDMA_SOK;
     uint32_t chIdx = 0U, cookie;
     CsitxDrv_ChObj *chObj;
+    CsitxDrv_InstObj *instObj;
 
     /* Check for NULL pointers */
-    GT_assert(CsitxTrace, (instObj != NULL));
+    GT_assert(CsitxTrace, (NULL != virtContext));
     GT_assert(CsitxTrace,
-              (instObj->createParams.numCh <= CSITX_NUM_CH));
+              (CSITX_NUM_CH >= virtContext->numCh));
+    instObj = virtContext->instObj;
     /* Pend the instance semaphore */
     (void)SemaphoreP_pend(&instObj->lockSem, SystemP_WAIT_FOREVER);
     /* Disable HW interrupts here */
     cookie = HwiP_disable();
-    for (chIdx = 0U ; chIdx < instObj->createParams.numCh ; chIdx++)
+    for (chIdx = 0U ; chIdx < virtContext->numCh ; chIdx++)
     {
-        /* Get channel object */
-        chObj = &instObj->chObj[chIdx];
+         /* Get channel object */
+        chObj = &instObj->chObj[(virtContext->chId[chIdx])];
         /* set channel state to stopping */
         chObj->status = CSITX_DRV_CH_STATE_STOPPING;
-        /* Get channel object */
-        chObj = &instObj->chObj[chIdx];
         /* Disable DMA context for PSIL threads and UDMA channels only
            for capture channels */
-        if (chObj->chCfg->chType == CSITX_CH_TYPE_TX)
+        if (CSITX_CH_TYPE_TX == chObj->chCfg->chType)
         {
-            if (retVal == FVID2_SOK)
+            if (FVID2_SOK == retVal)
             {
                 /* Disable UDMA channel */
                 tempRetVal = Udma_chDisable(&chObj->txChObj,
                                             UDMA_DEFAULT_CH_DISABLE_TIMEOUT);
-                if(tempRetVal != UDMA_SOK)
+                if(UDMA_SOK != tempRetVal)
                 {
                     retVal = FVID2_EFAIL;
                     GT_0trace(
@@ -1499,7 +1649,7 @@ static int32_t CsitxDrv_stopIoctl(CsitxDrv_InstObj *instObj)
                 }
             }
         }
-        if (retVal == FVID2_SOK)
+        if (FVID2_SOK == retVal)
         {
             /* set channel state to stopped */
             chObj->status = CSITX_DRV_CH_STATE_STOPPED;
@@ -1511,7 +1661,7 @@ static int32_t CsitxDrv_stopIoctl(CsitxDrv_InstObj *instObj)
     if (retVal == FVID2_SOK)
     {
         /* change driver isntance to stopped state */
-        instObj->state = CSITX_DRV_STATE_STOPPED;
+        virtContext->state = CSITX_DRV_STATE_STOPPED;
     }
 
     /* Post the instance semaphore */
@@ -1520,17 +1670,24 @@ static int32_t CsitxDrv_stopIoctl(CsitxDrv_InstObj *instObj)
     return retVal;
 }
 
-static int32_t CsitxDrv_getStatusIoctl(CsitxDrv_InstObj *instObj,
+static int32_t CsitxDrv_getStatusIoctl(const CsitxDrv_VirtContext *virtContext,
                                        Csitx_InstStatus *txStat)
 {
     int32_t retVal = FVID2_SOK;
+    uint32_t chIdx;
+    CsitxDrv_InstObj *instObj;
 
+    instObj = virtContext->instObj;
     /* Pend on the instance semaphore */
     (void)SemaphoreP_pend(&instObj->lockSem, SystemP_WAIT_FOREVER);
     /* Copy capture status from DRV object to application provided parameter */
-    Fvid2Utils_memcpy(txStat,
-                      &instObj->status,
-                      sizeof (instObj->status));
+   for (chIdx = 0U ; chIdx < virtContext->numCh ; chIdx++)
+    {
+        txStat->queueCount[chIdx] =
+            instObj->status.queueCount[virtContext->chId[chIdx]];
+        txStat->dequeueCount[chIdx] =
+            instObj->status.dequeueCount[virtContext->chId[chIdx]];
+    }
     /* Post the instance semaphore */
     SemaphoreP_post(&instObj->lockSem);
 
@@ -1694,3 +1851,31 @@ int32_t CsitxDrv_dphytxSetLaneState(CsitxDrv_InstObj *instObj,
 
     return retVal;
 }
+
+static int32_t CsitxDrv_getFreeChNumIoctl(CsitxDrv_InstObj *instObj,
+                                          uint32_t *chNum)
+{
+    int32_t retVal = FVID2_SOK;
+    uint32_t chIdx;
+
+    GT_assert(CsitxTrace, (instObj != NULL));
+
+    for (chIdx = 0U ; chIdx < CSITX_NUM_CH ; chIdx++)
+    {
+        if (CSITX_DRV_CH_STATE_IDLE == instObj->chObj[chIdx].status)
+        {
+            break;
+        }
+    }
+
+    if (chIdx < CSITX_NUM_CH)
+    {
+        *chNum = chIdx;
+    }
+    else
+    {
+        retVal = FVID2_EAGAIN;
+    }
+
+    return retVal;
+}
diff --git a/source/drivers/csitx/v0/src/csitx_drvInit.c b/source/drivers/csitx/v0/src/csitx_drvInit.c
index 2cb3ca2..78a34a9 100755
--- a/source/drivers/csitx/v0/src/csitx_drvInit.c
+++ b/source/drivers/csitx/v0/src/csitx_drvInit.c
@@ -86,7 +86,7 @@ int32_t CsitxDrv_init(CsitxDrv_CommonObj *txObj);
 int32_t Csitx_init(const Csitx_InitParams *initParams)
 {
     int32_t retVal = FVID2_SOK;
-    uint32_t instCnt, CsitxInstCnt = 0, loopCnt;
+    uint32_t instCnt, CsitxInstCnt = 0, loopCnt, contextId;
     CsitxDrv_CommonObj *txObj;
     CsitxDrv_InstObj *instObj;
     int32_t status = SystemP_SUCCESS;
@@ -112,12 +112,33 @@ int32_t Csitx_init(const Csitx_InitParams *initParams)
         gCsitxCommonObj.getTimeStamp = NULL;
         for (instCnt = 0U; instCnt < CSITX_INSTANCE_ID_MAX; instCnt++)
         {
+            for (contextId = 0U ;
+                 contextId < CSITX_NUM_VIRTUAL_CONTEXT ;
+                 contextId++)
+            {
+                txObj->virtContext[instCnt][contextId].contextId = contextId;
+                txObj->virtContext[instCnt][contextId].numCh     = 0U;
+                txObj->virtContext[instCnt][contextId].state     =
+                                                        CSITX_DRV_STATE_IDLE;
+                Fvid2Utils_memset(
+                        &txObj->virtContext[instCnt][contextId].chId[0U],
+                        0U,
+                        sizeof (txObj->virtContext[instCnt][contextId].chId));
+                txObj->virtContext[instCnt][contextId].instObj   =
+                                            &instObj[instCnt];
+                txObj->virtContext[instCnt][contextId].inUse     =
+                                            CSITX_DRV_USAGE_STATUS_NOT_USED;
+                txObj->numVirtContUsed[instCnt]                  = 0U;
+            }
+
+            instObj[instCnt].dpyCfgDone                 = 0U;
+            instObj[instCnt].eventRegDone               = 0U;
             /* Initialize D-PHY configuration parameters */
             instObj[instCnt].dphyCfg.inst                = instCnt;
             instObj[instCnt].drvInstId                   = instCnt;
+            instObj[instCnt].commonObjRef                = txObj;
             instObj[instCnt].inUse                       =
                                                 CSITX_DRV_USAGE_STATUS_NOT_USED;
-            instObj[instCnt].state                       = CSITX_DRV_STATE_IDLE;
             instObj[instCnt].numTxCh                     = 0U;
             instObj[instCnt].numColorbarCh               = 0U;
             instObj[instCnt].numLpbkCh                   = 0U;
@@ -131,6 +152,8 @@ int32_t Csitx_init(const Csitx_InitParams *initParams)
             Csitx_instStatusInit(&instObj[instCnt].status);
             for (loopCnt = 0U ; loopCnt < CSITX_NUM_CH; loopCnt++)
             {
+                instObj[instCnt].chObj[loopCnt].chId             = loopCnt;
+                instObj[instCnt].chObj[loopCnt].virtContext      = NULL;
                 instObj[instCnt].chObj[loopCnt].psilThreadstatus =
                                                             (uint32_t)FALSE;
             }
@@ -174,7 +197,7 @@ int32_t Csitx_deInit(void)
     int32_t retVal = FVID2_SOK;
     CsitxDrv_CommonObj *txObj;
     CsitxDrv_InstObj *instObj;
-    uint32_t instIdx;
+    uint32_t instIdx, contextId;
 
     txObj = &gCsitxCommonObj;
     /* un-initialize instance object variables */
@@ -185,7 +208,16 @@ int32_t Csitx_deInit(void)
         instObj->inUse = CSITX_DRV_USAGE_STATUS_NOT_USED;
         /* putting to init state, this will prevent condition where
            user calls create() before calling init() after doing unint()*/
-        instObj->state = CSITX_DRV_STATE_UNINIT;
+        for (contextId = 0U ;
+             contextId < CSITX_NUM_VIRTUAL_CONTEXT ;
+             contextId++)
+        {
+            txObj->virtContext[instIdx][contextId].state =
+                                                    CSITX_DRV_STATE_UNINIT;
+            txObj->virtContext[instIdx][contextId].numCh     = 0U;
+            txObj->virtContext[instIdx][contextId].inUse     =
+                                        CSITX_DRV_USAGE_STATUS_NOT_USED;
+        }
         /* Delete semaphore */
         SemaphoreP_destruct(&instObj->lockSem);
     }
@@ -317,7 +349,7 @@ static int32_t CsitxDrv_chInit(CsitxDrv_InstObj *instObj)
             /* Only capture channel will have 'psilThreadId' other than
                'CSITX_DRV_DEF_PSIL_THREAD_ID' */
             instObj[instCnt].chObj[chNum].psilThreadId =
-                                        CSITX_DRV_DEF_PSIL_THREAD_ID;
+                                        chNum;
         }
     }
 
diff --git a/source/drivers/csitx/v0/src/csitx_drvUdma.c b/source/drivers/csitx/v0/src/csitx_drvUdma.c
index 5b0d275..4143324 100755
--- a/source/drivers/csitx/v0/src/csitx_drvUdma.c
+++ b/source/drivers/csitx/v0/src/csitx_drvUdma.c
@@ -200,125 +200,110 @@ int32_t CsitxDrv_setDMACfgParams(CsitxDrv_ChObj *chObj)
     return retVal;
 }
 
-int32_t CsitxDrv_setUdmaParams(CsitxDrv_CommonObj *txObj,
-                               CsitxDrv_InstObj *instObj)
+int32_t CsitxDrv_setChUdmaParams(CsitxDrv_ChObj *chObj)
 {
     int32_t retVal = FVID2_SOK, tempRetVal = UDMA_SOK;
-    uint32_t chIdx, chType;
-    CsitxDrv_ChObj *chObj;
+    uint32_t chType;
     Udma_EventHandle eventHandle;
     Udma_EventPrms eventParams;
+    CsitxDrv_CommonObj *txObj;
 
-
-    if(retVal ==FVID2_SOK)
+    txObj = chObj->instObj->commonObjRef;
+    if (chObj->chCfg->chType == CSITX_CH_TYPE_TX)
     {
-        for (chIdx = 0U ; chIdx < instObj->createParams.numCh ; chIdx++)
+        if (txObj->initParams.drvHandle == NULL)
+        {
+            retVal = FVID2_EBADARGS;
+            GT_0trace(CsitxTrace,
+                        GT_ERR,
+                        "Invalid UDMA DRV Handle!!\r\n");
+        }
+        if (gCsitxUdmaMasterEvntInitDone != INITIALIZED)
         {
-            chObj =&instObj->chObj[chIdx];
-            if (chObj->chCfg->chType == CSITX_CH_TYPE_TX)
-            {
-                if (txObj->initParams.drvHandle == NULL)
-                {
-                    retVal = FVID2_EBADARGS;
-                    GT_0trace(CsitxTrace,
-                              GT_ERR,
-                              "Invalid UDMA DRV Handle!!\r\n");
-                    break;
-                }
-                if (gCsitxUdmaMasterEvntInitDone != INITIALIZED)
-                {
-
-                    /* Register the UDMA Master event handle */
-                    UdmaEventPrms_init(&eventParams);
-                    eventParams.eventType         = UDMA_EVENT_TYPE_MASTER;
-                    eventParams.appData           = txObj;
-                    tempRetVal = Udma_eventRegister(txObj->initParams.drvHandle,
-                                                    &txObj->masterEvent,
-                                                    &eventParams);
-                    gCsitxUdmaMasterEvntInitDone = INITIALIZED;
-                }
-                /* Program UDMA channels only for Tx channels */
-                chType = UDMA_CH_TYPE_TX_TR;
-                /* Open UDMA channel */
-                tempRetVal = Udma_chOpen(txObj->initParams.drvHandle,
-                                         &chObj->txChObj,
-                                         chType,
-                                         &chObj->chParams);
-
-                if(tempRetVal != UDMA_SOK)
-                {
-                    retVal = FVID2_EFAIL;
-                    GT_0trace(CsitxTrace,
-                              GT_ERR,
-                              "[ERROR]UDMA channel open FAILED!!!\r\n");
-                }
-
-                if (retVal == FVID2_SOK)
-                {
-                    /* Configure UDMA Tx Channel */
-                    tempRetVal = Udma_chConfigTx(&chObj->txChObj,
-                                                 chObj->txChParams);
-
-                    if(tempRetVal != UDMA_SOK)
-                    {
-                        retVal = FVID2_EFAIL;
-                        GT_0trace(CsitxTrace,
-                              GT_ERR,
-                              "[ERROR]UDMA TX channel config FAILED!!!\r\n");
-                    }
 
-                }
+            /* Register the UDMA Master event handle */
+            UdmaEventPrms_init(&eventParams);
+            eventParams.eventType         = UDMA_EVENT_TYPE_MASTER;
+            eventParams.appData           = txObj;
+            tempRetVal = Udma_eventRegister(txObj->initParams.drvHandle,
+                                            &txObj->masterEvent,
+                                            &eventParams);
+            gCsitxUdmaMasterEvntInitDone = INITIALIZED;
+        }
+        /* Program UDMA channels only for Tx channels */
+        chType = UDMA_CH_TYPE_TX_TR;
+        /* Open UDMA channel */
+        tempRetVal = Udma_chOpen(txObj->initParams.drvHandle,
+                                    &chObj->txChObj,
+                                    chType,
+                                    &chObj->chParams);
+
+        if(tempRetVal != UDMA_SOK)
+        {
+            retVal = FVID2_EFAIL;
+            GT_0trace(CsitxTrace,
+                        GT_ERR,
+                        "[ERROR]UDMA channel open FAILED!!!\r\n");
+        }
 
-                if (retVal == FVID2_SOK)
-                {
-                    /* Register callbacks here */
-                    /* Register ring completion callback */
-                    eventHandle = &chObj->cqEventObj;
-                    UdmaEventPrms_init(&eventParams);
-                    eventParams.eventType         = UDMA_EVENT_TYPE_DMA_COMPLETION;
-                    eventParams.eventMode         = UDMA_EVENT_MODE_SHARED;
-                    eventParams.chHandle          = &chObj->txChObj;
-                    eventParams.masterEventHandle = &txObj->masterEvent;
-                    eventParams.eventCb           = &CsitxDrv_udmaCQEventCb;
-                    eventParams.appData           = chObj;
-                    tempRetVal = Udma_eventRegister(txObj->initParams.drvHandle,
-                                                    eventHandle,
-                                                    &eventParams);
-
-                    if(tempRetVal != UDMA_SOK)
-                    {
-                        retVal = FVID2_EFAIL;
-                        GT_0trace(CsitxTrace,
-                              GT_ERR,
-                              "[ERROR]UDMA CQ event register FAILED!!!\r\n");
-                    }
+        if (retVal == FVID2_SOK)
+        {
+            /* Configure UDMA Tx Channel */
+            tempRetVal = Udma_chConfigTx(&chObj->txChObj,
+                                            chObj->txChParams);
 
-                }
+            if(tempRetVal != UDMA_SOK)
+            {
+                retVal = FVID2_EFAIL;
+                GT_0trace(CsitxTrace,
+                        GT_ERR,
+                        "[ERROR]UDMA TX channel config FAILED!!!\r\n");
             }
 
-            if (retVal == FVID2_SOK)
+        }
+
+        if (retVal == FVID2_SOK)
+        {
+            /* Register callbacks here */
+            /* Register ring completion callback */
+            eventHandle = &chObj->cqEventObj;
+            UdmaEventPrms_init(&eventParams);
+            eventParams.eventType         = UDMA_EVENT_TYPE_DMA_COMPLETION;
+            eventParams.eventMode         = UDMA_EVENT_MODE_SHARED;
+            eventParams.chHandle          = &chObj->txChObj;
+            eventParams.masterEventHandle = &txObj->masterEvent;
+            eventParams.eventCb           = &CsitxDrv_udmaCQEventCb;
+            eventParams.appData           = chObj;
+            tempRetVal = Udma_eventRegister(txObj->initParams.drvHandle,
+                                            eventHandle,
+                                            &eventParams);
+
+            if(tempRetVal != UDMA_SOK)
             {
-                /* Set channel status to created */
-                chObj->status = CSITX_DRV_CH_STATE_CREATED;
+                retVal = FVID2_EFAIL;
+                GT_0trace(CsitxTrace,
+                        GT_ERR,
+                        "[ERROR]UDMA CQ event register FAILED!!!\r\n");
             }
 
         }
     }
 
+    if (retVal == FVID2_SOK)
+    {
+        /* Set channel status to created */
+        chObj->status = CSITX_DRV_CH_STATE_CREATED;
+    }
+
     return retVal;
 }
 
-int32_t CsitxDrv_clearUdmaParams(CsitxDrv_InstObj *instObj)
+int32_t CsitxDrv_clearUdmaParams(CsitxDrv_ChObj *chObj)
 {
     int32_t retVal = FVID2_SOK, tempRetVal = UDMA_SOK;
-    uint32_t chIdx;
-    CsitxDrv_ChObj *chObj;
     Udma_EventHandle eventHandle;
 
-    for (chIdx = 0U ; chIdx < instObj->createParams.numCh ; chIdx++)
-    {
-        chObj =&instObj->chObj[chIdx];
-        if (chObj->chCfg->chType == CSITX_CH_TYPE_TX)
+        if (CSITX_CH_TYPE_TX == chObj->chCfg->chType)
         {
             /* Unregister ring completion callback */
             eventHandle = &chObj->cqEventObj;
@@ -327,9 +312,8 @@ int32_t CsitxDrv_clearUdmaParams(CsitxDrv_InstObj *instObj)
             /* Close UDMA channel */
             tempRetVal += Udma_chClose(&chObj->txChObj);
         }
-    }
 
-    if (tempRetVal != UDMA_SOK)
+    if (UDMA_SOK != tempRetVal)
     {
         retVal = FVID2_EFAIL;
     }
@@ -669,9 +653,9 @@ void CsitxDrv_udmaCQEventCb(Udma_EventHandle eventHandle,
             /* Application call back */
             if (appCb == 1U)
             {
-                if(instObj->fdmCbParams.fdmCbFxn != NULL)
+                if(NULL != chObj->virtContext->fdmCbParams.fdmCbFxn)
                 {
-                    instObj->fdmCbParams.fdmCbFxn(instObj->fdmCbParams.fdmData);
+                    chObj->virtContext->fdmCbParams.fdmCbFxn(chObj->virtContext->fdmCbParams.fdmData);
                 }
             }
         }
-- 
2.34.1

