diff --git a/XilinxProcessorIPLib/drivers/v_hscaler/data/v_hscaler.tcl b/XilinxProcessorIPLib/drivers/v_hscaler/data/v_hscaler.tcl index 3a3207ea..926a0c15 100644 --- a/XilinxProcessorIPLib/drivers/v_hscaler/data/v_hscaler.tcl +++ b/XilinxProcessorIPLib/drivers/v_hscaler/data/v_hscaler.tcl @@ -10,14 +10,37 @@ proc generate {drv_handle} { "NUM_INSTANCES" \ "DEVICE_ID" \ "C_S_AXI_CTRL_BASEADDR" \ - "C_S_AXI_CTRL_HIGHADDR" + "C_S_AXI_CTRL_HIGHADDR" \ + "SAMPLES_PER_CLOCK" \ + "MAX_COLS" \ + "MAX_ROWS" \ + "MAX_DATA_WIDTH" \ + "PHASE_SHIFT" \ + "SCALE_MODE" \ + "TAPS" xdefine_config_file $drv_handle "xv_hscaler_g.c" "XV_hscaler" \ "DEVICE_ID" \ - "C_S_AXI_CTRL_BASEADDR" + "C_S_AXI_CTRL_BASEADDR" \ + "SAMPLES_PER_CLOCK" \ + "MAX_COLS" \ + "MAX_ROWS" \ + "MAX_DATA_WIDTH" \ + "PHASE_SHIFT" \ + "SCALE_MODE" \ + "TAPS" + xdefine_canonical_xpars $drv_handle "xparameters.h" "XV_hscaler" \ "DEVICE_ID" \ "C_S_AXI_CTRL_BASEADDR" \ - "C_S_AXI_CTRL_HIGHADDR" + "C_S_AXI_CTRL_HIGHADDR" \ + "SAMPLES_PER_CLOCK" \ + "MAX_COLS" \ + "MAX_ROWS" \ + "MAX_DATA_WIDTH" \ + "PHASE_SHIFT" \ + "SCALE_MODE" \ + "TAPS" } + diff --git a/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler.c b/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler.c index 005bf7d3..2cdb1b86 100644 --- a/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler.c +++ b/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler.c @@ -7,6 +7,7 @@ /***************************** Include Files *********************************/ #include "xv_hscaler.h" +#include "string.h" /************************** Function Implementation *************************/ #ifndef __linux__ @@ -14,6 +15,11 @@ int XV_hscaler_CfgInitialize(XV_hscaler *InstancePtr, XV_hscaler_Config *ConfigP Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(ConfigPtr != NULL); + /* Setup the instance */ + (void)memset((void *)InstancePtr, 0, sizeof(XV_hscaler)); + (void)memcpy((void *)&(InstancePtr->Config), (const void *)ConfigPtr, + sizeof(XV_hscaler_Config)); + InstancePtr->Ctrl_BaseAddress = ConfigPtr->Ctrl_BaseAddress; InstancePtr->IsReady = XIL_COMPONENT_IS_READY; diff --git a/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler.h b/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler.h index 054f5089..b43a671c 100644 --- a/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler.h +++ b/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler.h @@ -38,15 +38,31 @@ typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; #else +/** +* This typedef contains configuration information for the horizontal scaler +* core. Each core instance should have a configuration structure +* associated. +*/ typedef struct { - u16 DeviceId; - u32 Ctrl_BaseAddress; + u16 DeviceId; /**< Unique ID of device */ + u32 Ctrl_BaseAddress; /**< The base address of the core instance. */ + int PixPerClk; /**< Samples Per Clock supported by core instance */ + u16 MaxWidth; /**< Maximum columns supported by core instance */ + u16 MaxHeight; /**< Maximum rows supported by core instance */ + int MaxDataWidth; /**< Maximum Data width of each channel */ + u16 PhaseShift; /**< Max num of phases (2^PhaseShift) */ + int ScalerType; /**< Scaling Algorithm Selected */ + int NumTaps; /**< Number of taps */ } XV_hscaler_Config; #endif +/** +* Driver instance data. An instance must be allocated for each core in use. +*/ typedef struct { - u32 Ctrl_BaseAddress; - u32 IsReady; + XV_hscaler_Config Config; /**< Hardware Configuration */ + u32 Ctrl_BaseAddress; /**< The base address of the core instance. */ + u32 IsReady; /**< Device is initialized and ready */ } XV_hscaler; /***************** Macros (Inline Functions) Definitions *********************/ diff --git a/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler_l2.c b/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler_l2.c index 0a00b44e..5a7e226d 100644 --- a/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler_l2.c +++ b/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler_l2.c @@ -73,24 +73,21 @@ static float TempCoeffs[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_MAX_H_TAPS]; static float WinCoeffs[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_MAX_H_TAPS]; static float NormCoeffs[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_MAX_H_TAPS]; -int HSC_SAMPLES_PER_CLOCK = 2; -int HSC_MAX_WIDTH = 4096; -int STEP_PRECISION_SHIFT = 16; -int HSC_PHASE_SHIFT = 6; +const int STEP_PRECISION_SHIFT = 16; /************************** Function Prototypes ******************************/ static float hamming( int x, int taps); static float sinc(float x); -static void CalculatePhases(XV_hscaler_l2 *pHscL2Data, +static void CalculatePhases(XV_hscaler *pHsc, + XV_hscaler_l2 *pHscL2Data, u32 WidthIn, u32 WidthOut, u32 PixelRate); -static void XV_HScalerGetCoeff(XV_hscaler *InstancePtr, +static void XV_HScalerGetCoeff(XV_hscaler *pHsc, XV_hscaler_l2 *pHscL2Data, u32 WidthIn, - u32 WidthOut, - u32 PixPerClk); -static void XV_HScalerSetCoeff(XV_hscaler *InstancePtr, + u32 WidthOut); +static void XV_HScalerSetCoeff(XV_hscaler *pHsc, XV_hscaler_l2 *pHscL2Data); /*****************************************************************************/ @@ -171,15 +168,14 @@ static float sinc(float x) * @return None * ******************************************************************************/ -static void CalculatePhases(XV_hscaler_l2 *pHscL2Data, +static void CalculatePhases(XV_hscaler *pHsc, + XV_hscaler_l2 *pHscL2Data, u32 WidthIn, u32 WidthOut, u32 PixelRate) { int loopWidth; - loopWidth = ((WidthIn > WidthOut) ? WidthIn +(HSC_SAMPLES_PER_CLOCK-1) : WidthOut +(HSC_SAMPLES_PER_CLOCK-1))/HSC_SAMPLES_PER_CLOCK; - - int x, s; + int x,s; int offset = 0; int xWritePos = 0; int OutputWriteEn; @@ -189,15 +185,19 @@ static void CalculatePhases(XV_hscaler_l2 *pHscL2Data, int xReadPos = 0; int nrRds = 0; int nrRdsClck = 0; + int MaxPhases = (1<Config.PhaseShift); + loopWidth = ((WidthIn > WidthOut) ? WidthIn + (pHsc->Config.PixPerClk-1) + : WidthOut +(pHsc->Config.PixPerClk-1))/pHsc->Config.PixPerClk; + arrayIdx = 0; for (x=0; xphasesH[x] = 0; nrRdsClck = 0; - for (s=0; sConfig.PixPerClk; s++) { - PhaseH = (offset>>(STEP_PRECISION_SHIFT-HSC_PHASE_SHIFT)) & (XV_HSCALER_MAX_H_PHASES-1);//(HSC_PHASES-1); + PhaseH = (offset>>(STEP_PRECISION_SHIFT-pHsc->Config.PhaseShift)) & (MaxPhases-1);//(HSC_PHASES-1); GetNewPix = 0; OutputWriteEn = 0; if ((offset >> STEP_PRECISION_SHIFT) != 0) @@ -217,21 +217,19 @@ static void CalculatePhases(XV_hscaler_l2 *pHscL2Data, OutputWriteEn = 1; xWritePos++; } - //printf("x %5d, offset %5d, phase %5d, arrayIdx %5d, readpos %5d writepos %5d rden %3d wren %3d\n", (int)x*HSC_SAMPLES_PER_CLOCK+s, offset, (int)PhaseH, (int)arrayIdx, (int)xReadPos, xWritePos, GetNewPix, OutputWriteEn); pHscL2Data->phasesH[x] = pHscL2Data->phasesH[x] | (PhaseH << (s*9)); pHscL2Data->phasesH[x] = pHscL2Data->phasesH[x] | (arrayIdx << (6 + (s*9))); pHscL2Data->phasesH[x] = pHscL2Data->phasesH[x] | (OutputWriteEn << (8 + (s*9))); if (GetNewPix) nrRdsClck++; } - if (arrayIdx>=HSC_SAMPLES_PER_CLOCK) arrayIdx &= (HSC_SAMPLES_PER_CLOCK-1); + if (arrayIdx>=pHsc->Config.PixPerClk) + arrayIdx &= (pHsc->Config.PixPerClk-1); - //printf("%d nrRds per clock %d left hanging\n", nrRdsClck, nrRds); nrRds += nrRdsClck; - if (nrRds>=HSC_SAMPLES_PER_CLOCK) + if (nrRds>=pHsc->Config.PixPerClk) { - nrRds -= HSC_SAMPLES_PER_CLOCK; - //printf("getting %d new samples\n", HSC_SAMPLES_PER_CLOCK); + nrRds -= pHsc->Config.PixPerClk; } } } @@ -247,30 +245,30 @@ static void CalculatePhases(XV_hscaler_l2 *pHscL2Data, ******************************************************************************/ void XV_HscalerLoadUsrCoeffients(XV_hscaler *InstancePtr, XV_hscaler_l2 *pHscL2Data, - const short HCoeff[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_MAX_H_TAPS]) + u16 num_phases, + u16 num_taps, + const short *Coeff) { - int i,j,k, pad, offset; - int num_phases = XV_HSCALER_MAX_H_PHASES; - int num_taps = pHscL2Data->EffectiveTaps; + int i,j, pad, offset; /* * Assert validates the input arguments */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(pHscL2Data != NULL); - Xil_AssertVoid((pHscL2Data->EffectiveTaps > 0) && - (pHscL2Data->EffectiveTaps <= XV_HSCALER_MAX_H_TAPS)); + Xil_AssertVoid(num_taps <= InstancePtr->Config.NumTaps); + Xil_AssertVoid(num_phases <= (1<Config.PhaseShift)); //determine if coefficient needs padding (effective vs. max taps) - pad = XV_HSCALER_MAX_H_TAPS - num_taps; + pad = XV_HSCALER_MAX_H_TAPS - InstancePtr->Config.NumTaps; offset = ((pad) ? (pad>>1) : 0); //Load User defined coefficients into scaler coefficient table for (i = 0; i < num_phases; i++) { - for (k=0,j=offset; jcoeff[i][j] = HCoeff[i][k]; + pHscL2Data->coeff[i][j+offset] = Coeff[i*num_taps+j]; } } @@ -290,6 +288,9 @@ void XV_HscalerLoadUsrCoeffients(XV_hscaler *InstancePtr, } } } + + /* Enable use of external coefficients */ + pHscL2Data->UseExtCoeff = TRUE; } /*****************************************************************************/ @@ -305,26 +306,19 @@ void XV_HscalerLoadUsrCoeffients(XV_hscaler *InstancePtr, * @return None * ******************************************************************************/ -static void XV_HScalerGetCoeff(XV_hscaler *InstancePtr, +static void XV_HScalerGetCoeff(XV_hscaler *pHsc, XV_hscaler_l2 *pHscL2Data, u32 WidthIn, - u32 WidthOut, - u32 PixPerClk) + u32 WidthOut) { - int num_phases = XV_HSCALER_MAX_H_PHASES; - int num_taps = pHscL2Data->EffectiveTaps; + int num_phases = (1<Config.PhaseShift); + int num_taps = pHsc->Config.NumTaps; int center_tap = num_taps/2; int i,j, pad, offset; float x, fc; float sum[XV_HSCALER_MAX_H_PHASES]; float cos_win[XV_HSCALER_MAX_H_TAPS]; - /* - * Assert validates the input arguments - */ - Xil_AssertVoid((pHscL2Data->EffectiveTaps > 0) && - (pHscL2Data->EffectiveTaps <= XV_HSCALER_MAX_H_TAPS)); - if(WidthIn < WidthOut) { fc = (float)WidthIn/(float)WidthOut; @@ -393,10 +387,10 @@ static void XV_HScalerGetCoeff(XV_hscaler *InstancePtr, for (i = 0; i < num_phases; i++) { - for (j = offset; j < num_taps; j++) + for (j = 0; j < num_taps; j++) { NormCoeffs[i][j] = WinCoeffs[i][j]/sum[i]; - pHscL2Data->coeff[i][j] = (short) ((NormCoeffs[i][j] * COEFF_QUANT) + 0.5); + pHscL2Data->coeff[i][j+offset] = (short) ((NormCoeffs[i][j] * COEFF_QUANT) + 0.5); } } @@ -435,27 +429,29 @@ static void XV_HScalerGetCoeff(XV_hscaler *InstancePtr, * maintain the sw latency for driver version which would eventually use * computed coefficients ******************************************************************************/ -static void XV_HScalerSetCoeff(XV_hscaler *InstancePtr, +static void XV_HScalerSetCoeff(XV_hscaler *pHsc, XV_hscaler_l2 *pHscL2Data) { - int num_phases = XV_HSCALER_MAX_H_PHASES; - int num_taps = XV_HSCALER_MAX_H_TAPS/2; - int val,i,j; + int num_phases = 1<Config.PhaseShift; + int num_taps = pHsc->Config.NumTaps/2; + int val,i,j,offset,rdIndx; u32 baseAddr; - baseAddr = XV_hscaler_Get_HwReg_hfltCoeff_BaseAddress(InstancePtr); + offset = (XV_HSCALER_MAX_H_TAPS - pHsc->Config.NumTaps)/2; + baseAddr = XV_hscaler_Get_HwReg_hfltCoeff_BaseAddress(pHsc); for (i = 0; i < num_phases; i++) { - for(j=0; j< num_taps; j++) + for(j=0; j < num_taps; j++) { - val = (pHscL2Data->coeff[i][(j*2)+1] << 16) | (pHscL2Data->coeff[i][j*2] & XMASK_LOW_16BITS); + rdIndx = j*2+offset; + val = (pHscL2Data->coeff[i][rdIndx+1] << 16) | (pHscL2Data->coeff[i][rdIndx] & XMASK_LOW_16BITS); Xil_Out32(baseAddr+((i*num_taps+j)*4), val); } } //program phases - baseAddr = XV_hscaler_Get_HwReg_phasesH_V_BaseAddress(InstancePtr); - for (i = 0; i < (HSC_MAX_WIDTH/HSC_SAMPLES_PER_CLOCK); i++) + baseAddr = XV_hscaler_Get_HwReg_phasesH_V_BaseAddress(pHsc); + for (i = 0; i < (pHsc->Config.MaxWidth/pHsc->Config.PixPerClk); i++) { Xil_Out32(baseAddr+(i*4), pHscL2Data->phasesH[i]); } @@ -480,7 +476,6 @@ void XV_HScalerSetup(XV_hscaler *InstancePtr, u32 HeightIn, u32 WidthIn, u32 WidthOut, - u32 PixPerClk, u32 cformat) { u32 PixelRate; @@ -493,19 +488,24 @@ void XV_HScalerSetup(XV_hscaler *InstancePtr, PixelRate = (u32) ((float)((WidthIn * STEP_PRECISION) + (WidthOut/2))/(float)WidthOut); - /* Compute Phase for 1 line */ - CalculatePhases(pHscL2Data, WidthIn, WidthOut, PixelRate); - - if(pHscL2Data->ScalerType == XV_HSCALER_POLYPHASE) + if(InstancePtr->Config.ScalerType == XV_HSCALER_POLYPHASE) { + /* Compute Phase for 1 line */ + CalculatePhases(InstancePtr, pHscL2Data, WidthIn, WidthOut, PixelRate); + if(!pHscL2Data->UseExtCoeff) //No predefined coefficients { + /* If user has not selected any filter set default */ + if(pHscL2Data->FilterSel == 0) + { + XV_HScalerSetFilterType(pHscL2Data, XV_HFILT_LANCZOS); + } + /* Generate coefficients for horizontal scaling ratio */ XV_HScalerGetCoeff(InstancePtr, pHscL2Data, WidthIn, - WidthOut, - PixPerClk); + WidthOut); } /* Program generated coefficients into the IP register bank */ @@ -535,7 +535,6 @@ void XV_HScalerDbgReportStatus(XV_hscaler *InstancePtr) XV_hscaler *pHsc = InstancePtr; u32 done, idle, ready, ctrl; u32 widthin, widthout, heightin, pixrate, cformat; - u32 type = 3; //hard-coded to polyphase for now u32 baseAddr, taps, phases; int val,i,j; @@ -553,27 +552,26 @@ void XV_HScalerDbgReportStatus(XV_hscaler *InstancePtr) heightin = XV_hscaler_Get_HwReg_Height(pHsc); widthin = XV_hscaler_Get_HwReg_WidthIn(pHsc); widthout = XV_hscaler_Get_HwReg_WidthOut(pHsc); -// type = XV_hscaler_Get_Hwreg_scaletype_v(pHsc); cformat = XV_hscaler_Get_HwReg_ColorMode(pHsc); pixrate = XV_hscaler_Get_HwReg_PixelRate(pHsc); - taps = XV_HSCALER_MAX_H_TAPS/2; - phases = XV_HSCALER_MAX_H_PHASES; + taps = pHsc->Config.NumTaps/2; + phases = (1<Config.PhaseShift); xil_printf("IsDone: %d\r\n", done); xil_printf("IsIdle: %d\r\n", idle); xil_printf("IsReady: %d\r\n", ready); xil_printf("Ctrl: 0x%x\r\n\r\n", ctrl); + xil_printf("Scaler Type: %d\r\n",pHsc->Config.ScalerType); xil_printf("Input Height: %d\r\n",heightin); xil_printf("Input Width: %d\r\n",widthin); xil_printf("Output Width: %d\r\n",widthout); -// xil_printf("Scaler Type: %d\r\n",type); xil_printf("Color Format: %d\r\n",cformat); xil_printf("Pixel Rate: %d\r\n",pixrate); xil_printf("Num Phases: %d\r\n",phases); xil_printf("Num Taps: %d\r\n",taps*2); - if(type == 3) + if(pHsc->Config.ScalerType == XV_HSCALER_POLYPHASE) { short lsb, msb; diff --git a/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler_l2.h b/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler_l2.h index 8d65f1dd..3e13ed0e 100644 --- a/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler_l2.h +++ b/XilinxProcessorIPLib/drivers/v_hscaler/src/xv_hscaler_l2.h @@ -108,7 +108,6 @@ extern "C" { #endif -#include "xvidc.h" #include "xv_hscaler.h" /************************** Constant Definitions *****************************/ @@ -122,8 +121,9 @@ extern "C" { * accessible via instance pointer * */ -#define XV_HSCALER_MAX_H_TAPS (6) +#define XV_HSCALER_MAX_H_TAPS (10) #define XV_HSCALER_MAX_H_PHASES (64) +#define XV_HSCALER_MAX_LINE_WIDTH (4096) /**************************** Type Definitions *******************************/ /** @@ -152,28 +152,40 @@ typedef enum */ typedef struct { - u8 EffectiveTaps; u8 UseExtCoeff; XV_HFILTER_ID FilterSel; - XV_HSCALER_TYPE ScalerType; - u8 Gain; short coeff[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_MAX_H_TAPS]; - u32 phasesH[4096]; + u32 phasesH[XV_HSCALER_MAX_LINE_WIDTH]; }XV_hscaler_l2; +/************************** Macros Definitions *******************************/ +/*****************************************************************************/ +/** + * This macro selects the filter used for generating coefficients. + * Applicable only for Ployphase Scaler Type + * + * @param pHscL2Data is pointer to the H Scaler Layer 2 structure instance + * @param value is the filter type + * + * @return None + * + *****************************************************************************/ +#define XV_HScalerSetFilterType(pHscL2Data, value) \ + ((pHscL2Data)->FilterSel = value) /************************** Function Prototypes ******************************/ void XV_HScalerStart(XV_hscaler *InstancePtr); void XV_HScalerStop(XV_hscaler *InstancePtr); void XV_HscalerLoadUsrCoeffients(XV_hscaler *InstancePtr, XV_hscaler_l2 *pHscL2Data, - const short HCoeff[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_MAX_H_TAPS]); + u16 num_phases, + u16 num_taps, + const short *Coeff); void XV_HScalerSetup(XV_hscaler *InstancePtr, XV_hscaler_l2 *pHscL2Data, u32 HeightIn, u32 WidthIn, u32 WidthOut, - u32 PixPerClk, u32 cformat); void XV_HScalerDbgReportStatus(XV_hscaler *InstancePtr);