summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mainboard/motorola/sandpoint/flash/amd800.c230
-rw-r--r--src/mainboard/motorola/sandpoint/flash/flash.c48
-rw-r--r--src/mainboard/motorola/sandpoint/nvram/bsp_nvram.c54
-rw-r--r--src/mainboard/motorola/sandpoint/nvram/nvram.c103
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();
+}
+