/*
 * File created by Dean Jenkins Liberte Software Limited

 * 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
 */

/* [DJ] */

#include <common.h>

#if defined(CFG_ENV_IS_IN_MIU_SPI_FLASH) /* Environment is in MIU SPI Flash */

#include <command.h>
#include <environment.h>
#include <linux/stddef.h>


/*
 * USEFUL INFORMATION
 *
 * meaning of some #defines and variables
 *
 * CFG_ENV_SIZE defines the total size of the env_t structure
 * CFG_FLASH_BASE defines Flash base address
 * CFG_ENV_OFFSET defines the offset into the Flash where the environment is stored
 * CFG_ENV_ADDR defines the base address in Flash of the environmental structure
 */


/* For information only from include/environment.h 
typedef	struct environment_s {
	unsigned long	crc;		CRC32 over data bytes
	unsigned char	data[ENV_SIZE]; Environment data
} env_t;
*/

/**********************************/
/* Exported functions for env API */
/**********************************/

uchar env_get_char_spec (int index);
void env_relocate_spec (void);
int saveenv(void);
int env_init(void);


/*************/
/* Externals */
/*************/

extern flash_info_t flash_info[CFG_MAX_FLASH_BANKS];

/**********************/
/* Exported variables */
/**********************/

/* Pointer to RAM based environmental structure after relocate */
env_t *env_ptr = NULL;

char * env_name_spec = "MIU_SPI_FLASH";


/************************/
/* Local file variables */
/************************/


/*
 * Function reads an unsigned char out of Flash structure
 *
 * Inputs:
 *	index = index into data element of the structure
 * Outputs:
 *	returns the unsigned char located at data[index]
 */
/* WARNING: Print out of debug maybe incomplete due to serial port being reinitialised during print out */
uchar env_get_char_spec (int index) {

	env_t *flash_env_ptr = (env_t *)CFG_ENV_ADDR;
	uchar c;

	debugX( 2, "env_get_char_spec called\n");

	debugX( 2, "index = %X\n", index);

	/* read a char out of the Flash environmental variable structure */
	c = (uchar)flash_env_ptr->data[index];

	debugX( 2, "read uchar = %c\n", c >= 32 ? c : '.');

	return (c);
}

/*
 * Function copies the contents of the Flash into the RAM based malloced structure
 *
 * Inputs:
 *	env_ptr = points to the RAM based malloced empty image of the environmental structure
 * Outputs:
 *	none
 */
void env_relocate_spec (void) {

	debugX( 2, "env_relocate_spec called\n");

	if (env_ptr != NULL) {
		/* do a struct to struct copy out of Flash */
		*env_ptr = *((env_t *)CFG_ENV_ADDR);
	}
	else {
		printf ("Error: Environmental structure base address is NULL, failed to relocate\n");
	}
}


/*
 * Function saves the RAM based environmental variables into Flash
 *
 * Inputs:
 *	env_ptr = point to the RAM based malloced image of the environmental structure
 * Outputs:
 *	error code ??
 */
int saveenv(void) {

	debugX( 2, "saveenv called\n");

	debugX( 2, "Environmental structure base address is %08lX\n", (ulong) env_ptr);

	if (env_ptr != NULL) {

		/* Save the environmental structure to the Flash part on bank #1 */
		/* DJ FIXME ignore sector protection for now */
		write_buff (&flash_info[0], (uchar *)env_ptr, CFG_ENV_ADDR, CFG_ENV_SIZE);
	}
	else {
		printf ("Error: Environmental structure base address is NULL, failed to save\n");
	}

	/* DJ FIXME add appropriate error code */

}


/*
 * Function reads checks the CRC value of the environmental structure
 * it is assumed that the MIU SPI command is already set to the read command
 *
 * This function is called from board.c during the initialisation phase
 *
 * Inputs:
 *	
 * Outputs:
 *	indicates within gd structure base address of the data array
 *	if Flash based structure is invalid then use default array
 *	indicates within gd structure whether Flash based environment is valid 
 */

/* WARNING: Cannot print out debug or printf as serial port not configured at this point */
int env_init(void) {

	DECLARE_GLOBAL_DATA_PTR;

	ulong rec_crc, calc_crc;
	env_t *flash_env_ptr = (env_t *)CFG_ENV_ADDR;

	/* assume the MIU driven SPI Flash is in a readable state */
	/* therefore no Flash initialisation required */

	/* read recorded CRC field */
	rec_crc = (ulong)flash_env_ptr->crc;

	/* calculate the crc for the data array element */
	calc_crc = crc32(0, &flash_env_ptr->data[0], ENV_SIZE);

	/* is the crc check good ? */
	if (rec_crc == calc_crc) {
		/* save address of data[] element of the Flash structure */
		gd->env_addr  = (ulong)&(flash_env_ptr->data[0]);
		gd->env_valid = 1;
	}
	else {
		gd->env_addr  = NULL;
		gd->env_valid = 0;
	}

	return (0);
}

#endif /* CFG_ENV_IS_IN_MIU_SPI_FLASH */
