/*********************************************************************
 *
 *  Copyright (C) 2005  Freescale Semiconductors, Inc.
 *
 ********************************************************************/
/*********************************************************************
 *  FILE: main.c
 *
 *  DESCRIPTION :
 *    Contains the entry point to the application to bring up the
 *    RapidIO system. Also contains other functions related to the
 *    user interface.
 *    main : sets up and discovers the basic system, and presents
 *     the user with a number of options
 *    print_menu : Prints a list of possible options to the user
 *     interface
 *    print_switch_info : prints information about the state of the
 *     tsi500 to the user interface
 *    print_rioport_info : prints information about the state of the
 *     RapidIO ports on each of the endpoints
 *
 * NOTES :
 *
 *
 * HISTORY
 * Version    Date     Auth.,Loc.     Comments
 *   0.1    27-Jul-04  LM, EKB       First released version
 *   0.2    14-Apr-05  LM, EKB	     Adapted to SRIO on MPC8548
 ********************************************************************/

#include <common.h>
#include <syscall.h>
#include <asm-ppc/immap_85xx.h>
#include <asm-ppc/mmu.h>

//#include "rio_regs.h"
#include "rio_bringup.h"
#include "srio_msgs.h"




/********************************************************************
Globally defined variables
*********************************************************************/
volatile srio_device_t *srio_device;
volatile immap_t *local_imm;
volatile ccsr_srio_t *local_srio;
volatile ccsr_local_ecm_t *local_ecm;
u32 system_type;
u32 hostdeviceid;
u32 nextdevid ;
int ipportstops,opportstops,testbs,testas;


/*define the size of the larget message inbound queue can accept */ 
#define MAX_IB_MSG 4096
#define IBMSG_FRM_SIZE 0x0B

/*define the number of messages which can be held in the inbound queue */ 
#define MESSAGES_IN_IBQ 4
#define IBMSG_CIRQ_SIZE 1

#define MESSAGES_IN_OBQ 4



/********************************************************************
Locally defined functions
********************************************************************/
void print_menu (void);
void print_switch_info (void);
void print_rioport_info (int device_id);
void print_perport_info (int port);

/********************************************************************
int main (int argc, char *argv[])
Sets up the local coonfiguration, discovers other processors,
sets up access to the configuration space of the agents then presents
a user interface with options to boot, monitor, tests etc.
********************************************************************/
int
main (int argc, char *argv[])
{
  volatile srio_device_t srio_device_array[MAX_DEVICES_IN_SYSTEM];
  int result;
  u32 volatile *rio_maint_window, tempstore;
  char input, input2;
  int calibration, i;
  int device;
  volatile data_msg_cntrllr *message_unit1, *message_unit2;  

 
  	
   static uchar ib_message_q1[MAX_IB_MSG * MESSAGES_IN_IBQ] __attribute__ ((aligned (32)));
   static uchar ib_message_q2[MAX_IB_MSG * MESSAGES_IN_IBQ] __attribute__ ((aligned (32)));
   static u32 ob_message_q1[8 * MESSAGES_IN_OBQ] __attribute__((aligned(32)));
   static u32 ob_message_q2[8 * MESSAGES_IN_OBQ] __attribute__((aligned(32)));


   //temp stuff in here to check out port stop errors
   //seems to be fixed with imroved clocking 
   //ipportstops = opportstops = testbs = testas = 0;
       
  /*******************************************************************
  array will hold information about all devices in the system, init
  all these devices to default information
  *******************************************************************/
  srio_device = srio_device_array;
   for(i=0;i<MAX_DEVICES_IN_SYSTEM;i++)
  {
  	srio_device_array[i].imm = NULL;
	srio_device_array[i].srio = NULL;
	srio_device_array[i].ecm = NULL;
	srio_device_array[i].mem_block = NULL;
	srio_device_array[i].booted = 0;
  }

  
  /********************************************************************
  Pointers to the register structures within the local processor
  ********************************************************************/
  local_imm = (immap_t *) CCSR_BAR;
  local_srio = (ccsr_srio_t*)(((char*)(local_imm)) + 0xC0000);
  local_ecm = &(local_imm->im_local_ecm);
  
  message_unit1 = (data_msg_cntrllr*) &(local_srio->om0mr);
  message_unit2 = (data_msg_cntrllr*)(((char*)(local_imm)) + 0xD3100);
  
  
 // printf("local pescsr = 0x%08x \n", local_srio->p0escsr);
 // if(local_srio->p0escsr & 0x00010000) 
 // 	opportstops++;
 //  if(local_srio->p0escsr & 0x00000100) 
 // 	ipportstops++;
	
	
   
  /*******************************************************************
  put this device into accept all mode 
  *******************************************************************/
  local_srio->pptaacr |= 0x00000001;

 

  /*******************************************************************
  STEP 1: Local configuration
  Sets up the configuration on the local processor and ensures that
  RapidIO is trained.
  *******************************************************************/
  result = rio_local_config ();
  if (result != SUCCESS) {
    printf ("Completed rio_local_config() with error code %d\n", result);
    return result;
  }

  printf (" ---- rio_local_config() completed successfully ---- \n\n");
   /*******************************************************************
  STEP 2 : Simplified Discovery
  'Discover' the other elements in the system.
  Limited to a single TSI500 system or 2 MPC8540/60 communicating point-to-point
  *******************************************************************/
  result = rio_discovery ();
  if (result != SUCCESS) {
    printf ("Completed rio discovery with error code %d \n", result);
    return result;
  }
  else {
  	printf("Discovered %d other devices \n", nextdevid-1); 
  }
  

  printf (" ---- rio_discovery() completed successfully ---- \n\n");

  /*take the local processor out of accept all mode */ 
  local_srio->pptaacr = 0; 

   
  /***********************************************************************
  STEP 3: Set up the lcsbacsr register which allows NREAD/NWRITE access into the
  agent devices internal memory space. Set up one single outbound (multi-segment)
  window on the host, then set up each of the agent devices in turn. 
  *********************************************************************/
  /*c1000000 = 1MByte window, lcs device 0 */
  printf("Set up ROWs of local processor for access through LCS window \n"); 
  if(system_type == FABRIC_SYSTEM)
  {
  	printf("Allow access back to host, through switch\n");
	  	local_srio->rowbar2 = 0x000c1000;
  	local_srio->rowar2 = 0x80045013;
  	local_srio->rowtar2 = 0x00001000;
  	printf("\nROW2 is for LCS access back to device 0\n");
	printf ("rowbar2 = 0x%08x, rowar2 = 0x%08x, rowtar2 = 0x%08x\n",
          local_srio->rowbar2, local_srio->rowar2, local_srio->rowtar2);
	  result = setup_remote_lcs_access (0); 

	        if (result != SUCCESS) 
	{
		printf("ERROR : Problem setting up LCS access \n"); 
	}
  
  }
  
  if(nextdevid > 1)
  {		
  /*c1100000 = 1MByte window, lcs device 1 */ 
  local_srio->rowbar3 = 0x000c1100;
  local_srio->rowar3 = 0x80045013;
  local_srio->rowtar3 = 0x00401000;
  printf("\nROW3 is for LCS access back to device 1\n");
  printf ("rowbar3 = 0x%08x, rowar3 = 0x%08x, rowtar3 = 0x%08x\n",
  local_srio->rowbar3, local_srio->rowar3, local_srio->rowtar3);
  	result = setup_remote_lcs_access (1);
        if (result != SUCCESS) 
	{
	printf("ERROR : Problem setting up LCS access \n"); 
	}

   }
  
  if(nextdevid > 2)
  {
  /*c1200000 = 1MByte window, lcs device 2 */ 
  local_srio->rowbar4 = 0x000c1200;
  local_srio->rowar4 = 0x80045013;
  local_srio->rowtar4 = 0x00801000;
  printf("\nROW4 is for LCS access back to device 2\n");
  printf ("rowbar4 = 0x%08x, rowar4 = 0x%08x, rowtar4 = 0x%08x\n",
  local_srio->rowbar4, local_srio->rowar4, local_srio->rowtar4);
  	result = setup_remote_lcs_access (2);
        if (result != SUCCESS) 
	{
	printf("ERROR : Problem setting up LCS access \n"); 
	}

  }
  
  if(nextdevid > 3)
  {
  	printf("Discovery found more devices in the system that this\n");
	printf("window setup was designed to handle \n"); 
	
  }

   printf
    (" ---- set up remote LCS access to all trained processors ---- \n\n");
    


  /* c6000000 = 4MByte window, i/o device 0 */ 
  local_srio->rowbar5 = 0x000c6000;
  local_srio->rowar5 = 0x80045015;
  local_srio->rowtar5 = 0x00000000;
   printf("\nROW5 is for memory access to device 0\n");
  printf ("rowbar5 = 0x%08x, rowar5 = 0x%08x, rowtar5 = 0x%08x\n",
  local_srio->rowbar5, local_srio->rowar5, local_srio->rowtar5);



  if(nextdevid > 1)
  {  
  /* c6400000 = 4MByte window, i/o device 1 */ 
  local_srio->rowbar6 = 0x000c6400;
  local_srio->rowar6 = 0x80045015;
  local_srio->rowtar6 = 0x00400000;
    printf("\nROW6 is for memory access to device 1\n");
  printf ("rowbar6 = 0x%08x, rowar6 = 0x%08x, rowtar6 = 0x%08x\n",
  local_srio->rowbar6, local_srio->rowar6, local_srio->rowtar6);

  }
  if(nextdevid > 2)
  {  
  /* c6800000 = 4MByte window, i/o device 2 */ 
  local_srio->rowbar7 = 0x000c6800;
  local_srio->rowar7 = 0x80045015;
  local_srio->rowtar7 = 0x00800000;
    printf("\nROW7 is for memroy access to device 2\n");
  printf ("rowbar7 = 0x%08x, rowar7 = 0x%08x, rowtar7 = 0x%08x\n",
  local_srio->rowbar7, local_srio->rowar7, local_srio->rowtar7);

  }


   
  for (i = (hostdeviceid+1); i < nextdevid; i++) 
    {
    	
	/* rather dodgy check to see if the device has been booted */
	printf("\n\n\nCheck boot status of device %d\n", i); 
	if(srio_device[i].ecm->ccsrbar == 0x000e0000)
	{
		srio_device[i].booted = 1; 
		printf("Looks like the device has already been booted \n"); 
	}
	else
	{
		printf("don't think this has been booted, ccsrbar = 0x%08x \n", srio_device[i].ecm->ccsrbar); 
		rio_boot(i);
	}
	printf("Set up access to device %d's memory space \n", i); 
	result = enable_rio_mem_access (i);
        if (result != SUCCESS)
              printf ("enable_rio_mem_access returned error code 0x%08x \n",
                      result);
	else
	{
		printf("setup memory access to device %d \n", i); 
	}
	


     }
  

     
  

 
  /********************************************************************
  STEP 4: After booting etc, software may be written on the agent devices
  to access the memory location on the host. This function sets up the
  host to accept incoming rio trasactions in the same manner as the agent
  i.e. catch the bottom 16MBytes of the RIO memory map and re-direct to
  local memory 0x01000000-0x01FFFFFF.
  Also set up the host so that agents will be able to access it through the
  LCSBACSR in the same manner that the host accesses the agent
  NOTE: These steps are not required for this application as the agents do not
  atempt to read back to the host, however, put them in here for future use.
  *********************************************************************/
  local_setup_inbound_window ();
  local_srio->lcsbacsr = CCSR_ADDR_ON_RIO >> SHIFT_RIO_ADDR_TO_LCSBACSR;
  printf
    (" ---- Provided LCSBASCR and memory access back to local processor ---- \n\n");
 
 
  printf("Enabling inbound doorbells \n"); 
  enable_ib_dbs();  
  printf("Enabling inbound data messages \n"); 
  enable_ib_msgs(message_unit1,  ib_message_q1, MAX_IB_MSG, MESSAGES_IN_IBQ);
  enable_ib_msgs(message_unit2,  ib_message_q2, MAX_IB_MSG, MESSAGES_IN_IBQ);
  printf("Enabling direct mode data messaging \n"); 
  enable_ob_msg_ch(message_unit1, ob_message_q1,MESSAGES_IN_OBQ ); 
  enable_ob_msg_ch(message_unit2, ob_message_q2,MESSAGES_IN_OBQ ); 

//   printf("local pescsr = 0x%08x \n", local_srio->p0escsr);
//  if(local_srio->p0escsr & 0x00010000) 
//  	opportstops++;
//  if(local_srio->p0escsr & 0x00000100) 
//  	ipportstops++;

  		      
  /*********************************************************************
  STEP 5: Present the user with a menu to select a number of options
  *********************************************************************/
  	print_menu ();
  	while (1) {
    	input = getc ();

    /****************************************************************
    option to quit
    ****************************************************************/
    	if ((input == 'q') || (input == 'Q'))
      		break;

    /****************************************************************
    option to boot agent processors
    ****************************************************************/
    	else if ((input == 'b') || (input == 'B')) {
      		if (system_type == FABRIC_SYSTEM) 
      		{
        		printf ("B. Boot processor. Which processor number ?  ");
        		input = getc ();
	    		device = input - 48;
	    		if((device > hostdeviceid) & (device < nextdevid))
		   			printf("%d \n", device);
	    		else
	    		{	 
        			printf ("%d is not a valid deviceid \n", device);
		    		device = 0;
	    		}
    		}
    		else
       			device = hostdeviceid+1;
        
   			if(device != 0)
   			{
       			result = rio_boot (device);
       			if (result == SUCCESS) 
	   			{
       			}
       			else
          			printf ("rio_boot returned error code 0x%08x \n", result);
  			}
  		} 	
      
    	else if ((system_type == FABRIC_SYSTEM) &
             ((input == 'd') || (input == 'D'))) 
		{
			printf("Running doorbell test.\n"); 
			printf("Sending doorbells to myself, polling to receive \n"); 
			doorbelltest(); 
		}
 
  		else if ((system_type == FABRIC_SYSTEM) &
       		((input == 'm') || (input == 'M'))) 
		{
			printf("Running data message test.\n"); 
			printf("Sending data messages to myself, polling to receive \n"); 
			datamessagetest(message_unit1); 
		}

      
    /****************************************************************
    option to print switch information
    ****************************************************************/
    	else if ((system_type == FABRIC_SYSTEM) &
             ((input == 's') || (input == 'S'))) 
        {
      		printf ("S. Print Switch info\n");
      		print_switch_info ();
    	}
    
    
    /****************************************************************
    option to read the rio information from the processors
    ***************************************************************/
    	else if ((input == 'r') || (input == 'R'))
    	{
      		printf("R. Read RIO information for which device number ? \n");
      		input = getc ();
      		device = input - 48;
      		if((device >= hostdeviceid ) & (device < nextdevid))
      		{
				printf("%d \n", device);
				print_rioport_info (device);
			} else {	 
        		printf ("%d is not a valid deviceid \n", device);
			}           
    	}

    /****************************************************************
    option to run tests
    ****************************************************************/
    	else if ((input == 't') || (input == 'T'))
    	{
      		printf ("T. Which demo do you want to run ? \n");
      		printf ("A = execute 100 32bit writes to agent, read back and compare \n");
      		printf ("B = DMA transfer 64kbytes block to agent, read back and compare  \n");
      		input = getc ();
        	if (system_type == FABRIC_SYSTEM) 
      		{
          		printf("On which device do you want to run demo %c  ? \n", input);
          		input2 = getc ();
	  			device = input2 - 48; 
      		}
      		else
      		{
      		device = hostdeviceid+1;
      		}
      		if ((device >= hostdeviceid) & (device < nextdevid))
      		{
      	   		if(device == hostdeviceid)
		   			printf("loopback test to self, through switch\n"); 

	   			if ((input == 'a') || (input == 'A'))
            		result = testa (device);

	    		else if ((input == 'b') || (input == 'B'))
	    			result = testb(device, 8*1024, 16, 0);

	   			else if ((input == 'c') || (input == 'C'))
					result = testc(device, 1000, 0);

	    		else if ((input == 'd') || (input == 'D'))
	    			result = testb(device, 8*1024, 1024, 0);

	    		else if ((input == 'e') || (input == 'E'))
	    			result = testb(device, 1024*1024, 1024, 0);

	   			else if ((input == 'm') || (input == 'M'))
					result = testc(device, 1000, 1);

	   			else if ((input == 'n') || (input == 'N'))
					result = testc(device, 100000, 1);

	   			else if ((input == 's') || (input == 'S'))
            		result = testa (device);

	    		else if ((input == 't') || (input == 'T'))
	    			result = testb(device, 8*1024, 16, 1);

	    		else if ((input == 'u') || (input == 'U'))
	    			result = testb(device, 8*1024, 1024, 1);

	    		else if ((input == 'v') || (input == 'V'))
	    			result = testb(device, 1024*1024, 8, 1);

	    		else if ((input == 'z') || (input == 'z'))
	    			result = testb(device, 4*1024*1024, 1024, 1);
	   			else
	    			printf("Not a valid test \n"); 
	    
      		}
      		else
      		{
	  			printf("Not a valid device ID \n"); 
      		}
         
    	}

    /****************************************************************
    Default option, print menu
    ****************************************************************/
    	else
      		print_menu ();

    /****************************************************************
    always re-print cursor after every command
    ****************************************************************/
    printf (">");
  }
}

/********************************************************************
User interface function to print out all the available options
********************************************************************/
void
print_menu (void)
{
  int i;
  
  printf ("\n\nHost processor is deviceid %d \n", hostdeviceid);
  printf ("Discovered %d agent processors \n", nextdevid-1);
  if(nextdevid-1)
  {
  	printf("With deviceID = ");
	for(i=1;i<nextdevid;i++)
	{
		printf(" %d  ", i);
	}  
	printf("\n");
  } 
  printf ("Options : \n");
 // printf ("b = boot another processor\n");
  printf ("h = print this list of options\n");
  printf ("q = quit this application \n");
  if (system_type == FABRIC_SYSTEM)
  {
    printf ("s = read back info from tsi568 \n");
    printf ("d = run doorbell test \n"); 
    printf ("m = run data message test \n"); 
  }
  printf ("r = SRIO setup and status \n");
  printf ("t = run one of the NREAD/NWRITE demos \n");
}

/********************************************************************
User interface function to print out information about the status of
the rapidio switch
********************************************************************/
void
print_switch_info (void)
{

  int i; 
  u32 numport;

  MAINT_READ (0xFF, 0x00, TSI568_SW_PORT, numport);
  numport = numport >> 8;
  printf("port       err_status     ctl  \n"); 
  for(i=0;i<numport;i++)
  {
	print_perport_info(i);
  }
 
 }

void
print_perport_info (int port)
{
  
   u32 temp;

  
   
  printf("port %2d    ",port); 
  MAINT_READ (0xFF, 0x00, (P0_ERR_STATUS_OFFSET + (TSI568_PORT_STRIDE * port)), temp);
  printf("  0x%08x  ", temp);
  MAINT_READ (0xFF, 0x00, (P0_CTL_OFFSET + (TSI568_PORT_STRIDE * port)), temp);
  printf("  0x%08x  \n" , temp);
  }

/********************************************************************
User interface function to print out information about the status of
the rapidIO ports of all devices in the system
********************************************************************/
void
print_rioport_info (int device_id)
{
  int ok = 0;
  volatile ccsr_srio_t *target_rio;
  char input;

  target_rio = srio_device[device_id].srio;
  
  
  if (target_rio != NULL) {
    printf ("Rio port information from device %d \n", device_id);
    printf ("didcar   = 0x%08x       bdidcsr = 0x%08x\n", target_rio->didcar,
            target_rio->bdidcsr);
    printf ("predr    = 0x%08x       pnfedr  = 0x%08x\n", target_rio->predr,
            target_rio->pnfedr);
    printf ("pccsr   = 0x%08x       pescsr  = 0x%08x\n", target_rio->p0ccsr,
    	    target_rio->p0escsr);	    
    printf ("row0 :                 tar=0x%08x, ar=0x%08x  \n",
            target_rio->rowtar0, target_rio->rowar0);
    printf ("row1 : bar=0x%08x, tar=0x%08x, ar=0x%08x  \n",
            target_rio->rowbar1, target_rio->rowtar1, target_rio->rowar1);
    printf ("row2 : bar=0x%08x, tar=0x%08x, ar=0x%08x  \n",
            target_rio->rowbar2, target_rio->rowtar2, target_rio->rowar2);
    printf ("row3 : bar=0x%08x, tar=0x%08x, ar=0x%08x  \n",
            target_rio->rowbar3, target_rio->rowtar3, target_rio->rowar3);
    printf ("row4 : bar=0x%08x, tar=0x%08x, ar=0x%08x  \n",
            target_rio->rowbar4, target_rio->rowtar4, target_rio->rowar4);
    printf ("row5 : bar=0x%08x, tar=0x%08x, ar=0x%08x  \n",
            target_rio->rowbar5, target_rio->rowtar5, target_rio->rowar5);
    printf ("row6 : bar=0x%08x, tar=0x%08x, ar=0x%08x  \n",
            target_rio->rowbar6, target_rio->rowtar6, target_rio->rowar6);
    printf ("row7 : bar=0x%08x, tar=0x%08x, ar=0x%08x  \n",
            target_rio->rowbar7, target_rio->rowtar7, target_rio->rowar7);
    printf ("row8 : bar=0x%08x, tar=0x%08x, ar=0x%08x  \n",
            target_rio->rowbar8, target_rio->rowtar8, target_rio->rowar8);
    printf ("riw0 :                 tar=0x%08x, ar=0x%08x  \n",
            target_rio->riwtar0, target_rio->riwar0);
    printf ("riw1 : bar=0x%08x, tar=0x%08x, ar=0x%08x  \n",
            target_rio->riwbar1, target_rio->riwtar1, target_rio->riwar1);
    printf ("riw2 : bar=0x%08x, tar=0x%08x, ar=0x%08x  \n",
            target_rio->riwbar2, target_rio->riwtar2, target_rio->riwar2);
    printf ("riw3 : bar=0x%08x, tar=0x%08x, ar=0x%08x  \n",
            target_rio->riwbar3, target_rio->riwtar3, target_rio->riwar3);
    printf ("riw4 : bar=0x%08x, tar=0x%08x, ar=0x%08x  \n",
            target_rio->riwbar4, target_rio->riwtar4, target_rio->riwar4);
  }
  else
  {
  	printf("Don't have a pointer to deviceid %d's srio \n", device_id);
  }
}
