/**************************************************************
***************************************************************
**
** C-SIMULATION, 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 $
**************************************************************/

/*******  Include Files         ***************************************/
#include "stdio.h"

#include "bme.h"
#include "bme_app.h"
#include "mem.h"
#include "afe.h" 
#include "hostType.h" 
 
#define INVALID_GAIN    0x7d

// dont know if we need [4] here or not
// i.e., one for each AFE
static AFE_DATABASE	afeDataBase [NUM_AFE_REGISTERS] = {
	{0x20, TRUE,	0},				// 1	
	{0x21, TRUE,	0},				// 2
	{0x22, TRUE,	0},				// 3
	{0x23, TRUE,	0},				// 4
	{0x24, TRUE,	0},				// 5
	{0x25, TRUE,	0},				// 6
	{0x26, TRUE,	0},				// 7
	{0x29, TRUE,	0},				// 8
	{0x2D, TRUE,	0},				// 9
	{0x30, TRUE,	0xC000},		// 10
	{0x31, FALSE,	0},				// 11
	{0x32, TRUE,	0xC000},		// 12
	{0x33, FALSE,	0},				// 13
	{0x34, TRUE,	0},				// 14
	{0x36, TRUE,	0},				// 15
	{0x3F, FALSE,	0x810},			// 16
	{0x70, TRUE,	0},				// 17
	{0x72, FALSE,	0},				// 18
	{0x7A, TRUE,	0},				// 19
	{0x7C, TRUE,	0},				// 20
	{0x86, TRUE,	0x700C},		// 21
	{0x87, TRUE,	0x700C},		// 22
	{0x88, TRUE,	0x300C},		// 23
	{0x89, TRUE,	0x300C},		// 24
	{0x8A, TRUE,	0x0001},		// 25
	{0x90, TRUE,	0},				// 26
	{0x91, TRUE,	0},				// 27
	{0x92, TRUE,	0},				// 28
	{0x93, TRUE,	0},				// 29
	{0xA0, FALSE,	0},				// 30
	{0xA1, FALSE,	0},				// 31
	{0xA2, FALSE,	0},				// 32
	{0xA3, FALSE,	0},				// 33
	{0xA8, TRUE,	0},				// 34
	{0xA9, TRUE,	0},				// 35
	{0xF0, TRUE,	0},				// 36
	{0xF1, TRUE,	0},				// 37
};

extern char capTest;
		
/*
************************************************************************
	Function: initAFE
	
	Description: init the AFE registers with defaults..
		
	Return Value: 
************************************************************************
*/
 	
void setAFE_filter_coeff(u16 *address_array, u16 *coef_array, int num_coefs, int afe_index, FILTER_COEF_TYPE coef_type)
{
	u16	readCoef;
	int	i;
	int	val_address;
	int caddr;
	int	mask=0;
	int    j;	
	for(i=0;i<num_coefs;i++) {

		switch(coef_type) {

 
			case TX_FILTER_COEF:
		   		val_address = afeDataBase[TXCOEF].address;
				mask = 0xfff;
				break;
			case RX_FILTER_COEF:
				val_address = afeDataBase[RXCOEF].address;
				mask = 0x3fff;
				break;
			case RFI_FILTER_COEF:
				val_address = afeDataBase[RFCOEF].address;
				break;
			default:
				logMsg("\n unknown coeff array type");
				return;		

		}
		
		caddr = CADDR;

		j = 0;
		while(1) {			
			afeWriteRegister(afeDataBase[caddr].address, afe_index, address_array[i]);				
			afeWriteRegister(val_address, afe_index, coef_array[i]);
            		iposDelay();		
			afeWriteRegister(afeDataBase[caddr].address, afe_index, address_array[i]);	
			readCoef = (u16)afeReadRegister(val_address, afe_index);
			if((readCoef&mask) == (coef_array[i]&mask))
				break;
			j++;
			if(j>0x5000) {
				logMsg("\n Wrong coef for index = %d", i);
				break;
			}
		}	
	}
}

void set_tx_filter(int afe_index, LOCATION loc, BAND_PLANS bandplan)
{

	u16 addr_array_ch_1[32] = {0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
							   0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f};
	
	u16 addr_array_ch_2[32] = {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
							   0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f};

	// 4096 IFFT & 4khz
	int	num_coef = 20;
	
	u16	coef_array_mxu_up[20] =   {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0fff, 0x0003, 0x0ffa, 0x000b, 0x0fec, 0x0022, 0x0fc9, 0x0057, 0x0f77, 0x00df, 0x0e65, 0x050f, 0x07ff };
	u16 coef_array_mxu_down[20] = {0x001a, 0x0ff4, 0x000f, 0x0fee, 0x0015, 0x0fe6, 0x001f, 0x0fdc, 0x002b, 0x0fcd, 0x003c, 0x0fb8, 0x0057, 0x0f95, 0x0088, 0x0f4d, 0x0100, 0x0e51, 0x0516, 0x07ff }; 
		
	u16 *coef_array[MAX_BANDPLAN][2] = {
		{coef_array_mxu_up, coef_array_mxu_down},
		{NULL, NULL}
	};

	setAFE_filter_coeff(addr_array_ch_1, coef_array[bandplan][loc], num_coef, afe_index, TX_FILTER_COEF);
	setAFE_filter_coeff(addr_array_ch_2, coef_array[bandplan][loc], num_coef, afe_index, TX_FILTER_COEF);
}

void set_rx_filter(int afe_index, LOCATION loc, BAND_PLANS bandplan)
{

	u16 addr_array_ch_1[16] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
	u16 addr_array_ch_2[16] = {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f};

	int	num_coef = 16;

	u16 coef_array_mxu_down[16] = {0x3efe, 0x0234, 0x044a, 0x0285, 0x3eb5, 0x3e9a, 0x01ca, 0x01ab, 0x3dc0, 0x3dcd, 0x0312, 0x034c, 0x3b37, 0x39d2, 0x0af5, 0x1fff }; 
	u16	coef_array_mxu_up[16] =   {0x3ffe, 0x0002, 0x0011, 0x0001, 0x3fc5, 0x3fed, 0x0095, 0x004d, 0x3ec5, 0x3f28, 0x0260, 0x020f, 0x3b71, 0x3ac1, 0x0b5e, 0x1fff }; 

	u16 *coef_array[MAX_BANDPLAN][2] = {
		{coef_array_mxu_up, coef_array_mxu_down},
		{NULL, NULL}
	};


	setAFE_filter_coeff(addr_array_ch_1, coef_array[bandplan][loc], num_coef, afe_index, RX_FILTER_COEF);
	setAFE_filter_coeff(addr_array_ch_2, coef_array[bandplan][loc], num_coef, afe_index, RX_FILTER_COEF);
}

void set_rfi_filter(int afe_index, LOCATION loc, BAND_PLANS bandplan)
{
	u16 addr_array_ch_1[8] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7};
	u16 addr_array_ch_2[8] = {0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
		
	int	num_coef = 8;

	u16 coef_array_mxu_down[8] = {0x8, 0xaf5, 0x755, 0xf951, 0xee73, 0xfec4, 0x2b32, 0x5333};
	u16	coef_array_mxu_up[8] = {0xf1e0,0xdbdd,0x1430,0x0c11,0xef65,0xe560,0x29d9,0x7fff};	


	u16 *coef_array[MAX_BANDPLAN][2] = {
		{coef_array_mxu_up, coef_array_mxu_down},
		{NULL, NULL}
	};

	setAFE_filter_coeff(addr_array_ch_1, coef_array[bandplan][loc], num_coef, afe_index, RFI_FILTER_COEF);
	setAFE_filter_coeff(addr_array_ch_2, coef_array[bandplan][loc], num_coef, afe_index, RFI_FILTER_COEF);

}

void turn_on_afe(int AFE_index, int chan_num)
{
	int index;

	index = (chan_num == 1?  AFE_VCH0: AFE_VCH1);	

	afeWriteRegister(afeDataBase[index].address, AFE_index, 0x0);

}

#define HFE_GAIN_MASK   0x1ff

int read_afe_pwr(int afe_index, int chan_num)
{

	int	reg_index;
	int	data;
		 	
	if(chan_num<1 && chan_num>2) {
        logMsg("\n wrong channel number");
        return -1;
    }

	reg_index = (chan_num == 1?  PMC1CH0:PMC1CH1);
	data = afeReadRegister(afeDataBase[reg_index].address, afe_index);
    return data; 
}

void calibrate_afe(int afe_index, int chan_num)
{
	int cal_status;
	int cal_status_addr;
	int status_mask;
	int	cal_code;

	// AFE_2
	if(chan_num == 1){
		status_mask = 0x10;
		cal_code = 0x01;
	} else
	{
		status_mask = 0x20;
		cal_code = 0x02;
	}

	afeWriteRegister(afeDataBase[CAL_CREG].address, afe_index, 0x10); 
    iposDelay();
    afeWriteRegister(afeDataBase[CAL_CREG].address, afe_index, cal_code); 
    iposDelay();
	afeWriteRegister(afeDataBase[CAL_CREG].address, afe_index, 0x10); 

	cal_status_addr = CAL_SREG;	

	while(1) {
		cal_status = afeReadRegister(afeDataBase[cal_status_addr].address, afe_index);
		if(cal_status & status_mask) {
            if (!capTest) {
                logMsg("\n AFE # %d, chan = %d ADC cal done", afe_index,chan_num);
            }
			break;
		}
	}
	


	return;
}


void check_ADC_status(int afe_index, int ch)
{

	int status_addr;
	int status;

	status_addr = (ch == 1)? VCH0ST : VCH1ST;
	
	status = afeReadRegister(afeDataBase[status_addr].address, afe_index);
    if (!capTest) {
        if(status & BIT0) {
                logMsg("\n AFE # %d, chan = %d ADC Overflow!", afe_index,ch);
        }

        if(status & BIT1) {
                logMsg("\n AFE # %d, chan = %d ADC Underflow!", afe_index,ch);
        }
    }
}

void set_fifo(int afe_index, int ch)
{

	int addr;
	int data;

	int rx_ptr = 0x300;			// bit[9:0]
	int rx_set = 1;				// bit[12]
	int rx_adv = 0;				// bit[14]
	int tx_ptr = 0x100;			// bit[25:16]		
	int tx_set = 1;				// bit[28]
	int tx_adv = 0;				// bit[30]
	
	addr = (ch == 1)? FIFOCH0 : FIFOCH1;

	data = rx_ptr + (rx_set << 12) + (rx_adv << 14) + (tx_ptr << 16) + (tx_set << 28) + (tx_adv << 30); 

	afeWriteRegister(afeDataBase[addr].address, afe_index, data);

}

void set_rfi_registers(int afe_index, int ch)
{
	int addr;
	int data=0;

	addr = (ch == 1)? RFI_CH0 : RFI_CH1;

#ifdef BY_PASS
	data = 0;
#endif

	afeWriteRegister(afeDataBase[addr].address, afe_index, data);
}

void set_tx_registers(int afe_index, int ch)
{
	int addr;
	int data;
	int rate;		// bit[15:14]
	int radix;		// bit[12:10]
	int turn_on;	// bit[8]

	addr = (ch == 1)? VTXCH0 : VTXCH1;

	rate = 1;		// 4 
	radix = 7;		// 14 LSB
	turn_on = 1;
	data =  (rate<<14) + ( radix<<10) + (turn_on << 8);

	afeWriteRegister(afeDataBase[addr].address, afe_index, data);
}

void set_rx_registers(int afe_index, int ch)
{
	int addr;
	int data;
	int rate;		// bit[6:5]
	int radix;		// bit[2:0]
	int turn_on;	// bit[7]
	int service_type;

	addr = (ch == 1)? VRXCH0 : VRXCH1;

	service_type = 0;
	rate = 0;		// 2
	radix = 3;
	turn_on = 1;
	data = (rate << 5) + radix + (turn_on << 7) + (service_type<<15);

	afeWriteRegister(afeDataBase[addr].address, afe_index, data);
}

void set_pwr_registers(int afe_index, int ch)
{
	int addr;
	int data;
	int enable_dec_out;		// bit[7]
	int enable_adc_out;		// bit[6]
	int interval_dec_out;	// bit[3:2]
	int interval_adc_out;	// bit[1:0]

	addr = (ch == 1)? INTEG0 : INTEG1;

	enable_dec_out = 1;
	enable_adc_out = 1;

	interval_dec_out = 3; // 2048*4 samples
	interval_adc_out = 3; // 2048*4 samples

	data = (enable_dec_out << 7)  + (enable_adc_out << 6) + (interval_dec_out << 2) + interval_adc_out;

	afeWriteRegister(afeDataBase[addr].address, afe_index, data);
}

void config_afe(int AFE_index, int chan_num, LOCATION loc, BAND_PLANS bandplan)
{
	calibrate_afe(AFE_index, chan_num);

	// check ADC overflow status
	check_ADC_status(AFE_index, chan_num);

	// program fifo control registers
	set_fifo(AFE_index, chan_num);

	// set rfi registers
	set_rfi_registers(AFE_index, chan_num);
		
	// set interpolator registers
	set_tx_registers(AFE_index, chan_num);

	// set decimator registers
	set_rx_registers(AFE_index, chan_num);

	// set power measurement registers
	set_pwr_registers(AFE_index, chan_num);
}

void initVDSL_AFE2(int AFE_index, int chan_num, LOCATION loc, BAND_PLANS bandplan)
{
	
	// set DCXO to central frequency
	afeWriteRegister(afeDataBase[DCXO].address, AFE_index, 0x00);

	// Retune IFE0/IFE1
	afeWriteRegister(afeDataBase[IFE0_RETUNE_CNTL].address, AFE_index, 0x1);
	afeWriteRegister(afeDataBase[IFE1_RETUNE_CNTL].address, AFE_index, 0x1);

	afeWriteRegister(afeDataBase[IFE0_RETUNE_CNTL].address, AFE_index, 0x0);
	afeWriteRegister(afeDataBase[IFE1_RETUNE_CNTL].address, AFE_index, 0x0);

	// Program IFE0/IFE1 gain control registers
	// ifeGainControl(AFE_index, chan_num);

	// Program AFE global registers
	afeWriteRegister(afeDataBase[GBLCTR].address, AFE_index, 0x1);
	afeWriteRegister(afeDataBase[VDSLBG].address, AFE_index, 0x0);
	afeWriteRegister(afeDataBase[VBIAS].address, AFE_index, 0x0);

	// set filter coeff's
	set_tx_filter(AFE_index, loc, bandplan);
	set_rx_filter(AFE_index, loc, bandplan);
//	set_rfi_filter(AFE_index, loc, bandplan);

	// power up ADC/DAC
	turn_on_afe(AFE_index, 1);
	turn_on_afe(AFE_index, 2);

	// ADC calibration
	calibrate_afe(AFE_index, chan_num);

    // check ADC overflow status
	check_ADC_status(AFE_index, chan_num);

	// program fifo control registers
	set_fifo(AFE_index, chan_num);

	// set rfi registers
	set_rfi_registers(AFE_index, chan_num);
		
	// set interpolator registers
	set_tx_registers(AFE_index, chan_num);

	// set decimator registers
	set_rx_registers(AFE_index, chan_num);

	// set power measurement registers
	set_pwr_registers(AFE_index, chan_num);
}

int write_ife_vga_gain(int hfe_index, int chan_num, VGA_GAINS gain_val)
{
	int		addr;
	int		curr_val;
	int		final_val;
	int		new_vga_gain;
	int		status;
	int		mask;
	int		vga_gain_array[8] = {0, 1, 2, 3, 4, 5, 6, 7};
	
	if(gain_val>7) {
		logMsg("\n bad ife vga gain %d", gain_val);
		return(0);
	}
		
	new_vga_gain = vga_gain_array[gain_val];
	addr = (chan_num == 1)? IFE_GCH00 : IFE_GCH10;
	curr_val = afeReadRegister(afeDataBase[addr].address, hfe_index);
	mask = (chan_num == 1)? (1<<1) : (1<<17);
	while(1) {
		status = afeReadRegister(afeDataBase[IFE_XFER_STATUS].address, hfe_index);		
		if(status&mask)
			break;
		logMsg("\n VGA: waiting for IFE_GCH00 read valid bit: 0x%x", status);
	}	
	curr_val = afeReadRegister(afeDataBase[addr].address, hfe_index);
	final_val = (curr_val & 0xfff0ffff) | ((new_vga_gain&0xf)<<16);
	afeWriteRegister(afeDataBase[addr].address, hfe_index, final_val);
	return(1);
	
}

int write_ife_pga_1_gain(int hfe_index, int chan_num, PGA_1_GAINS gain_val)
{
	int		addr;
	int		curr_val;
	int		final_val;
	int		status;
	int		new_pga1_gain;
	int		mask;
	int		pga_1_gain_array[18] = {0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x11, 0x12, 0x13, 0x15, 0x16, 0x17, 0x19, 0x1a, 0x1b, 0x1d, 0x1e, 0x1f};
	
	if(gain_val>18) {
		logMsg("\n bad ife pga1 gain %d", gain_val);
		return(0);
	}
	
	new_pga1_gain =  pga_1_gain_array[gain_val];
	addr = (chan_num == 1)? IFE_GCH00 : IFE_GCH10;
	mask = (chan_num == 1)? (1<<1) : (1<<17);
	curr_val = afeReadRegister(afeDataBase[addr].address, hfe_index);
	while(1) {
		status = afeReadRegister(afeDataBase[IFE_XFER_STATUS].address, hfe_index);		
		if(status&mask)
			break;
		logMsg("\n PGA1: waiting for IFE_GCH00 read valid bit: 0x%x", status);
	}	
	curr_val = afeReadRegister(afeDataBase[addr].address, hfe_index);	
	
	mask = (chan_num == 1)? 1: (1<<16);
	final_val = (0xe0ffffff&curr_val) | ((new_pga1_gain&0x1f)<<24);
	afeWriteRegister(afeDataBase[addr].address, hfe_index, final_val);
	while(1) {
	   	status = afeReadRegister(afeDataBase[IFE_XFER_STATUS].address, hfe_index);
		if(status&mask)
			break;	
		logMsg("\nPGA1: waiting for IFE_GCH00 write valid bit: 0x%x", status);		
	}
	// logMsg("\n pg1 gain = 0x%x", new_pga1_gain);	
	return(1);
}

int write_ife_pga_2_gain(int hfe_index, int chan_num, PGA_2_GAINS gain_val)
{
	int		addr;
	int		curr_val;
	int		final_val;
	int		new_pga2_gain;
	int		status;
	int		mask;
	int		pga_2_gain_array[3] = {0, 1, 2};
	
	if(gain_val>2) {
		logMsg("\n bad ife pga2 gain %d", gain_val);
		return(0);
	}
	
	new_pga2_gain =  pga_2_gain_array[gain_val];
	addr = (chan_num == 1)? IFE_GCH00 : IFE_GCH10;
	curr_val = afeReadRegister(afeDataBase[addr].address, hfe_index);
	mask = (chan_num == 1)? (1<<1) : (1<<17);
	while(1) {
		status = afeReadRegister(afeDataBase[IFE_XFER_STATUS].address, hfe_index);		
		if(status&mask)
			break;
		logMsg("\n PGA2: waiting for IFE_GCH00 read valid bit: 0x%x", status);
	}	
	curr_val = afeReadRegister(afeDataBase[addr].address, hfe_index);	

	final_val = (0x9fffffff&curr_val) | ((new_pga2_gain&0x3)<<29);
	afeWriteRegister(afeDataBase[addr].address, hfe_index, final_val);
	mask = (chan_num == 1)? 1: (1<<16);
	while(1) {
	   	status = afeReadRegister(afeDataBase[IFE_XFER_STATUS].address, hfe_index);		
		if(status&mask)
			break;	
		logMsg("\nPGA2: waiting for IFE_GCH00 write valid bit: 0x%x", status);
	}
	// logMsg("\n pg2 gain = 0x%x", new_pga2_gain);
	return(1);
}
