/*
 * (C) Copyright 2001
 * ELTEC Elektronik AG
 * Frank Gottschling <fgottschling@eltec.de>
 *
 * Board specific routines for the miniHiPerCam
 *
 * - initialisation (eeprom)
 * - memory controller
 * - serial io initialisation
 * - ethernet io initialisation
 *
 * -----------------------------------------------------------------
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */
#include <stdarg.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/ctype.h>

#include <ppcboot.h>
#include <commproc.h>
#include "mpc8xx.h"

#if (CONFIG_COMMANDS & CFG_CMD_EEPROM)
#include "rev.h"

/* imports from common/main.c */
extern char console_buffer[CFG_CBSIZE];

extern void eeprom_init  (void);
extern void eeprom_read  (unsigned offset, uchar *buffer, unsigned cnt);
extern void eeprom_write (unsigned offset, uchar *buffer, unsigned cnt);
#endif

/* ------------------------------------------------------------------------- */

static const uint sdram_table[] =
{
    /* read single beat cycle */
          0xef0efc04, 0x0e2dac04, 0x01ba5c04, 0x1ff5fc00,
          0xfffffc05, 0xeffafc34, 0x0ff0bc34, 0x1ff57c35,

   /* read burst cycle */
          0xef0efc04, 0x0e3dac04, 0x10ff5c04, 0xf0fffc00,
          0xf0fffc00, 0xf1fffc00, 0xfffffc00, 0xfffffc05,
          0xfffffc04, 0xfffffc04, 0xfffffc04, 0xfffffc04,
          0xfffffc04, 0xfffffc04, 0xfffffc04, 0xfffffc04,

   /* write single beat cycle */
          0xef0efc04, 0x0e29ac00, 0x01b25c04, 0x1ff5fc05,
          0xfffffc04, 0xfffffc04, 0xfffffc04, 0xfffffc04,

   /* write burst cycle */
          0xef0ef804, 0x0e39a000, 0x10f75000, 0xf0fff440,
          0xf0fffc40, 0xf1fffc04, 0xfffffc05, 0xfffffc04,
          0xfffffc04, 0xfffffc04, 0xfffffc04, 0xfffffc04,
          0xfffffc04, 0xfffffc04, 0xfffffc04, 0xfffffc04,

   /* periodic timer expired */
          0xeffebc84, 0x1ffd7c04, 0xfffffc04, 0xfffffc84,
          0xeffebc04, 0x1ffd7c04, 0xfffffc04, 0xfffffc05,
          0xfffffc04, 0xfffffc04, 0xfffffc04, 0xfffffc04,

   /* exception */
          0xfffffc04, 0xfffffc05, 0xfffffc04, 0xfffffc04
};

/* ------------------------------------------------------------------------- */

int board_pre_init (void)
{
        volatile immap_t  *im = (immap_t *)CFG_IMMR;
	volatile cpm8xx_t *cp = &(im->im_cpm);
	volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport);

	/* reset the port A s.a. cpm-routines */
	ip->iop_padat = 0x0000;
	ip->iop_papar = 0x0000;
	ip->iop_padir = 0x0800;
	ip->iop_paodr = 0x0000;

	/* reset the port B for digital and LCD output */
	cp->cp_pbdat  = 0x0300;
	cp->cp_pbpar  = 0x5001;
	cp->cp_pbdir  = 0x5301;
	cp->cp_pbodr  = 0x0000;

	/* reset the port C configured for SMC1 serial port and aqc. control */
	ip->iop_pcdat = 0x0800;
	ip->iop_pcpar = 0x0000;
	ip->iop_pcdir = 0x0e30;
	ip->iop_pcso  = 0x0000;

	/* Config port D for LCD output */
	ip->iop_pdpar = 0x1fff;
	ip->iop_pddir = 0x1fff;

	return (0);
}

/* ------------------------------------------------------------------------- */

/*
 * Check Board Identity
 */
int checkboard (void)
{

#if (CONFIG_COMMANDS & CFG_CMD_EEPROM)
    revinfo  mhpcRevInfo;
    char     *mhpcSensorTypes[] = { "OMNIVISON OV7610/7620 color",
                                    "OMNIVISON OV7110 b&w", 
				    NULL };
#endif

    printf ("ELTEC miniHiperCam\n");

#if (CONFIG_COMMANDS & CFG_CMD_EEPROM)
    eeprom_init ();
    eeprom_read (480, (char*)&mhpcRevInfo, 32);

    /* is eeprom initialized ? */
    if (strncmp((char *)&mhpcRevInfo.board[2], "MHPC", 4) == 0)
    {
	printf ("       Revision: %d.%c\n", mhpcRevInfo.revision[0], 
		mhpcRevInfo.revision[1]);
	printf ("       Order  #: %s\n", (char *)&mhpcRevInfo.board);
	printf ("       Sensor  : %s\n", 
	       (mhpcRevInfo.sensor < (sizeof(mhpcSensorTypes)-1)) ? 
		mhpcSensorTypes[(int)mhpcRevInfo.sensor] :
	    "Sensor type unknown");
	printf ("       Serial #: %s\n", (char *)&mhpcRevInfo.serial);
	printf ("       Etheradr: %02x:%02x:%02x:%02x:%02x:%02x\n",
	     mhpcRevInfo.etheraddr[0], mhpcRevInfo.etheraddr[1],
	     mhpcRevInfo.etheraddr[2], mhpcRevInfo.etheraddr[3],
             mhpcRevInfo.etheraddr[4], mhpcRevInfo.etheraddr[5]);
    }
    else
    {
	printf("\nRevision eeprom not initialized !\n");
    }
#endif

    return(1);
}

/* ------------------------------------------------------------------------- */

void
misc_init_r(bd_t *bd)
{
#if (CONFIG_COMMANDS & CFG_CMD_EEPROM)
    revinfo  mhpcRevInfo;
    char     nid[32];
    char     *mhpcSensorTypes[] = { "OMNIVISON OV7610/7620 color",
                                    "OMNIVISON OV7110 b&w", 
				    NULL };
    char     hex[23] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 
			  0, 0, 0, 0, 10, 11, 12, 13, 14, 15 };
    int      i;
    
    /*
     * check revision data 
     */
    eeprom_read (480, (char*)&mhpcRevInfo, 32);

    if (strncmp((char *)&mhpcRevInfo.board[2], "MHPC", 4) != 0)
    {
	printf ("Enter revision number (0-255): %d  ", mhpcRevInfo.revision[0]);
	if (0 != readline (NULL))
	{
	    mhpcRevInfo.revision[0] = 
		(unsigned char)simple_strtoul(console_buffer, NULL, 10);
	}

	printf ("Enter revision character (A-Z): %c  ", mhpcRevInfo.revision[1]);
	if (1 == readline (NULL))
	{
	    mhpcRevInfo.revision[1] = (char)toupper(console_buffer[0]);
	}

	printf("Enter board name (V-XXXX-XXXX): %s  ", (char *)&mhpcRevInfo.board);
	if (11 == readline (NULL))
	{
	    for (i=0; i<11; i++)
	    {
	      mhpcRevInfo.board[i] =  (char)toupper(console_buffer[i]);
	      mhpcRevInfo.board[11] = '\0';
	    }
	}

	printf("Supported sensor types:\n");
	i=0;
	do 
	{
	    printf("\n    \'%d\' : %s\n", i, mhpcSensorTypes[i]);
	} while ( mhpcSensorTypes[++i] != NULL );
	
	do
	{
	    printf("\nEnter sensor number (0-255): %d  ", (int)mhpcRevInfo.sensor );
	    if (0 != readline (NULL))
	    {
		mhpcRevInfo.sensor = (unsigned char)simple_strtoul(console_buffer, NULL, 10);
	    } 
	} while ( mhpcRevInfo.sensor >= i );

	printf("Enter serial number: %s ", (char *)&mhpcRevInfo.serial );
	if (6 == readline (NULL))
	{
	    for (i=0; i<6; i++)
	    {
		mhpcRevInfo.serial[i] = console_buffer[i];
	    }
	    mhpcRevInfo.serial[6] = '\0';
	}
 
	printf("Enter ether node ID with leading zero (HEX): %02x%02x%02x%02x%02x%02x  ",
              mhpcRevInfo.etheraddr[0], mhpcRevInfo.etheraddr[1],
              mhpcRevInfo.etheraddr[2], mhpcRevInfo.etheraddr[3],
              mhpcRevInfo.etheraddr[4], mhpcRevInfo.etheraddr[5]  );
	if (12 == readline (NULL))
	{
	    for (i=0; i<12; i+=2)
	    {
		mhpcRevInfo.etheraddr[i>>1] = (char)(16*hex[toupper(console_buffer[i])-'0'] +
						     hex[toupper(console_buffer[i+1])-'0']);
	    }
	}

	/* 
	 * setup new revision data
	 */
	eeprom_write (480, (char*)&mhpcRevInfo, 32);
    }

    /*
     *set environment
     */
    sprintf (nid, "%02x:%02x:%02x:%02x:%02x:%02x",
	     mhpcRevInfo.etheraddr[0], mhpcRevInfo.etheraddr[1],
	     mhpcRevInfo.etheraddr[2], mhpcRevInfo.etheraddr[3],
             mhpcRevInfo.etheraddr[4], mhpcRevInfo.etheraddr[5]);
    setenv("ethaddr", nid);

#endif
}

/* ------------------------------------------------------------------------- */

long int initdram (int board_type)
{
    volatile immap_t     *immap  = (immap_t *)CFG_IMMR;
    volatile memctl8xx_t *memctl = &immap->im_memctl;

    upmconfig(UPMA, (uint *)sdram_table, sizeof(sdram_table)/sizeof(uint));
    
    memctl->memc_mamr  = CFG_MAMR & (~(MAMR_PTAE)); /* no refresh yet */
    memctl->memc_mbmr  = MAMR_GPL_B4DIS;
    memctl->memc_mptpr = MPTPR_PTP_DIV64;
    memctl->memc_mar   = 0x00008800;

    /*
     * Map controller SDRAM bank 0
     */
    memctl->memc_or1 = CFG_OR1_PRELIM;
    memctl->memc_br1 = CFG_BR1_PRELIM;
    udelay(200);

    /*
     * Map controller SDRAM bank 1
     */
    memctl->memc_or2 = CFG_OR2;
    memctl->memc_br2 = CFG_BR2;

    /* 
     * Perform SDRAM initializsation sequence 
     */
    memctl->memc_mcr  = 0x80002105;	/* SDRAM bank 0 */
    udelay(1);
    memctl->memc_mcr  = 0x80002730;	/* SDRAM bank 0 - execute twice */
    udelay(1);
    memctl->memc_mamr |= MAMR_PTAE;	/* enable refresh */

    udelay(10000);

    /* leave place for framebuffers */
    return (SDRAM_MAX_SIZE-SDRAM_RES_SIZE);
}















