This commit is contained in:
Greg Watson 2003-04-15 19:17:56 +00:00
parent 777e522d45
commit 89f71da2cf
3 changed files with 280 additions and 0 deletions

View file

@ -0,0 +1,2 @@
object flash.o
object amd800.o

View file

@ -0,0 +1,230 @@
/* $Id$ */
/* Copyright 2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
#include <types.h>
#include <printk.h>
#include <stdlib.h>
#include "../flash.h"
struct data_amd800
{
unsigned base;
unsigned spacing;
unsigned cs;
const char *tag;
};
static const char *identify_amd (struct flash_device *flash_device);
static int erase_flash_amd800 (void *data, unsigned offset, unsigned length);
static int program_flash_amd800 (void *data, unsigned offset, const void *source,
unsigned length);
static u8 read_byte_amd800(void *data, unsigned offset);
static flash_fn fn_amd800 = {
identify_amd,
0,
0,
erase_flash_amd800,
program_flash_amd800,
read_byte_amd800
};
const char *identify_amd (struct flash_device *flash_device)
{
struct data_amd800 *d800 = flash_device->data;
if (!d800->tag)
{
volatile unsigned char *flash =
(volatile unsigned char *) d800->base;
unsigned char type,
id;
*(flash + 0xaaa * d800->spacing) = 0xaa;
*(flash + 0x555 * d800->spacing) = 0x55;
*(flash + 0xaaa * d800->spacing) = 0x90;
type = *(flash + 2 * d800->spacing);
id = *flash;
*flash = 0xf0;
if ((id == 1 || id == 0x20) && type == 0x5b)
{
d800->cs = 45;
d800->tag = "Am29LV800BB";
flash_device->base = d800->base;
flash_device->size = 1024*1024;
flash_device->erase_size = 64*1024;
flash_device->store_size = 1;
}
else
{
printk_info("Unknown flash ID: 0x%02x 0x%02x\n", id, type);
}
}
return d800->tag;
}
int erase_flash_amd800 (void *data, unsigned offset, unsigned length)
{
struct data_amd800 *d800 = data;
volatile unsigned char *flash = (volatile unsigned char *) d800->base;
volatile unsigned char *flash_aaa = flash + 0xaaa * d800->spacing;
volatile unsigned char *flash_555 = flash + 0x555 * d800->spacing;
int id;
int cs = 9999;
printk_info("Erase from 0x%08x to 0x%08x\n", offset, offset + length);
*flash_aaa = 0xAA; // Chip Erase
*flash_555 = 0x55;
*flash_aaa = 0x80;
*flash_aaa = 0xAA;
*flash_555 = 0x55;
*flash_aaa = 0x10;
for (; cs > 0; cs--)
{
id = *(flash + 16);
if (id & 0xA0) // DQ7 or DQ5 set: done or error
break;
printk_info("%4d\b\b\b\b", cs);
}
*flash_aaa = 0xF0; // In case of error
printk_info("\b\b\b\b \b\b\b\b");
if (cs == 0)
{
printk_info("Could not erase flash, timeout.\n");
return -1;
}
else if ((id & 0x80) == 0)
{
printk_info("Could not erase flash, status=%02x.\n", id);
return -1;
}
printk_info("Flash erased\n");
return 0;
}
int init_flash_amd800 (char *tag, unsigned base, unsigned spacing)
{
struct data_amd800 *data = malloc (sizeof (struct data_amd800));
if (data)
{
data->base = base;
data->spacing = spacing;
data->tag = 0;
if (register_flash_device (&fn_amd800, tag, data) < 0)
{
free (data);
return -1;
}
}
else
return -1;
return 0;
}
int program_flash_amd800 (void *data, unsigned offset, const void *source,
unsigned length)
{
struct data_amd800 *d800 = data;
volatile unsigned char *flash = (volatile unsigned char *) d800->base;
volatile unsigned char *flash_aaa = flash + 0xaaa * d800->spacing;
volatile unsigned char *flash_555 = flash + 0x555 * d800->spacing;
int id = 0;
int cs;
int errs = 0;
volatile char *s;
volatile char *d;
printk_info("Program from 0x%08x to 0x%08x\n", offset, offset + length);
printk_info("Data at %p\n", source);
*flash_aaa = 0xAA; // Unlock Bypass
*flash_555 = 0x55;
*flash_aaa = 0x20;
s = (unsigned char *) source;
d = flash + offset * d800->spacing;
cs = length;
while (cs > 0 && !errs)
{
*flash = 0xA0; // Unlock Bypass Program
*d = *s; // Program data
while (1)
{
id = *d;
if ((id & 0x80) == (*s & 0x80)) // DQ7 right? => program done
break;
else if (id & 0x20)
{ // DQ5 set? => maybe errors
id = *d;
if ((id & 0x80) != (*s & 0x80))
{
errs++;
break;
}
}
}
// PRINT("Set %08lx = %02x\n", d, *d);
s += 1;
d += d800->spacing;
cs--;
}
*flash = 0x90; // Unlock Bypass Program Reset
*flash = 0x00;
*flash = 0xF0;
if (errs != 0)
{
printk_info("FAIL: Status=%02x Address=%p.\n", id, d - d800->spacing);
return -1;
}
printk_info("OK.\n");
// Step 4: Verify the flash.
printk_info(" Verifying flash : ...");
errs = 0;
s = (unsigned char *) source;
d = flash + offset * d800->spacing;
for (cs = 0; cs < length; cs++)
{
if (*s != *d)
{
if (errs == 0)
printk_info("ERROR: Addr: %08p, PCI: %02x Lcl: %02x.\n",
s, *s, *d);
errs++;
}
s += 1;
d += d800->spacing;
}
if (errs == 0)
printk_info("OK.\n");
else
{
printk_info(" FAIL: %d errors.\n", errs);
return -1;
}
return 0;
}
u8 read_byte_amd800 (void *data, unsigned offset)
{
struct data_amd800 *d800 = data;
volatile unsigned char *flash = (volatile unsigned char *) d800->base;
return *(flash + offset * d800->spacing);
}

View file

@ -0,0 +1,48 @@
/* $Id$ */
/* Copyright 2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
#include <types.h>
#include <string.h>
#include <printk.h>
#include <stdlib.h>
#include "../flash.h"
static flash_device *first_flash = 0;
int register_flash_device (const flash_fn * fn, char *tag, void *data)
{
flash_device *device = malloc (sizeof (flash_device));
if (device)
{
const char *result;
device->fn = fn;
device->tag = tag;
device->data = data;
if ((result = fn->identify(device)) != 0)
{
printk_info("Registered flash %s\n", result);
device->next = first_flash;
first_flash = device;
}
return result ? 0 : -1;
}
return -1;
}
flash_device *find_flash_device(const char *name)
{
int len = strlen(name);
if (first_flash)
{
flash_device *flash;
for (flash = first_flash; flash; flash = flash->next)
if (strlen(flash->tag) == len && memcmp(name, flash->tag, len) == 0)
return flash;
}
printk_info ("No flash %s registered\n", name);
return 0;
}