/*
 * Write a word to Flash, returns:
 * 0 - OK
 * 1 - write timeout
 * 2 - Flash not erased
 */
static int write_word (flash_info_t *info, ulong dest, ulong data)
{
	volatile ulong addr = info->start[0];
	ulong start;
	int i;

	flash_to_xd();

	/* Check if Flash is (sufficiently) erased */
	if ((in32(dest) & data) != data) {
		flash_to_mem();
		return (2);
	}

	/* write each byte out */
	for (i = 0; i < 4; i++) {
		char *data_ch = (char *)&data;
		int flag = disable_interrupts();

		out8(addr + 0x555, 0xAA);
		iobarrier_rw();
		out8(addr + 0x2AA, 0x55);
		iobarrier_rw();
		out8(addr + 0x555, 0xA0);
		iobarrier_rw();
		out8(dest+i, data_ch[i]);
		iobarrier_rw();

		/* re-enable interrupts if necessary */
		if (flag)
			enable_interrupts();

		/* data polling for D7 */
		start = get_timer (0);
		while ((in8(dest+i) & 0x80) != (data_ch[i] & 0x80)) {
			if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
				flash_reset (addr);
				flash_to_mem();
				return (1);
			}
			iobarrier_rw();
		}
	}

	flash_reset (addr);
	flash_to_mem();
	return (0);
}
示例#2
0
文件: flash.c 项目: cmp1084/u-boot
ulong flash_get_size(FPWV * addr, flash_info_t * info) {
	int i;

	/* Write auto select command: read Manufacturer ID                     */
	/* Write auto select command sequence and test FLASH answer            */
	addr[FLASH_CYCLE1] = (FPW) 0x00AA00AA;	/* for AMD, Intel ignores this */
	addr[FLASH_CYCLE2] = (FPW) 0x00550055;	/* for AMD, Intel ignores this */
	addr[FLASH_CYCLE1] = (FPW) 0x00900090;	/* selects Intel or AMD        */

	/* The manufacturer codes are only 1 byte, so just use 1 byte.         */
	/* This works for any bus width and any FLASH device width.            */
	udelay(100);
	switch (addr[FLASH_ID1] & 0x00ff) {
	case (uchar) AMD_MANUFACT:
		info->flash_id = FLASH_MAN_AMD;
		break;
	default:
		printf("unknown vendor=%x ", addr[FLASH_ID1] & 0xff);
		info->flash_id = FLASH_UNKNOWN;
		info->sector_count = 0;
		info->size = 0;
		break;
	}

	/* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus.     */
	if (info->flash_id != FLASH_UNKNOWN) {
		switch ((FPW) addr[FLASH_ID2]) {
		case (FPW) AMD_ID_MIRROR:
			/* MIRROR BIT FLASH, read more ID bytes */
			if ((FPW) addr[FLASH_ID3] == (FPW) AMD_ID_LV256U_2
			    && (FPW) addr[FLASH_ID4] == (FPW) AMD_ID_LV256U_3) {
				/* attention: only the first 16 MB will be used in u-boot */
				info->flash_id += FLASH_AMLV256U;
				info->sector_count = 512;
				info->size = 0x02000000;
				for (i = 0; i < info->sector_count; i++) {
					info->start[i] =
					    (ulong) addr + 0x10000 * i;
				}
				break;
			}
			/* fall thru to here ! */
		default:
			printf("unknown AMD device=%x %x %x",
			       (FPW) addr[FLASH_ID2], (FPW) addr[FLASH_ID3],
			       (FPW) addr[FLASH_ID4]);
			info->flash_id = FLASH_UNKNOWN;
			info->sector_count = 0;
			info->size = 0x800000;
			break;
		}

		/* Put FLASH back in read mode */
		flash_reset(info);
	}
	return (info->size);
}
示例#3
0
/*
 * Write a word to Flash, returns:
 * 0 - OK
 * 1 - write timeout
 * 2 - Flash not erased
 */
static int write_word (flash_info_t *info, ulong dest, ulong data)
{
	volatile u32 addr = info->start[0];
	ulong start;
	int flag, i;

	/* Check if Flash is (sufficiently) erased */
	if ((in32(dest) & data) != data) {
		return (2);
	}
	/* Disable interrupts which might cause a timeout here */
	flag = disable_interrupts();

	/* first, perform an unlock bypass command to speed up flash writes */
	out8(addr + 0x555, 0xAA);
	iobarrier_rw();
	out8(addr + 0x2AA, 0x55);
	iobarrier_rw();
	out8(addr + 0x555, 0x20);
	iobarrier_rw();

	/* write each byte out */
	for (i = 0; i < 4; i++) {
		char *data_ch = (char *)&data;
		out8(addr, 0xA0);
		iobarrier_rw();
		out8(dest+i, data_ch[i]);
		iobarrier_rw();
		udelay(10); /* XXX */
	}

	/* we're done, now do an unlock bypass reset */
	out8(addr, 0x90);
	iobarrier_rw();
	out8(addr, 0x00);
	iobarrier_rw();

	/* re-enable interrupts if necessary */
	if (flag)
		enable_interrupts();

	/* data polling for D7 */
	start = get_timer (0);
	while ((in32(dest) & 0x80808080) != (data & 0x80808080)) {
		if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
			return (1);
		}
		iobarrier_rw();
	}

	flash_reset (addr);

	return (0);
}
示例#4
0
static int
flash_eraseblk(unsigned long addr)
{
	unsigned long a;
	uint16 st;

	a = (unsigned long)addr;
	if (a >= flashutl_desc->size)
		return 1;

	a = block(a, BLOCK_BASE);

	/* Ensure blocks are unlocked (for intel chips) */
	if (flashutl_cmd->type == BSC) {
		scmd((unsigned char)INTEL_UNLOCK1, a);
		scmd((unsigned char)INTEL_UNLOCK2, a);
	}

	if (flashutl_cmd->pre_erase)
		cmd(flashutl_cmd->pre_erase, CMD_ADDR);
	if (flashutl_cmd->erase_block)
		cmd(flashutl_cmd->erase_block, a);
	if (flashutl_cmd->confirm)
		scmd(flashutl_cmd->confirm, a);

	if (flashutl_wsz == sizeof(uint8))
		st = flash_poll(a, 0xff);
	else
		st = flash_poll(a, 0xffff);

	flash_reset();

	if (st) {
		DPRINT(("Erase of block 0x%08lx-0x%08lx failed\n",
			a, block((unsigned long)addr, BLOCK_LIM)));
		return st;
	}

	DPRINT(("Erase of block 0x%08lx-0x%08lx done\n", a, block((unsigned long)addr, BLOCK_LIM)));

	return 0;
}
示例#5
0
文件: flash.c 项目: sdikiy/VGAduino
int flash_page_program(uint8_t buf[], uint16_t row_addr) {
  int j;
  flash_reset(1);

  CLE_FLASH_HI();
  *(volatile uint8_t*)(FLASH_ADDR) = (uint8_t)0x80;
  CLE_FLASH_LO();
  ALE_FLASH_HI();
  *(volatile uint8_t*)(FLASH_ADDR) = (uint8_t)0x00;
  *(volatile uint8_t*)(FLASH_ADDR) = (uint8_t)0x00;
  *(volatile uint8_t*)(FLASH_ADDR) = (uint8_t)(0xFF & row_addr);
  *(volatile uint8_t*)(FLASH_ADDR) = (uint8_t)((0xFF & row_addr) >> 8);
  ALE_FLASH_LO();
  for(int i = 0; i < 2112; i++) {
    *(volatile uint8_t*)(FLASH_ADDR) = buf[i];
  }
  CLE_FLASH_HI();
  *(volatile uint8_t*)(FLASH_ADDR) = 0x10;
  CLE_FLASH_LO();
  j = flash_wait_rb(0x7FFF);
  return j;
}
示例#6
0
void main(void)
{
  byte test;
  byte manuf_id;
  word device_id;
  byte far *str;
  word test2,i;
  dword sec_size=0;
  long count=0;

  printf("Beginning test.....\n\n");

  /* First, poke around the memory map to see what kind of
     flash is installed in the socket...assume a DL800B */

  /* The purpose of init_flash is to perform any system memory
     mapping required, and to set up pointers to those region(s).
     init_flash() also selects the proper sector organization
     table defined in flash.c 
     Note: init_flash() will need to be provided by users of
     the flash.c routines */

  if(!init_flash(AM29DL800B)) {
	 exit(1);
  }

  /* Verify the manufacturer code is indeed 0x01 for AMD */
  manuf_id = flash_get_manuf_code(0);

  switch(manuf_id)
  {
	case AMDPART: printf("AMD Flash found in socket...\n");
   		      break;
	default: printf("Non AMD part found in socket...exiting.\n");
		 exit(1);
		 break;
  }

  /* Poll the device id so that the proper sector layout table
     is used for the device in the socket */

  printf("Polling part for Device ID...");

  /* Retrieve the device ID for this AMD flash part.  All device
     id's are stored in flash.h */

  device_id = flash_get_device_id(0);

  switch(device_id)
  {
	case ID_AM29DL800T: 	printf("found an Am29DL800T\n");
				if(!init_flash(AM29DL800T)) exit(1);
				break;

	case ID_AM29DL800B:  	printf("found an Am29DL800B\n");
				if(!init_flash(AM29DL800B)) exit(1);
				break;

	case ID_AM29LV800T:  	printf("found an Am29LV800T\n");
				if(!init_flash(AM29LV800T)) exit(1);
				break;

	case ID_AM29LV800B:  	printf("found an Am29LV800B\n");
				if(!init_flash(AM29LV800B)) exit(1);
				break;

	case ID_AM29LV160B:  	printf(  "found an Am29LV160B\n");
				if(!init_flash(AM29LV160B)) exit(1);
				break;

	case ID_AM29LV400B:  	printf(  "found an Am29LV400B\n");
				if(!init_flash(AM29LV400B)) exit(1);
				break;

	default: printf("error reading Device ID...exiting.\n");
		 exit(1);
		 break;
  }

  randomize();

  /* flash_get_status uses DQ7, DQ5, and DQ2 polling to get the
     status of the flash.  All status codes are defined in flash.h
     Also note that for the DL parts, status is bank dependent */

  printf("Checking current flash status...flash is ");
  test = flash_get_status(0);
  switch(test)
  {
	 case STATUS_READY: 	printf("[Ready]\n");break;
	 case STATUS_BUSY: 	printf("[Busy]\n");break;
	 case STATUS_ERSUSP: 	printf("[Erase Suspended]\n");break;
	 case STATUS_TIMEOUT: 	printf("[Timed Out]\n");break;
	 default: 		printf("Error!\n"); exit(1);break;
  }

  printf("Performing API tests...\n\n");

  /* flash_sector_erase_int() is the function which erases a single
     sector.  It is different from flash_sector_erase() in that it
     'interrupts' execution of the program until the erase is completed.
     For erasing a sector without pausing use flash_sector_erase(). */

  flash_reset(); /* Quick safe check */

  printf("Erasing sector 8...");
  flash_sector_erase_int(8);
  printf("done.\n");

  printf("Verifying erase...");

  flash_get_sector_size(8, &sec_size); /* Get # of byte */

  /* A simple test which reads every word from the flash, and checks
     to see if every word contains the data 0xFFFF, which indicates
     an erased word. */

  for (count=0 ; count < (sec_size/2); count++) {
	 if(count%2048 == 0)
		printf("."); /*print out some dots to show the program hasn't frozen */
	 if (flash_read_word(8,count) != 0xFFFF) {
		printf("erase not completed sucessfully!\n");
		exit(1);
	 }
  }
  printf("erase successful.\n");

  /* flash_write_word() takes word data and programs it to the flash
     at the indicated offset.  Note that this data must be *word aligned*,
     or else programming errors can result.
     It is also good to check the word for 0xFFFF data before programming. */
  
  printf("Writing a single word [0xABCD]\n");
  flash_write_word(8,0,0xABCD);

  /* flash_read_word() returns a single word of data at the specified
     sector/offset .  Must also be word aligned */
  
  printf("After write(0xABCD): %4x\n", flash_read_word(8,0));

  str = (byte far *) calloc(0x7FFF, sizeof(byte));

  /* Randomize the string with random ASCII characters */
  for(i=0; i<0x7FFF; i++) {
	 str[i] = (byte) (41 + (rand() % 26));
  }

  printf("Erasing sector 9...");
  flash_sector_erase_int(9);
  printf("done.\n");

  /* flash_write_string() is a function to program bulk data from a C
     buffer.  It is a bit faster than looping techniques using
     flash_write_word() because function overhead is eliminated. */
  
  printf("Writing 32 kbyte string...");
  flash_write_string(9,0,str,0x7FFE);

  printf("done.\n\n");

  printf("Testing erase suspend\n");
  printf("Beginning erase...\n");

/* This is an example of flash_sector_erase().  Note that the program will
     simply issue the command, and execution will continue while the
     flash is erasing. */
  
  flash_sector_erase(10);

  /* flash_erase_suspend will suspend an erase in progress.  The application
     can then do any reading of data from that sector, or another sector. */
  
  printf("Suspending erase...");
  flash_erase_suspend(10);
  printf("done.\n");

  /* The current flash status should now be STATUS_ERSUSP */
  printf("Checking current flash status...flash is ");
  test = flash_get_status(10);
  switch(test)
  {
	 case STATUS_READY: printf("[Ready]\n");break;
	 case STATUS_BUSY: printf("[Busy]\n");break;
	 case STATUS_ERSUSP: printf("[Erase Suspended]\n");break;
	 case STATUS_TIMEOUT: printf("[Timed Out]\n");break;
	 default: printf("Error!\n"); exit(1);break;
  }

  /* Now we can resume the erase previously suspended */
  printf("Resuming erase after status check..");
  flash_erase_resume(10);
  printf("done.\n");

  /* Now for a test of unlock bypass mode */
  /* Unlock bypass allows for faster programming of flash data in that
     the number of required bus cycles is cut in half.  The most benefit
     can be realized when programming large amounts of data using
     flash_write_string_ub() */

  printf("Entering unlock bypass mode...\n");
  flash_sector_erase_int(11);
  flash_ub(11); /* Enter unlock bypass mode */

  printf("Programming a string in unlock bypass mode..");
  flash_write_string_ub(11,0,str,0x7FFE);
  printf("done.\n");

  printf("Exiting unlock bypass mode..\n");
  flash_reset_ub();

  flash_reset();

  /* Last thing is a quick loop through all the sectors 
     to check for sector protection. */

  printf("\nVerifying sector protection...\n");

  flash_get_numsectors(&test2);

  printf("This device contains %3i sectors: \n", test2);
  for(i=0; i < test2; i++) {
	 test = flash_sector_protect_verify(i);
	 flash_get_sector_size(i, &size);
	 printf("Verify sector #%2i, size [%-5li]: ",
	          i, size);
	 if (test == 0x01)
		printf("sector is protected[%2i].\n", test);
	 else
		printf("sector is not protected[%2i].\n", test);
	 flash_reset();
  }


  printf("Test drive done!\n");
  free(str);
  exit(0);
}
示例#7
0
文件: flash.c 项目: cmp1084/u-boot
int flash_erase(flash_info_t * info, int s_first, int s_last) {
	FPWV *addr;
	int flag, prot, sect;
	int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
	ulong start, now, last;
	int rcode = 0;

	if ((s_first < 0) || (s_first > s_last)) {
		if (info->flash_id == FLASH_UNKNOWN) {
			printf("- missing\n");
		} else {
			printf("- no sectors to erase\n");
		}
		return 1;
	}

	switch (info->flash_id & FLASH_TYPEMASK) {
	case FLASH_AMLV256U:
		break;
	case FLASH_UNKNOWN:
	default:
		printf("Can't erase unknown flash type %08lx - aborted\n",
		       info->flash_id);
		return 1;
	}

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

	if (prot) {
		printf("- Warning: %d protected sectors will not be erased!\n",
		       prot);
	} else {
		printf("\n");
	}

	last = get_timer(0);

	/* Start erase on unprotected sectors */
	for (sect = s_first; sect <= s_last && rcode == 0; sect++) {
		if (info->protect[sect] != 0) {	/* protected, skip it */
			continue;
		}
		/* Disable interrupts which might cause a timeout here */
		flag = disable_interrupts();

		addr = (FPWV *) (info->start[sect]);
		if (intel) {
			*addr = (FPW) 0x00500050;	/* clear status register */
			*addr = (FPW) 0x00200020;	/* erase setup */
			*addr = (FPW) 0x00D000D0;	/* erase confirm */
		} else {
			/* must be AMD style if not Intel */
			FPWV *base;	/* first address in bank */

			base = (FPWV *) (info->start[0]);
			base[FLASH_CYCLE1] = (FPW) 0x00AA00AA;	/* unlock */
			base[FLASH_CYCLE2] = (FPW) 0x00550055;	/* unlock */
			base[FLASH_CYCLE1] = (FPW) 0x00800080;	/* erase mode */
			base[FLASH_CYCLE1] = (FPW) 0x00AA00AA;	/* unlock */
			base[FLASH_CYCLE2] = (FPW) 0x00550055;	/* unlock */
			*addr = (FPW) 0x00300030;	/* erase sector */
		}

		/* re-enable interrupts if necessary */
		if (flag) {
			enable_interrupts();
		}
		start = get_timer(0);

		/* wait at least 50us for AMD, 80us for Intel. */
		/* Let's wait 1 ms.                            */
		udelay(1000);

		while ((*addr & (FPW) 0x00800080) != (FPW) 0x00800080) {
			if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
				printf("Timeout\n");
				if (intel) {
					/* suspend erase        */
					*addr = (FPW) 0x00B000B0;
				}
				flash_reset(info);	/* reset to read mode */
				rcode = 1;	/* failed */
				break;
			}
			/* show that we're waiting */
			if ((get_timer(last)) > CFG_HZ) {
				/* every second */
				putc('.');
				last = get_timer(0);
			}
		}
		/* show that we're waiting */
		if ((get_timer(last)) > CFG_HZ) {
			/* every second */
			putc('.');
			last = get_timer(0);
		}
		flash_reset(info);	/* reset to read mode */
	}
	printf(" done\n");
	return (rcode);
}
示例#8
0
/* Read the flash ID and set the globals */
int
sysFlashInit(char *flash_str)
{
	osl_t *osh;
	uint32 fltype = PFLASH;
	uint16 flash_vendid = 0;
	uint16 flash_devid = 0;
	int idx;
	struct sflash *sflash;

	/*
	 * Check for serial flash.
	 */
	sih = si_kattach(SI_OSH);
	ASSERT(sih);

	osh = si_osh(sih);

	cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX);
	ASSERT(cc);

	flashutl_base = (void *)OSL_UNCACHED((uintptr)SI_FLASH2);
	/* Select SFLASH ? */
	fltype = R_REG(osh, &cc->capabilities) & CC_CAP_FLASH_MASK;
	if (fltype == SFLASH_ST || fltype == SFLASH_AT) {
		if (sih->ccrev == 12)
			flashutl_base = (void *)OSL_UNCACHED((uintptr)SI_FLASH2);
		else
			flashutl_base = (void *)OSL_CACHED((uintptr)SI_FLASH2);
		sflash = sflash_init(sih, cc);
		flashutl_cmd = &sflash_cmd_t;
		flashutl_desc = &sflash_desc;
		flashutl_desc->size = sflash->size;
		if (flash_str)
			sprintf(flash_str, "SFLASH %d kB", sflash->size/1024);
		return (0);
	}

	flashutl_wsz = (R_REG(osh, &cc->flash_config) & CC_CFG_DS) ? sizeof(uint16) : sizeof(uint8);
	ASSERT(flashutl_wsz == sizeof(uint8) || flashutl_wsz == sizeof(uint16));

	/*
	 * Parallel flash support
	 *  Some flashes have different unlock addresses, try each it turn
	 */
	for (idx = 0;
	     fltype == PFLASH && idx < ARRAYSIZE(flash_cmds);
	     idx ++) {
		flashutl_cmd = &flash_cmds[idx];
		if (flashutl_cmd->type == OLD)
			continue;

		if (flashutl_cmd->read_id) {
			cmd(flashutl_cmd->read_id, CMD_ADDR);
			/* Delay for turn around time */
			OSL_DELAY(1);
		}

#ifdef MIPSEB
#ifdef	BCMHND74K
		flash_vendid = flash_readword(FLASH_ADDR(0)^6);
		flash_devid = flash_readword(FLASH_ADDR(2)^6);
#else	/* !74K, bcm33xx */
		flash_vendid = flash_readword(FLASH_ADDR(2));
		flash_devid = flash_readword(FLASH_ADDR(0));
#endif	/* BCMHND74K */
#else
		flash_vendid = flash_readword(FLASH_ADDR(0));
		flash_devid = flash_readword(FLASH_ADDR(2));
#endif /* MIPSEB */

		/* Funky AMD, uses 3 byte device ID so use first byte (4th addr) to
		 * identify it is a 3-byte ID and use the next two bytes (5th & 6th addr)
		 * to form a word for unique identification of format xxyy, where
		 * xx = 5th addr and yy = 6th addr
		 */
		if ((flash_vendid == 1) &&
		      ((flash_devid == 0x227e && flashutl_wsz == sizeof(uint16)) ||
		        (flash_devid == 0x7e && flashutl_wsz == sizeof(uint8)))) {
			/* Get real devid */
			uint16 flash_devid_5th;
#ifdef MIPSEB
#ifdef	BCMHND74K
			flash_devid_5th = flash_readword(FLASH_ADDR(0x1c)^6) << 8;
			flash_devid = (flash_readword(FLASH_ADDR(0x1e)^6) & 0xff) | flash_devid_5th;
#else	/* !74K, bcm33xx */
			flash_devid_5th = flash_readword(FLASH_ADDR(0x1e)) << 8;
			flash_devid = (flash_readword(FLASH_ADDR(0x1c)) & 0xff) | flash_devid_5th;
#endif	/* BCMHND74K */
#else
			flash_devid_5th = flash_readword(FLASH_ADDR(0x1c)) << 8;
			flash_devid = (flash_readword(FLASH_ADDR(0x1e)) & 0xff) | flash_devid_5th;
#endif /* MIPSEB */
		}

		flashutl_desc = flashes;
		while (flashutl_desc->mfgid != 0 &&
		       !(flashutl_desc->mfgid == flash_vendid &&
		         flashutl_desc->devid == flash_devid)) {
			flashutl_desc++;
		}
		if (flashutl_desc->mfgid != 0)
			break;
	}

	if (flashutl_desc->mfgid == 0) {
		flashutl_desc = NULL;
		flashutl_cmd = NULL;
	} else {
		flashutl_cmd = flash_cmds;
		while (flashutl_cmd->type != 0 && flashutl_cmd->type != flashutl_desc->type)
			flashutl_cmd++;
		if (flashutl_cmd->type == 0)
			flashutl_cmd = NULL;
	}

	if (flashutl_cmd != NULL) {
		flash_reset();
	}

	if (flashutl_desc == NULL) {
		if (flash_str)
			sprintf(flash_str, "UNKNOWN 0x%x 0x%x", flash_vendid, flash_devid);
		DPRINT(("Flash type UNKNOWN\n"));
		return 1;
	}

	if (flash_str)
		strcpy(flash_str, flashutl_desc->desc);
	DPRINT(("Flash type \"%s\"\n", flashutl_desc->desc));

	return 0;
}
示例#9
0
static int
flash_write(unsigned long off, uint8 *src, uint nbytes)
{
	uint8 *dest;
	uint16 st, data;
	uint i, len;

	ASSERT(flashutl_desc != NULL);

	if (off >= flashutl_desc->size)
		return 1;

	ASSERT(!(off & (flashutl_wsz - 1)));

	dest = (uint8*)FLASH_ADDR(off);
	st = 0;

	while (nbytes) {
		if ((flashutl_desc->type == SCS) &&
		    flashutl_cmd->write_buf &&
		    ((off & (WBUFSIZE - 1)) == 0)) {
			/* issue write command */
			if (flashutl_cmd->write_buf)
				cmd(flashutl_cmd->write_buf, off);
			if ((st = flash_poll(off, DONE)))
				continue;

			len = MIN(nbytes, WBUFSIZE);

#ifndef MIPSEB
			/* write (length - 1) */
			cmd(len / sizeof(uint16) - 1, off);

			/* write data */
			for (i = 0; i < len; i += sizeof(uint16),
			             dest += sizeof(uint16), src += sizeof(uint16))
				*(uint16 *)dest = *(uint16 *)src;
#else
			/*
			 * BCM4710 endianness is word consistent but
			 * byte/short scrambled. This write buffer
			 * mechanism appears to be sensitive to the
			 * order of the addresses hence we need to
			 * unscramble them. We may also need to pad
			 * the source with two bytes of 0xffff in case
			 * an odd number of shorts are presented.
			 */

			/* write (padded length - 1) */
			cmd((ROUNDUP(len, sizeof(uint32)) / sizeof(uint16)) - 1, off);

			/* write data (plus pad if necessary) */
			for (i = 0; i < ROUNDUP(len, sizeof(uint32)); i += sizeof(uint32),
			             dest += sizeof(uint32), src += sizeof(uint32)) {
				*((uint16 *)dest + 1) = ((i + sizeof(uint16)) < len) ?
				        *((uint16 *)src + 1) : 0xffff;
				*(uint16 *)dest = *(uint16 *)src;
			}
#endif /* MIPSEB */

			/* write confirm */
			if (flashutl_cmd->confirm)
				cmd(flashutl_cmd->confirm, off);

			if ((st = flash_poll(off, DONE)))
				break;
		} else {
			/* issue write command */
			if (flashutl_cmd->write_word)
				cmd(flashutl_cmd->write_word, CMD_ADDR);

			/* write data */
			data = flash_readword((unsigned long)src);
			flash_writeword((unsigned long)dest, data);

			/* poll for done */
			if ((st = flash_poll(off, data)))
				break;

			len = MIN(nbytes, flashutl_wsz);
			dest += len;
			src += len;
		}

		nbytes -= len;
		off += len;
	}

	flash_reset();

	return st;
}
示例#10
0
/*
 * The following code cannot be run from FLASH!
 */
static ulong flash_get_size (u32 addr, flash_info_t *info)
{
	volatile uchar value;
#if 0
	int i;
#endif

	/* Write auto select command: read Manufacturer ID */
	out8(addr + 0x0555, 0xAA);
	iobarrier_rw();
	udelay(10);
	out8(addr + 0x02AA, 0x55);
	iobarrier_rw();
	udelay(10);
	out8(addr + 0x0555, 0x90);
	iobarrier_rw();
	udelay(10);

	value = in8(addr);
	iobarrier_rw();
	udelay(10);
	switch (value | (value << 16)) {
	case AMD_MANUFACT:
		info->flash_id = FLASH_MAN_AMD;
		break;

	case FUJ_MANUFACT:
		info->flash_id = FLASH_MAN_FUJ;
		break;

	default:
		info->flash_id = FLASH_UNKNOWN;
		flash_reset (addr);
		return 0;
	}

	value = in8(addr + 1);			/* device ID		*/
	iobarrier_rw();

	switch (value) {
	case AMD_ID_LV033C:
		info->flash_id += FLASH_AM033C;
		info->size = hwc_flash_size();
		if (info->size > CFG_MAX_FLASH_SIZE) {
			printf("U-Boot supports only %d MB\n",
			       CFG_MAX_FLASH_SIZE);
			info->size = CFG_MAX_FLASH_SIZE;
		}
		info->sector_count = info->size / 0x10000;
		break;				/* => 4 MB		*/

	default:
		info->flash_id = FLASH_UNKNOWN;
		flash_reset (addr);
		return (0);			/* => no or unknown flash */

	}

	if (!flash_get_offsets (addr, info)) {
		flash_reset (addr);
		return 0;
	}

#if 0
	/* check for protected sectors */
	for (i = 0; i < info->sector_count; i++) {
		/* read sector protection at sector address, (A7 .. A0) = 0x02 */
		/* D0 = 1 if protected */
		value = in8(info->start[i] + 2);
		iobarrier_rw();
		info->protect[i] = (value & 1) != 0;
	}
#endif

	/*
	 * Reset bank to read mode
	 */
	flash_reset (addr);

	return (info->size);
}
示例#11
0
文件: flash.c 项目: jing-git/rt-n56u
int	flash_erase(flash_info_t *info, int s_first, int s_last)
{
	FPWV *addr;
	int prot, sect;
	int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
	ulong start, now, last;
	int rcode = 0;
	int poll,kk,s_kk = 8;
	u32 s_sector_size = 0x00001000 ;
	FPWV *base;		/* first address in bank */
	

	if ((s_first < 0) || (s_first > s_last)) {
		if (info->flash_id == FLASH_UNKNOWN) {
			printf("- missing\n");
		} else {
			printf("- no sectors to erase\n");
		}
		return 1;
	}

	switch (info->flash_id & FLASH_TYPEMASK) {
	case FLASH_INTEL800B:
	case FLASH_INTEL160B:
	case FLASH_INTEL320B:
	case FLASH_INTEL640B:
	case FLASH_28F800C3B:
	case FLASH_28F160C3B:
	case FLASH_28F320C3B:
	case FLASH_28F640C3B:
	case FLASH_AM640U:
	case FLASH_MXLV320BT:
	case FLASH_MXLV160B:
	case FLASH_MXLV160T:
	case AMD_ID_LV320B:
	case EN_ID_29LV640H:
	case MX_ID_29LV640DB:
	case MX_ID_29LV128DB:
#if defined (RT3052_MP2) && defined (ON_BOARD_32M_FLASH_COMPONENT)
	case FLASH_S29GL256N:
#endif
		break;
	case FLASH_UNKNOWN:
	default:
		printf("Can't erase unknown flash type %08lx - aborted\n",
			info->flash_id);
		return 1;
	}

	prot = 0;
	for (sect=s_first; sect<=s_last; ++sect) {
		if (info->protect[sect]) {
			//kaiker,debug
			//info->protect[sect]=0;
			printf("\n protect sect[%d]\n",sect);
			
			prot++;
		}
	}

	if (prot) {
		printf("- Warning: %d protected sectors will not be erased!\n",
			prot);
	} else {
		printf("\n");
	}

	last  = get_timer(0);

	/* Start erase on unprotected sectors */

	if(flash_use_SSI_standard)
	{
		s_kk = 16;
		s_sector_size = 0x00000800;
		printf("\n SSI Manufacture so its small sector  \n");
	}
	
	for (sect = s_first; sect<=s_last && rcode == 0; sect++) {

		if (info->protect[sect] != 0)	/* protected, skip it */
		{
			printf("\n sect[%d] is protected,skip \n",sect);
			continue;
		}	
		printf("\n erase sector  = %d \n",sect);

		/* Disable interrupts which might cause a timeout here */
		//flag = disable_interrupts();

		addr = (FPWV *)(info->start[sect]);


		//add by kaiker
		if( sect == 0 || flash_use_SSI_standard == 1)
		{
			base = (FPWV *)(info->start[0]);

			if(flash_use_SSI_standard)
			{
				printf("\n Erase to sector address[%08X]\n",addr);
			}
			else
			{
				printf("\n Erase Sector 0 with 8K SIZE,The sector 0 is Total 64K\n");
			}
						
			for(kk =0 ; kk < s_kk ;kk++)
			{
				/* must be AMD style if not Intel */
			
				base[FLASH_CYCLE1] = (FPW)0x00AA00AA;	/* unlock */
				base[FLASH_CYCLE2] = (FPW)0x00550055;	/* unlock */
				base[FLASH_CYCLE1] = (FPW)0x00800080;	/* erase mode */
				base[FLASH_CYCLE1] = (FPW)0x00AA00AA;	/* unlock */
				base[FLASH_CYCLE2] = (FPW)0x00550055;	/* unlock */
				*addr = (FPW)0x00300030;	/* erase sector */
		
				start = get_timer(0);

				/* wait at least 50us for AMD, 80us for Intel.
					* Let's wait 1 ms.
				*/
				udelay(1000);

				poll = 0;
				
				while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) 
				{
					if ((now = get_timer(start)) > (ulong)CFG_FLASH_ERASE_TOUT) 
					{
						printf("Timeout\n");
						flash_reset(info);	/* reset to read mode */
						rcode = 1;		/* failed */
						break;
					}

					poll++;
					/* show that we're waiting */
					if ((get_timer(last)) > CFG_HZ) 
					{/* every second */
						putc('*');
						last = get_timer(0);
					}
				}
			//	printf("sect = %d,s_last = %d,erase poll = %d\n",sect,s_last,poll);

				/* show that we're waiting */
				if ((get_timer(last)) > CFG_HZ) {	/* every second */
					putc('.');
					last = get_timer(0);
				}

				flash_reset(info);	/* reset to read mode	*/

			//	printf("\n Pre addr = %08X \n",addr);
	
				addr = addr + s_sector_size;
			}
			
			if(!flash_use_SSI_standard)
			{
				printf("\n Exit Sector 0 erase  !! \n");
			}
			continue;
			sect = 7;
		}
		
		if (intel) {
			*addr = (FPW)0x00500050; /* clear status register */
			*addr = (FPW)0x00200020; /* erase setup */
			*addr = (FPW)0x00D000D0; /* erase confirm */
		} else {
			/* must be AMD style if not Intel */
		//	FPWV *base;		/* first address in bank */

			base = (FPWV *)(info->start[0]);
			base[FLASH_CYCLE1] = (FPW)0x00AA00AA;	/* unlock */
			base[FLASH_CYCLE2] = (FPW)0x00550055;	/* unlock */
			base[FLASH_CYCLE1] = (FPW)0x00800080;	/* erase mode */
			base[FLASH_CYCLE1] = (FPW)0x00AA00AA;	/* unlock */
			base[FLASH_CYCLE2] = (FPW)0x00550055;	/* unlock */
			*addr = (FPW)0x00300030;	/* erase sector */
		}

		/* re-enable interrupts if necessary */
		/*
		if (flag)
			enable_interrupts();
			*/

		start = get_timer(0);

#if 1
		/* wait at least 50us for AMD, 80us for Intel.
		 * Let's wait 1 ms.
		 */
		udelay(1000);

		poll = 0;
		while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) {
			if ((now = get_timer(start)) > (ulong)CFG_FLASH_ERASE_TOUT) {
				printf("Timeout\n");

				if (intel) {
					/* suspend erase	*/
					*addr = (FPW)0x00B000B0;
				}

				flash_reset(info);	/* reset to read mode */
				rcode = 1;		/* failed */
				break;
			}

			poll++;
			/* show that we're waiting */
			if ((get_timer(last)) > CFG_HZ) {/* every second */
				putc('*');
				last = get_timer(0);
			}
		}
		printf("sect = %d,s_last = %d,erase poll = %d\n",sect,s_last,poll);
#else

#endif


		/* show that we're waiting */
		if ((get_timer(last)) > CFG_HZ) {	/* every second */
			putc('.');
			last = get_timer(0);
		}

		flash_reset(info);	/* reset to read mode	*/
	}

	printf(" done\n");
	return rcode;
}
示例#12
0
文件: flash.c 项目: jing-git/rt-n56u
/*-----------------------------------------------------------------------
 */
int erase_all_chip(flash_info_t *info, int s_first, int s_last)
{
	int rcode = 0;
 	FPWV *addr;
	int sect = 0;
	int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
	ulong start, now, last;
	
	int poll;

	if ((s_first < 0) || (s_first > s_last)) {
		if (info->flash_id == FLASH_UNKNOWN) {
			printf("- missing\n");
		} else {
			printf("- no sectors to erase\n");
		}
		return 1;
	}

	switch (info->flash_id & FLASH_TYPEMASK) {
	case FLASH_INTEL800B:
	case FLASH_INTEL160B:
	case FLASH_INTEL320B:
	case FLASH_INTEL640B:
	case FLASH_28F800C3B:
	case FLASH_28F160C3B:
	case FLASH_28F320C3B:
	case FLASH_28F640C3B:
	case FLASH_AM640U:
	case FLASH_MXLV320BT:
	case FLASH_MXLV160B:
	case FLASH_MXLV160T:
	case AMD_ID_LV320B:	
	case EN_ID_29LV640H:	
		break;
	case FLASH_UNKNOWN:
	default:
		printf("Can't erase unknown flash type %08lx - aborted\n",
			info->flash_id);
		return 1;
	}

	last  = get_timer(0);

	/* Start erase on unprotected sectors */
	printf("\n Erase All \n");
//	for (sect = s_first; sect<=s_last && rcode == 0; sect++) 
	{
		/* Disable interrupts which might cause a timeout here */
		//flag = disable_interrupts();

		addr = (FPWV *)(info->start[sect]);
		{
			/* must be AMD style if not Intel */
			FPWV *base;		/* first address in bank */

			base = (FPWV *)(info->start[0]);
			base[FLASH_CYCLE1] = (FPW)0x00AA00AA;	/* unlock */
			base[FLASH_CYCLE2] = (FPW)0x00550055;	/* unlock */
			base[FLASH_CYCLE1] = (FPW)0x00800080;	/* erase mode */
			base[FLASH_CYCLE1] = (FPW)0x00AA00AA;	/* unlock */
			base[FLASH_CYCLE2] = (FPW)0x00550055;	/* unlock */
			base[FLASH_CYCLE1] = (FPW)0x10101010;   /* erase all */
			
		}

		/* re-enable interrupts if necessary */
		/*
		if (flag)
			enable_interrupts();
			*/

		start = get_timer(0);


		/* wait at least 50us for AMD, 80us for Intel.
		 * Let's wait 1 ms.
		 */
		udelay(1000);

		poll = 0;
		while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) {
			if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
				printf("Timeout\n");

				if (intel) {
					/* suspend erase	*/
					*addr = (FPW)0x00B000B0;
				}

				flash_reset(info);	/* reset to read mode */
				rcode = 1;		/* failed */
				break;
			}

			poll++;
			/* show that we're waiting */
			if ((get_timer(last)) > CFG_HZ) {/* every second */
				putc('*');
				last = get_timer(0);
			}
		}
		printf(" Erase all OK!! \n");

		for (sect=s_first; sect<=s_last; ++sect) {
		if (info->protect[sect]) {
			//kaiker,debug
			info->protect[sect]=0;
			
		}
		printf("protect off all  !\n");
	}

		

		flash_reset(info);	/* reset to read mode	*/
	}

	printf(" done\n");

	return rcode;
}
示例#13
0
文件: flash.c 项目: jing-git/rt-n56u
ulong flash_get_size(FPWV *addr, flash_info_t *info)
{
	/* Write auto select command: read Manufacturer ID */

	

	/* Write auto select command sequence and test FLASH answer */
	addr[FLASH_CYCLE1] = (FPW)0x00AA00AA;	/* for AMD, Intel ignores this */
	addr[FLASH_CYCLE2] = (FPW)0x00550055;	/* for AMD, Intel ignores this */
	addr[FLASH_CYCLE1] = (FPW)0x00900090;	/* selects Intel or AMD */

	/* The manufacturer codes are only 1 byte, so just use 1 byte.
	 * This works for any bus width and any FLASH device width.
	 */
#if 1 	 
	 if(addr[0] != (FPW)SST_MANUFACT)
	 {
		FLASH_CYCLE1 = 0x0555; 
		FLASH_CYCLE2 = 0x02aa; 
		
		addr[FLASH_CYCLE1] = (FPW)0x00AA00AA;	/* for AMD, Intel ignores this */
		addr[FLASH_CYCLE2] = (FPW)0x00550055;	/* for AMD, Intel ignores this */
		addr[FLASH_CYCLE1] = (FPW)0x00900090;	/* selects Intel or AMD */

		
	 }
	 else
	 {
		printf("\n The Flash follow SSI standard \n");
		flash_use_SSI_standard = 1;
		
	 }
	
#endif  
  //   printf("\n The Flash ID =%08X \n",addr[1]);
	
	switch (addr[0] & 0xff) {

	case (uchar)AMD_MANUFACT:
		info->flash_id = FLASH_MAN_AMD;
	//	printf("\nFLASH_MAN_AMD\n");
		break;

	case (uchar)INTEL_MANUFACT:
		info->flash_id = FLASH_MAN_INTEL;
	//	printf("\nFLASH_MAN_INTEL\n");
		break;

	case (uchar)MX_MANUFACT:
		info->flash_id = FLASH_MAN_MX;
	//	printf("\n vender : MX_MANUFACT  \n");
		break; 

	case (uchar)AMD_MANUFACT_EON:
		info->flash_id = FLASH_MAN_AMD;
	//	printf("\n vender : AMD_MANUFACT_EON  \n");
		break;

	default:
		info->flash_id = FLASH_MAN_AMD;
	//	printf("\n vender : AMD_MANUFACT_EON  \n");
		break;
		/*
		info->flash_id = FLASH_UNKNOWN;
		info->sector_count = 0;
		info->size = 0;
		printf("\n FLASH_UNKNOWN \n");
		*/
		break;
	}

	/* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
	if (info->flash_id != FLASH_UNKNOWN)

		switch (addr[1]) {

		case (FPW)AMD_ID_LV640U:	/* 29LV640 and 29LV641 have same ID */
			info->flash_id += FLASH_AM640U;
			info->sector_count = 128;
			info->size = 0x00800000 * (sizeof(FPW)/2);
			break;				/* => 8 or 16 MB	*/

		case (FPW)INTEL_ID_28F800C3B:
			info->flash_id += FLASH_28F800C3B;
			info->sector_count = 23;
			info->size = 0x00100000 * (sizeof(FPW)/2);
			break;				/* => 1 or 2 MB		*/

		case (FPW)INTEL_ID_28F800B3B:
			info->flash_id += FLASH_INTEL800B;
			info->sector_count = 23;
			info->size = 0x00100000 * (sizeof(FPW)/2);
			break;			  	/* => 1 or 2 MB		*/
   
		case (FPW)INTEL_ID_28F160C3B:
			info->flash_id += FLASH_28F160C3B;
			info->sector_count = 39;
			info->size = 0x00200000 * (sizeof(FPW)/2);
			break;				/* => 2 or 4 MB		*/

		case (FPW)INTEL_ID_28F160B3B:
			info->flash_id += FLASH_INTEL160B;
			info->sector_count = 39;
			info->size = 0x00200000 * (sizeof(FPW)/2);
			break;				/* => 2 or 4 MB		*/

		case (FPW)INTEL_ID_28F320C3B:
			info->flash_id += FLASH_28F320C3B;
			info->sector_count = 71;
			info->size = 0x00400000 * (sizeof(FPW)/2);
			break;				/* => 4 or 8 MB		*/

		case (FPW)INTEL_ID_28F320B3B:
			info->flash_id += FLASH_INTEL320B;
			info->sector_count = 71;
			info->size = 0x00400000 * (sizeof(FPW)/2);
			break;				/* => 4 or 8 MB		*/

		case (FPW)INTEL_ID_28F640C3B:
			info->flash_id += FLASH_28F640C3B;
			info->sector_count = 135;
			info->size = 0x00800000 * (sizeof(FPW)/2);
			break;				/* => 8 or 16 MB	*/

		case (FPW)INTEL_ID_28F640B3B:
			info->flash_id += FLASH_INTEL640B;
			info->sector_count = 135;
			info->size = 0x00800000 * (sizeof(FPW)/2);
			break;				/* => 8 or 16 MB	*/

		case (FPW)AMD_ID_LV320B:
			info->flash_id += AMD_ID_LV320B;
			info->sector_count = 71;
			info->size = 0x00400000 * (sizeof(FPW)/2);
		//	printf("\n AMD_ID_LV320B, Size = %08x bytes\n",info->size);
			break;				/* => 4 or 8 MB		*/
		 
		case (FPW)MX_ID_LV320BT:
			info->flash_id += MX_ID_LV320BT;
			info->sector_count = 71;
			info->size = 0x00400000 * (sizeof(FPW)/2);
		//	printf("\n MX_ID_LV320BT, Size = %08x bytes\n",info->size);
			break;				/* => 4 or 8 MB		*/

		case (FPW)MX_ID_LV160B:
		case (FPW)MX_ID_LV160T:
			info->flash_id += addr[1];
			info->sector_count = 35;
			info->size = 0x00200000 * (sizeof(FPW)/2);
		//	printf("\n MX_ID_LV160B, Size = %08x bytes\n",info->size);
			break;				

		case (FPW)MX_ID_29LV640DB:
			info->flash_id += MX_ID_29LV640DB;
			info->sector_count = 135;
			info->size = 0x00800000 * (sizeof(FPW)/2);
			break;

		case (FPW)MX_ID_29LV128DB:
			info->flash_id += MX_ID_29LV128DB;
			info->sector_count = 263;
			info->size = 0x01000000 * (sizeof(FPW)/2);
			break;

#if defined (RT3052_MP2) && defined (ON_BOARD_32M_FLASH_COMPONENT)
		case (FPW)FLASH_S29GL256N:
			/* winfred:
			 *  To support 32MB*1 (Spansion S29GL256N) flash on
			 *  RT3052 MP2, we separate it into 2 16MB bank:
			 *  bank 0: 0xBF000000 ~ 0xBFFFFFFF
			 *  bank 1: 0xBB000000 ~ 0xBBFFFFFF
			 *  So, we need to modify the flash info.
			 *  (We currently use first bank only, which makes
			 *   the sector_count to be 256 instead of 512.
			 *   Besides, sectorsize is 0x10000(wrong) instead of
			 *   0x20000, and size is 0x1000000(wront) instead of
			 *   0x2000000.)
			 */
			info->flash_id += FLASH_S29GL256N;
			info->sector_count = 256;
			info->size = 0x01000000 * (sizeof(FPW)/2);
			break;
#endif

		default:
			info->flash_id += EN_ID_29LV640H;
			info->sector_count = 128;
			info->size = 0x00800000 * (sizeof(FPW)/2);
		//	printf("\n EN_ID_29LV640H, Size = %08x bytes\n",info->size);
			break;
			#if 0
			info->flash_id = FLASH_UNKNOWN;
			info->sector_count = 0;
			info->size = 0;
			return (0);			/* => no or unknown flash */
			#endif
			break;
		}

	flash_get_offsets((ulong)addr, info);

	/* Put FLASH back in read mode */
	flash_reset(info);

	return (info->size);
}
示例#14
0
void init_jasmine(void)
{
	UINT32 i, bank;
	extern UINT32 Image$$ER_ZI$$ZI$$Base;
	extern UINT32 Image$$ER_ZI$$ZI$$Length;

	// PLL initialization

	SETREG(CLKSelCon, USE_BYPASS_CLK);

	SETREG(PllCon, PLL_PD); 					// power down
	delay(600);									// at least 500ns
	SETREG(PllCon, PLL_CLK_CONFIG | PLL_PD);	// change settings
	delay(600);									// at least 1us
	SETREG(PllCon, PLL_CLK_CONFIG);				// power up
	while ((GETREG(PllCon) & PLL_LD) == 0); 	// wait lock

	SETREG(CLKSelCon, USE_PLL_CLK);

	// reset hardware modules

	SETREG(PMU_ResetCon, RESET_SDRAM | RESET_BM | RESET_SATA | RESET_FLASH);

	// GPIO bits
	// There are 7 GPIO bits from 0 to 6.
	// 0: This bit is connected to J2 (Factory Mode jumper). The ROM firmware configures it as input mode.
	// While main firmware is running, it can be freely used for arbitrary purpose. Beware that a "1" output while
	// the Factory Mode jumper is set to Normal position (tied to ground) can lead to circuit damage.
	// A "0" output while the jumper is tied to Vcc will also lead to circuit damage.
	// 1: This bit is connected to J3 (Boot ROM). The controller hardware checks its status upon reset.
	// After the reset is done, you can remove the jumper and use the pin as output.
	// 2 through 5: The IO pins for these bits are shared between MAX3232C (UART chip) and J4.
	// In order to use J4, you have to turn on the switches of SW4 and turn off the switches 1 through 4 in SW2.
	// In order to use UART, you have to turn off the switches of SW4 and turn on the switches 1 through 4 in SW2.
	// 6: This bit is connected to D4 (LED) via SW2.

	#if OPTION_UART_DEBUG
	SETREG(GPIO_MOD, 0);
	SETREG(GPIO_DIR, BIT3 | BIT4 | BIT6);	// output pins: 3(UART_TXD), 4(UART_RTS), 6(LED)
	#else
	SETREG(GPIO_MOD, 7);
	SETREG(GPIO_DIR, BIT2 | BIT3 | BIT4 | BIT5 | BIT6);
	#endif

	SETREG(GPIO_REG, 0);					// initial state of LED is "off"

	// ZI region is zero-filled by hardware.
	mem_set_sram((UINT32) &Image$$ER_ZI$$ZI$$Base, 0x00000000, (UINT32) &Image$$ER_ZI$$ZI$$Length);

	SETREG(PHY_DEBUG, 0x40000139);
	while((GETREG(PHY_DEBUG) & BIT30) == 1);

	SETREG(SDRAM_INIT, SDRAM_PARAM_MAIN_FW_INIT);
	SETREG(SDRAM_REFRESH, SDRAM_PARAM_MAIN_FW_REFRESH);
	SETREG(SDRAM_TIMING, SDRAM_PARAM_MAIN_FW_TIMING);
	SETREG(SDRAM_MRS, SDRAM_PARAM_MAIN_FW_MRS);
	SETREG(SDRAM_CTRL, SDRAM_INITIALIZE);		// initialization of SDRAM begins now
	while (GETREG(SDRAM_STATUS) & 0x00000010);	// wait until the initialization completes (200us)

	for (i = 0; i < DRAM_SIZE / MU_MAX_BYTES; i++)
	{
		mem_set_dram(DRAM_BASE + i * MU_MAX_BYTES, 0x00000000, MU_MAX_BYTES);
	}

	#if OPTION_UART_DEBUG
	uart_init();
	uart_print("Welcome to OpenSSD");
	#endif

	SETREG(SDRAM_ECC_MON, 0xFFFFFFFF);

	// configure SDRAM interrupt
	SETREG(SDRAM_INTCTRL, SDRAM_INT_ENABLE);

	// clear interrupt flags in DRAM controller
	SETREG(SDRAM_INTSTATUS, 0xFFFFFFFF);

	// configure ICU
	SETREG(APB_ICU_CON, INTR_SATA);	// SATA = FIQ, other = IRQ
	SETREG(APB_INT_MSK, INTR_SATA | INTR_FLASH | INTR_SDRAM | INTR_TIMER_1 | INTR_TIMER_2 | INTR_TIMER_3);

	// clear interrupt flags in ICU
	SETREG(APB_INT_STS, 0xFFFFFFFF);

	flash_reset();

	SETREG(FCONF_PAUSE, 0);
	SETREG(INTR_MASK, 0);

	for (bank = 0; bank < NUM_BANKS; bank++)
	{
		flash_clear_irq();

		SETREG(FCP_CMD, FC_COL_ROW_READ_OUT);
		SETREG(FCP_OPTION, 0x06);				// FO_E
		SETREG(FCP_DMA_ADDR, g_temp_mem);
		SETREG(FCP_DMA_CNT, BYTES_PER_SECTOR);
		SETREG(FCP_COL, 0);
		SETREG(FCP_ROW_L(bank), STAMP_PAGE_OFFSET);
		SETREG(FCP_ROW_H(bank), STAMP_PAGE_OFFSET);

		flash_issue_cmd(bank, RETURN_WHEN_DONE);

		if ( (BSP_INTR(bank) & 0xFE)== 0 )
			break;
	}

	#if OPTION_FTL_TEST == FALSE
	sata_reset();
	#endif

    ftl_open();

	#if OPTION_FTL_TEST == TRUE
	extern void ftl_test();
	ftl_test();
    led(1);
    while (1);
    #endif
}
示例#15
0
文件: flash.c 项目: 0s4l/u-boot-xlnx
/*-----------------------------------------------------------------------
 */
ulong flash_get_size( ulong baseaddr, flash_info_t *info )
{
	short i;
	unsigned long flashtest_h, flashtest_l;

	/* Write auto select command sequence and test FLASH answer */
	V_ULONG(baseaddr + ((ulong)0x0555 << 3)) = 0x00AA00AA;
	V_ULONG(baseaddr + ((ulong)0x02AA << 3)) = 0x00550055;
	V_ULONG(baseaddr + ((ulong)0x0555 << 3)) = 0x00900090;
	V_ULONG(baseaddr + 4 + ((ulong)0x0555 << 3)) = 0x00AA00AA;
	V_ULONG(baseaddr + 4 + ((ulong)0x02AA << 3)) = 0x00550055;
	V_ULONG(baseaddr + 4 + ((ulong)0x0555 << 3)) = 0x00900090;

	flashtest_h = V_ULONG(baseaddr);		/* manufacturer ID	   */
	flashtest_l = V_ULONG(baseaddr + 4);

	if ((int)flashtest_h == AMD_MANUFACT) {
		info->flash_id = FLASH_MAN_AMD;
	} else {
		info->flash_id = FLASH_UNKNOWN;
		info->sector_count = 0;
		info->size = 0;
		return (0);				/* no or unknown flash	   */
	}

	flashtest_h = V_ULONG(baseaddr + 8);	        /* device ID		   */
	flashtest_l = V_ULONG(baseaddr + 12);
	if (flashtest_h != flashtest_l) {
		info->flash_id = FLASH_UNKNOWN;
		return(0);
	}

	switch((int)flashtest_h) {
	case AMD_ID_DL323B:
		info->flash_id += FLASH_AMDL323B;
		info->sector_count = 71;
		info->size = 0x01000000;	 /* 4 * 4 MB = 16 MB	*/
		break;
	case AMD_ID_LV640U:	/* AMDLV640 and AMDLV641 have same ID */
		info->flash_id += FLASH_AMLV640U;
		info->sector_count = 128;
		info->size = 0x02000000;	/* 4 * 8 MB = 32 MB	*/
		break;
	default:
		info->flash_id = FLASH_UNKNOWN;
		return(0);				/* no or unknown flash	   */
	}

	if(flashtest_h == AMD_ID_LV640U) {
		/* set up sector start adress table (uniform sector type) */
		for (i = 0; i < info->sector_count; i++)
			info->start[i] = baseaddr + (i * 0x00040000);
	} else {
		/* set up sector start adress table (bottom sector type) */
		for (i = 0; i < 8; i++) {
			info->start[i] = baseaddr + (i * 0x00008000);
		}
		for (i = 8; i < info->sector_count; i++) {
			info->start[i] = baseaddr + (i * 0x00040000) - 0x001C0000;
		}
	}
	/* check for protected sectors */
	for (i = 0; i < info->sector_count; i++) {
		/* read sector protection at sector address, (A7 .. A0) = 0x02 */
		if ((V_ULONG( info->start[i] + 16 ) & 0x00010001) ||
		    (V_ULONG( info->start[i] + 20 ) & 0x00010001)) {
			info->protect[i] = 1;		/* D0 = 1 if protected */
		} else {
			info->protect[i] = 0;
		}
	}

	flash_reset();
	return(info->size);
}
示例#16
0
/*
 * The following code cannot be run from FLASH!
 */
static ulong flash_get_size (ulong addr, flash_info_t *info)
{
	short i;
	uchar value;
	uchar *x = (uchar *)addr;

	flash_to_xd();

	/* Write auto select command: read Manufacturer ID */
	x[0x0555] =  0xAA;
	__asm volatile ("sync\n eieio");
	x[0x02AA] =  0x55;
	__asm volatile ("sync\n eieio");
	x[0x0555] =  0x90;
	__asm volatile ("sync\n eieio");

	value = x[0];
	__asm volatile ("sync\n eieio");

	DEBUGF("Manuf. ID @ 0x%08lx: 0x%08x\n", (ulong)addr, value);

	switch (value | (value << 16)) {
		case AMD_MANUFACT:
			info->flash_id = FLASH_MAN_AMD;
			break;

		case FUJ_MANUFACT:
			info->flash_id = FLASH_MAN_FUJ;
			break;

		case STM_MANUFACT:
			info->flash_id = FLASH_MAN_STM;
			break;

		default:
			info->flash_id = FLASH_UNKNOWN;
			info->sector_count = 0;
			info->size = 0;
			flash_reset (addr);
			return 0;
	}

	value = x[1];
	__asm volatile ("sync\n eieio");

	DEBUGF("Device ID @ 0x%08lx: 0x%08x\n", addr+1, value);

	switch (value) {
		case AMD_ID_F040B:
			DEBUGF("Am29F040B\n");
			info->flash_id += FLASH_AM040;
			info->sector_count = 8;
			info->size = 0x00080000;
			break;			/* => 512 kB		*/

		case AMD_ID_LV040B:
			DEBUGF("Am29LV040B\n");
			info->flash_id += FLASH_AM040;
			info->sector_count = 8;
			info->size = 0x00080000;
			break;			/* => 512 kB		*/

		case AMD_ID_LV400T:
			DEBUGF("Am29LV400T\n");
			info->flash_id += FLASH_AM400T;
			info->sector_count = 11;
			info->size = 0x00100000;
			break;			/* => 1 MB		*/

		case AMD_ID_LV400B:
			DEBUGF("Am29LV400B\n");
			info->flash_id += FLASH_AM400B;
			info->sector_count = 11;
			info->size = 0x00100000;
			break;			/* => 1 MB		*/

		case AMD_ID_LV800T:
			DEBUGF("Am29LV800T\n");
			info->flash_id += FLASH_AM800T;
			info->sector_count = 19;
			info->size = 0x00200000;
			break;			/* => 2 MB		*/

		case AMD_ID_LV800B:
			DEBUGF("Am29LV400B\n");
			info->flash_id += FLASH_AM800B;
			info->sector_count = 19;
			info->size = 0x00200000;
			break;			/* => 2 MB		*/

		case AMD_ID_LV160T:
			DEBUGF("Am29LV160T\n");
			info->flash_id += FLASH_AM160T;
			info->sector_count = 35;
			info->size = 0x00400000;
			break;			/* => 4 MB		*/

		case AMD_ID_LV160B:
			DEBUGF("Am29LV160B\n");
			info->flash_id += FLASH_AM160B;
			info->sector_count = 35;
			info->size = 0x00400000;
			break;			/* => 4 MB		*/

		case AMD_ID_LV320T:
			DEBUGF("Am29LV320T\n");
			info->flash_id += FLASH_AM320T;
			info->sector_count = 67;
			info->size = 0x00800000;
			break;			/* => 8 MB		*/

#if 0
		/* Has the same ID as AMD_ID_LV320T, to be fixed */
		case AMD_ID_LV320B:
			DEBUGF("Am29LV320B\n");
			info->flash_id += FLASH_AM320B;
			info->sector_count = 67;
			info->size = 0x00800000;
			break;			/* => 8 MB		*/
#endif

		case AMD_ID_LV033C:
			DEBUGF("Am29LV033C\n");
			info->flash_id += FLASH_AM033C;
			info->sector_count = 64;
			info->size = 0x01000000;
			break;			/* => 16Mb		*/

		case STM_ID_F040B:
			DEBUGF("M29F040B\n");
			info->flash_id += FLASH_AM040;
			info->sector_count = 8;
			info->size = 0x00080000;
			break;			/* => 512 kB		*/

		default:
			info->flash_id = FLASH_UNKNOWN;
			flash_reset (addr);
			flash_to_mem();
			return (0);		/* => no or unknown flash */

	}

	if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) {
		printf ("** ERROR: sector count %d > max (%d) **\n",
			info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
		info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
	}

	if (! flash_get_offsets (addr, info)) {
		flash_reset (addr);
		flash_to_mem();
		return 0;
	}

	/* check for protected sectors */
	for (i = 0; i < info->sector_count; i++) {
		/* read sector protection at sector address, (A7 .. A0) = 0x02 */
		/* D0 = 1 if protected */
		value = in8(info->start[i] + 2);
		iobarrier_rw();
		info->protect[i] = (value & 1) != 0;
	}

	/*
	 * Reset bank to read mode
	 */
	flash_reset (addr);

	flash_to_mem();

	return (info->size);
}
示例#17
0
int flash_erase (flash_info_t *info, int s_first, int s_last)
{
	volatile ulong addr = info->start[0];
	int flag, prot, sect, l_sect;
	ulong start, now, last;

	flash_to_xd();

	if (s_first < 0 || s_first > s_last) {
		if (info->flash_id == FLASH_UNKNOWN) {
			printf ("- missing\n");
		} else {
			printf ("- no sectors to erase\n");
		}
		flash_to_mem();
		return 1;
	}

	if (info->flash_id == FLASH_UNKNOWN) {
		printf ("Can't erase unknown flash type %08lx - aborted\n",
			info->flash_id);
		flash_to_mem();
		return 1;
	}

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

	if (prot) {
		printf ("- Warning: %d protected sectors will not be erased!\n",
			prot);
	} else {
		printf ("\n");
	}

	l_sect = -1;

	/* Disable interrupts which might cause a timeout here */
	flag = disable_interrupts();

	out8(addr + 0x555, 0xAA);
	iobarrier_rw();
	out8(addr + 0x2AA, 0x55);
	iobarrier_rw();
	out8(addr + 0x555, 0x80);
	iobarrier_rw();
	out8(addr + 0x555, 0xAA);
	iobarrier_rw();
	out8(addr + 0x2AA, 0x55);
	iobarrier_rw();

	/* Start erase on unprotected sectors */
	for (sect = s_first; sect<=s_last; sect++) {
		if (info->protect[sect] == 0) {	/* not protected */
			addr = info->start[sect];
			out8(addr, 0x30);
			iobarrier_rw();
			l_sect = sect;
		}
	}

	/* re-enable interrupts if necessary */
	if (flag)
		enable_interrupts();

	/* wait at least 80us - let's wait 1 ms */
	udelay (1000);

	/*
	 * We wait for the last triggered sector
	 */
	if (l_sect < 0)
		goto DONE;

	start = get_timer (0);
	last  = start;
	addr = info->start[l_sect];

	DEBUGF ("Start erase timeout: %d\n", CONFIG_SYS_FLASH_ERASE_TOUT);

	while ((in8(addr) & 0x80) != 0x80) {
		if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
			printf ("Timeout\n");
			flash_reset (info->start[0]);
			flash_to_mem();
			return 1;
		}
		/* show that we're waiting */
		if ((now - last) > 1000) {	/* every second */
			putc ('.');
			last = now;
		}
		iobarrier_rw();
	}

DONE:
	/* reset to read mode */
	flash_reset (info->start[0]);
	flash_to_mem();

	printf (" done\n");
	return 0;
}
示例#18
0
文件: flash.c 项目: 0s4l/u-boot-xlnx
/*-----------------------------------------------------------------------
 */
ulong flash_get_size (ulong baseaddr, flash_info_t * info)
{
	int i;
	unsigned long msr;
	DWORD flashtest;
	DWORD cmd_select[3] = { 0x00AA00AA00AA00AALL, 0x0055005500550055LL,
							0x0090009000900090LL };

	/* Enable FPU */
	msr = get_msr ();
	set_msr (msr | MSR_FP);

	/* Write auto-select command sequence */
	write_via_fpu ((DWORD*)(baseaddr + (0x0555 << 3)), &cmd_select[0] );
	write_via_fpu ((DWORD*)(baseaddr + (0x02AA << 3)), &cmd_select[1] );
	write_via_fpu ((DWORD*)(baseaddr + (0x0555 << 3)), &cmd_select[2] );

	/* Restore FPU */
	set_msr (msr);

	/* Read manufacturer ID */
	flashtest = *(volatile DWORD*)baseaddr;
	switch ((int)flashtest) {
	case AMD_MANUFACT:
		info->flash_id = FLASH_MAN_AMD;
		break;
	case FUJ_MANUFACT:
		info->flash_id = FLASH_MAN_FUJ;
		break;
	default:
		/* No, faulty or unknown flash */
		info->flash_id = FLASH_UNKNOWN;
		info->sector_count = 0;
		info->size = 0;
		return (0);
	}

	/* Read device ID */
	flashtest = *(volatile DWORD*)(baseaddr + 8);
	switch ((long)flashtest) {
	case AMD_ID_LV800T:
		info->flash_id += FLASH_AM800T;
		info->sector_count = 19;
		info->size = 0x00400000;
		break;
	case AMD_ID_LV800B:
		info->flash_id += FLASH_AM800B;
		info->sector_count = 19;
		info->size = 0x00400000;
		break;
	case AMD_ID_LV160T:
		info->flash_id += FLASH_AM160T;
		info->sector_count = 35;
		info->size = 0x00800000;
		break;
	case AMD_ID_LV160B:
		info->flash_id += FLASH_AM160B;
		info->sector_count = 35;
		info->size = 0x00800000;
		break;
	case AMD_ID_DL322T:
		info->flash_id += FLASH_AMDL322T;
		info->sector_count = 71;
		info->size = 0x01000000;
		break;
	case AMD_ID_DL322B:
		info->flash_id += FLASH_AMDL322B;
		info->sector_count = 71;
		info->size = 0x01000000;
		break;
	case AMD_ID_DL323T:
		info->flash_id += FLASH_AMDL323T;
		info->sector_count = 71;
		info->size = 0x01000000;
		break;
	case AMD_ID_DL323B:
		info->flash_id += FLASH_AMDL323B;
		info->sector_count = 71;
		info->size = 0x01000000;
		break;
	case AMD_ID_LV640U:
		info->flash_id += FLASH_AM640U;
		info->sector_count = 128;
		info->size = 0x02000000;
		break;
	default:
		/* Unknown flash type */
		info->flash_id = FLASH_UNKNOWN;
		return (0);
	}

	if ((long)flashtest == AMD_ID_LV640U) {
		/* set up sector start adress table (uniform sector type) */
		for (i = 0; i < info->sector_count; i++)
			info->start[i] = baseaddr + (i * 0x00040000);
	} else if (info->flash_id & FLASH_BTYPE) {
		/* set up sector start adress table (bottom sector type) */
		info->start[0] = baseaddr + 0x00000000;
		info->start[1] = baseaddr + 0x00010000;
		info->start[2] = baseaddr + 0x00018000;
		info->start[3] = baseaddr + 0x00020000;
		for (i = 4; i < info->sector_count; i++) {
			info->start[i] = baseaddr + (i * 0x00040000) - 0x000C0000;
		}
	} else {
		/* set up sector start adress table (top sector type) */
		i = info->sector_count - 1;
		info->start[i--] = baseaddr + info->size - 0x00010000;
		info->start[i--] = baseaddr + info->size - 0x00018000;
		info->start[i--] = baseaddr + info->size - 0x00020000;
		for (; i >= 0; i--) {
			info->start[i] = baseaddr + i * 0x00040000;
		}
	}

	/* check for protected sectors */
	for (i = 0; i < info->sector_count; i++) {
		/* read sector protection at sector address, (A7 .. A0) = 0x02 */
		if (*(volatile DWORD*)(info->start[i] + 16) & 0x0001000100010001LL) {
			info->protect[i] = 1;	/* D0 = 1 if protected */
		} else {
			info->protect[i] = 0;
		}
	}

	flash_reset ();
	return (info->size);
}
示例#19
0
文件: flash.c 项目: cmp1084/u-boot
/*-----------------------------------------------------------------------
 */
ulong flash_get_size (ulong baseaddr, flash_info_t * info)
{
	short i;
	unsigned long flashtest_h, flashtest_l;

	/* Write auto select command sequence and test FLASH answer */
	V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
	V_ULONG (baseaddr + ((ulong) 0x02AA << 3)) = 0x00550055;
	V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00900090;
	V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00AA00AA;
	V_ULONG (baseaddr + 4 + ((ulong) 0x02AA << 3)) = 0x00550055;
	V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00900090;

	flashtest_h = V_ULONG (baseaddr);	/* manufacturer ID     */
	flashtest_l = V_ULONG (baseaddr + 4);

	switch ((int) flashtest_h) {
	case AMD_MANUFACT:
		info->flash_id = FLASH_MAN_AMD;
		break;
	case FUJ_MANUFACT:
		info->flash_id = FLASH_MAN_FUJ;
		break;
	default:
		info->flash_id = FLASH_UNKNOWN;
		info->sector_count = 0;
		info->size = 0;
		return (0);			/* no or unknown flash     */
	}

	flashtest_h = V_ULONG (baseaddr + 8);	/* device ID           */
	flashtest_l = V_ULONG (baseaddr + 12);
	if (flashtest_h != flashtest_l) {
		info->flash_id = FLASH_UNKNOWN;
	} else {
		switch (flashtest_h) {
		case AMD_ID_LV800T:
			info->flash_id += FLASH_AM800T;
			info->sector_count = 19;
			info->size = 0x00400000;
			break;			/* 4 * 1 MB = 4 MB  */
		case AMD_ID_LV800B:
			info->flash_id += FLASH_AM800B;
			info->sector_count = 19;
			info->size = 0x00400000;
			break;			/* 4 * 1 MB = 4 MB  */
		case AMD_ID_LV160T:
			info->flash_id += FLASH_AM160T;
			info->sector_count = 35;
			info->size = 0x00800000;
			break;			/* 4 * 2 MB = 8 MB  */
		case AMD_ID_LV160B:
			info->flash_id += FLASH_AM160B;
			info->sector_count = 35;
			info->size = 0x00800000;
			break;			/* 4 * 2 MB = 8 MB  */
		case AMD_ID_DL322T:
			info->flash_id += FLASH_AMDL322T;
			info->sector_count = 71;
			info->size = 0x01000000;
			break;			/* 4 * 4 MB = 16 MB */
		case AMD_ID_DL322B:
			info->flash_id += FLASH_AMDL322B;
			info->sector_count = 71;
			info->size = 0x01000000;
			break;			/* 4 * 4 MB = 16 MB */
		case AMD_ID_DL323T:
			info->flash_id += FLASH_AMDL323T;
			info->sector_count = 71;
			info->size = 0x01000000;
			break;			/* 4 * 4 MB = 16 MB */
		case AMD_ID_DL323B:
			info->flash_id += FLASH_AMDL323B;
			info->sector_count = 71;
			info->size = 0x01000000;
			break;			/* 4 * 4 MB = 16 MB */
		case AMD_ID_LV640U:
			info->flash_id += FLASH_AM640U;
			info->sector_count = 128;
			info->size = 0x02000000;
			break;			/* 4 * 8 MB = 32 MB */
		default:
			info->flash_id = FLASH_UNKNOWN;
			return (0);		/* no or unknown flash     */
		}
	}

	if (flashtest_h == AMD_ID_LV640U) {

		/* set up sector start adress table (uniform sector type) */
		for (i = 0; i < info->sector_count; i++)
			info->start[i] = baseaddr + (i * 0x00040000);

	} else if (info->flash_id & FLASH_BTYPE) {

		/* set up sector start adress table (bottom sector type) */
		info->start[0] = baseaddr + 0x00000000;
		info->start[1] = baseaddr + 0x00010000;
		info->start[2] = baseaddr + 0x00018000;
		info->start[3] = baseaddr + 0x00020000;
		for (i = 4; i < info->sector_count; i++) {
			info->start[i] = baseaddr + (i * 0x00040000) - 0x000C0000;
		}

	} else {

		/* set up sector start adress table (top sector type) */
		i = info->sector_count - 1;
		info->start[i--] = baseaddr + info->size - 0x00010000;
		info->start[i--] = baseaddr + info->size - 0x00018000;
		info->start[i--] = baseaddr + info->size - 0x00020000;
		for (; i >= 0; i--) {
			info->start[i] = baseaddr + i * 0x00040000;
		}
	}

	/* check for protected sectors */
	for (i = 0; i < info->sector_count; i++) {
		/* read sector protection at sector address, (A7 .. A0) = 0x02 */
		if ((V_ULONG (info->start[i] + 16) & 0x00010001) ||
			(V_ULONG (info->start[i] + 20) & 0x00010001)) {
			info->protect[i] = 1;	/* D0 = 1 if protected */
		} else {
			info->protect[i] = 0;
		}
	}

	flash_reset ();
	return (info->size);
}
示例#20
0
/* Read the flash ID and set the globals */
int
sysFlashInit(char *flash_str)
{
	uint32 fltype = PFLASH;
	uint16 flash_vendid = 0;
	uint16 flash_devid = 0;
	uint16* flash = (uint16*)0xbfc00000;
	int idx;
	struct sflash *sflash;
	void *sbh;

	/*
	 * Check for serial flash.
	 */
	sbh = sb_kattach();
	ASSERT(sbh);
	cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0);

	if (cc) {
		flash = (uint16*)0xbc000000;
		fltype = R_REG(&cc->capabilities) & CAP_FLASH_MASK;
		/* Select SFLASH ? */
		if (fltype == SFLASH_ST || fltype == SFLASH_AT) {
			sflash = sflash_init(cc);
			flashutl_cmd = &sflash_cmd_t;
			flashutl_desc = &sflash_desc;
			flashutl_desc->size = sflash->size;
			if (flash_str) 
				sprintf(flash_str, "SFLASH %d kB", sflash->size/1024);
			return(0);
		}
	}

	flashutl_base = (uint8*)flash;

	/* 
	 * Parallel flash support
	 *  Some flashes have different unlock addresses, try each it turn
	 */
	idx = sizeof(flash_cmds)/sizeof(flash_cmds_t) - 2;
	flashutl_cmd = &flash_cmds[idx--];
	while((fltype == PFLASH) && flashutl_cmd->type) {

		if (flashutl_cmd->read_id)
			cmd(flashutl_cmd->read_id, CMD_ADDR);

#ifdef MIPSEB
		flash_vendid = *(flash + 1);
		flash_devid = *flash;	
#else
		flash_vendid = *flash;
		flash_devid = *(flash + 1);
#endif

		/* Funky AMD */
		if ((flash_vendid == 1) && (flash_devid == 0x227e)) {
			/* Get real devid */
#ifdef MIPSEB
			flash_devid = *(flash+0xe);	
#else
			flash_devid = *(flash+0xf);
#endif
		}

		flashutl_desc = flashes;
		while (flashutl_desc->mfgid != 0 &&
			   !(flashutl_desc->mfgid == flash_vendid &&
			 flashutl_desc->devid == flash_devid)) {
			flashutl_desc++;
		}
		if (flashutl_desc->mfgid != 0)
			break;

		flashutl_cmd = &flash_cmds[idx--];
	}

	if (flashutl_desc->mfgid == 0) {
		flashutl_desc = NULL;
		flashutl_cmd = NULL;
	} else {
		flashutl_cmd = flash_cmds;
		while (flashutl_cmd->type != 0 && flashutl_cmd->type != flashutl_desc->type)
			flashutl_cmd++;
		if (flashutl_cmd->type == 0)
			flashutl_cmd = NULL;
	}

	if (flashutl_cmd != NULL) {
		flash_reset();
	}

	if (flashutl_desc == NULL) {
		if (flash_str)
			sprintf(flash_str, "UNKNOWN 0x%x 0x%x", flash_vendid, flash_devid);
		DPRINT(("Flash type UNKNOWN\n"));
		return 1;
	}
	
	if (flash_str)
		strcpy(flash_str, flashutl_desc->desc);
	DPRINT(("Flash type \"%s\"\n", flashutl_desc->desc));

	return 0;
}