#include <stdio.h>
#include <stdlib.h>
#include <string.h>                                    
                                                                 
#include "bme.h"                     
#include "bme_app.h"
#include "mem.h"
#include "initASICHardware.h"
#include "sdram_map.h"
#include "vdsl_ch.h"
#include "framercpu.h"
#include "drvUtils.h" 
#include "xdsl_fmc.h"                                                                  
#include "afe.h"
#include "bme_dma.h"                                           
#include "bmeConfig.h"
#include "hostType.h"

#define CKM_CCR           0xe0070004     

#define CPE_ENABLED  1 
#define CO_ENABLED   1 
#define USE_ALL_VBUS_CHAN 1

SDRAM_MAP 		*sdram_map = (SDRAM_MAP *)(SDRAM_BASE_ADDR);
int				is_init_gain_table_written = 0;
int				isLoadFeqCgFromFile = 0;
int				write_q_mode = BUFFERED_WRITE;
#if CPU == PPC860 
int				host_mode_flag = 1;
#else
int				host_mode_flag = 0;
#endif
XDSL_LINE 		line[NUM_VDSL_CHANNELS];
FrmTxStatus_t 	*frm_status[4];
DMA_STATUS		dma_status = DMA_DONE;
int				curr_dma_chan = -1;
u16				CycExtnSize	= 0;
int             tot_dma_out_standing = 0;
int				is_sdram_mem_alloced = 0;
int				clk_val;
int				host_dma_delay = 0;
int				common_clk = 0;
short			timeData[4096];
short			a_data[4096*8];
int             tune_test = 0;
char            afelb;

extern int num1, num2;
extern char capTest;

static int		is_system_init = 0;
static int		afe_init[2][3] = 
{
	{0, 0, 0},
	{0, 0, 0}
};

extern void initVDSL_AFE2(int AFE_index, int chan_num, LOCATION loc, BAND_PLANS bandplan);
extern void config_afe(int AFE_index, int chan_num, LOCATION loc, BAND_PLANS bandplan);
extern void disable_clk_recv(XDSL_LINE *curr_line);

void init_with_ce(int ce_enable, LOCATION loc, BAND_PLANS bandplan, int vbus_chan, int afe_num, int afe_chan);

void init_xta(LOCATION loc, BAND_PLANS bandplan, int vbus_chan, int afe_num, int afe_chan)
{	
    int ce_enable;

  	ce_enable = 1;
	//@@@	ce_enable = 0;	// vsu

	// logMsg("\n reset bme hw");
	// bmeHWReset();
    init_with_ce(ce_enable, loc, bandplan, vbus_chan, afe_num, afe_chan); 
} 

void init_with_ce(int ce_enable, LOCATION loc, BAND_PLANS bandplan, int vbus_chan, int afe_num, int afe_chan)
{	
    u32 tmp, tmp1;


	if(!is_system_init) {	
		is_system_init = 1;

		if(!is_sdram_mem_alloced) {
			sdram_map = (SDRAM_MAP *)malloc(sizeof(SDRAM_MAP));
			if(sdram_map == NULL) {
				printf("\n cannot allocate sdram map in init()");
				exit(1);
			}
			is_sdram_mem_alloced = 1;
		}

		write_q_mode = DIRECT_WRITE_CMD_Q;	

		if(host_mode_flag);
			initHostIO(2, BME_BASE_ADDR);
		writePIO_SingleRegChannel ((int *)0xe0070008, 0x0, 0x0000012f);
            iposDelay();	
    	if(ce_enable) {
       		tmp = readPIO_SingleRegChannel((int *)CKM_CCR,0);
       		tmp1= (tmp&0xfc000000) + 0x04000000 + (552<<16) + (tmp&0xE001)+ (0x0<<1); //(0xcc0<<1);
       		writePIO_SingleRegChannel((int *)CKM_CCR, 0, tmp1); 
    	} else {
		tmp = readPIO_SingleRegChannel((int *)CKM_CCR,0);
       		tmp1= (tmp&0xfc000000) + 0x04000000 + (512<<16) + (tmp&0xE001)+(0xcc0<<1);
       		writePIO_SingleRegChannel((int *)CKM_CCR, 0, tmp1);
	}
	
		clk_val = readPIO_SingleRegChannel((int *)CKM_CCR,0);

#ifdef USE_ALL_VBUS_CHAN  
			init_vbus_all_chan_4k(ce_enable);	
			if(!ce_enable) {
				set_zero_ce();	
			}
#else	// new or old vbus init routines
			if(ce_enable) {
        		init_VBUS(ce_enable, vbus_chan, afe_num, afe_chan);
				set_non_zero_ce();
    		} else { 
        		init_VBUS_no_ce(0);
				set_zero_ce();
    		}
#endif		
	
		initASICHardware();
		initVDSL_AFE2(afe_num, afe_chan, loc, bandplan);
		afe_init[afe_num][afe_chan] = 1;
		initCpuCmdQ();
		downloaddmc(0);
    		downloadfmc(0);
    		downloadrmc(0);						
	
		if(write_q_mode == BUFFERED_WRITE)
			initCircBuffers();
		RxCpuInit();
	}
 
	if(!afe_init[afe_num][afe_chan]) {
		afe_init[afe_num][afe_chan] = 1;	
		config_afe(afe_num, afe_chan, loc, bandplan);		
	}
}

void proc_str(char *str)
{
	int i;
	
	for(i=0;i<strlen(str);i++) {
		if(str[i] == 0x0A||str[i]==0x0D)
			str[i] = '\0';
	}
}

int get_cfg(VDSL_CFG *vdsl_cfg, char *cfg_file)
{
	FILE	*fpin=0;
#ifdef VTU_O
	vdsl_cfg->loc = (BAND_PLANS)1;
#else
	vdsl_cfg->loc = (BAND_PLANS)0;
#endif
	vdsl_cfg->bandplan = (BAND_PLANS)0;
	vdsl_cfg->rx_vbus_chan_num = num1;
	vdsl_cfg->rx_afe_chan_num = 1;
	vdsl_cfg->rx_afe_chip_index = num1;
	fgets(vdsl_cfg->tx_showtime_param_file, 100, fpin);	
	proc_str(vdsl_cfg->tx_showtime_param_file);
	fgets(vdsl_cfg->tx_showtime_param_sem_file, 100, fpin);
	proc_str(vdsl_cfg->tx_showtime_param_sem_file);
	fgets(vdsl_cfg->tx_showtime_sem_file, 100, fpin);
	proc_str(vdsl_cfg->tx_showtime_sem_file);

#ifdef VTU_O
	vdsl_cfg->tx_pilot_tone = 70;
	vdsl_cfg->zbuf_offset = 0;
#else
	vdsl_cfg->tx_pilot_tone = 900;
	vdsl_cfg->zbuf_offset = 1400;
#endif
    fgets(vdsl_cfg->rx_showtime_param_file, 100, fpin);
	proc_str(vdsl_cfg->rx_showtime_param_file);
	fgets(vdsl_cfg->rx_showtime_param_sem_file, 100, fpin);
	proc_str(vdsl_cfg->rx_showtime_param_sem_file);
	fgets(vdsl_cfg->rx_showtime_sem_file, 100, fpin);
	proc_str(vdsl_cfg->rx_showtime_sem_file);
#ifdef VTU_O
	vdsl_cfg->num_rx_bands = 1;
	vdsl_cfg->rx_pilot_tone = 0x384;
	vdsl_cfg->noise_band_start = 0x708;
#else
	vdsl_cfg->num_rx_bands = 2;
	vdsl_cfg->rx_pilot_tone = 70;
	vdsl_cfg->noise_band_start = 1900;
#endif
	fgets(vdsl_cfg->rx_perf_dir, 100, fpin);
	proc_str(vdsl_cfg->rx_perf_dir);
	//get noise margin
	vdsl_cfg->noise_margin = 0x400;
	//get coding gain
	vdsl_cfg->coding_gain = 0x200;
	fclose(fpin);	
	// hard coded value for now
	if(vdsl_cfg->loc == DOWNSTREAM) {
		vdsl_cfg->tx_ptone_scr_on = 0;
		vdsl_cfg->rx_ptone_scr_on = 1;
	} else
	{
		vdsl_cfg->tx_ptone_scr_on = 1;
		vdsl_cfg->rx_ptone_scr_on = 0;
	}
	
	strcpy(vdsl_cfg->cpe_tx_medley_start_file_sem, "/tgtsvr/sync_dir/cpe_tx_medley_start.txt");
	strcpy(vdsl_cfg->cpe_tx_medley_start_done_file_sem, "/tgtsvr/sync_dir/cpe_tx_medley_start_done.txt");
	strcpy(vdsl_cfg->co_rx_medley_start_file_sem, vdsl_cfg->cpe_tx_medley_start_file_sem);
	strcpy(vdsl_cfg->co_rx_medley_start_done_file_sem, vdsl_cfg->cpe_tx_medley_start_done_file_sem);
	strcpy(vdsl_cfg->co_tx_medley_start_file_sem,  "/tgtsvr/sync_dir/co_tx_medley_start.txt");
	strcpy(vdsl_cfg->co_tx_medley_start_done_file_sem, "/tgtsvr/sync_dir/co_tx_medley_start_done.txt");
	strcpy(vdsl_cfg->cpe_rx_medley_start_file_sem, vdsl_cfg->co_tx_medley_start_file_sem);
	strcpy(vdsl_cfg->cpe_rx_medley_start_done_file_sem, vdsl_cfg->co_tx_medley_start_done_file_sem);
	strcpy(vdsl_cfg->co_rx_start_file_sem, "/tgtsvr/sync_dir/co_rx_start_file_sem.txt");
	strcpy(vdsl_cfg->cpe_tx_start_file_sem,  vdsl_cfg->co_rx_start_file_sem);

    if (tune_test == 1) {       /* single tone test */
        vdsl_cfg->num_tx_bands = 1;
        vdsl_cfg->tx_band_start[0] = 64;
        vdsl_cfg->tx_band_stop[0] = 64;
        vdsl_cfg->tx_pilot_tone = 4095;
    }
    else if (tune_test == 2) {  /* missing tone test */
        vdsl_cfg->num_tx_bands = 2;
        vdsl_cfg->tx_band_start[0] = 0x20;
        vdsl_cfg->tx_band_stop[0] = 0x12c;
        vdsl_cfg->tx_band_start[1] = 0x1f4;
        vdsl_cfg->tx_band_stop[1] = 0x364;
    }
    else {                      /* original setting */
        vdsl_cfg->num_tx_bands = 2;
        vdsl_cfg->tx_band_start[0] = 0x20;
        vdsl_cfg->tx_band_stop[0] = 0x364;
        vdsl_cfg->tx_band_start[1] = 0x4b4;
        vdsl_cfg->tx_band_stop[1] = 0x754;
    }
	
    if (!capTest) {
        printf("vdsl_cfg->loc = %x\n", vdsl_cfg->loc);
        printf("vdsl_cfg->bandplan = %x\n", vdsl_cfg->bandplan);
        printf("vdsl_cfg->rx_vbus_chan_num = %x\n", vdsl_cfg->rx_vbus_chan_num);
        printf("vdsl_cfg->rx_afe_chan_num = %x\n", vdsl_cfg->rx_afe_chan_num);
        printf("vdsl_cfg->rx_afe_chip_index = %x\n", vdsl_cfg->rx_afe_chip_index);
        printf("vdsl_cfg->tx_band_start[0] = %x\n",  vdsl_cfg->tx_band_start[0]);
        printf("vdsl_cfg->tx_band_stop[0] = %x\n", vdsl_cfg->tx_band_stop[0]);
        printf("vdsl_cfg->tx_band_start[1] = %x\n", vdsl_cfg->tx_band_start[1]);
        printf("vdsl_cfg->tx_band_stop[1] = %x\n", vdsl_cfg->tx_band_stop[1]);
        printf("vdsl_cfg->tx_pilot_tone = %x\n", vdsl_cfg->tx_pilot_tone);
        printf("vdsl_cfg->zbuf_offset = %x\n", vdsl_cfg->zbuf_offset);
        printf("vdsl_cfg->num_rx_bands = %x\n", vdsl_cfg->num_rx_bands);
        printf("vdsl_cfg->rx_pilot_tone = %x\n", vdsl_cfg->rx_pilot_tone);
        printf("vdsl_cfg->noise_band_start = %x\n", vdsl_cfg->noise_band_start);
        printf("vdsl_cfg->noise_margin = %x\n", vdsl_cfg->noise_margin);
        printf("vdsl_cfg->coding_gain = %x\n", vdsl_cfg->coding_gain);
    }
	return 1;
}

void co_tx(int line_num, int ce_enable, int periodic_data)
{
	char		cfg_file[100]= "/tgtsvr/co_cfg.txt";

	if(periodic_data)
		send_periodicData();
	tx_dmt(line_num, cfg_file, ce_enable); 
}

void cpe_tx(int line_num, int ce_enable, int periodic_data)
{
	char		cfg_file[100]= "/tgtsvr/cpe_cfg.txt";	

	if(periodic_data)
		send_periodicData();

	tx_dmt(line_num, cfg_file, ce_enable); 
}

void tx_dmt(int line_num, char *cfg_file, int ce_enable)
{
	VDSL_CFG	vdsl_cfg;
	int	 pkt_pfx_word; 
	
	if(get_cfg(&vdsl_cfg, cfg_file) == 0) {
		printf("\n cannot obtain cfg file %s", cfg_file);
		return;
	}
 
	init_with_ce(ce_enable, vdsl_cfg.loc, vdsl_cfg.bandplan, vdsl_cfg.rx_vbus_chan_num, vdsl_cfg.rx_afe_chip_index, vdsl_cfg.rx_afe_chan_num);	
	disable_clk_recv(line+line_num);
	init_ch_tx(line, line_num, vdsl_cfg.loc, &vdsl_cfg);
	write_ife_vga_gain(vdsl_cfg.rx_afe_chip_index, vdsl_cfg.rx_afe_chan_num, VGA_0db);
	if (ce_enable) 
		pkt_pfx_word = ((line_num << 8) | 0x04);
	else 
		pkt_pfx_word = ((line_num << 8) | 0x00);

    writePIO_short((short *)(ADDRESS_FRAMER_DCACHE_PIO + 0x024c + 4), pkt_pfx_word);

	// init_ch_rx(line, line_num, vdsl_cfg.loc, &vdsl_cfg);
	line[line_num].showtime_init_mode = 0;
	enable_tx(line_num);
	do_tx(line+line_num);
}

void rx_td_capture(int line_num, char *cfg_file, int no_ce) 
{
	VDSL_CFG	vdsl_cfg;
	int	 	ce_enable; 
	
	if(get_cfg(&vdsl_cfg, cfg_file) == 0) {
		printf("\n cannot obtain cfg file %s", cfg_file);
		return;
	}

	ce_enable = 1; 
	init_with_ce(ce_enable, vdsl_cfg.loc, vdsl_cfg.bandplan, vdsl_cfg.rx_vbus_chan_num, vdsl_cfg.rx_afe_chip_index, vdsl_cfg.rx_afe_chan_num);	

}

void capture_a_fifo(int chanNum, int duration, int no_ce)
{
	u8 *a_buf;
    int j,temp;
    signed short *sptr;

	a_buf = (u8 *) sdram_map->tx_bit_tone_table;
	writePIO_SingleRegChannel((int *)(CAFT_A), chanNum, 0x55);  /* configure for max size 128 k */
	capture_Abuf(a_buf, chanNum, 2048, 320*(no_ce-1), duration, 1);
    
    sptr = (signed short *)a_buf;
    if (!capTest) {
        for( j=0, temp=0; j < 4096*6-2; j++) {
            printf(" %x", (*(sptr+j+1) & 0xff));

            if ( *(sptr+j+1) == ((*(sptr+j)+1)&0xffff) ) 
                temp++;
            else {                                                       
                temp = 0;
            }
            if (temp > 100) {
                afelb = 1;
                break;
            }
        }	 				
    }
}


void co_td_capture(int ch_num, int duration, int no_ce)
{
	char		cfg_file[100]= "/tgtsvr/co_cfg.txt";


	rx_td_capture(ch_num, cfg_file, no_ce); 
	// do_agc(line+ch_num);
	capture_a_fifo(ch_num, duration, no_ce);
}

void cpe_td_capture(int ch_num, int duration, int no_ce)
{
	char		cfg_file[100]= "/tgtsvr/cpe_cfg.txt";


	rx_td_capture(ch_num, cfg_file, no_ce); 
	// do_agc(line+ch_num);
	capture_a_fifo(ch_num, duration, no_ce);
}

void enable_tx(int line_num)
{
	line[line_num].is_tx_enabled = 1;	
}

void enable_rx(int line_num)
{
	line[line_num].is_rx_enabled = 1;
}

void disable_tx(int line_num)
{
	line[line_num].is_tx_enabled = 0;	
}

void disable_rx(int line_num)
{
	line[line_num].is_rx_enabled = 0;
}


void use_common_clk()
{	
	common_clk = 1;
}

void use_separate_clk()
{
	common_clk = 0;
}

void send_zdata(int  line_num, char *filename)
{

	FILE *fpin=0;
	int	 i;
	
	u32		z_fifo_start_addr, start_addr;
	u32		fifo_size;
#define TD_SIZE	4096 
	// for now, data length is assumed to be fixed with 4096 
	for ( i = 0; i <  TD_SIZE; i++) {
		timeData[i] = i;
		//logMsg("timeData[%d] = %d\n", i,timeData[i]); 
	}

	fclose(fpin);		


	// DMA new data to z-fifo
	//hostWriteBMEMemories(char *dst, char *src, int len, int write_mode, int isFifo, int chan_num)
	z_fifo_start_addr = read_zfifo_status(line_num, &start_addr, &fifo_size);	

	//logMsg("\n Zfifo size = %x", fifo_size);

	for ( i = 0; i < (fifo_size/(TD_SIZE*2)) ; i++){
	
		hostWriteBMEMemories( (u8 *) (z_fifo_start_addr + 2 * TD_SIZE * i ),(u8*)timeData, 2*TD_SIZE, 1, 0, line_num);	
		logMsg("\n dst address:  %x     src address b = %x\n",(z_fifo_start_addr + 2 * TD_SIZE * i), (unsigned int)timeData); 

	}


}

void co_tx_td(int line_num, char *filename)
{

	// enable the tx first
	co_tx(line_num, 0, 1);	
	
	// disable mapper but keep V-bus on
    	framerCpu(line_num, START_DISABLE, 0, 0);

	// send new data to Z-fifo                                       
	send_zdata( line_num, filename);
	

}

void get_a_fifo(char *a_buf, int line_num, int duration, int ce)
{

	u32	a_fifo_start_addr;
	int	fifo_size;

	read_afifo_status(line_num, &a_fifo_start_addr, &fifo_size);	

	hostReadBMEMemories(a_buf, (u8 *)a_fifo_start_addr, 4096*2, 1, 0, line_num);

}

int afe2_lb(int line_num, int trial)
{

	int i;

	// enable the tx first
	co_tx(line_num, 1, 0);	
	
	// disable mapper but keep V-bus on
    framerCpu(line_num, START_DISABLE, 0, 0);	

	// set the AFE-2 loopback register
	afeWriteRegister (0x8a,num1,0x11);
    
    afelb = 0;
	for ( i = 0 ; i < trial ; i++) {
	
		// send new data to Z-fifo
		send_zdata( line_num, "/tgtsvr/test.txt");

		// capture data
		co_td_capture(line_num, 6, 0);

		iposDelay();

		// get the data from a-fifo 
		get_a_fifo((char *)a_data, line_num, 6, 0);

	}
    if (afelb)  {
        printf("\n\nAFE Digital Loopback test passed.\n");
        return 1;
    }
    else {
    }
        printf("\n\nAFE Digital Loopback test failed.\n");
        return 0;
}

void afe2_recv(int line_num, int trial)
{

	int i;

	for ( i = 0 ; i < trial ; i++) {
				
		// capture data
#ifdef VTU_O
		co_td_capture(line_num, 6, 0);
#else
		cpe_td_capture(line_num, 6, 0);
#endif
		iposDelay();

		// get the data from a-fifo 
		get_a_fifo((char *)a_data, line_num, 6, 0);
	
	}
#ifndef DIAG_BUILD
    if (afelb)  {
        printf("\n\nafe2_recv test passed.\n");
    }
    else {
    }
        printf("\n\nafe2_recv test failed.\n");
#endif
}

void delete_file(VDSL_CFG *vdsl_cfg)
{
	remove(vdsl_cfg->tx_showtime_param_file);
	remove(vdsl_cfg->tx_showtime_param_sem_file);
	remove(vdsl_cfg->tx_showtime_sem_file);
	remove(vdsl_cfg->cpe_tx_medley_start_file_sem);
	remove(vdsl_cfg->cpe_tx_medley_start_done_file_sem);
	remove(vdsl_cfg->cpe_rx_medley_start_file_sem);
	remove(vdsl_cfg->cpe_rx_medley_start_done_file_sem);
	remove(vdsl_cfg->co_tx_medley_start_file_sem);
	remove(vdsl_cfg->co_tx_medley_start_done_file_sem);
	remove(vdsl_cfg->co_rx_medley_start_file_sem);
	remove(vdsl_cfg->co_rx_medley_start_done_file_sem);
	remove(vdsl_cfg->co_rx_start_file_sem);
	remove(vdsl_cfg->cpe_tx_start_file_sem);
	remove(vdsl_cfg->rx_showtime_param_file);
	remove(vdsl_cfg->rx_showtime_sem_file);
	remove(vdsl_cfg->rx_showtime_param_sem_file);
}
//------------------------------------------------------------------------
// begin API fns for Rel 1 

int costart_flag=0;
int cpestart_flag=0;


void banner()
{
        printf ("\n********************************************************");
        printf ("\n**           Copyright (C) 2000-2002                  **");
        printf ("\n**    Ikanos Communication, Fremont, CA               **");
        printf ("\n**           All rights reserved.                     **");
        printf ("\n**                                                    **");
        printf ("\n**     Ikanos Programmable Operating System (iPOS)    **");
        printf ("\n**   Firmware and Application Programming Interface   **");
        printf ("\n**                   for the                          **");
        printf ("\n**   SmartLeap 8100 and CleverConnect 150             **");
        printf ("\n**           EFM/LRFE/VDSL Chipsets                   **");
        printf ("\n**             Release 1.0                            **");
        printf ("\n********************************************************\n\n"); 

}


#define	MAX_XFER_SIZE	256











