Moved from freebios
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@864 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
parent
f655bf7f3e
commit
dc18ef018d
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2001
|
||||||
|
* Humboldt Solutions Ltd, adrian@humboldt.co.uk.
|
||||||
|
*
|
||||||
|
* 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 <arch/io.h>
|
||||||
|
#include "../nvram.h"
|
||||||
|
|
||||||
|
static unsigned bsp_size(struct nvram_device *data)
|
||||||
|
{
|
||||||
|
return 8 * 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bsp_read_block(struct nvram_device *dev, unsigned offset,
|
||||||
|
unsigned char *data, unsigned length)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for(i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
outb(((offset + i) >> 8) & 0xff, 0x74);
|
||||||
|
outb((offset + i) & 0xff, 0x75);
|
||||||
|
data[i] = inb(0x76);
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bsp_write_byte(struct nvram_device *data, unsigned offset, unsigned char byte)
|
||||||
|
{
|
||||||
|
outb((offset >> 8) & 0xff, 0x74);
|
||||||
|
outb(offset & 0xff, 0x75);
|
||||||
|
outb(byte, 0x76);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvram_device bsp_nvram = {
|
||||||
|
bsp_size, bsp_read_block, bsp_write_byte, NULL, NULL
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
/* $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 "../nvram.h"
|
||||||
|
|
||||||
|
/* NVRAM layout
|
||||||
|
*
|
||||||
|
* Environment variable record runs:
|
||||||
|
* [length]NAME=value[length]NAME=value[0]\0
|
||||||
|
* A deleted variable is:
|
||||||
|
* [length]\0AME=value
|
||||||
|
*
|
||||||
|
* When memory is full, we compact.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static nvram_device *nvram_dev = 0;
|
||||||
|
static unsigned char *nvram_buffer = 0;
|
||||||
|
static unsigned nvram_size = 0;
|
||||||
|
static u8 nvram_csum = 0;
|
||||||
|
#define NVRAM_INVALID (! nvram_dev)
|
||||||
|
|
||||||
|
static void update_device(unsigned i, unsigned char data)
|
||||||
|
{
|
||||||
|
if (i < nvram_size)
|
||||||
|
{
|
||||||
|
nvram_csum -= nvram_buffer[i];
|
||||||
|
nvram_buffer[i] = data;
|
||||||
|
nvram_dev->write_byte(nvram_dev, i, data);
|
||||||
|
nvram_csum += data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
printk_info("Offset %d out of range in nvram\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_csum(void)
|
||||||
|
{
|
||||||
|
nvram_dev->write_byte(nvram_dev, nvram_size, nvram_csum);
|
||||||
|
if (nvram_dev->commit)
|
||||||
|
nvram_dev->commit(nvram_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_string_device(unsigned i, const unsigned char *data,
|
||||||
|
unsigned len)
|
||||||
|
{
|
||||||
|
if (i + len < nvram_size)
|
||||||
|
{
|
||||||
|
unsigned j;
|
||||||
|
for(j = 0; j < len; j++)
|
||||||
|
{
|
||||||
|
nvram_csum -= nvram_buffer[i];
|
||||||
|
nvram_buffer[i] = *data;
|
||||||
|
nvram_dev->write_byte(nvram_dev, i, *data);
|
||||||
|
nvram_csum += *data;
|
||||||
|
data++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
printk_info("Offset %d out of range in nvram\n", i + len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nvram_init (struct nvram_device *dev)
|
||||||
|
{
|
||||||
|
nvram_dev = dev;
|
||||||
|
|
||||||
|
if (! nvram_size)
|
||||||
|
nvram_size = dev->size(dev) - 1;
|
||||||
|
printk_info("NVRAM size is %d\n", nvram_size);
|
||||||
|
if (!nvram_buffer)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
nvram_buffer = malloc (nvram_size);
|
||||||
|
if (!nvram_buffer)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
nvram_csum = 0;
|
||||||
|
dev->read_block(dev, 0, nvram_buffer, nvram_size+1);
|
||||||
|
for(i = 0; i < nvram_size; i++)
|
||||||
|
nvram_csum += nvram_buffer[i];
|
||||||
|
|
||||||
|
if (nvram_csum != nvram_buffer[nvram_size])
|
||||||
|
{
|
||||||
|
printk_info("NVRAM checksum invalid - erasing\n");
|
||||||
|
//update_device(0, 0);
|
||||||
|
//update_csum();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printk_info("Initialised nvram\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nvram_clear(void)
|
||||||
|
{
|
||||||
|
printk_info("Erasing NVRAM\n");
|
||||||
|
update_device(0, 0);
|
||||||
|
update_csum();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue