/* $Id: setup.c,v 1.2 2005/06/16 13:46:21 cgoh Exp $
 *
 * setup.c: handles the architecture-dependent parts of initialization
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) Equator Technologies
 */
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/console.h>
#ifdef CONFIG_BLK_DEV_RAM
#include <linux/blk.h>
#endif
#include <asm/processor.h>
#include <libdev/etiTLB.h>
#include <libdev/etiProcessor.h>
#include <libdev/etiBoard.h>
#ifdef CONFIG_PCI
#include <asm/pci.h>
#endif
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
#include <linux/ide.h>
#endif
#include <asm/keyboard.h>
#include <eti/mm.h>
#include <asm/mmu_context.h>
#include <asm/assert.h>

#ifdef CONFIG_VT
#include <linux/console.h>
extern struct kbd_ops std_kbd_ops;
extern struct consw dummy_con;
#endif
extern struct kbd_ops no_kbd_ops;
struct kbd_ops *kbd_ops;

#include <etilib/etiLocal.h>
#include <etilib/etiErrors.h>

#include <kernelLib/etiDriverOsal.h>

#ifdef CONFIG_PCI
#include <libdev/etiPci.h>
#include <libdev/etiPciDriver.h>
#include <libdev/etiPciBiosDriver.h>
#include <libdev/etiPciDolphinDriver.h>
#endif

#include <etilib/etiBoardEepromHeader.h>
#include <libdev/etiGraphicPrint.h>

/* default values for screen_info variable (Colour VGA) */
#define DEFAULT_SCREEN_INFO {0, 0, 0, 52, 3, 80, 4626, 3, 9, 50, 0x22, 16}
struct screen_info screen_info = DEFAULT_SCREEN_INFO;

extern int boot_cmd_line_start; /* from pboots.s: start of cmd line */
extern int boot_cmd_line_end;  
#ifdef CONFIG_BLK_DEV_INITRD
extern unsigned char ramdiskImage[];
extern unsigned long ramdiskImageSize;
#endif

#define CL_SIZE 256
char saved_command_line[CL_SIZE];


/*
 * Define __SYSLOG mechanism,
 * and tell BSP board support that
 * this will work from booting onward:
 */

__SYSLOG_Fun    __SYSLOG            = printk;
Bool            syslogLEAVE_ALONE   = True;


char default_command_line[] =
#ifdef CONFIG_ETI_DEFAULT_LINUX_CMD
    CONFIG_ETI_DEFAULT_LINUX_CMD_STRING
#else
    #ifdef  CONFIG_ETI_PCI_SLAVE       
           /* For HOST_PC board like Stingray, 
            * ipconfig is added later on to 
            * the default command line 
            */
    #else
    #ifndef CONFIG_BLK_DEV_INITRD 
    //	"ip=10.0.0.121:10.0.0.193:10.0.0.1:255.255.255.0:starfish.cam.equator.com:eth0:none "
	    "ip=:::::eth0:dhcp "
    #endif
    #endif    

    #ifdef CONFIG_BLK_DEV_INITRD
	    "rw root=/dev/ram "
    #else
           //"ro root=/dev/hda1 "
           //"ro root=/dev/hdg2 "
           "rw nfsroot=10.0.0.135:/usr/rootfs "     
    #endif
#endif    
   ;

struct cpuinfo_eti_bsp boot_cpu_data;

#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
extern struct ide_ops std_ide_ops; /* arch/bsp/lib/ide-std.c */
struct ide_ops *ide_ops;
#endif

/*
 * This flag is set if a EISA slots are available.
 */
int EISA_bus = 0;


#include <libdev/etiBoard.h>

#ifdef  CONFIG_ETI_PCI_SLAVE
/* Function to add an ip definition to the default command line (assume it is not defined yet)*/
static void setIpInfoFromL2image( char *cmdline ) {

     ldimgL2HdrExtension_t  l2HdrExt = procGetL2HeaderExtension ( );

     if (l2HdrExt) {     
            
        /* Ip format : ip= ip_address:server_addr:gateway_addr:netmask:domain:device_name:flag*/     
         strcat(cmdline," ip=");
         strcat(cmdline,in_ntoa(l2HdrExt->ipNetInfo.ownIpAddress));
         strcat(cmdline,"::");
         strcat(cmdline,in_ntoa(l2HdrExt->ipNetInfo.gatewayIpAddress));
         strcat(cmdline,":");
         strcat(cmdline,in_ntoa(l2HdrExt->ipNetInfo.netmask));
         strcat(cmdline,":");
         strcat(cmdline,l2HdrExt->ipNetInfo.domainName);
         strcat(cmdline,":eth0:none ");
     }    

}
#endif



/* ------------------------ Get Linux commandline from Eeprom --------------- */

#define E(x) \
     {                                     \
       if (x) {                            \
            __SYSLOG("@@@ Reading board info from eeprom failed on: "#x"\n"); \
            errPrintBacktrace( Null );     \
            goto finish;                   \
     } }



static void get_board_info(void) {
        brdBoard_t   brd;
        brdSetup_t   setup;
        Pointer      board_command_line;
        UInt         flags;
        Bool         isOpen= False;        
        Bool         wipeout;

        E(       brdOpen     (EEPROM_BOARDCONFIG,&brd) );  isOpen= True;
        E(       brdGetSetup ( brd, &setup           ) );
        wipeout= brdGetValue ( brd, "WipeBootCmd",  &board_command_line, &flags) == BRD_OK;
        E(       brdGetValue ( brd, "LinuxBootCmd", &board_command_line, &flags) );

        printk("Using EEPROM cmdline: %s\n", board_command_line);
        strncpy(default_command_line, board_command_line, CL_SIZE);

        if (wipeout) { E( brdRemoveValue(brd,"LinuxBootCmd" ) ); }
        brdRemoveValue(brd,"WipeBootCmd"); 

   finish:
        if (isOpen) { brdClose(brd); }
}




void setup_arch(char **cmdline_p,
                unsigned long * memory_start_p, unsigned long * memory_end_p)
{
        procCapabilities_t  caps;
        procGlobalSetup_t   setup;

        char         *boot_cmd_line;
        unsigned long maxlen, len;
        unsigned long mem_size;
        unsigned long memory_start, memory_end;
        unsigned long last_kernel_address= PGOFFS_VMALLOC_START + PGOFFS_VMALLOC_LEN;

        /* Initialize initial mm context with boot-up values */
        init_mm.context.asid     = hmpv_read_asid_cl0    ();
        init_mm.context.eer      = hmpv_read_eer_cl0     ();
        init_mm.context.ibrka    = hmpv_read_ibrka_cl0   ();
        init_mm.context.ibrkmsk  = hmpv_read_ibrkmsk_cl0 ();
        init_mm.context.dbrka    = hmpv_read_dbrka_cl0   ();
        init_mm.context.dbrkmsk  = hmpv_read_dbrkmsk_cl0 ();
        init_mm.context.ceer[0]  = hmpv_read_ceer_cl0    ();
        init_mm.context.ceer[1]  = hmpv_read_ceer_cl1    ();

        procGetCapabilities( &caps  );
        procGetGlobalSetup ( &setup );
#ifdef CONFIG_ETI_GRAPHICS_SYSLOG       
        /* Recover the address of the graphics memory which has been
           initialized by the Splashboot */ 
        if( setup.data[16] ) { etiGraphicsSyslogInit(setup.data[16]); 
        __VSYSLOG = etiGraphicsSyslog;}
#endif        

        printk("CPU frequency: %3d MHz\n", caps.cpuFrequency / 1000000);
        printk("Mem frequency: %3d MHz\n", caps.memFrequency / 1000000);

        ASSERT( last_kernel_address < setup.PIOBase, ("PIO base in kernel space") );

        initOsal();

#ifndef CONFIG_ETI_IGNORE_EEPROM_LINUX_CMD
        /* Get EEPROM info */
        get_board_info();
#endif
#ifdef  CONFIG_ETI_PCI_SLAVE
        /* Add the ip configuration to the default command line if not already there*/
        if ( strstr(default_command_line, " ip=") == Null){
            printk(KERN_DEBUG "IP information taken from L2 Header\n");
            setIpInfoFromL2image(default_command_line);
        }
        else {
            printk(KERN_DEBUG "Warning: Default IP information taken from EEPROM, not from L2 Header !\n");
        }
        printk(KERN_DEBUG "Default command line : %s\n",default_command_line);  
#endif

        /* Get command line */
        if ((*(unsigned long *)&boot_cmd_line_start) == 0xdeadbeef) {
                strncpy((char *)&boot_cmd_line_start, 
                        default_command_line, CL_SIZE);
        }
                
        boot_cmd_line = (char *)&boot_cmd_line_start;
        *cmdline_p = boot_cmd_line;
        maxlen = (int)&boot_cmd_line_end - (int)&boot_cmd_line_start;  
        len = strlen(boot_cmd_line);

        if (len) {
                printk( KERN_DEBUG "setup_arch(): cmdline='%s'\n", boot_cmd_line);

                /* copy it to saved_command_line */
                memcpy(saved_command_line, boot_cmd_line, CL_SIZE);

                /* sanity check cmd line length.  If it's too long, it
                 * probably overwrote something important (of course,
                 * if it did, we probably would never get here, but
                 * one can never be too safe -- khilman */
                if (len >= maxlen)
                        printk(KERN_DEBUG 
                               "setup_arch(): cmdline length > max\n");
        }

        /* Setup memory bounds 
         *
         * end of kernel image to end of 'virtual' address space */
       *memory_start_p = memory_start = caps.memHeap;
       *memory_end_p   = memory_end   = caps.memStart + caps.memSize - caps.hiMemGap - caps.l2ExtensionSize;


#ifdef CONFIG_BLK_DEV_INITRD
        /* Use staticly linked ramdisk image */
        initrd_start = (unsigned long)ramdiskImage;
        initrd_end = initrd_start + ramdiskImageSize;
        initrd_below_start_ok = 1;
#endif /* CONFIG_BLK_DEV_INITRD */

        mem_size = *memory_end_p - *memory_start_p;
        printk(KERN_DEBUG 
               "setup_arch():Mem: start=0x%08x, end=0x%08x, size=%d (~%dM)\n", 
               *memory_start_p, *memory_end_p, mem_size, mem_size>>20);

        /* Initialize TLB manager */
        TLB_init();

#ifdef CONFIG_VT
        conswitchp = &dummy_con;

        /* Standard PC keyboard */
        kbd_ops = &std_kbd_ops;
#else
        kbd_ops = &no_kbd_ops;
#endif
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
        ide_ops = &std_ide_ops;
#endif

        return;
}



void eti_early_setup(void) 
{
    procGlobalSetup_t setup;

    /*
     * Give boot memory pool some slack to honor memory
     * allocation requests during Linux kernel booting.
     * This until the real etiOsal memory pool is created 
     * on top of kmalloc (in late setup, kernelUp()):
     */
     etiFREE( etiMALLOC( 0x1000 ) );


    /*
     * After that, prevent the boot heap
     * from expanding. This boot heap uses 
     * procSBRK, which would overrun memory 
     * now being occupied by Linux:
     */
     procGetGlobalSetup(&setup);
     setup.heapLocked= True;
     procGlobalSetup(&setup);
}


/* Put setup stuff in here that needs to be done in do_basic_setup() 
 * from init/main.c */
void eti_do_basic_setup(void) 
{

    kernelUp();
    drosInitDrivers();
#ifdef CONFIG_ETI_TTY_CONSOLE     
    ttyGen_init();
#endif    
}


/* Put setup stuff in here that needs to be done late in the setup
 * (after root filesystem is mounted) */
void eti_late_setup(void) 
{

        /* If it doesn't exist yet, make sure there's a console device.
         * This is so mounting a rootFS with and empty /dev directory
         * will go somewhere. */
        sys_mknod("/dev/console", 
                  S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH,
                  (5<<8)|1);


        
#ifdef CONFIG_ETI_GRAPHICS_SYSLOG        
        etiGraphicsSyslogClose();
#endif

}

#ifdef CONFIG_ETI_HARDCODED_BOARD_ID
void __identifyBoard( UInt *boardId,  etiVersion_t *boardVersion,
                      UInt *dBoardId, etiVersion_t *dBoardVersion)
{
    *boardId  = CONFIG_ETI_BOARD_ID;
    *dBoardId = 0;
}
#endif
