diff options
-rw-r--r-- | src/mainboard/motorola/sandpoint/flash/amd800.c | 230 | ||||
-rw-r--r-- | src/mainboard/motorola/sandpoint/flash/flash.c | 48 | ||||
-rw-r--r-- | src/mainboard/motorola/sandpoint/nvram/bsp_nvram.c | 54 | ||||
-rw-r--r-- | src/mainboard/motorola/sandpoint/nvram/nvram.c | 103 |
4 files changed, 435 insertions, 0 deletions
diff --git a/src/mainboard/motorola/sandpoint/flash/amd800.c b/src/mainboard/motorola/sandpoint/flash/amd800.c new file mode 100644 index 0000000000..8623c0dfb6 --- /dev/null +++ b/src/mainboard/motorola/sandpoint/flash/amd800.c @@ -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); +} + diff --git a/src/mainboard/motorola/sandpoint/flash/flash.c b/src/mainboard/motorola/sandpoint/flash/flash.c new file mode 100644 index 0000000000..b9401ec9e6 --- /dev/null +++ b/src/mainboard/motorola/sandpoint/flash/flash.c @@ -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; +} diff --git a/src/mainboard/motorola/sandpoint/nvram/bsp_nvram.c b/src/mainboard/motorola/sandpoint/nvram/bsp_nvram.c new file mode 100644 index 0000000000..bf5a81c812 --- /dev/null +++ b/src/mainboard/motorola/sandpoint/nvram/bsp_nvram.c @@ -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 +}; + diff --git a/src/mainboard/motorola/sandpoint/nvram/nvram.c b/src/mainboard/motorola/sandpoint/nvram/nvram.c new file mode 100644 index 0000000000..d715dee4ac --- /dev/null +++ b/src/mainboard/motorola/sandpoint/nvram/nvram.c @@ -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(); +} + |