/*
 * board/mx1ads/syncflash.c
 *
 * (c) Copyright 2004
 * Techware Information Technology, Inc.
 * http://www.techware.com.tw/
 *
 * Ming-Len Wu <minglen_wu@techware.com.tw>
 *
 * 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 <common.h>
/*#include <mc9328.h>*/
#include <asm/arch/imx-regs.h>

typedef unsigned long * p_u32;

/* 4Mx16x2 IAM=0 CSD1 */

flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];	/* info for FLASH chips    */

/*  Following Setting is for CSD1	*/
#define SFCTL			0x00221004
#define reg_SFCTL		__REG(SFCTL)

#define SYNCFLASH_A10		(0x00100000)

#define CMD_NORMAL		(0x81020300)			/* Normal Mode			*/
#define CMD_PREC		(CMD_NORMAL + 0x10000000)	/* Precharge Command		*/
#define CMD_AUTO		(CMD_NORMAL + 0x20000000)	/* Auto Refresh Command		*/
#define CMD_LMR			(CMD_NORMAL + 0x30000000)	/* Load Mode Register Command	*/
#define CMD_LCR			(CMD_NORMAL + 0x60000000)	/* LCR Command			*/
#define CMD_PROGRAM		(CMD_NORMAL + 0x70000000)

#define MODE_REG_VAL		(CONFIG_SYS_FLASH_BASE+0x0008CC00)	/* Cas Latency 3		*/

/* LCR Command */
#define LCR_READSTATUS		(0x0001C000)			/* 0x70				*/
#define LCR_ERASE_CONFIRM	(0x00008000)			/* 0x20				*/
#define LCR_ERASE_NVMODE	(0x0000C000)			/* 0x30				*/
#define LCR_PROG_NVMODE		(0x00028000)			/* 0xA0				*/
#define LCR_SR_CLEAR		(0x00014000)			/* 0x50				*/

/* Get Status register			*/
u32 SF_SR(void) {
	u32 tmp,tmp1;

	reg_SFCTL	= CMD_PROGRAM;
	tmp		= __REG(CONFIG_SYS_FLASH_BASE);

	reg_SFCTL	= CMD_NORMAL;

	reg_SFCTL	= CMD_LCR;			/* Activate LCR Mode		*/
	tmp1		= __REG(CONFIG_SYS_FLASH_BASE + LCR_SR_CLEAR);

	return tmp;
}

/* check if SyncFlash is ready		*/
u8 SF_Ready(void) {
	u32 tmp;

	tmp	= SF_SR();

	if ((tmp & 0x00800000) && (tmp & 0x001C0000)) {
		printf ("SyncFlash Error code %08x\n",tmp);
	};

	if ((tmp & 0x00000080) && (tmp & 0x0000001C)) {
		printf ("SyncFlash Error code %08x\n",tmp);
	};

	if (tmp == 0x00800080)		/* Test Bit 7 of SR	*/
		return 1;
	else
		return 0;
}

/* Issue the precharge all command		*/
void SF_PrechargeAll(void) {

	u32 tmp;

	reg_SFCTL	= CMD_PREC;			/* Set Precharge Command	*/
	tmp		= __REG(CONFIG_SYS_FLASH_BASE + SYNCFLASH_A10); /* Issue Precharge All Command */
}

/* set SyncFlash to normal mode			*/
void SF_Normal(void) {

	SF_PrechargeAll();

	reg_SFCTL	= CMD_NORMAL;
}

/* Erase SyncFlash				*/
void SF_Erase(u32 RowAddress) {
	u32 tmp;

	reg_SFCTL	= CMD_NORMAL;
	tmp		= __REG(RowAddress);

	reg_SFCTL	= CMD_PREC;
	tmp		= __REG(RowAddress);

	reg_SFCTL	= CMD_LCR;			/* Set LCR mode		*/
	__REG(RowAddress + LCR_ERASE_CONFIRM)	= 0;	/* Issue Erase Setup Command	*/

	reg_SFCTL	= CMD_NORMAL;			/* return to Normal mode	*/
	__REG(RowAddress)	= 0xD0D0D0D0;		/* Confirm			*/

	while(!SF_Ready());
}

void SF_NvmodeErase(void) {
	SF_PrechargeAll();

	reg_SFCTL	= CMD_LCR;			/* Set to LCR mode		*/
	__REG(CONFIG_SYS_FLASH_BASE + LCR_ERASE_NVMODE)  = 0;	/* Issue Erase Nvmode Reg Command */

	reg_SFCTL	= CMD_NORMAL;			/* Return to Normal mode	*/
	__REG(CONFIG_SYS_FLASH_BASE + LCR_ERASE_NVMODE) = 0xC0C0C0C0;	/* Confirm		*/

	while(!SF_Ready());
}

void SF_NvmodeWrite(void) {
	SF_PrechargeAll();

	reg_SFCTL	= CMD_LCR;			/* Set to LCR mode		*/
	__REG(CONFIG_SYS_FLASH_BASE+LCR_PROG_NVMODE) = 0;	/* Issue Program Nvmode reg command */

	reg_SFCTL	= CMD_NORMAL;			/* Return to Normal mode	*/
	__REG(CONFIG_SYS_FLASH_BASE+LCR_PROG_NVMODE) = 0xC0C0C0C0;	/* Confirm not needed	*/
}

/****************************************************************************************/

ulong flash_init(void) {
	int i, j;
	u32 tmp;

/* Turn on CSD1 for negating RESETSF of SyncFLash */

	reg_SFCTL	|= 0x80000000;		/* enable CSD1 for SyncFlash		*/
	udelay(200);

	reg_SFCTL	= CMD_LMR;		/* Set Load Mode Register Command	*/
	tmp		= __REG(MODE_REG_VAL);	/* Issue Load Mode Register Command	*/

	SF_Normal();

	i = 0;

	flash_info[i].flash_id	=  FLASH_MAN_MT | FLASH_MT28S4M16LC;

	flash_info[i].size	= FLASH_BANK_SIZE;
	flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT;

	memset(flash_info[i].protect, 0, CONFIG_SYS_MAX_FLASH_SECT);

	for (j = 0; j < flash_info[i].sector_count; j++) {
		flash_info[i].start[j] = CONFIG_SYS_FLASH_BASE + j * 0x00100000;
	}

	flash_protect(FLAG_PROTECT_SET,
		CONFIG_SYS_FLASH_BASE,
		CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1,
		&flash_info[0]);

	flash_protect(FLAG_PROTECT_SET,
		CONFIG_ENV_ADDR,
		CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
		&flash_info[0]);

	return FLASH_BANK_SIZE;
}

void flash_print_info (flash_info_t *info) {

	int i;

	switch (info->flash_id & FLASH_VENDMASK) {
		case (FLASH_MAN_MT & FLASH_VENDMASK):
			printf("Micron: ");
			break;
		default:
			printf("Unknown Vendor ");
			break;
	}

	switch (info->flash_id & FLASH_TYPEMASK) {
		case (FLASH_MT28S4M16LC & FLASH_TYPEMASK):
			printf("2x FLASH_MT28S4M16LC (16MB Total)\n");
			break;
		default:
			printf("Unknown Chip Type\n");
			return;
			break;
	}

	printf("  Size: %ld MB in %d Sectors\n",
		info->size >> 20, info->sector_count);

	printf("  Sector Start Addresses: ");

	for (i = 0; i < info->sector_count; i++) {
		if ((i % 5) == 0)
			printf ("\n   ");

		printf (" %08lX%s", info->start[i],
			info->protect[i] ? " (RO)" : "     ");
	}

	printf ("\n");
}

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

int flash_erase (flash_info_t *info, int s_first, int s_last) {
	int iflag, cflag, prot, sect;
	int rc = ERR_OK;

/* first look for protection bits */

	if (info->flash_id == FLASH_UNKNOWN)
		return ERR_UNKNOWN_FLASH_TYPE;

	if ((s_first < 0) || (s_first > s_last))
		return ERR_INVAL;

	if ((info->flash_id & FLASH_VENDMASK) != (FLASH_MAN_MT & FLASH_VENDMASK))
		return ERR_UNKNOWN_FLASH_VENDOR;

	prot = 0;

	for (sect = s_first; sect <= s_last; ++sect) {
		if (info->protect[sect])
			prot++;
	}

	if (prot) {
		printf("protected!\n");
		return ERR_PROTECTED;
	}
/*
 * Disable interrupts which might cause a timeout
 * here. Remember that our exception vectors are
 * at address 0 in the flash, and we don't want a
 * (ticker) exception to happen while the flash
 * chip is in programming mode.
 */

	cflag = icache_status();
	icache_disable();
	iflag = disable_interrupts();

/* Start erase on unprotected sectors */
	for (sect = s_first; sect <= s_last && !ctrlc(); sect++) {

		printf("Erasing sector %2d ... ", sect);

/* arm simple, non interrupt dependent timer */

		reset_timer_masked();

		SF_NvmodeErase();
		SF_NvmodeWrite();

		SF_Erase(CONFIG_SYS_FLASH_BASE + (0x0100000 * sect));
		SF_Normal();

		printf("ok.\n");
	}

	if (ctrlc())
		printf("User Interrupt!\n");

	if (iflag)
		enable_interrupts();

	if (cflag)
		icache_enable();

	return rc;
}

/*-----------------------------------------------------------------------
 * Copy memory to flash.
 */

int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) {
	int i;

	for(i = 0; i < cnt; i += 4) {

		SF_PrechargeAll();

		reg_SFCTL	= CMD_PROGRAM;		/* Enter SyncFlash Program mode */
		__REG(addr + i) = __REG((u32)src  + i);

		while(!SF_Ready());
	}

	SF_Normal();

	return ERR_OK;
}
