-+ /* Indicate to per-port code that all tuples have been freed */
-+ BCMINIT(_nvram_free)(NULL);
-+}
-+
-+/* String hash */
-+static INLINE uint
-+hash(const char *s)
-+{
-+ uint hash = 0;
-+
-+ while (*s)
-+ hash = 31 * hash + *s++;
-+
-+ return hash;
-+}
-+
-+/* (Re)initialize the hash table. Should be locked. */
-+static int
-+BCMINITFN(nvram_rehash)(struct nvram_header *header)
-+{
-+ char buf[] = "0xXXXXXXXX", *name, *value, *end, *eq;
-+
-+ /* (Re)initialize hash table */
-+ BCMINIT(nvram_free)();
-+
-+ /* Parse and set "name=value\0 ... \0\0" */
-+ name = (char *) &header[1];
-+ end = (char *) header + NVRAM_SPACE - 2;
-+ end[0] = end[1] = '\0';
-+ for (; *name; name = value + strlen(value) + 1) {
-+ if (!(eq = strchr(name, '=')))
-+ break;
-+ *eq = '\0';
-+ value = eq + 1;
-+ BCMINIT(_nvram_set)(name, value);
-+ *eq = '=';
-+ }
-+
-+ /* Set special SDRAM parameters */
-+ if (!BCMINIT(_nvram_get)("sdram_init")) {
-+ sprintf(buf, "0x%04X", (uint16)(header->crc_ver_init >> 16));
-+ BCMINIT(_nvram_set)("sdram_init", buf);
-+ }
-+ if (!BCMINIT(_nvram_get)("sdram_config")) {
-+ sprintf(buf, "0x%04X", (uint16)(header->config_refresh & 0xffff));
-+ BCMINIT(_nvram_set)("sdram_config", buf);
-+ }
-+ if (!BCMINIT(_nvram_get)("sdram_refresh")) {
-+ sprintf(buf, "0x%04X", (uint16)((header->config_refresh >> 16) & 0xffff));
-+ BCMINIT(_nvram_set)("sdram_refresh", buf);
-+ }
-+ if (!BCMINIT(_nvram_get)("sdram_ncdl")) {
-+ sprintf(buf, "0x%08X", header->config_ncdl);
-+ BCMINIT(_nvram_set)("sdram_ncdl", buf);
-+ }
-+
-+ return 0;
-+}
-+
-+/* Get the value of an NVRAM variable. Should be locked. */
-+char *
-+BCMINITFN(_nvram_get)(const char *name)
-+{
-+ uint i;
-+ struct nvram_tuple *t;
-+ char *value;
-+
-+ if (!name)
-+ return NULL;
-+
-+ /* Hash the name */
-+ i = hash(name) % ARRAYSIZE(BCMINIT(nvram_hash));
-+
-+ /* Find the associated tuple in the hash table */
-+ for (t = BCMINIT(nvram_hash)[i]; t && strcmp(t->name, name); t = t->next);
-+
-+ value = t ? t->value : NULL;
-+
-+ return value;
-+}
-+
-+/* Get the value of an NVRAM variable. Should be locked. */
-+int
-+BCMINITFN(_nvram_set)(const char *name, const char *value)
-+{
-+ uint i;
-+ struct nvram_tuple *t, *u, **prev;
-+
-+ /* Hash the name */
-+ i = hash(name) % ARRAYSIZE(BCMINIT(nvram_hash));
-+
-+ /* Find the associated tuple in the hash table */
-+ for (prev = &BCMINIT(nvram_hash)[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev);
-+
-+ /* (Re)allocate tuple */
-+ if (!(u = BCMINIT(_nvram_realloc)(t, name, value)))
-+ return -12; /* -ENOMEM */
-+
-+ /* Value reallocated */
-+ if (t && t == u)
-+ return 0;
-+
-+ /* Move old tuple to the dead table */
-+ if (t) {
-+ *prev = t->next;
-+ t->next = nvram_dead;
-+ nvram_dead = t;
-+ }
-+
-+ /* Add new tuple to the hash table */
-+ u->next = BCMINIT(nvram_hash)[i];
-+ BCMINIT(nvram_hash)[i] = u;
-+
-+ return 0;
-+}
-+
-+/* Unset the value of an NVRAM variable. Should be locked. */
-+int
-+BCMINITFN(_nvram_unset)(const char *name)
-+{
-+ uint i;
-+ struct nvram_tuple *t, **prev;
-+
-+ if (!name)
-+ return 0;
-+
-+ /* Hash the name */
-+ i = hash(name) % ARRAYSIZE(BCMINIT(nvram_hash));
-+
-+ /* Find the associated tuple in the hash table */
-+ for (prev = &BCMINIT(nvram_hash)[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev);
-+
-+ /* Move it to the dead table */
-+ if (t) {
-+ *prev = t->next;
-+ t->next = nvram_dead;
-+ nvram_dead = t;
-+ }
-+
-+ return 0;
-+}
-+
-+/* Get all NVRAM variables. Should be locked. */
-+int
-+BCMINITFN(_nvram_getall)(char *buf, int count)
-+{
-+ uint i;
-+ struct nvram_tuple *t;
-+ int len = 0;
-+
-+ bzero(buf, count);
-+
-+ /* Write name=value\0 ... \0\0 */
-+ for (i = 0; i < ARRAYSIZE(BCMINIT(nvram_hash)); i++) {
-+ for (t = BCMINIT(nvram_hash)[i]; t; t = t->next) {
-+ if ((count - len) > (strlen(t->name) + 1 + strlen(t->value) + 1))
-+ len += sprintf(buf + len, "%s=%s", t->name, t->value) + 1;
-+ else
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+/* Regenerate NVRAM. Should be locked. */
-+int
-+BCMINITFN(_nvram_commit)(struct nvram_header *header)
-+{
-+ char *init, *config, *refresh, *ncdl;
-+ char *ptr, *end;
-+ int i;
-+ struct nvram_tuple *t;
-+ struct nvram_header tmp;
-+ uint8 crc;
-+
-+ /* Regenerate header */
-+ header->magic = NVRAM_MAGIC;
-+ header->crc_ver_init = (NVRAM_VERSION << 8);
-+ if (!(init = BCMINIT(_nvram_get)("sdram_init")) ||
-+ !(config = BCMINIT(_nvram_get)("sdram_config")) ||
-+ !(refresh = BCMINIT(_nvram_get)("sdram_refresh")) ||
-+ !(ncdl = BCMINIT(_nvram_get)("sdram_ncdl"))) {
-+ header->crc_ver_init |= SDRAM_INIT << 16;
-+ header->config_refresh = SDRAM_CONFIG;
-+ header->config_refresh |= SDRAM_REFRESH << 16;
-+ header->config_ncdl = 0;
-+ } else {
-+ header->crc_ver_init |= (bcm_strtoul(init, NULL, 0) & 0xffff) << 16;
-+ header->config_refresh = bcm_strtoul(config, NULL, 0) & 0xffff;
-+ header->config_refresh |= (bcm_strtoul(refresh, NULL, 0) & 0xffff) << 16;
-+ header->config_ncdl = bcm_strtoul(ncdl, NULL, 0);
-+ }
-+
-+ /* Clear data area */
-+ ptr = (char *) header + sizeof(struct nvram_header);
-+ bzero(ptr, NVRAM_SPACE - sizeof(struct nvram_header));
-+
-+ /* Leave space for a double NUL at the end */
-+ end = (char *) header + NVRAM_SPACE - 2;
-+
-+ /* Write out all tuples */
-+ for (i = 0; i < ARRAYSIZE(BCMINIT(nvram_hash)); i++) {
-+ for (t = BCMINIT(nvram_hash)[i]; t; t = t->next) {
-+ if ((ptr + strlen(t->name) + 1 + strlen(t->value) + 1) > end)
-+ break;
-+ ptr += sprintf(ptr, "%s=%s", t->name, t->value) + 1;
-+ }
-+ }
-+
-+ /* End with a double NUL */
-+ ptr += 2;
-+
-+ /* Set new length */
-+ header->len = ROUNDUP(ptr - (char *) header, 4);
-+
-+ /* Little-endian CRC8 over the last 11 bytes of the header */
-+ tmp.crc_ver_init = htol32(header->crc_ver_init);
-+ tmp.config_refresh = htol32(header->config_refresh);
-+ tmp.config_ncdl = htol32(header->config_ncdl);
-+ crc = hndcrc8((char *) &tmp + 9, sizeof(struct nvram_header) - 9, CRC8_INIT_VALUE);
-+
-+ /* Continue CRC8 over data bytes */
-+ crc = hndcrc8((char *) &header[1], header->len - sizeof(struct nvram_header), crc);
-+
-+ /* Set new CRC8 */
-+ header->crc_ver_init |= crc;
-+
-+ /* Reinitialize hash table */
-+ return BCMINIT(nvram_rehash)(header);
-+}
-+
-+/* Initialize hash table. Should be locked. */
-+int
-+BCMINITFN(_nvram_init)(void)
-+{
-+ struct nvram_header *header;
-+ int ret;
-+ void *osh;
-+
-+ /* get kernel osl handler */
-+ osh = osl_attach(NULL);
-+
-+ if (!(header = (struct nvram_header *) MALLOC(osh, NVRAM_SPACE))) {
-+ printf("nvram_init: out of memory, malloced %d bytes\n", MALLOCED(osh));
-+ return -12; /* -ENOMEM */
-+ }
-+
-+ if ((ret = BCMINIT(_nvram_read)(header)) == 0 &&
-+ header->magic == NVRAM_MAGIC)
-+ BCMINIT(nvram_rehash)(header);
-+
-+ MFREE(osh, header, NVRAM_SPACE);
-+ return ret;
-+}
-+
-+/* Free hash table. Should be locked. */
-+void
-+BCMINITFN(_nvram_exit)(void)
-+{
-+ BCMINIT(nvram_free)();
-+}
-diff -Naur linux.old/arch/mips/bcm947xx/nvram_linux.c linux.dev/arch/mips/bcm947xx/nvram_linux.c
---- linux.old/arch/mips/bcm947xx/nvram_linux.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/arch/mips/bcm947xx/nvram_linux.c 2006-04-06 15:34:14.000000000 +0200
-@@ -0,0 +1,653 @@
-+/*
-+ * NVRAM variable manipulation (Linux kernel half)
-+ *
-+ * Copyright 2005, Broadcom Corporation
-+ * All Rights Reserved.
-+ *
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/interrupt.h>
-+#include <linux/spinlock.h>
-+#include <linux/slab.h>
-+#include <linux/bootmem.h>
-+#include <linux/wrapper.h>
-+#include <linux/fs.h>
-+#include <linux/miscdevice.h>
-+#include <linux/mtd/mtd.h>
-+#include <asm/addrspace.h>
-+#include <asm/io.h>
-+#include <asm/uaccess.h>
-+
-+#include <typedefs.h>
-+#include <bcmendian.h>
-+#include <bcmnvram.h>
-+#include <bcmutils.h>
-+#include <sbconfig.h>
-+#include <sbchipc.h>
-+#include <sbutils.h>
-+#include <sbmips.h>
-+#include <sflash.h>
-+
-+/* In BSS to minimize text size and page aligned so it can be mmap()-ed */
-+static char nvram_buf[NVRAM_SPACE] __attribute__((aligned(PAGE_SIZE)));
-+
-+#ifdef MODULE
-+
-+#define early_nvram_get(name) nvram_get(name)
-+
-+#else /* !MODULE */
-+
-+/* Global SB handle */
-+extern void *bcm947xx_sbh;
-+extern spinlock_t bcm947xx_sbh_lock;
-+
-+static int cfe_env;
-+extern char *cfe_env_get(char *nv_buf, const char *name);
-+
-+/* Convenience */
-+#define sbh bcm947xx_sbh
-+#define sbh_lock bcm947xx_sbh_lock
-+#define KB * 1024
-+#define MB * 1024 * 1024
-+
-+/* Probe for NVRAM header */
-+static void __init
-+early_nvram_init(void)
-+{
-+ struct nvram_header *header;
-+ chipcregs_t *cc;
-+ struct sflash *info = NULL;
-+ int i;
-+ uint32 base, off, lim;
-+ u32 *src, *dst;
-+
-+ if ((cc = sb_setcore(sbh, SB_CC, 0)) != NULL) {
-+ base = KSEG1ADDR(SB_FLASH2);
-+ switch (readl(&cc->capabilities) & CAP_FLASH_MASK) {
-+ case PFLASH:
-+ lim = SB_FLASH2_SZ;
-+ break;
-+
-+ case SFLASH_ST:
-+ case SFLASH_AT:
-+ if ((info = sflash_init(cc)) == NULL)
-+ return;
-+ lim = info->size;
-+ break;
-+
-+ case FLASH_NONE:
-+ default:
-+ return;
-+ }
-+ } else {
-+ /* extif assumed, Stop at 4 MB */
-+ base = KSEG1ADDR(SB_FLASH1);
-+ lim = SB_FLASH1_SZ;
-+ }
-+
-+ /* XXX: hack for supporting the CFE environment stuff on WGT634U */
-+ src = (u32 *) KSEG1ADDR(base + 8 * 1024 * 1024 - 0x2000);
-+ dst = (u32 *) nvram_buf;
-+ if ((lim == 0x02000000) && ((*src & 0xff00ff) == 0x000001)) {
-+ printk("early_nvram_init: WGT634U NVRAM found.\n");
-+
-+ for (i = 0; i < 0x1ff0; i++) {
-+ if (*src == 0xFFFFFFFF)
-+ break;
-+ *dst++ = *src++;
-+ }
-+ cfe_env = 1;
-+ return;
-+ }
-+
-+ off = FLASH_MIN;
-+ while (off <= lim) {
-+ /* Windowed flash access */
-+ header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE);
-+ if (header->magic == NVRAM_MAGIC)
-+ goto found;
-+ off <<= 1;
-+ }
-+
-+ /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
-+ header = (struct nvram_header *) KSEG1ADDR(base + 4 KB);
-+ if (header->magic == NVRAM_MAGIC)
-+ goto found;
-+
-+ header = (struct nvram_header *) KSEG1ADDR(base + 1 KB);
-+ if (header->magic == NVRAM_MAGIC)
-+ goto found;
-+
-+ printk("early_nvram_init: NVRAM not found\n");
-+ return;
-+
-+found:
-+ src = (u32 *) header;
-+ dst = (u32 *) nvram_buf;
-+ for (i = 0; i < sizeof(struct nvram_header); i += 4)
-+ *dst++ = *src++;
-+ for (; i < header->len && i < NVRAM_SPACE; i += 4)
-+ *dst++ = ltoh32(*src++);
-+}
-+
-+/* Early (before mm or mtd) read-only access to NVRAM */
-+static char * __init
-+early_nvram_get(const char *name)
-+{
-+ char *var, *value, *end, *eq;
-+
-+ if (!name)
-+ return NULL;
-+
-+ /* Too early? */
-+ if (sbh == NULL)
-+ return NULL;
-+
-+ if (!nvram_buf[0])
-+ early_nvram_init();
-+
-+ if (cfe_env)
-+ return cfe_env_get(nvram_buf, name);
-+
-+ /* Look for name=value and return value */
-+ var = &nvram_buf[sizeof(struct nvram_header)];
-+ end = nvram_buf + sizeof(nvram_buf) - 2;
-+ end[0] = end[1] = '\0';
-+ for (; *var; var = value + strlen(value) + 1) {
-+ if (!(eq = strchr(var, '=')))
-+ break;
-+ value = eq + 1;
-+ if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0)
-+ return value;
-+ }
-+
-+ return NULL;
-+}
-+
-+#endif /* !MODULE */
-+
-+extern char * _nvram_get(const char *name);
-+extern int _nvram_set(const char *name, const char *value);
-+extern int _nvram_unset(const char *name);
-+extern int _nvram_getall(char *buf, int count);
-+extern int _nvram_commit(struct nvram_header *header);
-+extern int _nvram_init(void);
-+extern void _nvram_exit(void);
-+
-+/* Globals */
-+static spinlock_t nvram_lock = SPIN_LOCK_UNLOCKED;
-+static struct semaphore nvram_sem;
-+static unsigned long nvram_offset = 0;
-+static int nvram_major = -1;
-+static devfs_handle_t nvram_handle = NULL;
-+static struct mtd_info *nvram_mtd = NULL;
-+
-+int
-+_nvram_read(char *buf)
-+{
-+ struct nvram_header *header = (struct nvram_header *) buf;
-+ size_t len;
-+
-+ if (!nvram_mtd ||
-+ MTD_READ(nvram_mtd, nvram_mtd->size - NVRAM_SPACE, NVRAM_SPACE, &len, buf) ||
-+ len != NVRAM_SPACE ||
-+ header->magic != NVRAM_MAGIC) {
-+ /* Maybe we can recover some data from early initialization */
-+ memcpy(buf, nvram_buf, NVRAM_SPACE);
-+ }
-+
-+ return 0;
-+}
-+
-+struct nvram_tuple *
-+_nvram_realloc(struct nvram_tuple *t, const char *name, const char *value)
-+{
-+ if ((nvram_offset + strlen(value) + 1) > NVRAM_SPACE)
-+ return NULL;
-+
-+ if (!t) {
-+ if (!(t = kmalloc(sizeof(struct nvram_tuple) + strlen(name) + 1, GFP_ATOMIC)))
-+ return NULL;
-+
-+ /* Copy name */
-+ t->name = (char *) &t[1];
-+ strcpy(t->name, name);
-+
-+ t->value = NULL;
-+ }
-+
-+ /* Copy value */
-+ if (!t->value || strcmp(t->value, value)) {
-+ t->value = &nvram_buf[nvram_offset];
-+ strcpy(t->value, value);
-+ nvram_offset += strlen(value) + 1;
-+ }
-+
-+ return t;
-+}
-+
-+void
-+_nvram_free(struct nvram_tuple *t)
-+{
-+ if (!t)
-+ nvram_offset = 0;
-+ else
-+ kfree(t);
-+}
-+
-+int
-+nvram_set(const char *name, const char *value)
-+{
-+ unsigned long flags;
-+ int ret;
-+ struct nvram_header *header;
-+
-+ spin_lock_irqsave(&nvram_lock, flags);
-+ if ((ret = _nvram_set(name, value))) {
-+ /* Consolidate space and try again */
-+ if ((header = kmalloc(NVRAM_SPACE, GFP_ATOMIC))) {
-+ if (_nvram_commit(header) == 0)
-+ ret = _nvram_set(name, value);
-+ kfree(header);
-+ }
-+ }
-+ spin_unlock_irqrestore(&nvram_lock, flags);
-+
-+ return ret;
-+}
-+
-+char *
-+real_nvram_get(const char *name)
-+{
-+ unsigned long flags;
-+ char *value;
-+
-+ spin_lock_irqsave(&nvram_lock, flags);
-+ value = _nvram_get(name);
-+ spin_unlock_irqrestore(&nvram_lock, flags);
-+
-+ return value;
-+}
-+
-+char *
-+nvram_get(const char *name)
-+{
-+ if (nvram_major >= 0)
-+ return real_nvram_get(name);
-+ else
-+ return early_nvram_get(name);
-+}
-+
-+int
-+nvram_unset(const char *name)
-+{
-+ unsigned long flags;
-+ int ret;
-+
-+ spin_lock_irqsave(&nvram_lock, flags);
-+ ret = _nvram_unset(name);
-+ spin_unlock_irqrestore(&nvram_lock, flags);
-+
-+ return ret;
-+}
-+
-+static void
-+erase_callback(struct erase_info *done)
-+{
-+ wait_queue_head_t *wait_q = (wait_queue_head_t *) done->priv;
-+ wake_up(wait_q);
-+}
-+
-+int
-+nvram_commit(void)
-+{
-+ char *buf;
-+ size_t erasesize, len;
-+ unsigned int i;
-+ int ret;
-+ struct nvram_header *header;
-+ unsigned long flags;
-+ u_int32_t offset;
-+ DECLARE_WAITQUEUE(wait, current);
-+ wait_queue_head_t wait_q;
-+ struct erase_info erase;
-+
-+ if (!nvram_mtd) {
-+ printk("nvram_commit: NVRAM not found\n");
-+ return -ENODEV;
-+ }
-+
-+ if (in_interrupt()) {
-+ printk("nvram_commit: not committing in interrupt\n");
-+ return -EINVAL;
-+ }
-+
-+ /* Backup sector blocks to be erased */
-+ erasesize = ROUNDUP(NVRAM_SPACE, nvram_mtd->erasesize);
-+ if (!(buf = kmalloc(erasesize, GFP_KERNEL))) {
-+ printk("nvram_commit: out of memory\n");
-+ return -ENOMEM;
-+ }
-+
-+ down(&nvram_sem);
-+
-+ if ((i = erasesize - NVRAM_SPACE) > 0) {
-+ offset = nvram_mtd->size - erasesize;
-+ len = 0;
-+ ret = MTD_READ(nvram_mtd, offset, i, &len, buf);
-+ if (ret || len != i) {
-+ printk("nvram_commit: read error ret = %d, len = %d/%d\n", ret, len, i);
-+ ret = -EIO;
-+ goto done;
-+ }
-+ header = (struct nvram_header *)(buf + i);
-+ } else {
-+ offset = nvram_mtd->size - NVRAM_SPACE;
-+ header = (struct nvram_header *)buf;
-+ }
-+
-+ /* Regenerate NVRAM */
-+ spin_lock_irqsave(&nvram_lock, flags);
-+ ret = _nvram_commit(header);
-+ spin_unlock_irqrestore(&nvram_lock, flags);
-+ if (ret)
-+ goto done;
-+
-+ /* Erase sector blocks */
-+ init_waitqueue_head(&wait_q);
-+ for (; offset < nvram_mtd->size - NVRAM_SPACE + header->len; offset += nvram_mtd->erasesize) {
-+ erase.mtd = nvram_mtd;
-+ erase.addr = offset;
-+ erase.len = nvram_mtd->erasesize;
-+ erase.callback = erase_callback;
-+ erase.priv = (u_long) &wait_q;
-+
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ add_wait_queue(&wait_q, &wait);
-+
-+ /* Unlock sector blocks */
-+ if (nvram_mtd->unlock)
-+ nvram_mtd->unlock(nvram_mtd, offset, nvram_mtd->erasesize);
-+
-+ if ((ret = MTD_ERASE(nvram_mtd, &erase))) {
-+ set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&wait_q, &wait);
-+ printk("nvram_commit: erase error\n");
-+ goto done;
-+ }
-+
-+ /* Wait for erase to finish */
-+ schedule();
-+ remove_wait_queue(&wait_q, &wait);
-+ }
-+
-+ /* Write partition up to end of data area */
-+ offset = nvram_mtd->size - erasesize;
-+ i = erasesize - NVRAM_SPACE + header->len;
-+ ret = MTD_WRITE(nvram_mtd, offset, i, &len, buf);
-+ if (ret || len != i) {
-+ printk("nvram_commit: write error\n");
-+ ret = -EIO;
-+ goto done;
-+ }
-+
-+ offset = nvram_mtd->size - erasesize;
-+ ret = MTD_READ(nvram_mtd, offset, 4, &len, buf);
-+
-+ done:
-+ up(&nvram_sem);
-+ kfree(buf);
-+ return ret;
-+}
-+
-+int
-+nvram_getall(char *buf, int count)
-+{
-+ unsigned long flags;
-+ int ret;
-+
-+ spin_lock_irqsave(&nvram_lock, flags);
-+ ret = _nvram_getall(buf, count);
-+ spin_unlock_irqrestore(&nvram_lock, flags);
-+
-+ return ret;
-+}
-+
-+EXPORT_SYMBOL(nvram_get);
-+EXPORT_SYMBOL(nvram_getall);
-+EXPORT_SYMBOL(nvram_set);
-+EXPORT_SYMBOL(nvram_unset);
-+EXPORT_SYMBOL(nvram_commit);
-+
-+/* User mode interface below */
-+
-+static ssize_t
-+dev_nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-+{
-+ char tmp[100], *name = tmp, *value;
-+ ssize_t ret;
-+ unsigned long off;
-+
-+ if (count > sizeof(tmp)) {
-+ if (!(name = kmalloc(count, GFP_KERNEL)))
-+ return -ENOMEM;
-+ }
-+
-+ if (copy_from_user(name, buf, count)) {
-+ ret = -EFAULT;
-+ goto done;
-+ }
-+
-+ if (*name == '\0') {
-+ /* Get all variables */
-+ ret = nvram_getall(name, count);
-+ if (ret == 0) {
-+ if (copy_to_user(buf, name, count)) {
-+ ret = -EFAULT;
-+ goto done;
-+ }
-+ ret = count;
-+ }
-+ } else {
-+ if (!(value = nvram_get(name))) {
-+ ret = 0;
-+ goto done;
-+ }
-+
-+ /* Provide the offset into mmap() space */
-+ off = (unsigned long) value - (unsigned long) nvram_buf;
-+
-+ if (put_user(off, (unsigned long *) buf)) {
-+ ret = -EFAULT;
-+ goto done;
-+ }
-+
-+ ret = sizeof(unsigned long);
-+ }
-+
-+ flush_cache_all();
-+
-+done:
-+ if (name != tmp)
-+ kfree(name);
-+
-+ return ret;
-+}
-+
-+static ssize_t
-+dev_nvram_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
-+{
-+ char tmp[100], *name = tmp, *value;
-+ ssize_t ret;
-+
-+ if (count > sizeof(tmp)) {
-+ if (!(name = kmalloc(count, GFP_KERNEL)))
-+ return -ENOMEM;
-+ }
-+
-+ if (copy_from_user(name, buf, count)) {
-+ ret = -EFAULT;
-+ goto done;
-+ }
-+
-+ value = name;
-+ name = strsep(&value, "=");
-+ if (value)
-+ ret = nvram_set(name, value) ? : count;
-+ else
-+ ret = nvram_unset(name) ? : count;
-+
-+ done:
-+ if (name != tmp)
-+ kfree(name);
-+
-+ return ret;
-+}
-+
-+static int
-+dev_nvram_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+ if (cmd != NVRAM_MAGIC)
-+ return -EINVAL;
-+ return nvram_commit();
-+}
-+
-+static int
-+dev_nvram_mmap(struct file *file, struct vm_area_struct *vma)
-+{
-+ unsigned long offset = virt_to_phys(nvram_buf);
-+
-+ if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start,
-+ vma->vm_page_prot))
-+ return -EAGAIN;
-+
-+ return 0;
-+}
-+
-+static int
-+dev_nvram_open(struct inode *inode, struct file * file)
-+{
-+ MOD_INC_USE_COUNT;
-+ return 0;
-+}
-+
-+static int
-+dev_nvram_release(struct inode *inode, struct file * file)
-+{
-+ MOD_DEC_USE_COUNT;
-+ return 0;
-+}
-+
-+static struct file_operations dev_nvram_fops = {
-+ owner: THIS_MODULE,
-+ open: dev_nvram_open,
-+ release: dev_nvram_release,
-+ read: dev_nvram_read,
-+ write: dev_nvram_write,
-+ ioctl: dev_nvram_ioctl,
-+ mmap: dev_nvram_mmap,
-+};
-+
-+static void
-+dev_nvram_exit(void)
-+{
-+ int order = 0;
-+ struct page *page, *end;
-+
-+ if (nvram_handle)
-+ devfs_unregister(nvram_handle);
-+
-+ if (nvram_major >= 0)
-+ devfs_unregister_chrdev(nvram_major, "nvram");
-+
-+ if (nvram_mtd)
-+ put_mtd_device(nvram_mtd);
-+
-+ while ((PAGE_SIZE << order) < NVRAM_SPACE)
-+ order++;
-+ end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
-+ for (page = virt_to_page(nvram_buf); page <= end; page++)
-+ mem_map_unreserve(page);
-+
-+ _nvram_exit();
-+}
-+
-+static int __init
-+dev_nvram_init(void)
-+{
-+ int order = 0, ret = 0;
-+ struct page *page, *end;
-+ unsigned int i;
-+
-+ /* Allocate and reserve memory to mmap() */
-+ while ((PAGE_SIZE << order) < NVRAM_SPACE)
-+ order++;
-+ end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
-+ for (page = virt_to_page(nvram_buf); page <= end; page++)
-+ mem_map_reserve(page);
-+
-+#ifdef CONFIG_MTD
-+ /* Find associated MTD device */
-+ for (i = 0; i < MAX_MTD_DEVICES; i++) {
-+ nvram_mtd = get_mtd_device(NULL, i);
-+ if (nvram_mtd) {
-+ if (!strcmp(nvram_mtd->name, "nvram") &&
-+ nvram_mtd->size >= NVRAM_SPACE)
-+ break;
-+ put_mtd_device(nvram_mtd);
-+ }
-+ }
-+ if (i >= MAX_MTD_DEVICES)
-+ nvram_mtd = NULL;
-+#endif
-+
-+ /* Initialize hash table lock */
-+ spin_lock_init(&nvram_lock);
-+
-+ /* Initialize commit semaphore */
-+ init_MUTEX(&nvram_sem);
-+
-+ /* Register char device */
-+ if ((nvram_major = devfs_register_chrdev(0, "nvram", &dev_nvram_fops)) < 0) {
-+ ret = nvram_major;
-+ goto err;
-+ }
-+
-+ /* Initialize hash table */
-+ _nvram_init();
-+
-+ /* Create /dev/nvram handle */
-+ nvram_handle = devfs_register(NULL, "nvram", DEVFS_FL_NONE, nvram_major, 0,
-+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &dev_nvram_fops, NULL);
-+
-+ /* Set the SDRAM NCDL value into NVRAM if not already done */
-+ if (getintvar(NULL, "sdram_ncdl") == 0) {
-+ unsigned int ncdl;
-+ char buf[] = "0x00000000";
-+
-+ if ((ncdl = sb_memc_get_ncdl(sbh))) {
-+ sprintf(buf, "0x%08x", ncdl);
-+ nvram_set("sdram_ncdl", buf);
-+ nvram_commit();
-+ }
-+ }
-+
-+ return 0;
-+
-+ err:
-+ dev_nvram_exit();
-+ return ret;
-+}
-+
-+module_init(dev_nvram_init);
-+module_exit(dev_nvram_exit);
-diff -Naur linux.old/arch/mips/bcm947xx/pcibios.c linux.dev/arch/mips/bcm947xx/pcibios.c
---- linux.old/arch/mips/bcm947xx/pcibios.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/arch/mips/bcm947xx/pcibios.c 2006-04-06 15:34:14.000000000 +0200
-@@ -0,0 +1,355 @@
-+/*
-+ * Low-Level PCI and SB support for BCM47xx (Linux support code)
-+ *
-+ * Copyright 2005, Broadcom Corporation
-+ * All Rights Reserved.
-+ *
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-+ *
-+ * $Id$
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/pci.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+#include <asm/io.h>
-+#include <asm/irq.h>
-+#include <asm/paccess.h>
-+
-+#include <typedefs.h>
-+#include <bcmutils.h>
-+#include <sbconfig.h>
-+#include <sbutils.h>
-+#include <sbpci.h>
-+#include <pcicfg.h>
-+#include <bcmdevs.h>
-+#include <bcmnvram.h>
-+
-+/* Global SB handle */
-+extern sb_t *bcm947xx_sbh;
-+extern spinlock_t bcm947xx_sbh_lock;
-+
-+/* Convenience */
-+#define sbh bcm947xx_sbh
-+#define sbh_lock bcm947xx_sbh_lock
-+
-+static int
-+sbpci_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-+{
-+ unsigned long flags;
-+ int ret;
-+
-+ spin_lock_irqsave(&sbh_lock, flags);
-+ ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, value, sizeof(*value));
-+ spin_unlock_irqrestore(&sbh_lock, flags);
-+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-+}
-+
-+static int
-+sbpci_read_config_word(struct pci_dev *dev, int where, u16 *value)
-+{
-+ unsigned long flags;
-+ int ret;
-+
-+ spin_lock_irqsave(&sbh_lock, flags);
-+ ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, value, sizeof(*value));
-+ spin_unlock_irqrestore(&sbh_lock, flags);
-+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-+}
-+
-+static int
-+sbpci_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-+{
-+ unsigned long flags;
-+ int ret;
-+
-+ spin_lock_irqsave(&sbh_lock, flags);
-+ ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, value, sizeof(*value));
-+ spin_unlock_irqrestore(&sbh_lock, flags);
-+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-+}
-+
-+static int
-+sbpci_write_config_byte(struct pci_dev *dev, int where, u8 value)
-+{
-+ unsigned long flags;
-+ int ret;
-+
-+ spin_lock_irqsave(&sbh_lock, flags);
-+ ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, &value, sizeof(value));
-+ spin_unlock_irqrestore(&sbh_lock, flags);
-+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-+}
-+
-+static int
-+sbpci_write_config_word(struct pci_dev *dev, int where, u16 value)
-+{
-+ unsigned long flags;
-+ int ret;
-+
-+ spin_lock_irqsave(&sbh_lock, flags);
-+ ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, &value, sizeof(value));
-+ spin_unlock_irqrestore(&sbh_lock, flags);
-+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-+}
-+
-+static int
-+sbpci_write_config_dword(struct pci_dev *dev, int where, u32 value)
-+{
-+ unsigned long flags;
-+ int ret;
-+
-+ spin_lock_irqsave(&sbh_lock, flags);
-+ ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, &value, sizeof(value));
-+ spin_unlock_irqrestore(&sbh_lock, flags);
-+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
-+}
-+
-+static struct pci_ops pcibios_ops = {
-+ sbpci_read_config_byte,
-+ sbpci_read_config_word,
-+ sbpci_read_config_dword,
-+ sbpci_write_config_byte,
-+ sbpci_write_config_word,
-+ sbpci_write_config_dword
-+};
-+
-+
-+void __init
-+pcibios_init(void)
-+{
-+ ulong flags;
-+
-+ if (!(sbh = sb_kattach()))
-+ panic("sb_kattach failed");
-+ spin_lock_init(&sbh_lock);
-+
-+ spin_lock_irqsave(&sbh_lock, flags);
-+ sbpci_init(sbh);
-+ spin_unlock_irqrestore(&sbh_lock, flags);
-+
-+ set_io_port_base((unsigned long) ioremap_nocache(SB_PCI_MEM, 0x04000000));
-+
-+ mdelay(300); //By Joey for Atheros Card
-+
-+ /* Scan the SB bus */
-+ pci_scan_bus(0, &pcibios_ops, NULL);
-+
-+}
-+
-+char * __init
-+pcibios_setup(char *str)
-+{
-+ if (!strncmp(str, "ban=", 4)) {
-+ sbpci_ban(simple_strtoul(str + 4, NULL, 0));
-+ return NULL;
-+ }
-+
-+ return (str);
-+}
-+
-+static u32 pci_iobase = 0x100;
-+static u32 pci_membase = SB_PCI_DMA;
-+
-+void __init
-+pcibios_fixup_bus(struct pci_bus *b)
-+{
-+ struct list_head *ln;
-+ struct pci_dev *d;
-+ struct resource *res;
-+ int pos, size;
-+ u32 *base;
-+ u8 irq;
-+
-+ printk("PCI: Fixing up bus %d\n", b->number);
-+
-+ /* Fix up SB */
-+ if (b->number == 0) {
-+ for (ln=b->devices.next; ln != &b->devices; ln=ln->next) {
-+ d = pci_dev_b(ln);
-+ /* Fix up interrupt lines */
-+ pci_read_config_byte(d, PCI_INTERRUPT_LINE, &irq);
-+ d->irq = irq + 2;
-+ pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
-+ }
-+ }
-+
-+ /* Fix up external PCI */
-+ else {
-+ for (ln=b->devices.next; ln != &b->devices; ln=ln->next) {
-+ d = pci_dev_b(ln);
-+ /* Fix up resource bases */
-+ for (pos = 0; pos < 6; pos++) {
-+ res = &d->resource[pos];
-+ base = (res->flags & IORESOURCE_IO) ? &pci_iobase : &pci_membase;
-+ if (res->end) {
-+ size = res->end - res->start + 1;
-+ if (*base & (size - 1))
-+ *base = (*base + size) & ~(size - 1);
-+ res->start = *base;
-+ res->end = res->start + size - 1;
-+ *base += size;
-+ pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
-+ }
-+ /* Fix up PCI bridge BAR0 only */
-+ if (b->number == 1 && PCI_SLOT(d->devfn) == 0)
-+ break;
-+ }
-+ /* Fix up interrupt lines */
-+ if (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL))
-+ d->irq = (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL))->irq;
-+ pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
-+ }
-+ }
-+}
-+
-+unsigned int
-+pcibios_assign_all_busses(void)
-+{
-+ return 1;
-+}
-+
-+void
-+pcibios_align_resource(void *data, struct resource *res,
-+ unsigned long size, unsigned long align)
-+{
-+}
-+
-+int
-+pcibios_enable_resources(struct pci_dev *dev)
-+{
-+ u16 cmd, old_cmd;
-+ int idx;
-+ struct resource *r;
-+
-+ /* External PCI only */
-+ if (dev->bus->number == 0)
-+ return 0;
-+
-+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
-+ old_cmd = cmd;
-+ for(idx=0; idx<6; idx++) {
-+ r = &dev->resource[idx];
-+ if (r->flags & IORESOURCE_IO)
-+ cmd |= PCI_COMMAND_IO;
-+ if (r->flags & IORESOURCE_MEM)
-+ cmd |= PCI_COMMAND_MEMORY;
-+ }
-+ if (dev->resource[PCI_ROM_RESOURCE].start)
-+ cmd |= PCI_COMMAND_MEMORY;
-+ if (cmd != old_cmd) {
-+ printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
-+ pci_write_config_word(dev, PCI_COMMAND, cmd);
-+ }
-+ return 0;
-+}
-+
-+int
-+pcibios_enable_device(struct pci_dev *dev, int mask)
-+{
-+ ulong flags;
-+ uint coreidx;
-+
-+ /* External PCI device enable */
-+ if (dev->bus->number != 0)
-+ return pcibios_enable_resources(dev);
-+
-+ /* These cores come out of reset enabled */
-+ if (dev->device == SB_MIPS ||
-+ dev->device == SB_MIPS33 ||
-+ dev->device == SB_EXTIF ||
-+ dev->device == SB_CC)
-+ return 0;
-+
-+ spin_lock_irqsave(&sbh_lock, flags);
-+ coreidx = sb_coreidx(sbh);
-+ if (!sb_setcoreidx(sbh, PCI_SLOT(dev->devfn)))
-+ return PCIBIOS_DEVICE_NOT_FOUND;
-+
-+ /*
-+ * The USB core requires a special bit to be set during core
-+ * reset to enable host (OHCI) mode. Resetting the SB core in
-+ * pcibios_enable_device() is a hack for compatibility with
-+ * vanilla usb-ohci so that it does not have to know about
-+ * SB. A driver that wants to use the USB core in device mode
-+ * should know about SB and should reset the bit back to 0
-+ * after calling pcibios_enable_device().
-+ */
-+ if (sb_coreid(sbh) == SB_USB) {
-+ sb_core_disable(sbh, sb_coreflags(sbh, 0, 0));
-+ sb_core_reset(sbh, 1 << 29);
-+ } else
-+ sb_core_reset(sbh, 0);
-+
-+ sb_setcoreidx(sbh, coreidx);
-+ spin_unlock_irqrestore(&sbh_lock, flags);
-+
-+ return 0;
-+}
-+
-+void
-+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
-+ struct resource *res, int resource)
-+{
-+ unsigned long where, size;
-+ u32 reg;
-+
-+ /* External PCI only */
-+ if (dev->bus->number == 0)
-+ return;
-+
-+ where = PCI_BASE_ADDRESS_0 + (resource * 4);
-+ size = res->end - res->start;
-+ pci_read_config_dword(dev, where, ®);
-+ reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
-+ pci_write_config_dword(dev, where, reg);
-+}
-+
-+static void __init
-+quirk_sbpci_bridge(struct pci_dev *dev)
-+{
-+ if (dev->bus->number != 1 || PCI_SLOT(dev->devfn) != 0)
-+ return;
-+
-+ printk("PCI: Fixing up bridge\n");
-+
-+ /* Enable PCI bridge bus mastering and memory space */
-+ pci_set_master(dev);
-+ pcibios_enable_resources(dev);
-+
-+ /* Enable PCI bridge BAR1 prefetch and burst */
-+ pci_write_config_dword(dev, PCI_BAR1_CONTROL, 3);
-+}
-+
-+struct pci_fixup pcibios_fixups[] = {
-+ { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, quirk_sbpci_bridge },
-+ { 0 }
-+};
-+
-+/*
-+ * If we set up a device for bus mastering, we need to check the latency
-+ * timer as certain crappy BIOSes forget to set it properly.
-+ */
-+unsigned int pcibios_max_latency = 255;
-+
-+void pcibios_set_master(struct pci_dev *dev)
-+{
-+ u8 lat;
-+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
-+ if (lat < 16)
-+ lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
-+ else if (lat > pcibios_max_latency)
-+ lat = pcibios_max_latency;
-+ else
-+ return;
-+ printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
-+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
-+}
-+
-diff -Naur linux.old/arch/mips/bcm947xx/prom.c linux.dev/arch/mips/bcm947xx/prom.c
---- linux.old/arch/mips/bcm947xx/prom.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/arch/mips/bcm947xx/prom.c 2006-04-06 15:34:14.000000000 +0200
-@@ -0,0 +1,41 @@
-+/*
-+ * Early initialization code for BCM94710 boards
-+ *
-+ * Copyright 2004, Broadcom Corporation
-+ * All Rights Reserved.
-+ *
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-+ *
-+ * $Id: prom.c,v 1.1 2005/03/16 13:49:59 wbx Exp $
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <asm/bootinfo.h>
-+
-+void __init
-+prom_init(int argc, const char **argv)
-+{
-+ unsigned long mem;
-+
-+ mips_machgroup = MACH_GROUP_BRCM;
-+ mips_machtype = MACH_BCM947XX;
-+
-+ /* Figure out memory size by finding aliases */
-+ for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) {
-+ if (*(unsigned long *)((unsigned long)(prom_init) + mem) ==
-+ *(unsigned long *)(prom_init))
-+ break;
-+ }
-+ add_memory_region(0, mem, BOOT_MEM_RAM);
-+}
-+
-+void __init
-+prom_free_prom_memory(void)
-+{
-+}
-diff -Naur linux.old/arch/mips/bcm947xx/sbmips.c linux.dev/arch/mips/bcm947xx/sbmips.c
---- linux.old/arch/mips/bcm947xx/sbmips.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/arch/mips/bcm947xx/sbmips.c 2006-04-06 15:34:14.000000000 +0200
-@@ -0,0 +1,1038 @@
-+/*
-+ * BCM47XX Sonics SiliconBackplane MIPS core routines
-+ *
-+ * Copyright 2005, Broadcom Corporation
-+ * All Rights Reserved.
-+ *
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-+ *
-+ * $Id$
-+ */
-+
-+#include <typedefs.h>
-+#include <osl.h>
-+#include <sbutils.h>
-+#include <bcmdevs.h>
-+#include <bcmnvram.h>
-+#include <bcmutils.h>
-+#include <hndmips.h>
-+#include <sbconfig.h>
-+#include <sbextif.h>
-+#include <sbchipc.h>
-+#include <sbmemc.h>
-+#include <mipsinc.h>
-+#include <sbutils.h>
-+
-+/*
-+ * Returns TRUE if an external UART exists at the given base
-+ * register.
-+ */
-+static bool
-+BCMINITFN(serial_exists)(uint8 *regs)
-+{
-+ uint8 save_mcr, status1;
-+
-+ save_mcr = R_REG(®s[UART_MCR]);
-+ W_REG(®s[UART_MCR], UART_MCR_LOOP | 0x0a);
-+ status1 = R_REG(®s[UART_MSR]) & 0xf0;
-+ W_REG(®s[UART_MCR], save_mcr);
-+
-+ return (status1 == 0x90);
-+}
-+
-+/*
-+ * Initializes UART access. The callback function will be called once
-+ * per found UART.
-+ */
-+void
-+BCMINITFN(sb_serial_init)(sb_t *sbh, void (*add)(void *regs, uint irq, uint baud_base, uint reg_shift))
-+{
-+ void *regs;
-+ ulong base;
-+ uint irq;
-+ int i, n;
-+
-+ if ((regs = sb_setcore(sbh, SB_EXTIF, 0))) {
-+ extifregs_t *eir = (extifregs_t *) regs;
-+ sbconfig_t *sb;
-+
-+ /* Determine external UART register base */
-+ sb = (sbconfig_t *)((ulong) eir + SBCONFIGOFF);
-+ base = EXTIF_CFGIF_BASE(sb_base(R_REG(&sb->sbadmatch1)));
-+
-+ /* Determine IRQ */
-+ irq = sb_irq(sbh);
-+
-+ /* Disable GPIO interrupt initially */
-+ W_REG(&eir->gpiointpolarity, 0);
-+ W_REG(&eir->gpiointmask, 0);
-+
-+ /* Search for external UARTs */
-+ n = 2;
-+ for (i = 0; i < 2; i++) {
-+ regs = (void *) REG_MAP(base + (i * 8), 8);
-+ if (BCMINIT(serial_exists)(regs)) {
-+ /* Set GPIO 1 to be the external UART IRQ */
-+ W_REG(&eir->gpiointmask, 2);
-+ if (add)
-+ add(regs, irq, 13500000, 0);
-+ }
-+ }
-+
-+ /* Add internal UART if enabled */
-+ if (R_REG(&eir->corecontrol) & CC_UE)
-+ if (add)
-+ add((void *) &eir->uartdata, irq, sb_clock(sbh), 2);
-+ } else if ((regs = sb_setcore(sbh, SB_CC, 0))) {
-+ chipcregs_t *cc = (chipcregs_t *) regs;
-+ uint32 rev, cap, pll, baud_base, div;
-+
-+ /* Determine core revision and capabilities */
-+ rev = sb_corerev(sbh);
-+ cap = R_REG(&cc->capabilities);
-+ pll = cap & CAP_PLL_MASK;
-+
-+ /* Determine IRQ */
-+ irq = sb_irq(sbh);
-+
-+ if (pll == PLL_TYPE1) {
-+ /* PLL clock */
-+ baud_base = sb_clock_rate(pll,
-+ R_REG(&cc->clockcontrol_n),
-+ R_REG(&cc->clockcontrol_m2));
-+ div = 1;
-+ } else {
-+ if (rev >= 11) {
-+ /* Fixed ALP clock */
-+ baud_base = 20000000;
-+ div = 1;
-+ /* Set the override bit so we don't divide it */
-+ W_REG(&cc->corecontrol, CC_UARTCLKO);
-+ } else if (rev >= 3) {
-+ /* Internal backplane clock */
-+ baud_base = sb_clock(sbh);
-+ div = 2; /* Minimum divisor */
-+ W_REG(&cc->clkdiv,
-+ ((R_REG(&cc->clkdiv) & ~CLKD_UART) | div));
-+ } else {
-+ /* Fixed internal backplane clock */
-+ baud_base = 88000000;
-+ div = 48;
-+ }
-+
-+ /* Clock source depends on strapping if UartClkOverride is unset */
-+ if ((rev > 0) &&
-+ ((R_REG(&cc->corecontrol) & CC_UARTCLKO) == 0)) {
-+ if ((cap & CAP_UCLKSEL) == CAP_UINTCLK) {
-+ /* Internal divided backplane clock */
-+ baud_base /= div;
-+ } else {
-+ /* Assume external clock of 1.8432 MHz */
-+ baud_base = 1843200;
-+ }
-+ }
-+ }
-+
-+ /* Add internal UARTs */
-+ n = cap & CAP_UARTS_MASK;
-+ for (i = 0; i < n; i++) {
-+ /* Register offset changed after revision 0 */
-+ if (rev)
-+ regs = (void *)((ulong) &cc->uart0data + (i * 256));
-+ else
-+ regs = (void *)((ulong) &cc->uart0data + (i * 8));
-+
-+ if (add)
-+ add(regs, irq, baud_base, 0);
-+ }
-+ }
-+}
-+
-+/*
-+ * Initialize jtag master and return handle for
-+ * jtag_rwreg. Returns NULL on failure.
-+ */
-+void *
-+sb_jtagm_init(sb_t *sbh, uint clkd, bool exttap)
-+{
-+ void *regs;
-+
-+ if ((regs = sb_setcore(sbh, SB_CC, 0)) != NULL) {
-+ chipcregs_t *cc = (chipcregs_t *) regs;
-+ uint32 tmp;
-+
-+ /*
-+ * Determine jtagm availability from
-+ * core revision and capabilities.
-+ */
-+ tmp = sb_corerev(sbh);
-+ /*
-+ * Corerev 10 has jtagm, but the only chip
-+ * with it does not have a mips, and
-+ * the layout of the jtagcmd register is
-+ * different. We'll only accept >= 11.
-+ */
-+ if (tmp < 11)
-+ return (NULL);
-+
-+ tmp = R_REG(&cc->capabilities);
-+ if ((tmp & CAP_JTAGP) == 0)
-+ return (NULL);
-+
-+ /* Set clock divider if requested */
-+ if (clkd != 0) {
-+ tmp = R_REG(&cc->clkdiv);
-+ tmp = (tmp & ~CLKD_JTAG) |
-+ ((clkd << CLKD_JTAG_SHIFT) & CLKD_JTAG);
-+ W_REG(&cc->clkdiv, tmp);
-+ }
-+
-+ /* Enable jtagm */
-+ tmp = JCTRL_EN | (exttap ? JCTRL_EXT_EN : 0);
-+ W_REG(&cc->jtagctrl, tmp);
-+ }
-+
-+ return (regs);
-+}
-+
-+void
-+sb_jtagm_disable(void *h)
-+{
-+ chipcregs_t *cc = (chipcregs_t *)h;
-+
-+ W_REG(&cc->jtagctrl, R_REG(&cc->jtagctrl) & ~JCTRL_EN);
-+}
-+
-+/*
-+ * Read/write a jtag register. Assumes a target with
-+ * 8 bit IR and 32 bit DR.
-+ */
-+#define IRWIDTH 8
-+#define DRWIDTH 32
-+uint32
-+jtag_rwreg(void *h, uint32 ir, uint32 dr)
-+{
-+ chipcregs_t *cc = (chipcregs_t *) h;
-+ uint32 tmp;
-+
-+ W_REG(&cc->jtagir, ir);
-+ W_REG(&cc->jtagdr, dr);
-+ tmp = JCMD_START | JCMD_ACC_IRDR |
-+ ((IRWIDTH - 1) << JCMD_IRW_SHIFT) |
-+ (DRWIDTH - 1);
-+ W_REG(&cc->jtagcmd, tmp);
-+ while (((tmp = R_REG(&cc->jtagcmd)) & JCMD_BUSY) == JCMD_BUSY) {
-+ /* OSL_DELAY(1); */
-+ }
-+
-+ tmp = R_REG(&cc->jtagdr);
-+ return (tmp);
-+}
-+
-+/* Returns the SB interrupt flag of the current core. */
-+uint32
-+sb_flag(sb_t *sbh)
-+{
-+ void *regs;
-+ sbconfig_t *sb;
-+
-+ regs = sb_coreregs(sbh);
-+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
-+
-+ return (R_REG(&sb->sbtpsflag) & SBTPS_NUM0_MASK);
-+}
-+
-+static const uint32 sbips_int_mask[] = {
-+ 0,
-+ SBIPS_INT1_MASK,
-+ SBIPS_INT2_MASK,
-+ SBIPS_INT3_MASK,
-+ SBIPS_INT4_MASK
-+};
-+
-+static const uint32 sbips_int_shift[] = {
-+ 0,
-+ 0,
-+ SBIPS_INT2_SHIFT,
-+ SBIPS_INT3_SHIFT,
-+ SBIPS_INT4_SHIFT
-+};
-+
-+/*
-+ * Returns the MIPS IRQ assignment of the current core. If unassigned,
-+ * 0 is returned.
-+ */
-+uint
-+sb_irq(sb_t *sbh)
-+{
-+ uint idx;
-+ void *regs;
-+ sbconfig_t *sb;
-+ uint32 flag, sbipsflag;
-+ uint irq = 0;
-+
-+ flag = sb_flag(sbh);
-+
-+ idx = sb_coreidx(sbh);
-+
-+ if ((regs = sb_setcore(sbh, SB_MIPS, 0)) ||
-+ (regs = sb_setcore(sbh, SB_MIPS33, 0))) {
-+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
-+
-+ /* sbipsflag specifies which core is routed to interrupts 1 to 4 */
-+ sbipsflag = R_REG(&sb->sbipsflag);
-+ for (irq = 1; irq <= 4; irq++) {
-+ if (((sbipsflag & sbips_int_mask[irq]) >> sbips_int_shift[irq]) == flag)
-+ break;
-+ }
-+ if (irq == 5)
-+ irq = 0;
-+ }
-+
-+ sb_setcoreidx(sbh, idx);
-+
-+ return irq;
-+}
-+
-+/* Clears the specified MIPS IRQ. */
-+static void
-+BCMINITFN(sb_clearirq)(sb_t *sbh, uint irq)
-+{
-+ void *regs;
-+ sbconfig_t *sb;
-+
-+ if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
-+ !(regs = sb_setcore(sbh, SB_MIPS33, 0)))
-+ ASSERT(regs);
-+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
-+
-+ if (irq == 0)
-+ W_REG(&sb->sbintvec, 0);
-+ else
-+ OR_REG(&sb->sbipsflag, sbips_int_mask[irq]);
-+}
-+
-+/*
-+ * Assigns the specified MIPS IRQ to the specified core. Shared MIPS
-+ * IRQ 0 may be assigned more than once.
-+ */
-+static void
-+BCMINITFN(sb_setirq)(sb_t *sbh, uint irq, uint coreid, uint coreunit)
-+{
-+ void *regs;
-+ sbconfig_t *sb;
-+ uint32 flag;
-+
-+ regs = sb_setcore(sbh, coreid, coreunit);
-+ ASSERT(regs);
-+ flag = sb_flag(sbh);
-+
-+ if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
-+ !(regs = sb_setcore(sbh, SB_MIPS33, 0)))
-+ ASSERT(regs);
-+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
-+
-+ if (irq == 0)
-+ OR_REG(&sb->sbintvec, 1 << flag);
-+ else {
-+ flag <<= sbips_int_shift[irq];
-+ ASSERT(!(flag & ~sbips_int_mask[irq]));
-+ flag |= R_REG(&sb->sbipsflag) & ~sbips_int_mask[irq];
-+ W_REG(&sb->sbipsflag, flag);
-+ }
-+}
-+
-+/*
-+ * Initializes clocks and interrupts. SB and NVRAM access must be
-+ * initialized prior to calling.
-+ */
-+void
-+BCMINITFN(sb_mips_init)(sb_t *sbh)
-+{
-+ ulong hz, ns, tmp;
-+ extifregs_t *eir;
-+ chipcregs_t *cc;
-+ char *value;
-+ uint irq;
-+
-+ /* Figure out current SB clock speed */
-+ if ((hz = sb_clock(sbh)) == 0)
-+ hz = 100000000;
-+ ns = 1000000000 / hz;
-+
-+ /* Setup external interface timing */
-+ if ((eir = sb_setcore(sbh, SB_EXTIF, 0))) {
-+ /* Initialize extif so we can get to the LEDs and external UART */
-+ W_REG(&eir->prog_config, CF_EN);
-+
-+ /* Set timing for the flash */
-+ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
-+ tmp = tmp | (CEIL(40, ns) << FW_W1_SHIFT); /* W1 = 40nS */
-+ tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
-+ W_REG(&eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
-+
-+ /* Set programmable interface timing for external uart */
-+ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
-+ tmp = tmp | (CEIL(20, ns) << FW_W2_SHIFT); /* W2 = 20nS */
-+ tmp = tmp | (CEIL(100, ns) << FW_W1_SHIFT); /* W1 = 100nS */
-+ tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
-+ W_REG(&eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
-+ } else if ((cc = sb_setcore(sbh, SB_CC, 0))) {
-+ /* Set timing for the flash */
-+ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
-+ tmp |= CEIL(10, ns) << FW_W1_SHIFT; /* W1 = 10nS */
-+ tmp |= CEIL(120, ns); /* W0 = 120nS */
-+
-+ // Added by Chen-I for 5365
-+ if (BCMINIT(sb_chip)(sbh) == BCM5365_DEVICE_ID)
-+ {
-+ W_REG(&cc->flash_waitcount, tmp);
-+ W_REG(&cc->pcmcia_memwait, tmp);
-+ }
-+ else
-+ {
-+ if (sb_corerev(sbh) < 9)
-+ W_REG(&cc->flash_waitcount, tmp);
-+
-+ if ((sb_corerev(sbh) < 9) ||
-+ ((BCMINIT(sb_chip)(sbh) == BCM5350_DEVICE_ID) && BCMINIT(sb_chiprev)(sbh) == 0)) {
-+ W_REG(&cc->pcmcia_memwait, tmp);
-+ }
-+ }
-+ }
-+
-+ /* Chip specific initialization */
-+ switch (BCMINIT(sb_chip)(sbh)) {
-+ case BCM4710_DEVICE_ID:
-+ /* Clear interrupt map */
-+ for (irq = 0; irq <= 4; irq++)
-+ BCMINIT(sb_clearirq)(sbh, irq);
-+ BCMINIT(sb_setirq)(sbh, 0, SB_CODEC, 0);
-+ BCMINIT(sb_setirq)(sbh, 0, SB_EXTIF, 0);
-+ BCMINIT(sb_setirq)(sbh, 2, SB_ENET, 1);
-+ BCMINIT(sb_setirq)(sbh, 3, SB_ILINE20, 0);
-+ BCMINIT(sb_setirq)(sbh, 4, SB_PCI, 0);
-+ ASSERT(eir);
-+ value = BCMINIT(nvram_get)("et0phyaddr");
-+ if (value && !strcmp(value, "31")) {
-+ /* Enable internal UART */
-+ W_REG(&eir->corecontrol, CC_UE);
-+ /* Give USB its own interrupt */
-+ BCMINIT(sb_setirq)(sbh, 1, SB_USB, 0);
-+ } else {
-+ /* Disable internal UART */
-+ W_REG(&eir->corecontrol, 0);
-+ /* Give Ethernet its own interrupt */
-+ BCMINIT(sb_setirq)(sbh, 1, SB_ENET, 0);
-+ BCMINIT(sb_setirq)(sbh, 0, SB_USB, 0);
-+ }
-+ break;
-+ case BCM5350_DEVICE_ID:
-+ /* Clear interrupt map */
-+ for (irq = 0; irq <= 4; irq++)
-+ BCMINIT(sb_clearirq)(sbh, irq);
-+ BCMINIT(sb_setirq)(sbh, 0, SB_CC, 0);
-+ BCMINIT(sb_setirq)(sbh, 1, SB_D11, 0);
-+ BCMINIT(sb_setirq)(sbh, 2, SB_ENET, 0);
-+ BCMINIT(sb_setirq)(sbh, 3, SB_PCI, 0);
-+ BCMINIT(sb_setirq)(sbh, 4, SB_USB, 0);
-+ break;
-+ }
-+}
-+
-+uint32
-+BCMINITFN(sb_mips_clock)(sb_t *sbh)
-+{
-+ extifregs_t *eir;
-+ chipcregs_t *cc;
-+ uint32 n, m;
-+ uint idx;
-+ uint32 pll_type, rate = 0;
-+
-+ /* get index of the current core */
-+ idx = sb_coreidx(sbh);
-+ pll_type = PLL_TYPE1;
-+
-+ /* switch to extif or chipc core */
-+ if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
-+ n = R_REG(&eir->clockcontrol_n);
-+ m = R_REG(&eir->clockcontrol_sb);
-+ } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
-+ pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK;
-+ n = R_REG(&cc->clockcontrol_n);
-+ if ((pll_type == PLL_TYPE2) ||
-+ (pll_type == PLL_TYPE4) ||
-+ (pll_type == PLL_TYPE6) ||
-+ (pll_type == PLL_TYPE7))
-+ m = R_REG(&cc->clockcontrol_mips);
-+ else if (pll_type == PLL_TYPE5) {
-+ rate = 200000000;
-+ goto out;
-+ }
-+ else if (pll_type == PLL_TYPE3) {
-+ if (BCMINIT(sb_chip)(sbh) == BCM5365_DEVICE_ID) { /* 5365 is also type3 */
-+ rate = 200000000;
-+ goto out;
-+ } else
-+ m = R_REG(&cc->clockcontrol_m2); /* 5350 uses m2 to control mips */
-+ } else
-+ m = R_REG(&cc->clockcontrol_sb);
-+ } else
-+ goto out;
-+
-+ // Added by Chen-I for 5365
-+ if (BCMINIT(sb_chip)(sbh) == BCM5365_DEVICE_ID)
-+ rate = 100000000;
-+ else
-+ /* calculate rate */
-+ rate = sb_clock_rate(pll_type, n, m);
-+
-+ if (pll_type == PLL_TYPE6)
-+ rate = SB2MIPS_T6(rate);
-+
-+out:
-+ /* switch back to previous core */
-+ sb_setcoreidx(sbh, idx);
-+
-+ return rate;
-+}
-+
-+#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
-+
-+static void
-+BCMINITFN(handler)(void)
-+{
-+ /* Step 11 */
-+ __asm__ (
-+ ".set\tmips32\n\t"
-+ "ssnop\n\t"
-+ "ssnop\n\t"
-+ /* Disable interrupts */
-+ /* MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~(ALLINTS | STO_IE)); */
-+ "mfc0 $15, $12\n\t"
-+ /* Just a Hack to not to use reg 'at' which was causing problems on 4704 A2 */
-+ "li $14, -31746\n\t"
-+ "and $15, $15, $14\n\t"
-+ "mtc0 $15, $12\n\t"
-+ "eret\n\t"
-+ "nop\n\t"
-+ "nop\n\t"
-+ ".set\tmips0"
-+ );
-+}
-+
-+/* The following MUST come right after handler() */
-+static void
-+BCMINITFN(afterhandler)(void)
-+{
-+}
-+
-+/*
-+ * Set the MIPS, backplane and PCI clocks as closely as possible.
-+ */
-+bool
-+BCMINITFN(sb_mips_setclock)(sb_t *sbh, uint32 mipsclock, uint32 sbclock, uint32 pciclock)
-+{
-+ extifregs_t *eir = NULL;
-+ chipcregs_t *cc = NULL;
-+ mipsregs_t *mipsr = NULL;
-+ volatile uint32 *clockcontrol_n, *clockcontrol_sb, *clockcontrol_pci, *clockcontrol_m2;
-+ uint32 orig_n, orig_sb, orig_pci, orig_m2, orig_mips, orig_ratio_parm, orig_ratio_cfg;
-+ uint32 pll_type, sync_mode;
-+ uint ic_size, ic_lsize;
-+ uint idx, i;
-+ typedef struct {
-+ uint32 mipsclock;
-+ uint16 n;
-+ uint32 sb;
-+ uint32 pci33;
-+ uint32 pci25;
-+ } n3m_table_t;
-+ static n3m_table_t BCMINITDATA(type1_table)[] = {
-+ { 96000000, 0x0303, 0x04020011, 0x11030011, 0x11050011 }, /* 96.000 32.000 24.000 */
-+ { 100000000, 0x0009, 0x04020011, 0x11030011, 0x11050011 }, /* 100.000 33.333 25.000 */
-+ { 104000000, 0x0802, 0x04020011, 0x11050009, 0x11090009 }, /* 104.000 31.200 24.960 */
-+ { 108000000, 0x0403, 0x04020011, 0x11050009, 0x02000802 }, /* 108.000 32.400 24.923 */
-+ { 112000000, 0x0205, 0x04020011, 0x11030021, 0x02000403 }, /* 112.000 32.000 24.889 */
-+ { 115200000, 0x0303, 0x04020009, 0x11030011, 0x11050011 }, /* 115.200 32.000 24.000 */
-+ { 120000000, 0x0011, 0x04020011, 0x11050011, 0x11090011 }, /* 120.000 30.000 24.000 */
-+ { 124800000, 0x0802, 0x04020009, 0x11050009, 0x11090009 }, /* 124.800 31.200 24.960 */
-+ { 128000000, 0x0305, 0x04020011, 0x11050011, 0x02000305 }, /* 128.000 32.000 24.000 */
-+ { 132000000, 0x0603, 0x04020011, 0x11050011, 0x02000305 }, /* 132.000 33.000 24.750 */
-+ { 136000000, 0x0c02, 0x04020011, 0x11090009, 0x02000603 }, /* 136.000 32.640 24.727 */
-+ { 140000000, 0x0021, 0x04020011, 0x11050021, 0x02000c02 }, /* 140.000 30.000 24.706 */
-+ { 144000000, 0x0405, 0x04020011, 0x01020202, 0x11090021 }, /* 144.000 30.857 24.686 */
-+ { 150857142, 0x0605, 0x04020021, 0x02000305, 0x02000605 }, /* 150.857 33.000 24.000 */
-+ { 152000000, 0x0e02, 0x04020011, 0x11050021, 0x02000e02 }, /* 152.000 32.571 24.000 */
-+ { 156000000, 0x0802, 0x04020005, 0x11050009, 0x11090009 }, /* 156.000 31.200 24.960 */
-+ { 160000000, 0x0309, 0x04020011, 0x11090011, 0x02000309 }, /* 160.000 32.000 24.000 */
-+ { 163200000, 0x0c02, 0x04020009, 0x11090009, 0x02000603 }, /* 163.200 32.640 24.727 */
-+ { 168000000, 0x0205, 0x04020005, 0x11030021, 0x02000403 }, /* 168.000 32.000 24.889 */
-+ { 176000000, 0x0602, 0x04020003, 0x11050005, 0x02000602 }, /* 176.000 33.000 24.000 */
-+ };
-+ typedef struct {
-+ uint32 mipsclock;
-+ uint16 n;
-+ uint32 m2; /* that is the clockcontrol_m2 */
-+ } type3_table_t;
-+ static type3_table_t type3_table[] = { /* for 5350, mips clock is always double sb clock */
-+ { 150000000, 0x311, 0x4020005 },
-+ { 200000000, 0x311, 0x4020003 },
-+ };
-+ typedef struct {
-+ uint32 mipsclock;
-+ uint32 sbclock;
-+ uint16 n;
-+ uint32 sb;
-+ uint32 pci33;
-+ uint32 m2;
-+ uint32 m3;
-+ uint32 ratio_cfg;
-+ uint32 ratio_parm;
-+ } n4m_table_t;
-+
-+ static n4m_table_t BCMINITDATA(type2_table)[] = {
-+ { 180000000, 80000000, 0x0403, 0x01010000, 0x01020300, 0x01020600, 0x05000100, 8, 0x012a00a9 },
-+ { 180000000, 90000000, 0x0403, 0x01000100, 0x01020300, 0x01000100, 0x05000100, 11, 0x0aaa0555 },
-+ { 200000000, 100000000, 0x0303, 0x02010000, 0x02040001, 0x02010000, 0x06000001, 11, 0x0aaa0555 },
-+ { 211200000, 105600000, 0x0902, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 11, 0x0aaa0555 },
-+ { 220800000, 110400000, 0x1500, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 11, 0x0aaa0555 },
-+ { 230400000, 115200000, 0x0604, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 11, 0x0aaa0555 },
-+ { 234000000, 104000000, 0x0b01, 0x01010000, 0x01010700, 0x01020600, 0x05000100, 8, 0x012a00a9 },
-+ { 240000000, 120000000, 0x0803, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 11, 0x0aaa0555 },
-+ { 252000000, 126000000, 0x0504, 0x01000100, 0x01020500, 0x01000100, 0x05000100, 11, 0x0aaa0555 },
-+ { 264000000, 132000000, 0x0903, 0x01000200, 0x01020700, 0x01000200, 0x05000200, 11, 0x0aaa0555 },
-+ { 270000000, 120000000, 0x0703, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 8, 0x012a00a9 },
-+ { 276000000, 122666666, 0x1500, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 8, 0x012a00a9 },
-+ { 280000000, 140000000, 0x0503, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 11, 0x0aaa0555 },
-+ { 288000000, 128000000, 0x0604, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 8, 0x012a00a9 },
-+ { 288000000, 144000000, 0x0404, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 11, 0x0aaa0555 },
-+ { 300000000, 133333333, 0x0803, 0x01010000, 0x01020600, 0x01020600, 0x05000100, 8, 0x012a00a9 },
-+ { 300000000, 150000000, 0x0803, 0x01000100, 0x01020600, 0x01000100, 0x05000100, 11, 0x0aaa0555 }
-+ };
-+
-+ static n4m_table_t BCMINITDATA(type4_table)[] = {
-+ { 192000000, 96000000, 0x0702, 0x04000011, 0x11030011, 0x04000011, 0x04000003, 11, 0x0aaa0555 },
-+ { 198000000, 99000000, 0x0603, 0x11020005, 0x11030011, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
-+ { 200000000, 100000000, 0x0009, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 11, 0x0aaa0555 },
-+ { 204000000, 102000000, 0x0c02, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
-+ { 208000000, 104000000, 0x0802, 0x11030002, 0x11090005, 0x11030002, 0x04000003, 11, 0x0aaa0555 },
-+ { 210000000, 105000000, 0x0209, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
-+ { 216000000, 108000000, 0x0111, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
-+ { 224000000, 112000000, 0x0205, 0x11030002, 0x02002103, 0x11030002, 0x04000003, 11, 0x0aaa0555 },
-+ { 228000000, 101333333, 0x0e02, 0x11030003, 0x11210005, 0x01030305, 0x04000005, 8, 0x012a00a9 },
-+ { 228000000, 114000000, 0x0e02, 0x11020005, 0x11210005, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
-+ { 240000000, 102857143, 0x0109, 0x04000021, 0x01050203, 0x11030021, 0x04000003, 13, 0x254a14a9 },
-+ { 240000000, 120000000, 0x0109, 0x11030002, 0x01050203, 0x11030002, 0x04000003, 11, 0x0aaa0555 },
-+ { 252000000, 100800000, 0x0203, 0x04000009, 0x11050005, 0x02000209, 0x04000002, 9, 0x02520129 },
-+ { 252000000, 126000000, 0x0203, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 11, 0x0aaa0555 },
-+ { 264000000, 132000000, 0x0602, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 11, 0x0aaa0555 },
-+ { 272000000, 116571428, 0x0c02, 0x04000021, 0x02000909, 0x02000221, 0x04000003, 13, 0x254a14a9 },
-+ { 280000000, 120000000, 0x0209, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 13, 0x254a14a9 },
-+ { 288000000, 123428571, 0x0111, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 13, 0x254a14a9 },
-+ { 300000000, 120000000, 0x0009, 0x04000009, 0x01030203, 0x02000902, 0x04000002, 9, 0x02520129 },
-+ { 300000000, 150000000, 0x0009, 0x04000005, 0x01030203, 0x04000005, 0x04000002, 11, 0x0aaa0555 }
-+ };
-+
-+ static n4m_table_t BCMINITDATA(type7_table)[] = {
-+ { 183333333, 91666666, 0x0605, 0x04000011, 0x11030011, 0x04000011, 0x04000003, 11, 0x0aaa0555 },
-+ { 187500000, 93750000, 0x0a03, 0x04000011, 0x11030011, 0x04000011, 0x04000003, 11, 0x0aaa0555 },
-+ { 196875000, 98437500, 0x1003, 0x11020005, 0x11050011, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
-+ { 200000000, 100000000, 0x0311, 0x04000011, 0x11030011, 0x04000009, 0x04000003, 11, 0x0aaa0555 },
-+ { 200000000, 100000000, 0x0311, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 11, 0x0aaa0555 },
-+ { 206250000, 103125000, 0x1103, 0x11020005, 0x11050011, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
-+ { 212500000, 106250000, 0x0c05, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
-+ { 215625000, 107812500, 0x1203, 0x11090009, 0x11050005, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
-+ { 216666666, 108333333, 0x0805, 0x11020003, 0x11030011, 0x11020003, 0x04000003, 11, 0x0aaa0555 },
-+ { 225000000, 112500000, 0x0d03, 0x11020003, 0x11030011, 0x11020003, 0x04000003, 11, 0x0aaa0555 },
-+ { 233333333, 116666666, 0x0905, 0x11020003, 0x11030011, 0x11020003, 0x04000003, 11, 0x0aaa0555 },
-+ { 237500000, 118750000, 0x0e05, 0x11020005, 0x11210005, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
-+ { 240000000, 120000000, 0x0b11, 0x11020009, 0x11210009, 0x11020009, 0x04000009, 11, 0x0aaa0555 },
-+ { 250000000, 125000000, 0x0f03, 0x11020003, 0x11210003, 0x11020003, 0x04000003, 11, 0x0aaa0555 }
-+ };
-+
-+ ulong start, end, dst;
-+ bool ret = FALSE;
-+
-+ /* get index of the current core */
-+ idx = sb_coreidx(sbh);
-+ clockcontrol_m2 = NULL;
-+
-+ /* switch to extif or chipc core */
-+ if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
-+ pll_type = PLL_TYPE1;
-+ clockcontrol_n = &eir->clockcontrol_n;
-+ clockcontrol_sb = &eir->clockcontrol_sb;
-+ clockcontrol_pci = &eir->clockcontrol_pci;
-+ clockcontrol_m2 = &cc->clockcontrol_m2;
-+ } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
-+ pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK;
-+ if (pll_type == PLL_TYPE6) {
-+ clockcontrol_n = NULL;
-+ clockcontrol_sb = NULL;
-+ clockcontrol_pci = NULL;
-+ } else {
-+ clockcontrol_n = &cc->clockcontrol_n;
-+ clockcontrol_sb = &cc->clockcontrol_sb;
-+ clockcontrol_pci = &cc->clockcontrol_pci;
-+ clockcontrol_m2 = &cc->clockcontrol_m2;
-+ }
-+ } else
-+ goto done;
-+
-+ if (pll_type == PLL_TYPE6) {
-+ /* Silence compilers */
-+ orig_n = orig_sb = orig_pci = 0;
-+ } else {
-+ /* Store the current clock register values */
-+ orig_n = R_REG(clockcontrol_n);
-+ orig_sb = R_REG(clockcontrol_sb);
-+ orig_pci = R_REG(clockcontrol_pci);
-+ }
-+
-+ if (pll_type == PLL_TYPE1) {
-+ /* Keep the current PCI clock if not specified */
-+ if (pciclock == 0) {
-+ pciclock = sb_clock_rate(pll_type, R_REG(clockcontrol_n), R_REG(clockcontrol_pci));
-+ pciclock = (pciclock <= 25000000) ? 25000000 : 33000000;
-+ }
-+
-+ /* Search for the closest MIPS clock less than or equal to a preferred value */
-+ for (i = 0; i < ARRAYSIZE(BCMINIT(type1_table)); i++) {
-+ ASSERT(BCMINIT(type1_table)[i].mipsclock ==
-+ sb_clock_rate(pll_type, BCMINIT(type1_table)[i].n, BCMINIT(type1_table)[i].sb));
-+ if (BCMINIT(type1_table)[i].mipsclock > mipsclock)
-+ break;
-+ }
-+ if (i == 0) {
-+ ret = FALSE;
-+ goto done;
-+ } else {
-+ ret = TRUE;
-+ i--;
-+ }
-+ ASSERT(BCMINIT(type1_table)[i].mipsclock <= mipsclock);
-+
-+ /* No PLL change */
-+ if ((orig_n == BCMINIT(type1_table)[i].n) &&
-+ (orig_sb == BCMINIT(type1_table)[i].sb) &&
-+ (orig_pci == BCMINIT(type1_table)[i].pci33))
-+ goto done;
-+
-+ /* Set the PLL controls */
-+ W_REG(clockcontrol_n, BCMINIT(type1_table)[i].n);
-+ W_REG(clockcontrol_sb, BCMINIT(type1_table)[i].sb);
-+ if (pciclock == 25000000)
-+ W_REG(clockcontrol_pci, BCMINIT(type1_table)[i].pci25);
-+ else
-+ W_REG(clockcontrol_pci, BCMINIT(type1_table)[i].pci33);
-+
-+ /* Reset */
-+ sb_watchdog(sbh, 1);
-+
-+ while (1);
-+ } else if ((pll_type == PLL_TYPE3) &&
-+ (BCMINIT(sb_chip)(sbh) != BCM5365_DEVICE_ID)) {
-+ /* 5350 */
-+ /* Search for the closest MIPS clock less than or equal to a preferred value */
-+
-+ for (i = 0; i < ARRAYSIZE(type3_table); i++) {
-+ if (type3_table[i].mipsclock > mipsclock)
-+ break;
-+ }
-+ if (i == 0) {
-+ ret = FALSE;
-+ goto done;
-+ } else {
-+ ret = TRUE;
-+ i--;
-+ }
-+ ASSERT(type3_table[i].mipsclock <= mipsclock);
-+
-+ /* No PLL change */
-+ orig_m2 = R_REG(&cc->clockcontrol_m2);
-+ if ((orig_n == type3_table[i].n) &&
-+ (orig_m2 == type3_table[i].m2)) {
-+ goto done;
-+ }
-+
-+ /* Set the PLL controls */
-+ W_REG(clockcontrol_n, type3_table[i].n);
-+ W_REG(clockcontrol_m2, type3_table[i].m2);
-+
-+ /* Reset */
-+ sb_watchdog(sbh, 1);
-+ while (1);
-+ } else if ((pll_type == PLL_TYPE2) ||
-+ (pll_type == PLL_TYPE4) ||
-+ (pll_type == PLL_TYPE6) ||
-+ (pll_type == PLL_TYPE7)) {
-+ n4m_table_t *table = NULL, *te;
-+ uint tabsz = 0;
-+
-+ ASSERT(cc);
-+
-+ orig_mips = R_REG(&cc->clockcontrol_mips);
-+
-+ if (pll_type == PLL_TYPE6) {
-+ uint32 new_mips = 0;
-+
-+ ret = TRUE;
-+ if (mipsclock <= SB2MIPS_T6(CC_T6_M1))
-+ new_mips = CC_T6_MMASK;
-+
-+ if (orig_mips == new_mips)
-+ goto done;
-+
-+ W_REG(&cc->clockcontrol_mips, new_mips);
-+ goto end_fill;
-+ }
-+
-+ if (pll_type == PLL_TYPE2) {
-+ table = BCMINIT(type2_table);
-+ tabsz = ARRAYSIZE(BCMINIT(type2_table));
-+ } else if (pll_type == PLL_TYPE4) {
-+ table = BCMINIT(type4_table);
-+ tabsz = ARRAYSIZE(BCMINIT(type4_table));
-+ } else if (pll_type == PLL_TYPE7) {
-+ table = BCMINIT(type7_table);
-+ tabsz = ARRAYSIZE(BCMINIT(type7_table));
-+ } else
-+ ASSERT("No table for plltype" == NULL);
-+
-+ /* Store the current clock register values */
-+ orig_m2 = R_REG(&cc->clockcontrol_m2);
-+ orig_ratio_parm = 0;
-+ orig_ratio_cfg = 0;
-+
-+ /* Look up current ratio */
-+ for (i = 0; i < tabsz; i++) {
-+ if ((orig_n == table[i].n) &&
-+ (orig_sb == table[i].sb) &&
-+ (orig_pci == table[i].pci33) &&
-+ (orig_m2 == table[i].m2) &&
-+ (orig_mips == table[i].m3)) {
-+ orig_ratio_parm = table[i].ratio_parm;
-+ orig_ratio_cfg = table[i].ratio_cfg;
-+ break;
-+ }
-+ }
-+
-+ /* Search for the closest MIPS clock greater or equal to a preferred value */
-+ for (i = 0; i < tabsz; i++) {
-+ ASSERT(table[i].mipsclock ==
-+ sb_clock_rate(pll_type, table[i].n, table[i].m3));
-+ if ((mipsclock <= table[i].mipsclock) &&
-+ ((sbclock == 0) || (sbclock <= table[i].sbclock)))
-+ break;
-+ }
-+ if (i == tabsz) {
-+ ret = FALSE;
-+ goto done;
-+ } else {
-+ te = &table[i];
-+ ret = TRUE;
-+ }
-+
-+ /* No PLL change */
-+ if ((orig_n == te->n) &&
-+ (orig_sb == te->sb) &&
-+ (orig_pci == te->pci33) &&
-+ (orig_m2 == te->m2) &&
-+ (orig_mips == te->m3))
-+ goto done;
-+
-+ /* Set the PLL controls */
-+ W_REG(clockcontrol_n, te->n);
-+ W_REG(clockcontrol_sb, te->sb);
-+ W_REG(clockcontrol_pci, te->pci33);
-+ W_REG(&cc->clockcontrol_m2, te->m2);
-+ W_REG(&cc->clockcontrol_mips, te->m3);
-+
-+ /* Set the chipcontrol bit to change mipsref to the backplane divider if needed */
-+ if ((pll_type == PLL_TYPE7) &&
-+ (te->sb != te->m2) &&
-+ (sb_clock_rate(pll_type, te->n, te->m2) == 120000000))
-+ W_REG(&cc->chipcontrol, R_REG(&cc->chipcontrol) | 0x100);
-+
-+ /* No ratio change */
-+ if (orig_ratio_parm == te->ratio_parm)
-+ goto end_fill;
-+
-+ icache_probe(MFC0(C0_CONFIG, 1), &ic_size, &ic_lsize);
-+
-+ /* Preload the code into the cache */
-+ start = ((ulong) &&start_fill) & ~(ic_lsize - 1);
-+ end = ((ulong) &&end_fill + (ic_lsize - 1)) & ~(ic_lsize - 1);
-+ while (start < end) {
-+ cache_op(start, Fill_I);
-+ start += ic_lsize;
-+ }
-+
-+ /* Copy the handler */
-+ start = (ulong) &BCMINIT(handler);
-+ end = (ulong) &BCMINIT(afterhandler);
-+ dst = KSEG1ADDR(0x180);
-+ for (i = 0; i < (end - start); i += 4)
-+ *((ulong *)(dst + i)) = *((ulong *)(start + i));
-+
-+ /* Preload handler into the cache one line at a time */
-+ for (i = 0; i < (end - start); i += 4)
-+ cache_op(dst + i, Fill_I);
-+
-+ /* Clear BEV bit */
-+ MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~ST0_BEV);
-+
-+ /* Enable interrupts */
-+ MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) | (ALLINTS | ST0_IE));
-+
-+ /* Enable MIPS timer interrupt */
-+ if (!(mipsr = sb_setcore(sbh, SB_MIPS, 0)) &&
-+ !(mipsr = sb_setcore(sbh, SB_MIPS33, 0)))
-+ ASSERT(mipsr);
-+ W_REG(&mipsr->intmask, 1);
-+
-+ start_fill:
-+ /* step 1, set clock ratios */
-+ MTC0(C0_BROADCOM, 3, te->ratio_parm);
-+ MTC0(C0_BROADCOM, 1, te->ratio_cfg);
-+
-+ /* step 2: program timer intr */
-+ W_REG(&mipsr->timer, 100);
-+ (void) R_REG(&mipsr->timer);
-+
-+ /* step 3, switch to async */
-+ sync_mode = MFC0(C0_BROADCOM, 4);
-+ MTC0(C0_BROADCOM, 4, 1 << 22);
-+
-+ /* step 4, set cfg active */
-+ MTC0(C0_BROADCOM, 2, 0x9);
-+
-+
-+ /* steps 5 & 6 */
-+ __asm__ __volatile__ (
-+ ".set\tmips3\n\t"
-+ "wait\n\t"
-+ ".set\tmips0"
-+ );
-+
-+ /* step 7, clear cfg_active */
-+ MTC0(C0_BROADCOM, 2, 0);
-+
-+ /* Additional Step: set back to orig sync mode */
-+ MTC0(C0_BROADCOM, 4, sync_mode);
-+
-+ /* step 8, fake soft reset */
-+ MTC0(C0_BROADCOM, 5, MFC0(C0_BROADCOM, 5) | 4);
-+
-+ end_fill:
-+ /* step 9 set watchdog timer */
-+ sb_watchdog(sbh, 20);
-+ (void) R_REG(&cc->chipid);
-+
-+ /* step 11 */
-+ __asm__ __volatile__ (
-+ ".set\tmips3\n\t"
-+ "sync\n\t"
-+ "wait\n\t"
-+ ".set\tmips0"
-+ );
-+ while (1);
-+ }
-+
-+done:
-+ /* switch back to previous core */
-+ sb_setcoreidx(sbh, idx);
-+
-+ return ret;
-+}
-+
-+/*
-+ * This also must be run from the cache on 47xx
-+ * so there are no mips core BIU ops in progress
-+ * when the PFC is enabled.
-+ */
-+
-+static void
-+BCMINITFN(_enable_pfc)(uint32 mode)
-+{
-+ /* write range */
-+ *(volatile uint32 *)PFC_CR1 = 0xffff0000;
-+
-+ /* enable */
-+ *(volatile uint32 *)PFC_CR0 = mode;
-+}
-+
-+void
-+BCMINITFN(enable_pfc)(uint32 mode)
-+{
-+ ulong start, end;
-+ int i;
-+
-+ /* If auto then choose the correct mode for this
-+ platform, currently we only ever select one mode */
-+ if (mode == PFC_AUTO)
-+ mode = PFC_INST;
-+
-+ /* enable prefetch cache if available */
-+ if (MFC0(C0_BROADCOM, 0) & BRCM_PFC_AVAIL) {
-+ start = (ulong) &BCMINIT(_enable_pfc);
-+ end = (ulong) &BCMINIT(enable_pfc);
-+
-+ /* Preload handler into the cache one line at a time */
-+ for (i = 0; i < (end - start); i += 4)
-+ cache_op(start + i, Fill_I);
-+
-+ BCMINIT(_enable_pfc)(mode);
-+ }
-+}
-+
-+/* returns the ncdl value to be programmed into sdram_ncdl for calibration */
-+uint32
-+BCMINITFN(sb_memc_get_ncdl)(sb_t *sbh)
-+{
-+ sbmemcregs_t *memc;
-+ uint32 ret = 0;
-+ uint32 config, rd, wr, misc, dqsg, cd, sm, sd;
-+ uint idx, rev;
-+
-+ idx = sb_coreidx(sbh);
-+
-+ memc = (sbmemcregs_t *)sb_setcore(sbh, SB_MEMC, 0);
-+ if (memc == 0)
-+ goto out;
-+
-+ rev = sb_corerev(sbh);
-+
-+ config = R_REG(&memc->config);
-+ wr = R_REG(&memc->wrncdlcor);
-+ rd = R_REG(&memc->rdncdlcor);
-+ misc = R_REG(&memc->miscdlyctl);
-+ dqsg = R_REG(&memc->dqsgatencdl);
-+
-+ rd &= MEMC_RDNCDLCOR_RD_MASK;
-+ wr &= MEMC_WRNCDLCOR_WR_MASK;
-+ dqsg &= MEMC_DQSGATENCDL_G_MASK;
-+
-+ if (config & MEMC_CONFIG_DDR) {
-+ ret = (wr << 16) | (rd << 8) | dqsg;
-+ } else {
-+ if (rev > 0)
-+ cd = rd;
-+ else
-+ cd = (rd == MEMC_CD_THRESHOLD) ? rd : (wr + MEMC_CD_THRESHOLD);
-+ sm = (misc & MEMC_MISC_SM_MASK) >> MEMC_MISC_SM_SHIFT;
-+ sd = (misc & MEMC_MISC_SD_MASK) >> MEMC_MISC_SD_SHIFT;
-+ ret = (sm << 16) | (sd << 8) | cd;
-+ }
-+
-+out:
-+ /* switch back to previous core */
-+ sb_setcoreidx(sbh, idx);
-+
-+ return ret;
-+}
-+
-diff -Naur linux.old/arch/mips/bcm947xx/sbpci.c linux.dev/arch/mips/bcm947xx/sbpci.c
---- linux.old/arch/mips/bcm947xx/sbpci.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/arch/mips/bcm947xx/sbpci.c 2006-04-06 15:34:14.000000000 +0200
-@@ -0,0 +1,588 @@
-+/*
-+ * Low-Level PCI and SB support for BCM47xx
-+ *
-+ * Copyright 2005, Broadcom Corporation
-+ * All Rights Reserved.
-+ *
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-+ *
-+ * $Id$
-+ */
-+
-+#include <typedefs.h>
-+#include <pcicfg.h>
-+#include <bcmdevs.h>
-+#include <sbconfig.h>
-+#include <osl.h>
-+#include <sbutils.h>
-+#include <sbpci.h>
-+#include <bcmendian.h>
-+#include <bcmutils.h>
-+#include <bcmnvram.h>
-+#include <hndmips.h>
-+
-+/* Can free sbpci_init() memory after boot */
-+#ifndef linux
-+#define __init
-+#endif
-+
-+/* Emulated configuration space */
-+static pci_config_regs sb_config_regs[SB_MAXCORES];
-+
-+/* Banned cores */
-+static uint16 pci_ban[32] = { 0 };
-+static uint pci_banned = 0;
-+
-+/* CardBus mode */
-+static bool cardbus = FALSE;
-+
-+/* Disable PCI host core */
-+static bool pci_disabled = FALSE;
-+
-+/*
-+ * Functions for accessing external PCI configuration space
-+ */
-+
-+/* Assume one-hot slot wiring */
-+#define PCI_SLOT_MAX 16
-+
-+static uint32
-+config_cmd(sb_t *sbh, uint bus, uint dev, uint func, uint off)
-+{
-+ uint coreidx;
-+ sbpciregs_t *regs;
-+ uint32 addr = 0;
-+
-+ /* CardBusMode supports only one device */
-+ if (cardbus && dev > 1)
-+ return 0;
-+
-+ coreidx = sb_coreidx(sbh);
-+ regs = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0);
-+
-+ /* Type 0 transaction */
-+ if (bus == 1) {
-+ /* Skip unwired slots */
-+ if (dev < PCI_SLOT_MAX) {
-+ /* Slide the PCI window to the appropriate slot */
-+ W_REG(®s->sbtopci1, SBTOPCI_CFG0 | ((1 << (dev + 16)) & SBTOPCI1_MASK));
-+ addr = SB_PCI_CFG | ((1 << (dev + 16)) & ~SBTOPCI1_MASK) |
-+ (func << 8) | (off & ~3);
-+ }
-+ }
-+
-+ /* Type 1 transaction */
-+ else {
-+ W_REG(®s->sbtopci1, SBTOPCI_CFG1);
-+ addr = SB_PCI_CFG | (bus << 16) | (dev << 11) | (func << 8) | (off & ~3);
-+ }
-+
-+ sb_setcoreidx(sbh, coreidx);
-+
-+ return addr;
-+}
-+
-+static int
-+extpci_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
-+{
-+ uint32 addr, *reg = NULL, val;
-+ int ret = 0;
-+
-+ if (pci_disabled ||
-+ !(addr = config_cmd(sbh, bus, dev, func, off)) ||
-+ !(reg = (uint32 *) REG_MAP(addr, len)) ||
-+ BUSPROBE(val, reg))
-+ val = 0xffffffff;
-+
-+ val >>= 8 * (off & 3);
-+ if (len == 4)
-+ *((uint32 *) buf) = val;
-+ else if (len == 2)
-+ *((uint16 *) buf) = (uint16) val;
-+ else if (len == 1)
-+ *((uint8 *) buf) = (uint8) val;
-+ else
-+ ret = -1;
-+
-+ if (reg)
-+ REG_UNMAP(reg);
-+
-+ return ret;
-+}
-+
-+static int
-+extpci_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
-+{
-+ uint32 addr, *reg = NULL, val;
-+ int ret = 0;
-+
-+ if (pci_disabled ||
-+ !(addr = config_cmd(sbh, bus, dev, func, off)) ||
-+ !(reg = (uint32 *) REG_MAP(addr, len)) ||
-+ BUSPROBE(val, reg))
-+ goto done;
-+
-+ if (len == 4)
-+ val = *((uint32 *) buf);
-+ else if (len == 2) {
-+ val &= ~(0xffff << (8 * (off & 3)));
-+ val |= *((uint16 *) buf) << (8 * (off & 3));
-+ } else if (len == 1) {
-+ val &= ~(0xff << (8 * (off & 3)));
-+ val |= *((uint8 *) buf) << (8 * (off & 3));
-+ } else
-+ ret = -1;
-+
-+ W_REG(reg, val);
-+
-+ done:
-+ if (reg)
-+ REG_UNMAP(reg);
-+
-+ return ret;
-+}
-+
-+/*
-+ * Functions for accessing translated SB configuration space
-+ */
-+
-+static int
-+sb_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
-+{
-+ pci_config_regs *cfg;
-+
-+ if (dev >= SB_MAXCORES || (off + len) > sizeof(pci_config_regs))
-+ return -1;
-+ cfg = &sb_config_regs[dev];
-+
-+ ASSERT(ISALIGNED(off, len));
-+ ASSERT(ISALIGNED((uintptr)buf, len));
-+
-+ if (len == 4)
-+ *((uint32 *) buf) = ltoh32(*((uint32 *)((ulong) cfg + off)));
-+ else if (len == 2)
-+ *((uint16 *) buf) = ltoh16(*((uint16 *)((ulong) cfg + off)));
-+ else if (len == 1)
-+ *((uint8 *) buf) = *((uint8 *)((ulong) cfg + off));
-+ else
-+ return -1;
-+
-+ return 0;
-+}
-+
-+static int
-+sb_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
-+{
-+ uint coreidx, n;
-+ void *regs;
-+ sbconfig_t *sb;
-+ pci_config_regs *cfg;
-+
-+ if (dev >= SB_MAXCORES || (off + len) > sizeof(pci_config_regs))
-+ return -1;
-+ cfg = &sb_config_regs[dev];
-+
-+ ASSERT(ISALIGNED(off, len));
-+ ASSERT(ISALIGNED((uintptr)buf, len));
-+
-+ /* Emulate BAR sizing */
-+ if (off >= OFFSETOF(pci_config_regs, base[0]) && off <= OFFSETOF(pci_config_regs, base[3]) &&
-+ len == 4 && *((uint32 *) buf) == ~0) {
-+ coreidx = sb_coreidx(sbh);
-+ if ((regs = sb_setcoreidx(sbh, dev))) {
-+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
-+ /* Highest numbered address match register */
-+ n = (R_REG(&sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT;
-+ if (off == OFFSETOF(pci_config_regs, base[0]))
-+ cfg->base[0] = ~(sb_size(R_REG(&sb->sbadmatch0)) - 1);
-+ else if (off == OFFSETOF(pci_config_regs, base[1]) && n >= 1)
-+ cfg->base[1] = ~(sb_size(R_REG(&sb->sbadmatch1)) - 1);
-+ else if (off == OFFSETOF(pci_config_regs, base[2]) && n >= 2)
-+ cfg->base[2] = ~(sb_size(R_REG(&sb->sbadmatch2)) - 1);
-+ else if (off == OFFSETOF(pci_config_regs, base[3]) && n >= 3)
-+ cfg->base[3] = ~(sb_size(R_REG(&sb->sbadmatch3)) - 1);
-+ }
-+ sb_setcoreidx(sbh, coreidx);
-+ return 0;
-+ }
-+
-+ if (len == 4)
-+ *((uint32 *)((ulong) cfg + off)) = htol32(*((uint32 *) buf));
-+ else if (len == 2)
-+ *((uint16 *)((ulong) cfg + off)) = htol16(*((uint16 *) buf));
-+ else if (len == 1)
-+ *((uint8 *)((ulong) cfg + off)) = *((uint8 *) buf);
-+ else
-+ return -1;
-+
-+ return 0;
-+}
-+
-+int
-+sbpci_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
-+{
-+ if (bus == 0)
-+ return sb_read_config(sbh, bus, dev, func, off, buf, len);
-+ else
-+ return extpci_read_config(sbh, bus, dev, func, off, buf, len);
-+}
-+
-+int
-+sbpci_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
-+{
-+ if (bus == 0)
-+ return sb_write_config(sbh, bus, dev, func, off, buf, len);
-+ else
-+ return extpci_write_config(sbh, bus, dev, func, off, buf, len);
-+}
-+
-+void
-+sbpci_ban(uint16 core)
-+{
-+ if (pci_banned < ARRAYSIZE(pci_ban))
-+ pci_ban[pci_banned++] = core;
-+}
-+
-+static int
-+sbpci_init_pci(sb_t *sbh)
-+{
-+ uint chip, chiprev, chippkg, host;
-+ uint32 boardflags;
-+ sbpciregs_t *pci;
-+ sbconfig_t *sb;
-+ uint32 val;
-+
-+ chip = sb_chip(sbh);
-+ chiprev = sb_chiprev(sbh);
-+ chippkg = sb_chippkg(sbh);
-+
-+ if (!(pci = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0))) {
-+ printf("PCI: no core\n");
-+ pci_disabled = TRUE;
-+ return -1;
-+ }
-+ sb_core_reset(sbh, 0);
-+
-+ boardflags = (uint32) getintvar(NULL, "boardflags");
-+
-+ if ((chip == BCM4310_DEVICE_ID) && (chiprev == 0))
-+ pci_disabled = TRUE;
-+
-+ /*
-+ * The 200-pin BCM4712 package does not bond out PCI. Even when
-+ * PCI is bonded out, some boards may leave the pins
-+ * floating.
-+ */
-+ if (((chip == BCM4712_DEVICE_ID) &&
-+ ((chippkg == BCM4712SMALL_PKG_ID) ||
-+ (chippkg == BCM4712MID_PKG_ID))) ||
-+ (boardflags & BFL_NOPCI))
-+ pci_disabled = TRUE;
-+
-+ /*
-+ * If the PCI core should not be touched (disabled, not bonded
-+ * out, or pins floating), do not even attempt to access core
-+ * registers. Otherwise, try to determine if it is in host
-+ * mode.
-+ */
-+ if (pci_disabled)
-+ host = 0;
-+ else
-+ host = !BUSPROBE(val, &pci->control);
-+
-+ if (!host) {
-+ /* Disable PCI interrupts in client mode */
-+ sb = (sbconfig_t *)((ulong) pci + SBCONFIGOFF);
-+ W_REG(&sb->sbintvec, 0);
-+
-+ /* Disable the PCI bridge in client mode */
-+ sbpci_ban(SB_PCI);
-+ printf("PCI: Disabled\n");
-+ } else {
-+ /* Reset the external PCI bus and enable the clock */
-+ W_REG(&pci->control, 0x5); /* enable the tristate drivers */
-+ W_REG(&pci->control, 0xd); /* enable the PCI clock */
-+ OSL_DELAY(150); /* delay > 100 us */
-+ W_REG(&pci->control, 0xf); /* deassert PCI reset */
-+ W_REG(&pci->arbcontrol, PCI_INT_ARB); /* use internal arbiter */
-+ OSL_DELAY(1); /* delay 1 us */
-+
-+ /* Enable CardBusMode */
-+ cardbus = nvram_match("cardbus", "1");
-+ if (cardbus) {
-+ printf("PCI: Enabling CardBus\n");
-+ /* GPIO 1 resets the CardBus device on bcm94710ap */
-+ sb_gpioout(sbh, 1, 1, GPIO_DRV_PRIORITY);
-+ sb_gpioouten(sbh, 1, 1, GPIO_DRV_PRIORITY);
-+ W_REG(&pci->sprom[0], R_REG(&pci->sprom[0]) | 0x400);
-+ }
-+
-+ /* 64 MB I/O access window */
-+ W_REG(&pci->sbtopci0, SBTOPCI_IO);
-+ /* 64 MB configuration access window */
-+ W_REG(&pci->sbtopci1, SBTOPCI_CFG0);
-+ /* 1 GB memory access window */
-+ W_REG(&pci->sbtopci2, SBTOPCI_MEM | SB_PCI_DMA);
-+
-+ /* Enable PCI bridge BAR0 prefetch and burst */
-+ val = 6;
-+ sbpci_write_config(sbh, 1, 0, 0, PCI_CFG_CMD, &val, sizeof(val));
-+
-+ /* Enable PCI interrupts */
-+ W_REG(&pci->intmask, PCI_INTA);
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+sbpci_init_cores(sb_t *sbh)
-+{
-+ uint chip, chiprev, chippkg, coreidx, i;
-+ sbconfig_t *sb;
-+ pci_config_regs *cfg;
-+ void *regs;
-+ char varname[8];
-+ uint wlidx = 0;
-+ uint16 vendor, core;
-+ uint8 class, subclass, progif;
-+ uint32 val;
-+ uint32 sbips_int_mask[] = { 0, SBIPS_INT1_MASK, SBIPS_INT2_MASK, SBIPS_INT3_MASK, SBIPS_INT4_MASK };
-+ uint32 sbips_int_shift[] = { 0, 0, SBIPS_INT2_SHIFT, SBIPS_INT3_SHIFT, SBIPS_INT4_SHIFT };
-+
-+ chip = sb_chip(sbh);
-+ chiprev = sb_chiprev(sbh);
-+ chippkg = sb_chippkg(sbh);
-+ coreidx = sb_coreidx(sbh);
-+
-+ /* Scan the SB bus */
-+ bzero(sb_config_regs, sizeof(sb_config_regs));
-+ for (cfg = sb_config_regs; cfg < &sb_config_regs[SB_MAXCORES]; cfg++) {
-+ cfg->vendor = 0xffff;
-+ if (!(regs = sb_setcoreidx(sbh, cfg - sb_config_regs)))
-+ continue;
-+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
-+
-+ /* Read ID register and parse vendor and core */
-+ val = R_REG(&sb->sbidhigh);
-+ vendor = (val & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT;
-+ core = (val & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;
-+ progif = 0;
-+
-+ /* Check if this core is banned */
-+ for (i = 0; i < pci_banned; i++)
-+ if (core == pci_ban[i])
-+ break;
-+ if (i < pci_banned)
-+ continue;
-+
-+ /* Known vendor translations */
-+ switch (vendor) {
-+ case SB_VEND_BCM:
-+ vendor = VENDOR_BROADCOM;
-+ break;
-+ }
-+
-+ /* Determine class based on known core codes */
-+ switch (core) {
-+ case SB_ILINE20:
-+ class = PCI_CLASS_NET;
-+ subclass = PCI_NET_ETHER;
-+ core = BCM47XX_ILINE_ID;
-+ break;
-+ case SB_ILINE100:
-+ class = PCI_CLASS_NET;
-+ subclass = PCI_NET_ETHER;
-+ core = BCM4610_ILINE_ID;
-+ break;
-+ case SB_ENET:
-+ class = PCI_CLASS_NET;
-+ subclass = PCI_NET_ETHER;
-+ core = BCM47XX_ENET_ID;
-+ break;
-+ case SB_SDRAM:
-+ case SB_MEMC:
-+ class = PCI_CLASS_MEMORY;
-+ subclass = PCI_MEMORY_RAM;
-+ break;
-+ case SB_PCI:
-+ class = PCI_CLASS_BRIDGE;
-+ subclass = PCI_BRIDGE_PCI;
-+ break;
-+ case SB_MIPS:
-+ case SB_MIPS33:
-+ class = PCI_CLASS_CPU;
-+ subclass = PCI_CPU_MIPS;
-+ break;
-+ case SB_CODEC:
-+ class = PCI_CLASS_COMM;
-+ subclass = PCI_COMM_MODEM;
-+ core = BCM47XX_V90_ID;
-+ break;
-+ case SB_USB:
-+ class = PCI_CLASS_SERIAL;
-+ subclass = PCI_SERIAL_USB;
-+ progif = 0x10; /* OHCI */
-+ core = BCM47XX_USB_ID;
-+ break;
-+ case SB_USB11H:
-+ class = PCI_CLASS_SERIAL;
-+ subclass = PCI_SERIAL_USB;
-+ progif = 0x10; /* OHCI */
-+ core = BCM47XX_USBH_ID;
-+ break;
-+ case SB_USB11D:
-+ class = PCI_CLASS_SERIAL;
-+ subclass = PCI_SERIAL_USB;
-+ core = BCM47XX_USBD_ID;
-+ break;
-+ case SB_IPSEC:
-+ class = PCI_CLASS_CRYPT;
-+ subclass = PCI_CRYPT_NETWORK;
-+ core = BCM47XX_IPSEC_ID;
-+ break;
-+ case SB_ROBO:
-+ class = PCI_CLASS_NET;
-+ subclass = PCI_NET_OTHER;
-+ core = BCM47XX_ROBO_ID;
-+ break;
-+ case SB_EXTIF:
-+ case SB_CC:
-+ class = PCI_CLASS_MEMORY;
-+ subclass = PCI_MEMORY_FLASH;
-+ break;
-+ case SB_D11:
-+ class = PCI_CLASS_NET;
-+ subclass = PCI_NET_OTHER;
-+ /* Let an nvram variable override this */
-+ sprintf(varname, "wl%did", wlidx);
-+ wlidx++;
-+ if ((core = getintvar(NULL, varname)) == 0) {
-+ if (chip == BCM4712_DEVICE_ID) {
-+ if (chippkg == BCM4712SMALL_PKG_ID)
-+ core = BCM4306_D11G_ID;
-+ else
-+ core = BCM4306_D11DUAL_ID;
-+ } else {
-+ /* 4310 */
-+ core = BCM4310_D11B_ID;
-+ }
-+ }
-+ break;
-+
-+ default:
-+ class = subclass = progif = 0xff;
-+ break;
-+ }
-+
-+ /* Supported translations */
-+ cfg->vendor = htol16(vendor);
-+ cfg->device = htol16(core);
-+ cfg->rev_id = chiprev;
-+ cfg->prog_if = progif;
-+ cfg->sub_class = subclass;
-+ cfg->base_class = class;
-+ cfg->base[0] = htol32(sb_base(R_REG(&sb->sbadmatch0)));
-+ cfg->base[1] = htol32(sb_base(R_REG(&sb->sbadmatch1)));
-+ cfg->base[2] = htol32(sb_base(R_REG(&sb->sbadmatch2)));
-+ cfg->base[3] = htol32(sb_base(R_REG(&sb->sbadmatch3)));
-+ cfg->base[4] = 0;
-+ cfg->base[5] = 0;
-+ if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI)
-+ cfg->header_type = PCI_HEADER_BRIDGE;
-+ else
-+ cfg->header_type = PCI_HEADER_NORMAL;
-+ /* Save core interrupt flag */
-+ cfg->int_pin = R_REG(&sb->sbtpsflag) & SBTPS_NUM0_MASK;
-+ /* Default to MIPS shared interrupt 0 */
-+ cfg->int_line = 0;
-+ /* MIPS sbipsflag maps core interrupt flags to interrupts 1 through 4 */
-+ if ((regs = sb_setcore(sbh, SB_MIPS, 0)) ||
-+ (regs = sb_setcore(sbh, SB_MIPS33, 0))) {
-+ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
-+ val = R_REG(&sb->sbipsflag);
-+ for (cfg->int_line = 1; cfg->int_line <= 4; cfg->int_line++) {
-+ if (((val & sbips_int_mask[cfg->int_line]) >> sbips_int_shift[cfg->int_line]) == cfg->int_pin)
-+ break;
-+ }
-+ if (cfg->int_line > 4)
-+ cfg->int_line = 0;
-+ }
-+ /* Emulated core */
-+ *((uint32 *) &cfg->sprom_control) = 0xffffffff;
-+ }
-+
-+ sb_setcoreidx(sbh, coreidx);
-+ return 0;
-+}
-+
-+int __init
-+sbpci_init(sb_t *sbh)
-+{
-+ sbpci_init_pci(sbh);
-+ sbpci_init_cores(sbh);
-+ return 0;
-+}
-+
-+void
-+sbpci_check(sb_t *sbh)
-+{
-+ uint coreidx;
-+ sbpciregs_t *pci;
-+ uint32 sbtopci1;
-+ uint32 buf[64], *ptr, i;
-+ ulong pa;
-+ volatile uint j;
-+
-+ coreidx = sb_coreidx(sbh);
-+ pci = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0);
-+
-+ /* Clear the test array */
-+ pa = (ulong) DMA_MAP(NULL, buf, sizeof(buf), DMA_RX, NULL);
-+ ptr = (uint32 *) OSL_UNCACHED(&buf[0]);
-+ memset(ptr, 0, sizeof(buf));
-+
-+ /* Point PCI window 1 to memory */
-+ sbtopci1 = R_REG(&pci->sbtopci1);
-+ W_REG(&pci->sbtopci1, SBTOPCI_MEM | (pa & SBTOPCI1_MASK));
-+
-+ /* Fill the test array via PCI window 1 */
-+ ptr = (uint32 *) REG_MAP(SB_PCI_CFG + (pa & ~SBTOPCI1_MASK), sizeof(buf));
-+ for (i = 0; i < ARRAYSIZE(buf); i++) {
-+ for (j = 0; j < 2; j++);
-+ W_REG(&ptr[i], i);
-+ }
-+ REG_UNMAP(ptr);
-+
-+ /* Restore PCI window 1 */
-+ W_REG(&pci->sbtopci1, sbtopci1);
-+
-+ /* Check the test array */
-+ DMA_UNMAP(NULL, pa, sizeof(buf), DMA_RX, NULL);
-+ ptr = (uint32 *) OSL_UNCACHED(&buf[0]);
-+ for (i = 0; i < ARRAYSIZE(buf); i++) {
-+ if (ptr[i] != i)
-+ break;
-+ }
-+
-+ /* Change the clock if the test fails */
-+ if (i < ARRAYSIZE(buf)) {
-+ uint32 req, cur;
-+
-+ cur = sb_clock(sbh);
-+ printf("PCI: Test failed at %d MHz\n", (cur + 500000) / 1000000);
-+ for (req = 104000000; req < 176000000; req += 4000000) {
-+ printf("PCI: Resetting to %d MHz\n", (req + 500000) / 1000000);
-+ /* This will only reset if the clocks are valid and have changed */
-+ sb_mips_setclock(sbh, req, 0, 0);
-+ }
-+ /* Should not reach here */
-+ ASSERT(0);
-+ }
-+
-+ sb_setcoreidx(sbh, coreidx);
-+}
-+
-diff -Naur linux.old/arch/mips/bcm947xx/setup.c linux.dev/arch/mips/bcm947xx/setup.c
---- linux.old/arch/mips/bcm947xx/setup.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/arch/mips/bcm947xx/setup.c 2006-04-06 15:34:14.000000000 +0200
-@@ -0,0 +1,234 @@
-+/*
-+ * Generic setup routines for Broadcom MIPS boards
-+ *
-+ * Copyright (C) 2005 Felix Fietkau <nbd@openwrt.org>
-+ *
-+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
-+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ *
-+ * 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.,
-+ * 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ *
-+ * Copyright 2005, Broadcom Corporation
-+ * All Rights Reserved.
-+ *
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/serialP.h>
-+#include <linux/ide.h>
-+#include <asm/bootinfo.h>
-+#include <asm/cpu.h>
-+#include <asm/time.h>
-+#include <asm/reboot.h>
-+
-+#include <typedefs.h>
-+#include <osl.h>
-+#include <sbutils.h>
-+#include <bcmutils.h>
-+#include <bcmnvram.h>
-+#include <sbmips.h>
-+#include <trxhdr.h>
-+
-+/* Global SB handle */
-+sb_t *bcm947xx_sbh = NULL;
-+spinlock_t bcm947xx_sbh_lock = SPIN_LOCK_UNLOCKED;
-+
-+/* Convenience */
-+#define sbh bcm947xx_sbh
-+#define sbh_lock bcm947xx_sbh_lock
-+
-+extern void bcm947xx_time_init(void);
-+extern void bcm947xx_timer_setup(struct irqaction *irq);
-+
-+#ifdef CONFIG_REMOTE_DEBUG
-+extern void set_debug_traps(void);
-+extern void rs_kgdb_hook(struct serial_state *);
-+extern void breakpoint(void);
-+#endif
-+
-+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-+extern struct ide_ops std_ide_ops;
-+#endif
-+
-+/* Kernel command line */
-+char arcs_cmdline[CL_SIZE] __initdata = CONFIG_CMDLINE;
-+
-+void
-+bcm947xx_machine_restart(char *command)
-+{
-+ printk("Please stand by while rebooting the system...\n");
-+
-+ /* Set the watchdog timer to reset immediately */
-+ __cli();
-+ sb_watchdog(sbh, 1);
-+ while (1);
-+}
-+
-+void
-+bcm947xx_machine_halt(void)
-+{
-+ printk("System halted\n");
-+
-+ /* Disable interrupts and watchdog and spin forever */
-+ __cli();
-+ sb_watchdog(sbh, 0);
-+ while (1);
-+}
-+
-+#ifdef CONFIG_SERIAL
-+
-+static int ser_line = 0;
-+
-+typedef struct {
-+ void *regs;
-+ uint irq;
-+ uint baud_base;
-+ uint reg_shift;
-+} serial_port;
-+
-+static serial_port ports[4];
-+static int num_ports = 0;
-+
-+static void
-+serial_add(void *regs, uint irq, uint baud_base, uint reg_shift)
-+{
-+ ports[num_ports].regs = regs;
-+ ports[num_ports].irq = irq;
-+ ports[num_ports].baud_base = baud_base;
-+ ports[num_ports].reg_shift = reg_shift;
-+ num_ports++;
-+}
-+
-+static void
-+do_serial_add(serial_port *port)
-+{
-+ void *regs;
-+ uint irq;
-+ uint baud_base;
-+ uint reg_shift;
-+ struct serial_struct s;
-+
-+ regs = port->regs;
-+ irq = port->irq;
-+ baud_base = port->baud_base;
-+ reg_shift = port->reg_shift;
-+
-+ memset(&s, 0, sizeof(s));
-+
-+ s.line = ser_line++;
-+ s.iomem_base = regs;
-+ s.irq = irq + 2;
-+ s.baud_base = baud_base / 16;
-+ s.flags = ASYNC_BOOT_AUTOCONF;
-+ s.io_type = SERIAL_IO_MEM;
-+ s.iomem_reg_shift = reg_shift;
-+
-+ if (early_serial_setup(&s) != 0) {
-+ printk(KERN_ERR "Serial setup failed!\n");
-+ }
-+}
-+
-+#endif /* CONFIG_SERIAL */
-+
-+void __init
-+brcm_setup(void)
-+{
-+ char *s;
-+ int i;
-+ char *value;
-+
-+ /* Get global SB handle */
-+ sbh = sb_kattach();
-+
-+ /* Initialize clocks and interrupts */
-+ sb_mips_init(sbh);
-+
-+ if (BCM330X(current_cpu_data.processor_id) &&
-+ (read_c0_diag() & BRCM_PFC_AVAIL)) {
-+ /*
-+ * Now that the sbh is inited set the proper PFC value
-+ */
-+ printk("Setting the PFC to its default value\n");
-+ enable_pfc(PFC_AUTO);
-+ }
-+
-+
-+#ifdef CONFIG_SERIAL
-+ sb_serial_init(sbh, serial_add);
-+
-+ /* reverse serial ports if nvram variable starts with console=ttyS1 */
-+ /* Initialize UARTs */
-+ s = nvram_get("kernel_args");
-+ if (!s) s = "";
-+ if (!strncmp(s, "console=ttyS1", 13)) {
-+ for (i = num_ports; i; i--)
-+ do_serial_add(&ports[i - 1]);
-+ } else {
-+ for (i = 0; i < num_ports; i++)
-+ do_serial_add(&ports[i]);
-+ }
-+#endif
-+
-+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-+ ide_ops = &std_ide_ops;
-+#endif
-+
-+ /* Override default command line arguments */
-+ value = nvram_get("kernel_cmdline");
-+ if (value && strlen(value) && strncmp(value, "empty", 5))
-+ strncpy(arcs_cmdline, value, sizeof(arcs_cmdline));
-+
-+
-+ /* Generic setup */
-+ _machine_restart = bcm947xx_machine_restart;
-+ _machine_halt = bcm947xx_machine_halt;
-+ _machine_power_off = bcm947xx_machine_halt;
-+
-+ board_time_init = bcm947xx_time_init;
-+ board_timer_setup = bcm947xx_timer_setup;
-+}
-+
-+const char *
-+get_system_type(void)
-+{
-+ static char s[32];
-+
-+ if (bcm947xx_sbh) {
-+ sprintf(s, "Broadcom BCM%X chip rev %d", sb_chip(bcm947xx_sbh),
-+ sb_chiprev(bcm947xx_sbh));
-+ return s;
-+ }
-+ else
-+ return "Broadcom BCM947XX";
-+}
-+
-+void __init
-+bus_error_init(void)
-+{
-+}
-+
-+EXPORT_SYMBOL(bcm947xx_sbh);
-diff -Naur linux.old/arch/mips/bcm947xx/sflash.c linux.dev/arch/mips/bcm947xx/sflash.c
---- linux.old/arch/mips/bcm947xx/sflash.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/arch/mips/bcm947xx/sflash.c 2006-04-06 15:34:14.000000000 +0200
-@@ -0,0 +1,418 @@
-+/*
-+ * Broadcom SiliconBackplane chipcommon serial flash interface
-+ *
-+ * Copyright 2005, Broadcom Corporation
-+ * All Rights Reserved.
-+ *
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-+ *
-+ * $Id$
-+ */
-+
-+#include <osl.h>
-+#include <typedefs.h>
-+#include <sbconfig.h>
-+#include <sbchipc.h>
-+#include <mipsinc.h>
-+#include <bcmutils.h>
-+#include <bcmdevs.h>
-+#include <sflash.h>
-+
-+/* Private global state */
-+static struct sflash sflash;
-+
-+/* Issue a serial flash command */
-+static INLINE void
-+sflash_cmd(chipcregs_t *cc, uint opcode)
-+{
-+ W_REG(&cc->flashcontrol, SFLASH_START | opcode);
-+ while (R_REG(&cc->flashcontrol) & SFLASH_BUSY);
-+}
-+
-+/* Initialize serial flash access */
-+struct sflash *
-+sflash_init(chipcregs_t *cc)
-+{
-+ uint32 id, id2;
-+
-+ bzero(&sflash, sizeof(sflash));
-+
-+ sflash.type = R_REG(&cc->capabilities) & CAP_FLASH_MASK;
-+
-+ switch (sflash.type) {
-+ case SFLASH_ST:
-+ /* Probe for ST chips */
-+ sflash_cmd(cc, SFLASH_ST_DP);
-+ sflash_cmd(cc, SFLASH_ST_RES);
-+ id = R_REG(&cc->flashdata);
-+ switch (id) {
-+ case 0x11:
-+ /* ST M25P20 2 Mbit Serial Flash */
-+ sflash.blocksize = 64 * 1024;
-+ sflash.numblocks = 4;
-+ break;
-+ case 0x12:
-+ /* ST M25P40 4 Mbit Serial Flash */
-+ sflash.blocksize = 64 * 1024;
-+ sflash.numblocks = 8;
-+ break;
-+ case 0x13:
-+ /* ST M25P80 8 Mbit Serial Flash */
-+ sflash.blocksize = 64 * 1024;
-+ sflash.numblocks = 16;
-+ break;
-+ case 0x14:
-+ /* ST M25P16 16 Mbit Serial Flash */
-+ sflash.blocksize = 64 * 1024;
-+ sflash.numblocks = 32;
-+ break;
-+ case 0x15:
-+ /* ST M25P32 32 Mbit Serial Flash */
-+ sflash.blocksize = 64 * 1024;
-+ sflash.numblocks = 64;
-+ break;
-+ case 0xbf:
-+ W_REG(&cc->flashaddress, 1);
-+ sflash_cmd(cc, SFLASH_ST_RES);
-+ id2 = R_REG(&cc->flashdata);
-+ if (id2 == 0x44) {
-+ /* SST M25VF80 4 Mbit Serial Flash */
-+ sflash.blocksize = 64 * 1024;
-+ sflash.numblocks = 8;
-+ }
-+ break;
-+ }
-+ break;
-+
-+ case SFLASH_AT:
-+ /* Probe for Atmel chips */
-+ sflash_cmd(cc, SFLASH_AT_STATUS);
-+ id = R_REG(&cc->flashdata) & 0x3c;
-+ switch (id) {
-+ case 0xc:
-+ /* Atmel AT45DB011 1Mbit Serial Flash */
-+ sflash.blocksize = 256;
-+ sflash.numblocks = 512;
-+ break;
-+ case 0x14:
-+ /* Atmel AT45DB021 2Mbit Serial Flash */
-+ sflash.blocksize = 256;
-+ sflash.numblocks = 1024;
-+ break;
-+ case 0x1c:
-+ /* Atmel AT45DB041 4Mbit Serial Flash */
-+ sflash.blocksize = 256;
-+ sflash.numblocks = 2048;
-+ break;
-+ case 0x24:
-+ /* Atmel AT45DB081 8Mbit Serial Flash */
-+ sflash.blocksize = 256;
-+ sflash.numblocks = 4096;
-+ break;
-+ case 0x2c:
-+ /* Atmel AT45DB161 16Mbit Serial Flash */
-+ sflash.blocksize = 512;
-+ sflash.numblocks = 4096;
-+ break;
-+ case 0x34:
-+ /* Atmel AT45DB321 32Mbit Serial Flash */
-+ sflash.blocksize = 512;
-+ sflash.numblocks = 8192;
-+ break;
-+ case 0x3c:
-+ /* Atmel AT45DB642 64Mbit Serial Flash */
-+ sflash.blocksize = 1024;
-+ sflash.numblocks = 8192;
-+ break;
-+ }
-+ break;
-+ }
-+
-+ sflash.size = sflash.blocksize * sflash.numblocks;
-+ return sflash.size ? &sflash : NULL;
-+}
-+
-+/* Read len bytes starting at offset into buf. Returns number of bytes read. */
-+int
-+sflash_read(chipcregs_t *cc, uint offset, uint len, uchar *buf)
-+{
-+ int cnt;
-+ uint32 *from, *to;
-+
-+ if (!len)
-+ return 0;
-+
-+ if ((offset + len) > sflash.size)
-+ return -22;
-+
-+ if ((len >= 4) && (offset & 3))
-+ cnt = 4 - (offset & 3);
-+ else if ((len >= 4) && ((uint32)buf & 3))
-+ cnt = 4 - ((uint32)buf & 3);
-+ else
-+ cnt = len;
-+
-+ from = (uint32 *)KSEG1ADDR(SB_FLASH2 + offset);
-+ to = (uint32 *)buf;
-+
-+ if (cnt < 4) {
-+ bcopy(from, to, cnt);
-+ return cnt;
-+ }
-+
-+ while (cnt >= 4) {
-+ *to++ = *from++;
-+ cnt -= 4;
-+ }
-+
-+ return (len - cnt);
-+}
-+
-+/* Poll for command completion. Returns zero when complete. */
-+int
-+sflash_poll(chipcregs_t *cc, uint offset)
-+{
-+ if (offset >= sflash.size)
-+ return -22;
-+
-+ switch (sflash.type) {
-+ case SFLASH_ST:
-+ /* Check for ST Write In Progress bit */
-+ sflash_cmd(cc, SFLASH_ST_RDSR);
-+ return R_REG(&cc->flashdata) & SFLASH_ST_WIP;
-+ case SFLASH_AT:
-+ /* Check for Atmel Ready bit */
-+ sflash_cmd(cc, SFLASH_AT_STATUS);
-+ return !(R_REG(&cc->flashdata) & SFLASH_AT_READY);
-+ }
-+
-+ return 0;
-+}
-+
-+/* Write len bytes starting at offset into buf. Returns number of bytes
-+ * written. Caller should poll for completion.
-+ */
-+int
-+sflash_write(chipcregs_t *cc, uint offset, uint len, const uchar *buf)
-+{
-+ struct sflash *sfl;
-+ int ret = 0;
-+ bool is4712b0;
-+ uint32 page, byte, mask;
-+
-+ if (!len)
-+ return 0;
-+
-+ if ((offset + len) > sflash.size)
-+ return -22;
-+
-+ sfl = &sflash;
-+ switch (sfl->type) {
-+ case SFLASH_ST:
-+ mask = R_REG(&cc->chipid);
-+ is4712b0 = (((mask & CID_ID_MASK) == BCM4712_DEVICE_ID) &&
-+ ((mask & CID_REV_MASK) == (3 << CID_REV_SHIFT)));
-+ /* Enable writes */
-+ sflash_cmd(cc, SFLASH_ST_WREN);
-+ if (is4712b0) {
-+ mask = 1 << 14;
-+ W_REG(&cc->flashaddress, offset);
-+ W_REG(&cc->flashdata, *buf++);
-+ /* Set chip select */
-+ OR_REG(&cc->gpioout, mask);
-+ /* Issue a page program with the first byte */
-+ sflash_cmd(cc, SFLASH_ST_PP);
-+ ret = 1;
-+ offset++;
-+ len--;
-+ while (len > 0) {
-+ if ((offset & 255) == 0) {
-+ /* Page boundary, drop cs and return */
-+ AND_REG(&cc->gpioout, ~mask);
-+ if (!sflash_poll(cc, offset)) {
-+ /* Flash rejected command */
-+ return -11;
-+ }
-+ return ret;
-+ } else {
-+ /* Write single byte */
-+ sflash_cmd(cc, *buf++);
-+ }
-+ ret++;
-+ offset++;
-+ len--;
-+ }
-+ /* All done, drop cs if needed */
-+ if ((offset & 255) != 1) {
-+ /* Drop cs */
-+ AND_REG(&cc->gpioout, ~mask);
-+ if (!sflash_poll(cc, offset)) {
-+ /* Flash rejected command */
-+ return -12;
-+ }
-+ }
-+ } else {
-+ ret = 1;
-+ W_REG(&cc->flashaddress, offset);
-+ W_REG(&cc->flashdata, *buf);
-+ /* Page program */
-+ sflash_cmd(cc, SFLASH_ST_PP);
-+ }
-+ break;
-+ case SFLASH_AT:
-+ mask = sfl->blocksize - 1;
-+ page = (offset & ~mask) << 1;
-+ byte = offset & mask;
-+ /* Read main memory page into buffer 1 */
-+ if (byte || len < sfl->blocksize) {
-+ W_REG(&cc->flashaddress, page);
-+ sflash_cmd(cc, SFLASH_AT_BUF1_LOAD);
-+ /* 250 us for AT45DB321B */
-+ SPINWAIT(sflash_poll(cc, offset), 1000);
-+ ASSERT(!sflash_poll(cc, offset));
-+ }
-+ /* Write into buffer 1 */
-+ for (ret = 0; ret < len && byte < sfl->blocksize; ret++) {
-+ W_REG(&cc->flashaddress, byte++);
-+ W_REG(&cc->flashdata, *buf++);
-+ sflash_cmd(cc, SFLASH_AT_BUF1_WRITE);
-+ }
-+ /* Write buffer 1 into main memory page */
-+ W_REG(&cc->flashaddress, page);
-+ sflash_cmd(cc, SFLASH_AT_BUF1_PROGRAM);
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+/* Erase a region. Returns number of bytes scheduled for erasure.
-+ * Caller should poll for completion.
-+ */
-+int
-+sflash_erase(chipcregs_t *cc, uint offset)
-+{
-+ struct sflash *sfl;
-+
-+ if (offset >= sflash.size)
-+ return -22;
-+
-+ sfl = &sflash;
-+ switch (sfl->type) {
-+ case SFLASH_ST:
-+ sflash_cmd(cc, SFLASH_ST_WREN);
-+ W_REG(&cc->flashaddress, offset);
-+ sflash_cmd(cc, SFLASH_ST_SE);
-+ return sfl->blocksize;
-+ case SFLASH_AT:
-+ W_REG(&cc->flashaddress, offset << 1);
-+ sflash_cmd(cc, SFLASH_AT_PAGE_ERASE);
-+ return sfl->blocksize;
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * writes the appropriate range of flash, a NULL buf simply erases
-+ * the region of flash
-+ */
-+int
-+sflash_commit(chipcregs_t *cc, uint offset, uint len, const uchar *buf)
-+{
-+ struct sflash *sfl;
-+ uchar *block = NULL, *cur_ptr, *blk_ptr;
-+ uint blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
-+ uint blk_offset, blk_len, copied;
-+ int bytes, ret = 0;
-+
-+ /* Check address range */
-+ if (len <= 0)
-+ return 0;
-+
-+ sfl = &sflash;
-+ if ((offset + len) > sfl->size)
-+ return -1;
-+
-+ blocksize = sfl->blocksize;
-+ mask = blocksize - 1;
-+
-+ /* Allocate a block of mem */
-+ if (!(block = MALLOC(NULL, blocksize)))
-+ return -1;
-+
-+ while (len) {
-+ /* Align offset */
-+ cur_offset = offset & ~mask;
-+ cur_length = blocksize;
-+ cur_ptr = block;
-+
-+ remainder = blocksize - (offset & mask);
-+ if (len < remainder)
-+ cur_retlen = len;
-+ else
-+ cur_retlen = remainder;
-+
-+ /* buf == NULL means erase only */
-+ if (buf) {
-+ /* Copy existing data into holding block if necessary */
-+ if ((offset & mask) || (len < blocksize)) {
-+ blk_offset = cur_offset;
-+ blk_len = cur_length;
-+ blk_ptr = cur_ptr;
-+
-+ /* Copy entire block */
-+ while(blk_len) {
-+ copied = sflash_read(cc, blk_offset, blk_len, blk_ptr);
-+ blk_offset += copied;
-+ blk_len -= copied;
-+ blk_ptr += copied;
-+ }
-+ }
-+
-+ /* Copy input data into holding block */
-+ memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
-+ }
-+
-+ /* Erase block */
-+ if ((ret = sflash_erase(cc, (uint) cur_offset)) < 0)
-+ goto done;
-+ while (sflash_poll(cc, (uint) cur_offset));
-+
-+ /* buf == NULL means erase only */
-+ if (!buf) {
-+ offset += cur_retlen;
-+ len -= cur_retlen;
-+ continue;
-+ }
-+
-+ /* Write holding block */
-+ while (cur_length > 0) {
-+ if ((bytes = sflash_write(cc,
-+ (uint) cur_offset,
-+ (uint) cur_length,
-+ (uchar *) cur_ptr)) < 0) {
-+ ret = bytes;
-+ goto done;
-+ }
-+ while (sflash_poll(cc, (uint) cur_offset));
-+ cur_offset += bytes;
-+ cur_length -= bytes;
-+ cur_ptr += bytes;
-+ }
-+
-+ offset += cur_retlen;
-+ len -= cur_retlen;
-+ buf += cur_retlen;
-+ }
-+
-+ ret = len;
-+done:
-+ if (block)
-+ MFREE(NULL, block, blocksize);
-+ return ret;
-+}
-+
-diff -Naur linux.old/arch/mips/bcm947xx/time.c linux.dev/arch/mips/bcm947xx/time.c
---- linux.old/arch/mips/bcm947xx/time.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/arch/mips/bcm947xx/time.c 2006-04-06 15:34:14.000000000 +0200
-@@ -0,0 +1,118 @@
-+/*
-+ * Copyright 2004, Broadcom Corporation
-+ * All Rights Reserved.
-+ *
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-+ *
-+ * $Id: time.c,v 1.1 2005/03/16 13:49:59 wbx Exp $
-+ */
-+#include <linux/config.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/serial_reg.h>
-+#include <linux/interrupt.h>
-+#include <asm/addrspace.h>
-+#include <asm/io.h>
-+#include <asm/time.h>
-+
-+#include <typedefs.h>
-+#include <osl.h>
-+#include <sbutils.h>
-+#include <bcmnvram.h>
-+#include <sbconfig.h>
-+#include <sbextif.h>
-+#include <sbmips.h>
-+
-+/* Global SB handle */
-+extern void *bcm947xx_sbh;
-+extern spinlock_t bcm947xx_sbh_lock;
-+
-+/* Convenience */
-+#define sbh bcm947xx_sbh
-+#define sbh_lock bcm947xx_sbh_lock
-+
-+extern int panic_timeout;
-+static int watchdog = 0;
-+static u8 *mcr = NULL;
-+
-+void __init
-+bcm947xx_time_init(void)
-+{
-+ unsigned int hz;
-+ extifregs_t *eir;
-+
-+ /*
-+ * Use deterministic values for initial counter interrupt
-+ * so that calibrate delay avoids encountering a counter wrap.
-+ */
-+ write_c0_count(0);
-+ write_c0_compare(0xffff);
-+
-+ if (!(hz = sb_mips_clock(sbh)))
-+ hz = 100000000;
-+
-+ printk("CPU: BCM%04x rev %d at %d MHz\n", sb_chip(sbh), sb_chiprev(sbh),
-+ (hz + 500000) / 1000000);
-+
-+ /* Set MIPS counter frequency for fixed_rate_gettimeoffset() */
-+ mips_hpt_frequency = hz / 2;
-+
-+ /* Set watchdog interval in ms */
-+ watchdog = simple_strtoul(nvram_safe_get("watchdog"), NULL, 0);
-+
-+ /* Please set the watchdog to 3 sec if it is less than 3 but not equal to 0 */
-+ if (watchdog > 0) {
-+ if (watchdog < 3000)
-+ watchdog = 3000;
-+ }
-+
-+
-+ /* Set panic timeout in seconds */
-+ panic_timeout = watchdog / 1000;
-+
-+ /* Setup blink */
-+ if ((eir = sb_setcore(sbh, SB_EXTIF, 0))) {
-+ sbconfig_t *sb = (sbconfig_t *)((unsigned int) eir + SBCONFIGOFF);
-+ unsigned long base = EXTIF_CFGIF_BASE(sb_base(readl(&sb->sbadmatch1)));
-+ mcr = (u8 *) ioremap_nocache(base + UART_MCR, 1);
-+ }
-+}
-+
-+static void
-+bcm947xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ /* Generic MIPS timer code */
-+ timer_interrupt(irq, dev_id, regs);
-+
-+ /* Set the watchdog timer to reset after the specified number of ms */
-+ if (watchdog > 0)
-+ sb_watchdog(sbh, WATCHDOG_CLOCK / 1000 * watchdog);
-+
-+#ifdef CONFIG_HWSIM
-+ (*((int *)0xa0000f1c))++;
-+#else
-+ /* Blink one of the LEDs in the external UART */
-+ if (mcr && !(jiffies % (HZ/2)))
-+ writeb(readb(mcr) ^ UART_MCR_OUT2, mcr);
-+#endif
-+}
-+
-+static struct irqaction bcm947xx_timer_irqaction = {
-+ bcm947xx_timer_interrupt,
-+ SA_INTERRUPT,
-+ 0,
-+ "timer",
-+ NULL,
-+ NULL
-+};
-+
-+void __init
-+bcm947xx_timer_setup(struct irqaction *irq)
-+{
-+ /* Enable the timer interrupt */
-+ setup_irq(7, &bcm947xx_timer_irqaction);
-+}
-diff -Naur linux.old/arch/mips/config-shared.in linux.dev/arch/mips/config-shared.in
---- linux.old/arch/mips/config-shared.in 2006-04-06 15:38:09.000000000 +0200
-+++ linux.dev/arch/mips/config-shared.in 2006-04-06 15:34:14.000000000 +0200
-@@ -208,6 +208,14 @@
- fi
- define_bool CONFIG_MIPS_RTC y
- fi
-+dep_bool 'Support for Broadcom MIPS-based boards' CONFIG_MIPS_BRCM $CONFIG_EXPERIMENTAL
-+dep_bool 'Support for Broadcom BCM947XX' CONFIG_BCM947XX $CONFIG_MIPS_BRCM
-+if [ "$CONFIG_BCM947XX" = "y" ] ; then
-+ bool ' Support for Broadcom BCM4710' CONFIG_BCM4710
-+ bool ' Support for Broadcom BCM4310' CONFIG_BCM4310
-+ bool ' Support for Broadcom BCM4704' CONFIG_BCM4704
-+ bool ' Support for Broadcom BCM5365' CONFIG_BCM5365
-+fi
- bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI
- bool 'Support for TANBAC TB0226 (Mbase)' CONFIG_TANBAC_TB0226
- bool 'Support for TANBAC TB0229 (VR4131DIMM)' CONFIG_TANBAC_TB0229
-@@ -229,6 +237,11 @@
- define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
-
- #
-+# Provide an option for a default kernel command line
-+#
-+string 'Default kernel command string' CONFIG_CMDLINE ""
-+
-+#
- # Select some configuration options automatically based on user selections.
- #
- if [ "$CONFIG_ACER_PICA_61" = "y" ]; then
-@@ -554,6 +567,13 @@
- define_bool CONFIG_SWAP_IO_SPACE_L y
- define_bool CONFIG_BOOT_ELF32 y
- fi
-+if [ "$CONFIG_BCM947XX" = "y" ] ; then
-+ define_bool CONFIG_PCI y
-+ define_bool CONFIG_NONCOHERENT_IO y
-+ define_bool CONFIG_NEW_TIME_C y
-+ define_bool CONFIG_NEW_IRQ y
-+ define_bool CONFIG_HND y
-+fi
- if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then
- define_bool CONFIG_ARC32 y
- define_bool CONFIG_ARC_MEMORY y
-@@ -1042,7 +1062,11 @@
-
- bool 'Are you using a crosscompiler' CONFIG_CROSSCOMPILE
- bool 'Enable run-time debugging' CONFIG_RUNTIME_DEBUG
--bool 'Remote GDB kernel debugging' CONFIG_KGDB
-+if [ "$CONFIG_BCM947XX" = "y" ] ; then
-+ bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
-+else
-+ bool 'Remote GDB kernel debugging' CONFIG_KGDB
-+fi
- dep_bool ' Console output to GDB' CONFIG_GDB_CONSOLE $CONFIG_KGDB
- if [ "$CONFIG_KGDB" = "y" ]; then
- define_bool CONFIG_DEBUG_INFO y
-diff -Naur linux.old/arch/mips/kernel/cpu-probe.c linux.dev/arch/mips/kernel/cpu-probe.c
---- linux.old/arch/mips/kernel/cpu-probe.c 2006-04-06 15:38:09.000000000 +0200
-+++ linux.dev/arch/mips/kernel/cpu-probe.c 2006-04-06 15:34:14.000000000 +0200
-@@ -162,7 +162,7 @@
-
- static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
- {
-- switch (c->processor_id & 0xff00) {
-+ switch (c->processor_id & PRID_IMP_MASK) {
- case PRID_IMP_R2000:
- c->cputype = CPU_R2000;
- c->isa_level = MIPS_CPU_ISA_I;
-@@ -172,7 +172,7 @@
- c->tlbsize = 64;
- break;
- case PRID_IMP_R3000:
-- if ((c->processor_id & 0xff) == PRID_REV_R3000A)
-+ if ((c->processor_id & PRID_REV_MASK) == PRID_REV_R3000A)
- if (cpu_has_confreg())
- c->cputype = CPU_R3081E;
- else
-@@ -187,12 +187,12 @@
- break;
- case PRID_IMP_R4000:
- if (read_c0_config() & CONF_SC) {
-- if ((c->processor_id & 0xff) >= PRID_REV_R4400)
-+ if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_R4400)
- c->cputype = CPU_R4400PC;
- else
- c->cputype = CPU_R4000PC;
- } else {
-- if ((c->processor_id & 0xff) >= PRID_REV_R4400)
-+ if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_R4400)
- c->cputype = CPU_R4400SC;
- else
- c->cputype = CPU_R4000SC;
-@@ -438,7 +438,7 @@
- static inline void cpu_probe_mips(struct cpuinfo_mips *c)
- {
- decode_config1(c);
-- switch (c->processor_id & 0xff00) {
-+ switch (c->processor_id & PRID_IMP_MASK) {
- case PRID_IMP_4KC:
- c->cputype = CPU_4KC;
- c->isa_level = MIPS_CPU_ISA_M32;
-@@ -479,10 +479,10 @@
- {
- decode_config1(c);
- c->options |= MIPS_CPU_PREFETCH;
-- switch (c->processor_id & 0xff00) {
-+ switch (c->processor_id & PRID_IMP_MASK) {
- case PRID_IMP_AU1_REV1:
- case PRID_IMP_AU1_REV2:
-- switch ((c->processor_id >> 24) & 0xff) {
-+ switch ((c->processor_id >> 24) & PRID_REV_MASK) {
- case 0:
- c->cputype = CPU_AU1000;
- break;
-@@ -510,10 +510,34 @@
- }
- }
-
-+static inline void cpu_probe_broadcom(struct cpuinfo_mips *c)
-+{
-+ decode_config1(c);
-+ c->options |= MIPS_CPU_PREFETCH;
-+ switch (c->processor_id & PRID_IMP_MASK) {
-+ case PRID_IMP_BCM4710:
-+ c->cputype = CPU_BCM4710;
-+ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
-+ MIPS_CPU_4KTLB | MIPS_CPU_COUNTER;
-+ c->scache.flags = MIPS_CACHE_NOT_PRESENT;
-+ break;
-+ case PRID_IMP_4KC:
-+ case PRID_IMP_BCM3302:
-+ c->cputype = CPU_BCM3302;
-+ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
-+ MIPS_CPU_4KTLB | MIPS_CPU_COUNTER;
-+ c->scache.flags = MIPS_CACHE_NOT_PRESENT;
-+ break;
-+ default:
-+ c->cputype = CPU_UNKNOWN;
-+ break;
-+ }
-+}
-+
- static inline void cpu_probe_sibyte(struct cpuinfo_mips *c)
- {
- decode_config1(c);
-- switch (c->processor_id & 0xff00) {
-+ switch (c->processor_id & PRID_IMP_MASK) {
- case PRID_IMP_SB1:
- c->cputype = CPU_SB1;
- c->isa_level = MIPS_CPU_ISA_M64;
-@@ -535,7 +559,7 @@
- static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c)
- {
- decode_config1(c);
-- switch (c->processor_id & 0xff00) {
-+ switch (c->processor_id & PRID_IMP_MASK) {
- case PRID_IMP_SR71000:
- c->cputype = CPU_SR71000;
- c->isa_level = MIPS_CPU_ISA_M64;
-@@ -560,7 +584,7 @@
- c->cputype = CPU_UNKNOWN;
-
- c->processor_id = read_c0_prid();
-- switch (c->processor_id & 0xff0000) {
-+ switch (c->processor_id & PRID_COMP_MASK) {
-
- case PRID_COMP_LEGACY:
- cpu_probe_legacy(c);
-@@ -571,6 +595,9 @@
- case PRID_COMP_ALCHEMY:
- cpu_probe_alchemy(c);
- break;
-+ case PRID_COMP_BROADCOM:
-+ cpu_probe_broadcom(c);
-+ break;
- case PRID_COMP_SIBYTE:
- cpu_probe_sibyte(c);
- break;
-diff -Naur linux.old/arch/mips/kernel/head.S linux.dev/arch/mips/kernel/head.S
---- linux.old/arch/mips/kernel/head.S 2006-04-06 15:38:09.000000000 +0200
-+++ linux.dev/arch/mips/kernel/head.S 2006-04-06 15:34:14.000000000 +0200
-@@ -28,12 +28,20 @@
- #include <asm/mipsregs.h>
- #include <asm/stackframe.h>
-
-+#ifdef CONFIG_BCM4710
-+#undef eret
-+#define eret nop; nop; eret
-+#endif
-+
- .text
-+ j kernel_entry
-+ nop
-+
- /*
- * Reserved space for exception handlers.
- * Necessary for machines which link their kernels at KSEG0.
- */
-- .fill 0x400
-+ .fill 0x3f4
-
- /* The following two symbols are used for kernel profiling. */
- EXPORT(stext)
-diff -Naur linux.old/arch/mips/kernel/proc.c linux.dev/arch/mips/kernel/proc.c
---- linux.old/arch/mips/kernel/proc.c 2006-04-06 15:38:09.000000000 +0200
-+++ linux.dev/arch/mips/kernel/proc.c 2006-04-06 15:34:14.000000000 +0200
-@@ -78,9 +78,10 @@
- [CPU_AU1550] "Au1550",
- [CPU_24K] "MIPS 24K",
- [CPU_AU1200] "Au1200",
-+ [CPU_BCM4710] "BCM4710",
-+ [CPU_BCM3302] "BCM3302",
- };
-
--
- static int show_cpuinfo(struct seq_file *m, void *v)
- {
- unsigned int version = current_cpu_data.processor_id;
-diff -Naur linux.old/arch/mips/kernel/setup.c linux.dev/arch/mips/kernel/setup.c
---- linux.old/arch/mips/kernel/setup.c 2006-04-06 15:38:09.000000000 +0200
-+++ linux.dev/arch/mips/kernel/setup.c 2006-04-06 15:34:14.000000000 +0200
-@@ -493,6 +493,7 @@
- void swarm_setup(void);
- void hp_setup(void);
- void au1x00_setup(void);
-+ void brcm_setup(void);
- void frame_info_init(void);
-
- frame_info_init();
-@@ -691,6 +692,11 @@
- pmc_yosemite_setup();
- break;
- #endif
-+#if defined(CONFIG_BCM4710) || defined(CONFIG_BCM4310)
-+ case MACH_GROUP_BRCM:
-+ brcm_setup();
-+ break;
-+#endif
- default:
- panic("Unsupported architecture");
- }
-diff -Naur linux.old/arch/mips/kernel/traps.c linux.dev/arch/mips/kernel/traps.c
---- linux.old/arch/mips/kernel/traps.c 2006-04-06 15:38:09.000000000 +0200
-+++ linux.dev/arch/mips/kernel/traps.c 2006-04-06 15:34:14.000000000 +0200
-@@ -920,6 +920,7 @@
- void __init trap_init(void)
- {
- extern char except_vec1_generic;
-+ extern char except_vec2_generic;
- extern char except_vec3_generic, except_vec3_r4000;
- extern char except_vec_ejtag_debug;
- extern char except_vec4;
-@@ -927,6 +928,7 @@
-
- /* Copy the generic exception handler code to it's final destination. */
- memcpy((void *)(KSEG0 + 0x80), &except_vec1_generic, 0x80);
-+ memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic, 0x80);
-
- /*
- * Setup default vectors
-@@ -985,6 +987,12 @@
- set_except_vector(13, handle_tr);
- set_except_vector(22, handle_mdmx);
-
-+ if (current_cpu_data.cputype == CPU_SB1) {
-+ /* Enable timer interrupt and scd mapped interrupt */
-+ clear_c0_status(0xf000);
-+ set_c0_status(0xc00);
-+ }