I need help with UBoot and Parallel Flash

This forum is for users of Microchip MPUs and who are interested in using Linux OS.

Moderator: nferre

romank@randrlabs.com
Location: Oregon
Posts: 12
Joined: Tue Dec 13, 2005 6:50 pm

I need help with UBoot and Parallel Flash

Sat Jun 10, 2006 5:07 pm

Hello,

I have a board similar to at91rm9200ek. The differences are minor. Mostly the differences are in a form of not having some peripherials of at91rm9200ek. However, one difference is giving me a tumor ->

Parallel flash I am using is ATMEL at49bv6416c. The difference is the package. THe only other difference, is that CFI 13h becomes 3 instead of 2 (2 was in the datasheet for the at91rm9200ek parallel flash chip).

If I do not modify UBoot and load, UBoot does not see Bank 1. I get Bank 0 - Ram perfect, but my Bank 1 is 0 and unknown.

I am reading through the UBoot source, but I don't know how to connect the dots betwwen the datasheet and the uboot config.

I think that I have to change the flash settings in /u-boot-1.1.4/include/configs/at91rm9200dk.h. I cannot figure out what settings are different between the at91rm9200ek flash and mine.

Please push me in a right direction.
Roman
User avatar
koan
Contact:
Location: Bergamo, Italia
Posts: 212
Joined: Wed May 12, 2004 6:59 pm

Sat Jun 10, 2006 6:00 pm

Hi Roman,
I have a board here with AT49BV6416 perfectly working with u-boot-1.1.4
In your case you may start playing with u-boot-1.1.4/board/at91rm9200dk/flash.c
digging and understanding what is happening, the CFI 13h you mentioned is a good path to the solution.
HTH
Best regards

Marco Cavallini
Koan s.a.s. - Bergamo - ITALIA
Embedded and Real-Time Software Engineering
www.KoanSoftware.com | www.KaeilOS.com
User avatar
koan
Contact:
Location: Bergamo, Italia
Posts: 212
Joined: Wed May 12, 2004 6:59 pm

Sat Jun 10, 2006 6:09 pm

BTW after a quick look to the AT49BV6416 and AT49BV641C datasheets
you can see into chapter 4. that the Command Definition Table are completely different.
So you will have to write your new flash.c driver for u-boot and maybe for Linux kernel too.
If you need help, this is the work my company and me usually do for living :wink:

Best regards

Marco Cavallini
Koan s.a.s. - Bergamo - ITALIA
Embedded and Real-Time Software Engineering
www.KoanSoftware.com | www.KaeilOS.com
romank@randrlabs.com
Location: Oregon
Posts: 12
Joined: Tue Dec 13, 2005 6:50 pm

Mon Jun 12, 2006 9:25 pm

koan wrote:BTW after a quick look to the AT49BV6416 and AT49BV641C datasheets
you can see into chapter 4. that the Command Definition Table are completely different.
So you will have to write your new flash.c driver for u-boot and maybe for Linux kernel too.
If you need help, this is the work my company and me usually do for living :wink:

Best regards

Marco Cavallini
Koan s.a.s. - Bergamo - ITALIA
Embedded and Real-Time Software Engineering
www.KoanSoftware.com | www.KaeilOS.com
I made a new trial driver for the at49bv6416c flash memory.
I think that it is wrong. It works, but it causes crashes. I don't think that the error is on uboot 1.1.4 side. I think that the error is mine.

Here is my new driver trial code

Code: Select all

/**
 * OUR FLASHY FLASH DRIVER
 **/

#include <common.h>


#define		MEM_FLASH_BASE		(*(volatile u16 *)(CFG_FLASH_BASE))


#define 	PRODUCT_ID_IN_CODE		0x90
#define		COMMAND_READ			0xFF
#define		COMMAND_SECTOR_UNLOCK_I		0x60
#define		COMMAND_SECTOR_UNLOCK_II	0xD0
#define		COMMAND_SECTOR_ERASE_SETUP	0x20
#define		COMMAND_GENERAL_ERASE_CONFIRM 	0xD0
#define		COMMAND_READ_STATUS_REGISTER	0x70
#define		COMMAND_WORD_PROGRAM_40		0x40

#define		ATM_ID_BV6416C			0xC5


#define READY 1
#define ERR   2
#define TMO   4


/**
 *	CFG_FLASH_BASE comes from include/configs/at91rm9200dk.h
 *	CFG_MAX_FLASH_BANKS comes from include/configs/at91rm9200dk.h
 *	PHYS_FLASH_1 comes from include/configs/at91rm9200dk.h
 **/

flash_info_t    flash_info[CFG_MAX_FLASH_BANKS];


/* Flash Organization Structure */
typedef struct OrgDef
{
	unsigned int sector_number;
	unsigned int sector_size;
} OrgDef;

OrgDef OrgAT49BV6416C[] =
{
	{   8,  8*1024 },	/*   8 *  8 kBytes sectors */
	{ 127, 64*1024 },	/* 127 * 64 kBytes sectors */
};


void flash_identification (flash_info_t * info)
{
	volatile u16 manuf_code, device_code, add_device_code;

	MEM_FLASH_BASE = PRODUCT_ID_IN_CODE;

	manuf_code 	= *(volatile u16 *) CFG_FLASH_BASE;
	device_code 	= *(volatile u16 *) (CFG_FLASH_BASE + 2);
	add_device_code = *(volatile u16 *) (CFG_FLASH_BASE + (3 << 1));

	/* Vendor type */
	info->flash_id = ATM_MANUFACT & FLASH_VENDMASK;
	printf ("Atmel: ");

 	if ((device_code & FLASH_TYPEMASK) == (ATM_ID_BV6416C & FLASH_TYPEMASK)) 
	{
 		info->flash_id |= ATM_ID_BV6416C & FLASH_TYPEMASK;
 		printf ("AT49BV6416C (64Mbit)\n");
 	}
}

ushort flash_number_sector(OrgDef *pOrgDef, unsigned int nb_blocks)
{
	int i, nb_sectors = 0;

	for (i=0; i<nb_blocks; i++){
		nb_sectors += pOrgDef[i].sector_number;
	}

	return nb_sectors;
}

void flash_unlock_sector(flash_info_t * info, unsigned int sector)
{
	volatile u16 *addr = (volatile u16 *) (info->start[sector]);
	
	*addr = COMMAND_SECTOR_UNLOCK_I;
	*addr = COMMAND_SECTOR_UNLOCK_II;
}

ulong flash_init (void)
{
	int i, j, k;
	unsigned int flash_nb_blocks, sector;
	unsigned int start_address;
	OrgDef *pOrgDef;

	ulong size = 0;

	for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) 
	{
		ulong flashbase = 0;

		flash_identification (&flash_info[i]);

		if ((flash_info[i].flash_id & FLASH_TYPEMASK) == (ATM_ID_BV6416C & FLASH_TYPEMASK))
		{	/* AT49BV6416C Flash */

			pOrgDef = OrgAT49BV6416C;
			flash_nb_blocks = sizeof (OrgAT49BV6416C) / sizeof (OrgDef);
		} else 
		{
			flash_nb_blocks = 0;
		}

		flash_info[i].sector_count = flash_number_sector(pOrgDef, flash_nb_blocks);
		memset (flash_info[i].protect, 0, flash_info[i].sector_count);

		if (i == 0)
			flashbase = PHYS_FLASH_1;
		else
			panic ("error: configured too many flash banks!\n");

		sector = 0;
		start_address = flashbase;
		flash_info[i].size = 0;

		for (j = 0; j < flash_nb_blocks; j++) {
			for (k = 0; k < pOrgDef[j].sector_number; k++) {
				flash_info[i].start[sector++] = start_address;
				start_address += pOrgDef[j].sector_size;
				flash_info[i].size += pOrgDef[j].sector_size;
			}
		}

		size += flash_info[i].size;


		/* Unlock all sectors at reset */
		for (j=0; j<flash_info[i].sector_count; j++){
			flash_unlock_sector(&flash_info[i], j);
		}
	}

	/* Protect binary boot image */
	flash_protect (FLAG_PROTECT_SET,
		       CFG_FLASH_BASE,
		       CFG_FLASH_BASE + CFG_BOOT_SIZE - 1, &flash_info[0]);

	/* Protect environment variables */
	flash_protect (FLAG_PROTECT_SET,
		       CFG_ENV_ADDR,
		       CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);

	/* Protect U-Boot gzipped image */
	flash_protect (FLAG_PROTECT_SET,
		       CFG_U_BOOT_BASE,
		       CFG_U_BOOT_BASE + CFG_U_BOOT_SIZE - 1, &flash_info[0]);

	return size;
}

void flash_print_info (flash_info_t * info)
{
	int i;

	switch (info->flash_id & FLASH_VENDMASK) 
	{
		case (ATM_MANUFACT & FLASH_VENDMASK):
			printf ("Atmel: ");
		break;

		default:
			printf ("Unknown Vendor ");
		break;
	}

	switch (info->flash_id & FLASH_TYPEMASK) 
	{
		case (ATM_ID_BV6416C & FLASH_TYPEMASK):
			printf ("AT49BV6416 (64Mbit)\n");
		break;
		default:
			printf ("Unknown Chip Type\n");
		return;
	}

	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)
{
	u16 result;
	int iflag, cflag, prot, sect;
	int rc = ERR_OK;
	int chip1;

	/* 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) !=
		(ATM_MANUFACT & FLASH_VENDMASK)) {
		return ERR_UNKNOWN_FLASH_VENDOR;
	}

	prot = 0;

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

	if (prot)
		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 ();

		if (info->protect[sect] == 0) 
		{
			/* not protected */
			volatile u16 *addr = (volatile u16 *) (info->start[sect]);

			*addr = COMMAND_SECTOR_ERASE_SETUP;
			*addr = COMMAND_GENERAL_ERASE_CONFIRM;

			/* wait until flash is ready */
			chip1 = 0;

			do
			{
				*addr  = COMMAND_READ_STATUS_REGISTER;
				result = *addr;

				/* check timeout */
				if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) 
				{
					chip1 = TMO;
					break;
				}

				if( result&0x0080 )
				{
					chip1 = READY;
				}

			}
			while (!chip1);

			*addr = COMMAND_READ;

			if (chip1 == ERR) 
			{
				rc = ERR_PROG_ERROR;
			}	
			else if (chip1 == TMO)
			{
				rc = ERR_TIMOUT;
			}
			else
			{
				printf ("ok.\n");
			}
		}
		else
		{
			/* it was protected */
			printf ("protected!\n");
		}
	}

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

	/* allow flash to settle - wait 10 ms */
	udelay_masked (10000);

	if (iflag)
		enable_interrupts ();

	if (cflag)
		icache_enable ();

	return rc;
}

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

volatile static int write_word (flash_info_t * info, ulong dest, ulong data)
{
	volatile ulong *addr = (volatile ulong *) dest;
	ulong result;
	int rc = ERR_OK;
	int cflag, iflag;
	int chip1;

	/*
	 * Check if Flash is (sufficiently) erased
	 */
	result = *addr;

	if ((result & data) != data)
		return ERR_NOT_ERASED;

	/*
	 * 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 ();

	*addr = COMMAND_WORD_PROGRAM_40;
	*addr = data;

	/* arm simple, non interrupt dependent timer */
	reset_timer_masked ();

	/* wait until flash is ready */
	chip1 = 0;
	do 
	{
		*addr  = COMMAND_READ_STATUS_REGISTER;
		result = *addr;

		/* check timeout */
		if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) 
		{
			chip1 = TMO;
			break;
		}

		if( result&0x0080 )
		{
			chip1 = READY;
		}
	} while (!chip1);

	*addr = COMMAND_READ;

	if (chip1 == TMO || *addr != data)
		rc = ERR_PROG_ERROR;

	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)
{
	ulong wp, data;
	int rc;

	if (addr & 1) {
		printf ("unaligned destination not supported\n");
		return ERR_ALIGN;
	};

	if ((int) src & 1) {
		printf ("unaligned source not supported\n");
		return ERR_ALIGN;
	};

	wp = addr;

	while (cnt >= 2) {
		data = *((volatile u16 *) src);
		if ((rc = write_word (info, wp, data)) != 0) {
			return (rc);
		}
		src += 2;
		wp += 2;
		cnt -= 2;
	}

	if (cnt == 1) {
		data = (*((volatile u8 *) src)) | (*((volatile u8 *) (wp + 1)) <<
										   8);
		if ((rc = write_word (info, wp, data)) != 0) {
			return (rc);
		}
		src += 1;
		wp += 1;
		cnt -= 1;
	};

	return ERR_OK;
}

romank@randrlabs.com
Location: Oregon
Posts: 12
Joined: Tue Dec 13, 2005 6:50 pm

Tue Jun 13, 2006 7:45 am

koan wrote:BTW after a quick look to the AT49BV6416 and AT49BV641C datasheets
you can see into chapter 4. that the Command Definition Table are completely different.
So you will have to write your new flash.c driver for u-boot and maybe for Linux kernel too.
If you need help, this is the work my company and me usually do for living :wink:

Best regards

Marco Cavallini
Koan s.a.s. - Bergamo - ITALIA
Embedded and Real-Time Software Engineering
www.KoanSoftware.com | www.KaeilOS.com
I believe that my flash memory becomes corrupt. I updated my driver, and my driver does readback and confirm on write. I also can flash new uboot in the parallel flash and execute it on booting ok.

However, if I write my env variables or anything else in flash later, I read back corrupted values. What could be off?

Roman

Return to “LINUX”

Who is online

Users browsing this forum: No registered users and 5 guests