/*****************************************************************************

Copyright (c) 2006 Analog Devices, Inc.	All	Rights Reserved. 

This software is proprietary and confidential to Analog	Devices, Inc. 
and	its	licensors.

*****************************************************************************

$RCSfile: JPEGImageEdgeDetection_yuv2itu.c,v $
$Revision: 1.2 $
$Date: 2007/05/23 02:29:17 $

Project:	BlackfinSDK (JPEG Image Edge Detection)
Title:		YUV to ITU656 conversion
Author(s):	bmk
Revised	by:	

Description:
			Functions to manage YUV to ITU656 conversion			

References:
			None

*****************************************************************************
Tab	Setting:			4

Target Processor:		ADSP-BF5xx
Target Tools Revision:	ADSP VisualDSP++ v4.5
******************************************************************************

Modification History:
====================
$Log: JPEGImageEdgeDetection_yuv2itu.c,v $
Revision 1.2  2007/05/23 02:29:17  randreol
Changes in ssl_init and VDSP5.0 porting

Revision 1.5  2006/11/20 05:56:50  bmk
Merged BF533 & BF561
Fixed BF561 cache issue

Revision 1.4  2006/11/03 07:11:16  bmk
SDK 2.0  files - Initial Entry

Revision 1.2  2006/07/27 07:36:27  bmk
Added more Debug info option

Revision 1.1  2006/07/25 08:09:09  bmk
initial entry
******************************************************************************
Include files
*****************************************************************************/

#include <JPEGImageEdgeDetection_System.h>	// system includes

/*****************
Macros
******************/

#define		NUM_DESCRIPTORS		6		// Number of descriptors

/*************************
Local function prototypes
*************************/
// Installs Memory DMA for YUV to ITU656 conversion
void 		InstallMDMA_YUVtoITU656	(void);
//Frees MDMA channels used for YUV to ITU656 conversion
void 		FreeMDMA_YUVtoITU656	(void);
// YUV to ITU656 frame conversion - MDMA callback function
static void	MDMA_YUVtoITU656Callback(void *AppHandle, u32  Event, void *pArg);

/*****************
Globals
******************/

// MDMA channel handles for YUV to ITU656 conversion
static ADI_DMA_CHANNEL_HANDLE 	MDMAHandleSrc;	// Source handle
static ADI_DMA_CHANNEL_HANDLE 	MDMAHandleDest;	// Destination handle

// 6 descriptors for source and 6 for destination
ADI_DMA_DESCRIPTOR_UNION 	SrcDescriptor[NUM_DESCRIPTORS];
ADI_DMA_DESCRIPTOR_UNION 	DestDescriptor[NUM_DESCRIPTORS];
// pointer to start of source descriptor chain
ADI_DMA_DESCRIPTOR_UNION 	*pSrcDescriptor ;
// pointer to start of destination descriptor chain
ADI_DMA_DESCRIPTOR_UNION 	*pDestDescriptor;

/*********************************************************************

	Function:		SetupMDMA_YUVtoITU656

	Description:	Initialises Descriptors for MDMA (for YUV to 
					ITU656 frame conversion)
					
	Create all descriptor pointers for the MEMDMA channels
	MDMA copies from YUV buffers and builds a ITU656 Video Frame

*********************************************************************/
#pragma optimize_off 
section("sdram0_bank1_cache")
void SetupMDMA_YUVtoITU656 (void)
{
	int i;
	
	for(i=0; i<NUM_DESCRIPTORS; i++) 
	{
		// Clear all the descriptor elements first
		memset(&SrcDescriptor[i],0,sizeof(ADI_DMA_DESCRIPTOR_UNION));
		
		SrcDescriptor[i].Large.Config.b_WNR 	= 0; 		// source
		SrcDescriptor[i].Large.Config.b_DMA2D 	= 1; 
		SrcDescriptor[i].Large.Config.b_RESTART = 1; 
		SrcDescriptor[i].Large.XModify 			= sizeof(char);
		SrcDescriptor[i].Large.YModify 			= sizeof(char);
		
		// Clear all the descriptor elements first
		memset(&DestDescriptor[i],0,sizeof(ADI_DMA_DESCRIPTOR_UNION));
		
		DestDescriptor[i].Large.Config.b_WNR 		= 1; 	// Destination
		DestDescriptor[i].Large.Config.b_DMA2D 		= 1; 
		DestDescriptor[i].Large.Config.b_RESTART 	= 1; 
		DestDescriptor[i].Large.XModify 			= sizeof(int); // Chroma stride should be 4 bytes
	}

	// XModify for luma (luma stride should be only 2 bytes)
	DestDescriptor[0].Large.XModify 	= sizeof(short);
	DestDescriptor[3].Large.XModify 	= sizeof(short);

	// Create the linked list of descriptors	
	for(i=0; i<(NUM_DESCRIPTORS-1); i++) 
	{
		SrcDescriptor [i].Large.pNext 	= (ADI_DMA_DESCRIPTOR_LARGE *)&SrcDescriptor [i+1];
		DestDescriptor[i].Large.pNext 	= (ADI_DMA_DESCRIPTOR_LARGE *)&DestDescriptor[i+1];
	}

	// Create the termination descriptor for the list	
	SrcDescriptor [NUM_DESCRIPTORS-1].Large.pNext 	= NULL;
	DestDescriptor[NUM_DESCRIPTORS-1].Large.pNext 	= NULL;

	pSrcDescriptor 		= &SrcDescriptor [0];	// start of source descriptor chain
	pDestDescriptor 	= &DestDescriptor[0];	// start of destination descriptor chain

	// Install MDMA Driver for YUV to ITU656 conversion
	InstallMDMA_YUVtoITU656();

	return;
}
#pragma optimize_as_cmd_line 

/*********************************************************************

    Function:       InstallMDMA_YUVtoITU656

    Description:    Installs Memory DMA for YUV to ITU656 conversion

*********************************************************************/
section("sdram0_bank1_cache")
void InstallMDMA_YUVtoITU656(void)
{
    	

    	// Open (memory)DMA channels
	ezErrorCheck( adi_dma_Open(	adi_dma_ManagerHandle, 				// DMA Manager Handle
								YUV_ITU656_MDMA_SRC_CHANNEL,	// MDMA Source channel ID
								NULL, 							// No client Handle
								&MDMAHandleSrc, 				// Address of Source Channel handle location
								ADI_DMA_MODE_DESCRIPTOR_LARGE, 	// DMA Mode
								DCBManagerHandle, 				// Deffered Callback Manager
								NULL) );						// No callback function provided for source channel

	ezErrorCheck( adi_dma_Open(	adi_dma_ManagerHandle, 				// DMA Manager Handle
								YUV_ITU656_MDMA_DEST_CHANNEL,	// MDMA Destination channel ID
								NULL, 							// No client Handle
								&MDMAHandleDest, 				// Address of Destination Channel handle location
								ADI_DMA_MODE_DESCRIPTOR_LARGE, 	// DMA Mode
								DCBManagerHandle, 				// Deffered Callback Manager
								MDMA_YUVtoITU656Callback) );	// Callback function for Destination channel

	// Enable MDMA dataflow
	ezErrorCheck(adi_dma_Control(MDMAHandleSrc, ADI_DMA_CMD_SET_DATAFLOW, (void*)TRUE) );
	ezErrorCheck(adi_dma_Control(MDMAHandleDest, ADI_DMA_CMD_SET_DATAFLOW, (void*)TRUE) );

	MDMASharedFlag	= TRUE;	// Lock MDMA until YUV to ITU656 frame conversion is done
		
	return;
}

/*********************************************************************

	Function:		KickOffMDMA_YUVtoITU656

	Description:	Kicks off MDMA for YUV to ITU656 frame conversion

*********************************************************************/
section("sdram0_bank1_cache")
void KickOffMDMA_YUVtoITU656(void)
{
	// Queue Source descriptor chain
	ezErrorCheck( adi_dma_Queue(MDMAHandleSrc, pSrcDescriptor) );
	// Queue Destination descriptor chain
	ezErrorCheck( adi_dma_Queue(MDMAHandleDest, pDestDescriptor) );

	return;
}

/*********************************************************************

    Function:       MDMA_YUVtoITU656Callback

    Description:    YUV to ITU656 frame conversion - MDMA callback function

*********************************************************************/
section ("Callback_Code")
static void MDMA_YUVtoITU656Callback(
	void *AppHandle,
	u32  Event,
	void *pArg
){         

	// CASEOF (event type)
	switch (Event) 
	{
		
		// CASE (buffer processed)
		case ADI_DMA_EVENT_DESCRIPTOR_PROCESSED:

    		// Release MDMA stream as YUV to ITU656 frame conversion is done
			MDMASharedFlag	= FALSE;
						
			break;
			
		// CASE (an error)
		case ADI_DMA_EVENT_ERROR_INTERRUPT:
		
			// turn on all LEDs and wait for help
			ezTurnOnAllLEDs();
			while (1) ;
			
	}

	return;
}

/*********************************************************************

	Function:		FreeMDMA_YUVtoITU656

	Description:	Frees MDMA channels used for YUV to ITU656 conversion

*********************************************************************/
section("sdram0_bank1_cache")
void FreeMDMA_YUVtoITU656(void)
{
	// stop the MDMA dataflow
	ezErrorCheck(adi_dma_Control(MDMAHandleSrc, ADI_DMA_CMD_SET_DATAFLOW, (void*)FALSE) );
	ezErrorCheck(adi_dma_Control(MDMAHandleDest, ADI_DMA_CMD_SET_DATAFLOW, (void*)FALSE) );

	// close the MDMA channel
	ezErrorCheck( adi_dma_Close(MDMAHandleSrc, FALSE) );
	ezErrorCheck( adi_dma_Close(MDMAHandleDest, FALSE) );

	return;
}

/*********************************************************************

	Function:		SetupMDMA_YUV420toITU656

	Description:	Configures MDMA Descriptors for YUV420 to 
					ITU656 frame conversion
					
	For YUV420 to ITU656 Conversion:
		uses 6 descriptors:	1st half of Y 	-> ITU656 field 1
							U 				-> ITU656 field 1
							V 				-> ITU656 field 1
							2nd half of Y 	-> ITU656 field 2
							U 				-> ITU656 field 2
							V 				-> ITU656 field 2

*********************************************************************/
section("sdram0_bank1_cache")
void	SetupMDMA_YUV420toITU656 (
	u32		JPEGImageWidth,	// Actual width of JPEG image
	u32		JPEGImageHeight	// Actual height of JPEG image
){
    u32	WidthOffset,HeightOffset;	// Display offsets
    
	u32	DisplayWidth;				// Image Width to be displayed
	u32	DisplayHeight;				// Image Height to be displayed
			
	// prepare MDMA for relevant YUV to ITU656 conversion
	// complete descriptor setup with the "variable" parts that we now have after decoding the image

	// Calculate Output image width & height. Maximum size can be ITU656 frame resolution
	// calculate maximum Output display width and Offset to center in output display
	if (JPEGImageWidth > ITU_PIXEL_PER_LINE)
	{
	    DisplayWidth = ITU_PIXEL_PER_LINE;
	    WidthOffset = 0;	// no width offset necessary for maximum resolution 
	}   
	else
	{
	    DisplayWidth = JPEGImageWidth;
		// Width offset  = 	Number of pixels(Y) to skip per line
		WidthOffset 	= (ITU_PIXEL_PER_LINE - DisplayWidth);
	}
	// calculate maximum Output display height and Offset to center in output display
	if (JPEGImageHeight > ActiveFrameLines)
	{
	    DisplayHeight = ActiveFrameLines;
	    HeightOffset = 0;	// no height offset necessary for maximum resolution 
	}
	else
	{
	    DisplayHeight = JPEGImageHeight;
		// Height offset = 	Number of active lines (data size in bytes) to skip
		HeightOffset 	= (((ActiveFrameLines - DisplayHeight)/4) * DataPerLine);
	}
       		
	// setup 1st half of YUV source descriptor chain (MDMA)
	// source Y 1st half
	SrcDescriptor[0].Large.StartAddress 	= (void *)pYUVBuf;
	SrcDescriptor[0].Large.XCount 			= DisplayWidth;
	SrcDescriptor[0].Large.YCount 			= DisplayHeight/2;
	SrcDescriptor[0].Large.YModify 			= JPEGImageWidth + (JPEGImageWidth - DisplayWidth) + SrcDescriptor[0].Large.XModify;

	// destination Y 1st half
	DestDescriptor[0].Large.StartAddress	= (void *)(pJPEGImageBuf + Field1Skip + ActiveVideoSkip + ITU_Y_OFFSET + WidthOffset + HeightOffset);
	DestDescriptor[0].Large.XCount 			= DisplayWidth;
	DestDescriptor[0].Large.YCount 			= DisplayHeight/2;
	DestDescriptor[0].Large.YModify 		= (WidthOffset*2) + ActiveVideoSkip + DestDescriptor[0].Large.XModify; // twice width offset to account for U/V data

	// source U 1st half
	SrcDescriptor[1].Large.StartAddress 	= (void *)(pYUVBuf + (JPEGImageWidth*JPEGImageHeight));
	SrcDescriptor[1].Large.XCount 			= DisplayWidth/2;
	SrcDescriptor[1].Large.YCount 			= DisplayHeight/2;
	SrcDescriptor[1].Large.YModify 			= (JPEGImageWidth - DisplayWidth)/2 + SrcDescriptor[1].Large.XModify;

	// destination U 1st half
	DestDescriptor[1].Large.StartAddress 	= (void *)(pJPEGImageBuf + Field1Skip + ActiveVideoSkip + ITU_U_OFFSET + WidthOffset + HeightOffset);
	DestDescriptor[1].Large.XCount 			= DisplayWidth/2;
	DestDescriptor[1].Large.YCount 			= DisplayHeight/2;
	DestDescriptor[1].Large.YModify 		= (WidthOffset*2) + ActiveVideoSkip + DestDescriptor[1].Large.XModify; // twice width offset to account for U/V data

	// source V 1st half
	SrcDescriptor[2].Large.StartAddress 	= (void *)(pYUVBuf + (JPEGImageWidth*JPEGImageHeight*5/4));
	SrcDescriptor[2].Large.XCount 			= DisplayWidth/2;
	SrcDescriptor[2].Large.YCount 			= DisplayHeight/2;
	SrcDescriptor[2].Large.YModify 			= (JPEGImageWidth - DisplayWidth)/2 + SrcDescriptor[2].Large.XModify; 

	// destination V 1st half
	DestDescriptor[2].Large.StartAddress 	= (void *)(pJPEGImageBuf + Field1Skip + ActiveVideoSkip + ITU_V_OFFSET + WidthOffset + HeightOffset);
	DestDescriptor[2].Large.XCount 			= DisplayWidth/2;
	DestDescriptor[2].Large.YCount 			= DisplayHeight/2;
	DestDescriptor[2].Large.YModify 		= (WidthOffset*2) + ActiveVideoSkip + DestDescriptor[2].Large.XModify; // twice width offset to account for U/V data

	// setup 2nd half of YUV source descriptor chain (MDMA)

	// source Y 2nd half
	SrcDescriptor[3].Large.StartAddress 	= (void *)(pYUVBuf + JPEGImageWidth);		// start at second row of Y buffer
	SrcDescriptor[3].Large.XCount 			= DisplayWidth;
	SrcDescriptor[3].Large.YCount 			= DisplayHeight/2;
	SrcDescriptor[3].Large.YModify 			= JPEGImageWidth + (JPEGImageWidth - DisplayWidth) + SrcDescriptor[3].Large.XModify;

	// destination Y 2nd half
	DestDescriptor[3].Large.StartAddress 	= (void *)(pJPEGImageBuf + Field2Skip + ActiveVideoSkip + ITU_Y_OFFSET + WidthOffset + HeightOffset);
	DestDescriptor[3].Large.XCount 			= DisplayWidth;
	DestDescriptor[3].Large.YCount 			= DisplayHeight/2;
	DestDescriptor[3].Large.YModify 		= (WidthOffset*2) + ActiveVideoSkip + DestDescriptor[3].Large.XModify; // twice width offset to account for U/V data

	// source U 2nd half
	SrcDescriptor[4].Large.StartAddress 	= (void *)(pYUVBuf + (JPEGImageWidth*JPEGImageHeight));
	SrcDescriptor[4].Large.XCount 			= DisplayWidth/2;
	SrcDescriptor[4].Large.YCount 			= DisplayHeight/2;
	SrcDescriptor[4].Large.YModify 			= (JPEGImageWidth - DisplayWidth)/2 + SrcDescriptor[4].Large.XModify;

	// destination U 2nd half
	DestDescriptor[4].Large.StartAddress 	= (void *)(pJPEGImageBuf + Field2Skip + ActiveVideoSkip + ITU_U_OFFSET + WidthOffset + HeightOffset);
	DestDescriptor[4].Large.XCount 			= DisplayWidth/2;
	DestDescriptor[4].Large.YCount 			= DisplayHeight/2;
	DestDescriptor[4].Large.YModify 		= (WidthOffset*2) + ActiveVideoSkip + DestDescriptor[4].Large.XModify; // twice width offset to account for U/V data

	// source V 2nd half
	SrcDescriptor[5].Large.StartAddress 	= (void *)(pYUVBuf + (JPEGImageWidth*JPEGImageHeight*5/4));
	SrcDescriptor[5].Large.XCount 			= DisplayWidth/2;
	SrcDescriptor[5].Large.YCount 			= DisplayHeight/2;
	SrcDescriptor[5].Large.YModify 			= (JPEGImageWidth - DisplayWidth)/2 + SrcDescriptor[5].Large.XModify;

	// destination V 2nd half
	DestDescriptor[5].Large.StartAddress 	= (void *)(pJPEGImageBuf + Field2Skip + ActiveVideoSkip + ITU_V_OFFSET + WidthOffset + HeightOffset);
	DestDescriptor[5].Large.XCount 			= DisplayWidth/2;
	DestDescriptor[5].Large.YCount 			= DisplayHeight/2;
	DestDescriptor[5].Large.YModify 		= (WidthOffset*2) + ActiveVideoSkip + DestDescriptor[5].Large.XModify; // twice width offset to account for U/V data

	// Enable callback for last Destination descriptor
	DestDescriptor[5].Large.CallbackFlag	= TRUE;
		
	return;
}


/*****/
