OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [orpmon/] [drivers/] [flash.c] - Rev 828

Go to most recent revision | Compare with Previous | Blame | View Log

#include "common.h"
#include "support.h"
#include "flash.h"
 
/* Returns nonzero if there is an error */
int fl_init (void)
{
  unsigned long tmp;
  REG32(FLASH_BASE_ADDR) = 0x00ff00ff;
 
  REG32(FLASH_BASE_ADDR) = 0x00900090;
  tmp = REG32(FLASH_BASE_ADDR) << 8;
  REG32(FLASH_BASE_ADDR) = 0x00900090;
  tmp = tmp | REG32(FLASH_BASE_ADDR + 4);
  debug("id = %08x ", tmp);
  if (tmp != 0x89188918) {
    printf ("bad ID\n");
    return 1;
  } else debug ("good ID\n");
  REG32(FLASH_BASE_ADDR) = 0x00ff00ff;
  return 0;
}
 
int check_error (unsigned long sr, unsigned long addr)
{
  if ((sr & (FL_SR_ERASE_ERR << 16)) || (sr & FL_SR_ERASE_ERR)) {
    printf ("erase error at %08lx\n", addr);
    /* Clear status register */
    REG32(FLASH_BASE_ADDR) = 0x05D00050;
    return 1;
  } else if ((sr & (FL_SR_PROG_ERR << 16)) || (sr & FL_SR_PROG_ERR)) {
    printf ("program error at %08lx\n", addr);
    /* Clear status register */
    REG32(FLASH_BASE_ADDR) = 0x05D00050;
    return 1;
  } else if ((sr & (FL_SR_PROG_LV << 16)) || (sr & FL_SR_PROG_LV)) {
    printf ("low voltage error\n");
    /* Clear status register */
    REG32(FLASH_BASE_ADDR) = 0x05D00050;
    return 1;
  } else if ((sr & (FL_SR_LOCK << 16)) || (sr & FL_SR_LOCK)) {
    printf ("lock bit error at %08lx\n", addr);
    /* Clear status register */
    REG32(FLASH_BASE_ADDR) = 0x05D00050;
    return 1;
  }
  return 0;
}
 
int fl_block_erase (unsigned long addr)
{
  unsigned long sr;
 
  REG32(addr & ~(FLASH_BLOCK_SIZE - 1)) = 0x00200020;
  REG32(addr & ~(FLASH_BLOCK_SIZE - 1)) = 0x00D000D0;
 
  do {
    REG32(FLASH_BASE_ADDR) = 0x00700070;
    sr = REG32(FLASH_BASE_ADDR);
  } while (!(sr & (FL_SR_WSM_READY << 16)) || !(sr & FL_SR_WSM_READY));
 
  REG32(FLASH_BASE_ADDR) = 0x00ff00ff;
  return check_error (sr, addr);
}
 
int fl_unlock_blocks (void)
{
  unsigned long sr;
 
  printf ("Clearing all lock bits... ");
  REG32(FLASH_BASE_ADDR) = 0x00600060;
  REG32(FLASH_BASE_ADDR) = 0x00d000d0;
 
  do {
    REG32(FLASH_BASE_ADDR) = 0x00700070;
    sr = REG32(FLASH_BASE_ADDR);
  } while (!(sr & (FL_SR_WSM_READY << 16)) || !(sr & FL_SR_WSM_READY));
  printf ("done\n");
  return check_error (sr, FLASH_BASE_ADDR);
}
 
int fl_word_program (unsigned long addr, unsigned long val)
{
  unsigned long sr;
 
  REG32(addr) = 0x00400040;
  REG32(addr) = val;
 
  do {
    REG32(FLASH_BASE_ADDR) = 0x00700070;
    sr = REG32(FLASH_BASE_ADDR);
  } while (!(sr & (FL_SR_WSM_READY << 16)) || !(sr & FL_SR_WSM_READY));
 
  REG32(FLASH_BASE_ADDR) = 0x00ff00ff;
  return check_error (sr, addr);
}
 
/* erase = 1 (whole chip), erase = 2 (required only) */
int fl_program (unsigned long src_addr, unsigned long dst_addr, unsigned long len, int erase, int verify)
{
  unsigned long tmp, taddr, tlen;
  unsigned long i;
 
  if (erase) {
    fl_unlock_blocks ();
 
    if (erase == 2) {
      taddr = dst_addr & ~(FLASH_BLOCK_SIZE - 1);
      tlen = (dst_addr + len + FLASH_BLOCK_SIZE - 1) / FLASH_BLOCK_SIZE;
    } else {
      taddr = FLASH_BASE_ADDR;
      tlen = FLASH_SIZE / FLASH_BLOCK_SIZE;
    }
 
    printf ("Erasing flash... ");
    for (i = 0, tmp = taddr; i < tlen; i++, tmp += FLASH_BLOCK_SIZE)
      if (fl_block_erase (tmp)) return 1;
    printf ("done\n");
 
    if (verify) {  
      printf ("Writing test pattern... ");
      for (tmp = taddr; tmp < taddr + tlen * FLASH_BLOCK_SIZE; i++, tmp += 4)
        if (fl_word_program (tmp, tmp)) return 1;
      printf ("done\n");
 
      printf ("Checking... ");
      for (tmp = taddr; tmp < taddr + tlen * FLASH_BLOCK_SIZE; i++, tmp += 4)
        if (REG32(tmp) != tmp) {
          printf ("failed on location %08lx: %08lx\n", tmp, REG32(tmp));
          return 1;
        }
      printf ("done\n");
    }
  }
 
  REG32(FLASH_BASE_ADDR) = 0x00ff00ff;
  printf ("Copying from %08lx-%08lx to %08lx-%08lx\n", src_addr, src_addr + len - 1, dst_addr, dst_addr + len - 1);
 
  tlen = len / 8;
  tmp = 0;
  printf ("Programing");
  for (i = 0; i < len; i += 4) {
    if (fl_word_program (dst_addr + i, REG32(src_addr + i))) return 1;
    if (i > tmp) {
      printf (".");
      tmp += tlen;
    }
  }
  printf (" done\n");
 
  if (verify) {
    printf ("Verifying");
    tmp = 0;
    for (i = 0; i < len; i += 4) {
      if (REG32(src_addr + i) != REG32(dst_addr + i)) {
        printf ("error at %08lx: %08lx != %08lx\n", src_addr + i, REG32(src_addr + i), REG32(dst_addr + i));
        return 1;
      }
      if (i > tmp) {
        printf (".");
        tmp += tlen;
      }
    }
  }
  printf (" done\n");
  return 0;
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.