/**************************************************************
$Workfile:   bme_c_api.c  $
***************************************************************
***************************************************************
**							    												
**	Filename    : bme_c_api.c	  		    									
**	Description : c source file defining the middle tier functions
		      to access BME	 					
**	Author	    : Samir Palnitkar   									
**	Date	    : 9/12/2001				 								
**	Notes	    :		  	   		    										
**      References  : Programmer's reference manual
**	Revision History :
**							    												
****************************************************************/
/***************************************************************
**
** FIRMWARE, Copyright (C) 2000-2002
** Ikanos Communication, Fremont, CA
** All rights reserved.
**
** The information and contents of this file are the
** proprietary information of Ikanos Communication and may not
** be disclosed or used without the formal written approval of
** Ikanos Communication
**
***************************************************************
$Revision: 1.1 $
$Date: 2006/10/16 04:34:50 $
**************************************************************/

/* #includes */ 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "apiosmacro.h"

#include "membase_defines.h"
#include "pio_defines.h"

 
/*#include "misc.h"*/                                           
/* #include "bmelapi.h" */

/* _BME_TEST_CODE_ */
/* #include "test.h" */
/* */
/* Note : these #includes to be included later */

/*defines*/
#define MAX_DATA_SIZE 	10000
#define LARGE_NUMBER 	9999999
#define TOFT_SIZE 	4096
#define CDMT_SIZE 	4096
#define UINT32 	unsigned long
#define BYTE 	unsigned char
  
#define MAX_DMA_SIZE 256

/*global variables*/
BYTE data_list[MAX_DATA_SIZE];
BYTE DmaReadBuffer[MAX_DATA_SIZE];

static BYTE tempArrayIn[];
/* global functions */
extern void pio_read (UINT32 srcAddr, UINT32 *data);
extern void pio_write (UINT32 destAddr, UINT32 data);
extern void doDmaWrite(UINT32 destAddr, BYTE *dataPtr, UINT32 dataLen, int destFifoFlag); 
extern void doDmaRead (UINT32 srcAddr, UINT32 codeLen, BYTE * BmeCodeArrayPtr, int destFifoFlag);
extern int testPIORead (int BmeNum, unsigned long addr);
extern void testPIOWrite_diag (int BmeNum, unsigned long addr, unsigned long data);
extern void doDmaRead_diag (int, int, char *, int);
extern void iposDelay (void);
extern int fnum;


/****************************************************************/
/*This routine returns the data read by the pio_read routine
Same functionality as pio_read, but slightly different interface*/
UINT32 pio_read_return(UINT32 srcAddr){
UINT32 readData;
pio_read(srcAddr, &readData);
return readData;
}
/****************************************************************/
/*This routine check the data read by the pio_read routine
against the expected data provided. This routine is useful for looping*/
UINT32 pio_read_check(UINT32 srcAddr, UINT32 expectedData){
UINT32 readData;
pio_read(srcAddr, &readData);
if (readData != expectedData){
	printf("PIO_READ_CHECK FAILED: readData = %lx, expectedData = %lx\n",readData, expectedData);
    fnum++;
	return 0;
} else {
	return 1;
}

}
/****************************************************************/
void computePointers(UINT32 blockName, /*Identifies block type XFI_BLOCK, YFI_BLOCK, ZFI_BLOCK etc*/
		     UINT32 subBlockName, /*Name of sub block, eg for YFI, TOFT, CYFT_A, CYFT_B etc*/
		     UINT32 regA, UINT32 regB, UINT32 regC, /*input registers*/
		     UINT32 *read_ptr, UINT32 *write_ptr,
		     UINT32 *read_wrap, UINT32 *write_wrap, 
		     UINT32 *buffer_size){ 
	UINT32 regAValue, regBValue,regCValue; /*hold values of registers that are read from BME*/
		     
	if ((blockName == XFI_BLOCK) || (blockName == CFI_BLOCK)){	     
		/*read the registers that contain read/write ptr info*/
		pio_read(regA, &regAValue);
		pio_read(regB, &regBValue);
		/*printf ("\n *regAValue 0x%08lx",regAValue);
		printf ("\n *regBValue 0x%08lx",regBValue);
*/
		/*compute the read and write pointers for this block*/
		*read_ptr = (regBValue & 0x3fff); /*bits [13:0] of regB*/
		*read_wrap = (regBValue >> 14) & 0x1; /*bit 14 of regB*/
		*write_ptr = (regBValue >> 15) & 0x3fff; /*bit 28:15 of regB*/
		*write_wrap = (regBValue >> 29) & 0x1; /*bit 29 of regB*/
		*buffer_size = 128 << ((regAValue  >> 3) &0x7); /*shift 128 left by bits [5:3] of regAValue*/
		/*printf ("\n *write_ptr 0x%08lx",*write_ptr);*/

	} else if (blockName == YFI_BLOCK){
	if (subBlockName == TOFT){
		/*read the registers that contain read/write ptr info*/
		pio_read(regB, &regBValue);
		/*compute the read and write pointers for this block*/
		*read_ptr = (regBValue >> 3)  & 0xfff; /*bits [14:3] of regB*/
		*read_wrap = (regBValue >> 15) & 0x1; /*bit 15 of regB*/
		*write_ptr = (regBValue >> 16) & 0xfff; /*bit 27:16 of regB*/
		*write_wrap = (regBValue >> 28) & 0x1; /*bit 28 of regB*/
		*buffer_size = TOFT_SIZE; 
	} else {/*Interleave YFIFO*/
		/*read the registers that contain read/write ptr info*/
		pio_read(regA, &regAValue);
		pio_read(regA, &regBValue);                                
		pio_read(regC, &regCValue);
		/*compute the read and write pointers for this block*/
		*read_ptr = (regBValue & 0xffff); /*bits [15:0] of regB*/
		*write_ptr = (regBValue >> 16) & 0xffff; /*bit 31:16 of regB*/
		*read_wrap = (regCValue) & 0x1; /*bit 0 of regC*/
		*write_wrap = (regCValue >> 1) & 0x1; /*bit 1 of regC*/
		*buffer_size = 128 << ((regAValue  >> 3) &0xf); /*shift 128 left by bits [6:3] of regAValue*/						
	} /*end of inner if*/
	} else if (blockName == BFI_BLOCK){
	if (subBlockName == CDMT_D){
		/*read the registers that contain read/write ptr info*/
		pio_read(regB, &regAValue);
		/*compute the read and write pointers for this block*/
		*read_ptr = (regBValue >> 3)  & 0x1fff; /*bits [15:3] of regB*/
		*read_wrap = (regBValue >> 16) & 0x1; /*bit 16 of regB*/
		*write_ptr = (regBValue >> 17) & 0x1fff; /*bit 29:17 of regB*/
		*write_wrap = (regBValue >> 30) & 0x1; /*bit 30 of regB*/
		*buffer_size = CDMT_SIZE; 
	} else if ((subBlockName == CBFT_A_D) || (subBlockName == CBFT_B_D)){/*Fast BFIFO*/
		/*read the registers that contain read/write ptr info*/
		pio_read(regA, &regAValue);
		pio_read(regA, &regBValue);

		/*compute the read and write pointers for this block*/
		*read_ptr = (regBValue & 0x1fff); /*bits [12:0] of regB*/
		*read_wrap = (regBValue >> 13) & 0x1; /*bit 13 of regB*/
		*write_ptr = (regBValue >> 14) & 0x1fff; /*bit 26:14 of regB*/
		*write_wrap = (regBValue >> 27) & 0x1; /*bit 27 of regB*/
		*buffer_size = 128 << ((regAValue  >> 3) &0x7); /*shift 128 left by bits [5:3] of regAValue*/					
	} else { /*interleave BFIFO*/
		/*read the registers that contain read/write ptr info*/
		pio_read(regA, &regAValue);
		pio_read(regA, &regBValue);
		pio_read(regC, &regCValue);
		/*compute the read and write pointers for this block*/
		*read_ptr = (regBValue & 0xffff); /*bits [15:0] of regB*/
		*write_ptr = (regBValue >> 16) & 0xffff; /*bit 31:16 of regB*/
		*read_wrap = (regCValue) & 0x1; /*bit 0 of regC*/
		*write_wrap = (regCValue >> 1) & 0x1; /*bit 1 of regC*/
		*buffer_size = 128 << ((regAValue  >> 3) &0xf); /*shift 128 left by bits [6:3] of regAValue*/	
	}/*end of inner if*/
		
	} else if (blockName == ZFI_BLOCK){
		/*read the registers that contain read/write ptr info*/
		pio_read(regA, &regAValue);
		pio_read(regA, &regBValue);
		pio_read(regC, &regCValue);
		/*compute the read and write pointers for this block*/
		*read_ptr = (regBValue & 0x1ffff); /*bits [16:0] of regB*/
		*read_wrap = (regBValue >> 17) & 0x1; /*bit 17 of regB*/
		*write_ptr = (regBValue & 0x1ffff); /*bit 31:16 of regC*/
		*write_wrap = (regBValue >> 17) & 0x1; /*bit 17 of regC*/
		*buffer_size = 128 << ((regAValue  >> 3) &0xf); /*shift 128 left by bits [6:3] of regAValue*/							
	} else if (blockName == AFI_BLOCK){
		/*read the registers that contain read/write ptr info*/
		pio_read(regA, &regAValue);
		pio_read(regA, &regBValue);
		pio_read(regC, &regCValue);
		/*compute the read and write pointers for this block*/
		*read_ptr = (regBValue & 0x1ffff); /*bits [16:0] of regB*/
		*read_wrap = (regBValue >> 17) & 0x1; /*bit 17 of regB*/
		*write_ptr = (regBValue & 0x1ffff); /*bit 31:16 of regC*/
		*write_wrap = (regBValue >> 17) & 0x1; /*bit 17 of regC*/
		*buffer_size = 128 << ((regAValue  >> 3) &0xf); /*shift 128 left by bits [6:3] of regAValue*/							
	} else {
		printf("Encountered Unknown Block = %lx, SubBlock = %lx \n", blockName, subBlockName);
	}
} /*end of subroutine*/

/****************************************************************/

UINT32 compute_data_space(UINT32 read_ptr, UINT32 write_ptr,
			UINT32 read_wrap, UINT32 write_wrap, 
			UINT32 buffer_size, UINT32 compute_available_data /*=1 if the routine is looking for data filled*/
	
		){
	UINT32 available_data;
	UINT32 return_value;

        if( write_ptr == read_ptr )
            available_data = (read_wrap == write_wrap ? 0 : buffer_size);
        else if( write_ptr > read_ptr )
            available_data = write_ptr - read_ptr;
        else 
            available_data = buffer_size + write_ptr - read_ptr;

	return_value = (compute_available_data)? available_data:buffer_size - available_data;
	return (return_value);
}
        
/****************************************************************/
void wait_for_fifo_data (UINT32 blockName, /*Identifies block type
						XFI_BLOCK, YFI_BLOCK, ZFI_BLOCK etc*/
			UINT32 subBlockName, /*Name of sub block, eg for YFI, TOFT, CYFT_A, CYFT_B etc*/
			UINT32 regA, UINT32 regB, UINT32 regC,
			UINT32 dataSize, /*number of bytes to wait for*/
			UINT32 computeAvailableData /*1 means check for fullness of FIFO
						      0 means check for emptiness of FIFO*/
			) {
	
	UINT32 spaceOrData;
	UINT32 trueCondition;

	UINT32 read_ptr, write_ptr, read_wrap, write_wrap, buffer_size;
	int counter=0;

	spaceOrData = 0;
	trueCondition = (dataSize <= spaceOrData);

	while(!trueCondition){
		/*compute the pointers by reading the appropriate registers*/
		computePointers(blockName, subBlockName, 
				regA, regB, regC, 
				&read_ptr, &write_ptr, 
				&read_wrap, &write_wrap, 
				&buffer_size);

		/*printf ("\nprinting");*/

		/*compute the Space or Data, based on computeAvailableData variable*/
 		spaceOrData = compute_data_space(read_ptr, write_ptr, 
						read_wrap, write_wrap, 
						buffer_size, computeAvailableData);
		/*Is the condition satisfied, where emptiness or fullness of FIFO
		is greater than the desired number*/
		trueCondition = (dataSize <= spaceOrData);
		iposTaskDelay(1);
/*	counter++;

*/	if (counter>800) {trueCondition=TRUE; testPIORead (1, 0xe0040100); printf ("\nNo cell. timeout");exit(0);}

	} /*end of while loop*/


/* printf ("\n Found DMA full1"); */
		
}

/****************************************************************/
void read_bytes_to_buffer(
			UINT32 srcAddr, 
			int size, /*size in bytes*/
			int fifo_transaction, /*set to 1 if source is a fifo*/
			int channel_num /*set only if fifo_transaction bit is set to 1*/
			){
BYTE * list_of_bytes;
int i=0,loop=0;
UINT32 size2=0;

/*Figure out the address based on whether source is a FIFO*/
if(fifo_transaction == 1)
	srcAddr = srcAddr + channel_num;
/*no else, because otherwise, channel_num is irrelevant*/

list_of_bytes=DmaReadBuffer; 

/*Call the DMA routine*/
loop=(int)((size-1)/MAX_DMA_SIZE)+1;

for (i=0;i<loop;i++)
	{
	if (i>0) srcAddr+=MAX_DMA_SIZE;

	if (i==(loop-1)) size2=size-((loop-1)*MAX_DMA_SIZE);
	else size2=MAX_DMA_SIZE;

	if (i>0) list_of_bytes+=(MAX_DMA_SIZE);
	doDmaRead_diag (srcAddr, size2, list_of_bytes,fifo_transaction);

	}

/*printf ("\nDmaReadBuffer[0] %x\n",DmaReadBuffer[0]);*/

/* Reset buffer */
list_of_bytes=DmaReadBuffer;

} /*end of subroutine*/


