From 3f21bcd139b590bbbce98fc2bcddaf8c1b0bfcce Mon Sep 17 00:00:00 2001
From: Rohit Consul <rohit.consul@xilinx.com>
Date: Thu, 27 Aug 2015 16:16:07 -0700
Subject: [PATCH] v_vscaler: Add filter table selection logic

There are 4 filter coefficient tables available. The table to be
loaded in IP register bank is determined by the scaling ratio

 Scale Up: Always use 6tap
 Scale Dn: Different table selected based on scaling ratio

Signed-off-by: Rohit Consul <rohit.consul@xilinx.com>
Acked-by: Andrei-Liviu Simion <andrei.simion@xilinx.com>
---
 .../drivers/v_vscaler/src/xv_vscaler_l2.c     | 157 +++++++++++++-----
 .../drivers/v_vscaler/src/xv_vscaler_l2.h     |   8 +-
 2 files changed, 118 insertions(+), 47 deletions(-)

diff --git a/XilinxProcessorIPLib/drivers/v_vscaler/src/xv_vscaler_l2.c b/XilinxProcessorIPLib/drivers/v_vscaler/src/xv_vscaler_l2.c
index d23a99bc..d1a2224d 100644
--- a/XilinxProcessorIPLib/drivers/v_vscaler/src/xv_vscaler_l2.c
+++ b/XilinxProcessorIPLib/drivers/v_vscaler/src/xv_vscaler_l2.c
@@ -72,8 +72,13 @@ const short XV_vscaler_fixedcoeff_taps10[XV_VSCALER_MAX_V_PHASES][XV_VSCALER_TAP
 const short XV_vscaler_fixedcoeff_taps12[XV_VSCALER_MAX_V_PHASES][XV_VSCALER_TAPS_12];
 
 /************************** Function Prototypes ******************************/
+static void XV_VScalerSelectCoeff(XV_vscaler *InstancePtr,
+		                          XV_vscaler_l2 *VscL2DataPtr,
+		                          u32 HeightIn,
+		                          u32 HeightOut);
+
 static void XV_VScalerSetCoeff(XV_vscaler *pVsc,
-                               XV_vscaler_l2 *pVscL2Data);
+                               XV_vscaler_l2 *VscL2DataPtr);
 
 /*****************************************************************************/
 /**
@@ -114,54 +119,119 @@ void XV_VScalerStop(XV_vscaler *InstancePtr)
 * storage based on the selected TAP configuration
 *
 * @param  InstancePtr is a pointer to the core instance to be worked on.
-* @param  pVscL2Data is a pointer to the core instance layer 2 data.
-*
+* @param  VscL2DataPtr is a pointer to the core instance layer 2 data.
+* @param  WidthIn is the input stream height
+* @param  Widthout is the output stream height
+
 * @return None
 *
 ******************************************************************************/
-void XV_VScalerLoadDefaultCoeff(XV_vscaler *InstancePtr,
-		                        XV_vscaler_l2 *pVscL2Data)
+static void XV_VScalerSelectCoeff(XV_vscaler *InstancePtr,
+		                          XV_vscaler_l2 *VscL2DataPtr,
+		                          u32 HeightIn,
+		                          u32 HeightOut)
 {
   const short *coeff;
   u16 numTaps, numPhases;
+  u16 ScalingRatio;
+  u16 IsScaleDown;
 
   /*
    * validates input arguments
    */
   Xil_AssertVoid(InstancePtr != NULL);
-  Xil_AssertVoid(pVscL2Data != NULL);
+  Xil_AssertVoid(VscL2DataPtr != NULL);
 
-  numTaps   = InstancePtr->Config.NumTaps;
   numPhases = (1<<InstancePtr->Config.PhaseShift);
 
-  switch(numTaps)
+  IsScaleDown = (HeightOut < HeightIn);
+  /* Scale Down Mode will use dynamic filter selection logic
+   * Scale Up Mode (including 1:1) will always use 6 tap filter
+   */
+  if(IsScaleDown)
   {
-    case XV_VSCALER_TAPS_6:
-	     coeff = &XV_vscaler_fixedcoeff_taps6[0][0];
-		 break;
+    ScalingRatio = ((HeightIn * 10)/HeightOut);
 
-    case XV_VSCALER_TAPS_8:
-	     coeff = &XV_vscaler_fixedcoeff_taps8[0][0];
-		 break;
+    switch(InstancePtr->Config.NumTaps)
+    {
+      case XV_VSCALER_TAPS_6:
+	       coeff = &XV_vscaler_fixedcoeff_taps6[0][0];
+           numTaps = XV_VSCALER_TAPS_6;
+		   break;
 
-    case XV_VSCALER_TAPS_10:
-	     coeff = &XV_vscaler_fixedcoeff_taps10[0][0];
-         break;
+      case XV_VSCALER_TAPS_8:
+	   if(ScalingRatio > 15)
+	   {
+		 coeff = &XV_vscaler_fixedcoeff_taps8[0][0];
+	         numTaps = XV_VSCALER_TAPS_8;
+	   }
+	   else // <= 1.5
+	   {
+	         coeff = &XV_vscaler_fixedcoeff_taps6[0][0];
+	         numTaps = XV_VSCALER_TAPS_6;
+	   }
+		   break;
+
+      case XV_VSCALER_TAPS_10:
+	       if(ScalingRatio > 25) // >2.5
+	       {
+		     coeff = &XV_vscaler_fixedcoeff_taps10[0][0];
+	         numTaps = XV_VSCALER_TAPS_10;
+	       }
+	       else if(ScalingRatio > 15) // 1.6 < ratio <= 2.5
+	       {
+	         coeff = &XV_vscaler_fixedcoeff_taps8[0][0];
+	         numTaps = XV_VSCALER_TAPS_8;
+	       }
+	       else // <= 1.5
+	       {
+	         coeff = &XV_vscaler_fixedcoeff_taps6[0][0];
+	         numTaps = XV_VSCALER_TAPS_6;
+	       }
+           break;
 
     case XV_VSCALER_TAPS_12:
-         coeff = &XV_vscaler_fixedcoeff_taps12[0][0];
-		 break;
+	       if(ScalingRatio > 35) // > 3.5
+	       {
+		     coeff = &XV_vscaler_fixedcoeff_taps12[0][0];
+	         numTaps = XV_VSCALER_TAPS_12;
+	       }
+	       else if(ScalingRatio > 25) //2.6 < Ratio <= 3.5
+	       {
+	         coeff = &XV_vscaler_fixedcoeff_taps10[0][0];
+	         numTaps = XV_VSCALER_TAPS_10;
+	       }
+	       else if(ScalingRatio > 15) //1.6 < Ratio <= 2.5
+	       {
+	         coeff = &XV_vscaler_fixedcoeff_taps8[0][0];
+	         numTaps = XV_VSCALER_TAPS_8;
+	       }
+	       else // <= 1.5
+	       {
+	         coeff = &XV_vscaler_fixedcoeff_taps6[0][0];
+	         numTaps = XV_VSCALER_TAPS_6;
+	       }
+		   break;
 
 	  default:
-		  xil_printf("ERR: V-Scaler %d Taps Not Supported",numTaps);
+		  xil_printf("ERR: H-Scaler %d Taps Not Supported",numTaps);
 		  return;
 	}
+  }
+  else //Scale Up
+  {
+    coeff = &XV_vscaler_fixedcoeff_taps6[0][0];
+    numTaps = XV_VSCALER_TAPS_6;
+  }
 
-	XV_VScalerLoadUsrCoeff(InstancePtr,
-			               pVscL2Data,
-		                   numPhases,
-		                   numTaps,
-		                   coeff);
+  XV_VScalerLoadExtCoeff(InstancePtr,
+		                 VscL2DataPtr,
+		                 numPhases,
+		                 numTaps,
+		                 coeff);
+
+  /* Disable use of external coefficients */
+  VscL2DataPtr->UseExtCoeff = FALSE;
 }
 
 /*****************************************************************************/
@@ -170,7 +240,7 @@ void XV_VScalerLoadDefaultCoeff(XV_vscaler *InstancePtr,
 * storage
 *
 * @param  InstancePtr is a pointer to the core instance to be worked on.
-* @param  pVscL2Data is a pointer to the core instance layer 2 data.
+* @param  VscL2DataPtr is a pointer to the core instance layer 2 data.
 * @param  num_phases is the number of phases in coefficient table
 * @param  num_taps is the number of taps in coefficient table
 * @param  Coeff is a pointer to user defined filter coefficients table
@@ -178,8 +248,8 @@ void XV_VScalerLoadDefaultCoeff(XV_vscaler *InstancePtr,
 * @return None
 *
 ******************************************************************************/
-void XV_VScalerLoadUsrCoeff(XV_vscaler *InstancePtr,
-                            XV_vscaler_l2 *pVscL2Data,
+void XV_VScalerLoadExtCoeff(XV_vscaler *InstancePtr,
+                            XV_vscaler_l2 *VscL2DataPtr,
                             u16 num_phases,
                             u16 num_taps,
                             const short *Coeff)
@@ -190,7 +260,7 @@ void XV_VScalerLoadUsrCoeff(XV_vscaler *InstancePtr,
    * validate input arguments
    */
   Xil_AssertVoid(InstancePtr != NULL);
-  Xil_AssertVoid(pVscL2Data != NULL);
+  Xil_AssertVoid(VscL2DataPtr != NULL);
   Xil_AssertVoid(num_taps <= InstancePtr->Config.NumTaps);
   Xil_AssertVoid(num_phases == (1<<InstancePtr->Config.PhaseShift));
   Xil_AssertVoid(Coeff != NULL);
@@ -209,7 +279,7 @@ void XV_VScalerLoadUsrCoeff(XV_vscaler *InstancePtr,
   }
 
   //determine if coefficient needs padding (effective vs. max taps)
-  pad = XV_VSCALER_MAX_V_TAPS - InstancePtr->Config.NumTaps;
+  pad = XV_VSCALER_MAX_V_TAPS - num_taps;
   offset = ((pad) ? (pad>>1) : 0);
 
   //Load User defined coefficients into scaler coefficient table
@@ -217,7 +287,7 @@ void XV_VScalerLoadUsrCoeff(XV_vscaler *InstancePtr,
   {
     for (j=0; j<num_taps; ++j)
     {
-      pVscL2Data->coeff[i][j+offset] = Coeff[i*num_taps+j];
+      VscL2DataPtr->coeff[i][j+offset] = Coeff[i*num_taps+j];
     }
   }
 
@@ -228,18 +298,18 @@ void XV_VScalerLoadUsrCoeff(XV_vscaler *InstancePtr,
       //pad left
       for (j = 0; j < offset; j++)
       {
-        pVscL2Data->coeff[i][j] = 0;
+        VscL2DataPtr->coeff[i][j] = 0;
       }
         //pad right
       for (j = (num_taps+offset); j < XV_VSCALER_MAX_V_TAPS; j++)
       {
-        pVscL2Data->coeff[i][j] = 0;
+        VscL2DataPtr->coeff[i][j] = 0;
       }
     }
   }
 
   /* Enable use of external coefficients */
-  pVscL2Data->UseExtCoeff = TRUE;
+  VscL2DataPtr->UseExtCoeff = TRUE;
 }
 
 /*****************************************************************************/
@@ -260,7 +330,7 @@ void XV_VScalerLoadUsrCoeff(XV_vscaler *InstancePtr,
 *        computed coefficients
 ******************************************************************************/
 static void XV_VScalerSetCoeff(XV_vscaler *pVsc,
-                               XV_vscaler_l2 *pVscL2Data)
+                               XV_vscaler_l2 *VscL2DataPtr)
 {
   int num_phases = 1<<pVsc->Config.PhaseShift;
   int num_taps   = pVsc->Config.NumTaps/2;
@@ -274,7 +344,7 @@ static void XV_VScalerSetCoeff(XV_vscaler *pVsc,
     for(j=0; j < num_taps; j++)
     {
        rdIndx = j*2+offset;
-       val = (pVscL2Data->coeff[i][rdIndx+1] << 16) | (pVscL2Data->coeff[i][rdIndx] & XVSC_MASK_LOW_16BITS);
+       val = (VscL2DataPtr->coeff[i][rdIndx+1] << 16) | (VscL2DataPtr->coeff[i][rdIndx] & XVSC_MASK_LOW_16BITS);
        Xil_Out32(baseAddr+((i*num_taps+j)*4), val);
     }
   }
@@ -294,7 +364,7 @@ static void XV_VScalerSetCoeff(XV_vscaler *pVsc,
 *
 ******************************************************************************/
 void XV_VScalerSetup(XV_vscaler  *InstancePtr,
-                     XV_vscaler_l2 *pVscL2Data,
+                     XV_vscaler_l2 *VscL2DataPtr,
                      u32         WidthIn,
                      u32         HeightIn,
                      u32         HeightOut)
@@ -305,7 +375,7 @@ void XV_VScalerSetup(XV_vscaler  *InstancePtr,
    * Assert validates the input arguments
    */
   Xil_AssertVoid(InstancePtr != NULL);
-  Xil_AssertVoid(pVscL2Data != NULL);
+  Xil_AssertVoid(VscL2DataPtr != NULL);
   Xil_AssertVoid((WidthIn>0) && (WidthIn<=InstancePtr->Config.MaxWidth));
   Xil_AssertVoid((HeightIn>0) && (HeightIn<=InstancePtr->Config.MaxHeight));
   Xil_AssertVoid((HeightOut>0) && (HeightOut<=InstancePtr->Config.MaxHeight));
@@ -314,14 +384,17 @@ void XV_VScalerSetup(XV_vscaler  *InstancePtr,
 
   if(InstancePtr->Config.ScalerType == XV_VSCALER_POLYPHASE)
   {
-    if(!pVscL2Data->UseExtCoeff) //No predefined coefficients
+    if(!VscL2DataPtr->UseExtCoeff) //No user defined coefficients
     {
-      xil_printf("\r\nERR: V Scaler coefficients not programmed\r\n");
-      return;
+      /* Determine coefficient table to use */
+      XV_VScalerSelectCoeff(InstancePtr,
+		                VscL2DataPtr,
+		                HeightIn,
+		                HeightOut);
     }
 
     /* Program coefficients into the IP register bank */
-    XV_VScalerSetCoeff(InstancePtr, pVscL2Data);
+    XV_VScalerSetCoeff(InstancePtr, VscL2DataPtr);
   }
 
   LineRate = (HeightIn * STEP_PRECISION)/HeightOut;
diff --git a/XilinxProcessorIPLib/drivers/v_vscaler/src/xv_vscaler_l2.h b/XilinxProcessorIPLib/drivers/v_vscaler/src/xv_vscaler_l2.h
index 0fded803..de8d7b68 100644
--- a/XilinxProcessorIPLib/drivers/v_vscaler/src/xv_vscaler_l2.h
+++ b/XilinxProcessorIPLib/drivers/v_vscaler/src/xv_vscaler_l2.h
@@ -160,15 +160,13 @@ typedef struct
 /************************** Function Prototypes ******************************/
 void XV_VScalerStart(XV_vscaler *InstancePtr);
 void XV_VScalerStop(XV_vscaler *InstancePtr);
-void XV_VScalerLoadDefaultCoeff(XV_vscaler *InstancePtr,
-		                        XV_vscaler_l2 *pVscL2Data);
-void XV_VScalerLoadUsrCoeff(XV_vscaler *InstancePtr,
-                            XV_vscaler_l2 *pVscL2Data,
+void XV_VScalerLoadExtCoeff(XV_vscaler *InstancePtr,
+                            XV_vscaler_l2 *VscL2DataPtr,
                             u16 num_phases,
                             u16 num_taps,
                             const short *Coeff);
 void XV_VScalerSetup(XV_vscaler *InstancePtr,
-                     XV_vscaler_l2 *pVscL2Data,
+                     XV_vscaler_l2 *VscL2DataPtr,
                      u32 WidthIn,
                      u32 HeightIn,
                      u32 HeightOut);