aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm63xx/files/arch
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2007-09-06 16:27:37 +0000
committerFelix Fietkau <nbd@openwrt.org>2007-09-06 16:27:37 +0000
commit56231056ea784f1cec6450f649b1adaed1f56366 (patch)
tree7b130d72d854cde2bcd3af8b11bd0f7be3dbff6a /target/linux/brcm63xx/files/arch
parente1184aaa1a7a5e5eeef8e072bf0ea98c291be22a (diff)
downloadupstream-56231056ea784f1cec6450f649b1adaed1f56366.tar.gz
upstream-56231056ea784f1cec6450f649b1adaed1f56366.tar.bz2
upstream-56231056ea784f1cec6450f649b1adaed1f56366.zip
strip the kernel version suffix from target directories, except for brcm-2.4 (the -2.4 will be included in the board name here). CONFIG_LINUX_<ver>_<board> becomes CONFIG_TARGET_<board>, same for profiles.
SVN-Revision: 8653
Diffstat (limited to 'target/linux/brcm63xx/files/arch')
-rw-r--r--target/linux/brcm63xx/files/arch/mips/bcm963xx/Makefile9
-rw-r--r--target/linux/brcm63xx/files/arch/mips/bcm963xx/info.c102
-rw-r--r--target/linux/brcm63xx/files/arch/mips/bcm963xx/int-handler.S59
-rw-r--r--target/linux/brcm63xx/files/arch/mips/bcm963xx/irq.c258
-rw-r--r--target/linux/brcm63xx/files/arch/mips/bcm963xx/prom.c73
-rw-r--r--target/linux/brcm63xx/files/arch/mips/bcm963xx/ser_init.c181
-rw-r--r--target/linux/brcm63xx/files/arch/mips/bcm963xx/setup.c472
-rw-r--r--target/linux/brcm63xx/files/arch/mips/bcm963xx/time.c116
-rw-r--r--target/linux/brcm63xx/files/arch/mips/bcm963xx/wdt.c246
-rw-r--r--target/linux/brcm63xx/files/arch/mips/cfe/Makefile5
-rw-r--r--target/linux/brcm63xx/files/arch/mips/cfe/cfe.c533
-rw-r--r--target/linux/brcm63xx/files/arch/mips/cfe/cfe_private.h176
-rw-r--r--target/linux/brcm63xx/files/arch/mips/pci/fixup-bcm96348.c95
-rw-r--r--target/linux/brcm63xx/files/arch/mips/pci/ops-bcm96348.c278
-rw-r--r--target/linux/brcm63xx/files/arch/mips/pci/pci-bcm96348.c62
15 files changed, 2665 insertions, 0 deletions
diff --git a/target/linux/brcm63xx/files/arch/mips/bcm963xx/Makefile b/target/linux/brcm63xx/files/arch/mips/bcm963xx/Makefile
new file mode 100644
index 0000000000..a9d1e55979
--- /dev/null
+++ b/target/linux/brcm63xx/files/arch/mips/bcm963xx/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the Broadcom BCM963xx SoC specific parts of the kernel
+#
+# Copyright (C) 2004 Broadcom Corporation
+#
+obj-y := irq.o prom.o setup.o time.o ser_init.o int-handler.o info.o wdt.o
+
+SRCBASE := $(TOPDIR)
+EXTRA_CFLAGS += -I$(SRCBASE)/include
diff --git a/target/linux/brcm63xx/files/arch/mips/bcm963xx/info.c b/target/linux/brcm63xx/files/arch/mips/bcm963xx/info.c
new file mode 100644
index 0000000000..d50b601e22
--- /dev/null
+++ b/target/linux/brcm63xx/files/arch/mips/bcm963xx/info.c
@@ -0,0 +1,102 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ * Copyright (C) 2007 Florian Fainelli <florian@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.
+ */
+
+#include <linux/types.h>
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+#include <asm/string.h>
+#include <asm/mach-bcm963xx/bootloaders.h>
+
+static char *boot_loader_names[BOOT_LOADER_LAST+1] = {
+ [BOOT_LOADER_UNKNOWN] = "Unknown",
+ [BOOT_LOADER_CFE] = "CFE",
+ [BOOT_LOADER_REDBOOT] = "RedBoot",
+ [BOOT_LOADER_CFE2] = "CFEv2"
+};
+
+/* boot loaders specific definitions */
+#define CFE_EPTSEAL 0x43464531 /* CFE1 is the magic number to recognize CFE from other bootloaders */
+
+int boot_loader_type;
+/*
+ * Boot loader detection routines
+ */
+static int __init detect_cfe(void)
+{
+ /*
+ * This method only works, when we are booted directly from the CFE.
+ */
+ uint32_t cfe_handle = (uint32_t) fw_arg0;
+ uint32_t cfe_a1_val = (uint32_t) fw_arg1;
+ uint32_t cfe_entry = (uint32_t) fw_arg2;
+ uint32_t cfe_seal = (uint32_t) fw_arg3;
+
+ /* Check for CFE by finding the CFE magic number */
+ if (cfe_seal != CFE_EPTSEAL)
+ /* We are not booted from CFE */
+ return 0;
+
+ /* cfe_a1_val must be 0, because only one CPU present in the ADM5120 SoC */
+ if (cfe_a1_val != 0)
+ return 0;
+
+ /* The cfe_handle, and the cfe_entry must be kernel mode addresses */
+ if ((cfe_handle < KSEG0) || (cfe_entry < KSEG0))
+ return 0;
+
+ return 1;
+}
+
+static int __init detect_redboot(void)
+{
+ /* On Inventel Livebox, the boot loader is passed as a command line argument, check for it */
+ if (!strncmp(arcs_cmdline, "boot_loader=RedBoot", 19))
+ return 1;
+ return 0;
+}
+
+void __init detect_bootloader(void)
+{
+ if (detect_cfe()) {
+ boot_loader_type = BOOT_LOADER_CFE;
+ }
+
+ if (detect_redboot()) {
+ boot_loader_type = BOOT_LOADER_REDBOOT;
+ }
+ else {
+ /* Some devices are using CFE, but it is not detected as is */
+ boot_loader_type = BOOT_LOADER_CFE2;
+ }
+ printk("Boot loader is : %s\n", boot_loader_names[boot_loader_type]);
+}
+
+void __init detect_board(void)
+{
+ switch (boot_loader_type)
+ {
+ case BOOT_LOADER_CFE:
+ break;
+ case BOOT_LOADER_REDBOOT:
+ break;
+ default:
+ break;
+ }
+}
+
+EXPORT_SYMBOL(boot_loader_type);
diff --git a/target/linux/brcm63xx/files/arch/mips/bcm963xx/int-handler.S b/target/linux/brcm63xx/files/arch/mips/bcm963xx/int-handler.S
new file mode 100644
index 0000000000..a7a9c9d20c
--- /dev/null
+++ b/target/linux/brcm63xx/files/arch/mips/bcm963xx/int-handler.S
@@ -0,0 +1,59 @@
+/*
+<:copyright-gpl
+ Copyright 2002 Broadcom Corp. All Rights Reserved.
+
+ This program is free software; you can distribute it and/or modify it
+ under the terms of the GNU General Public License (Version 2) as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+:>
+*/
+/*
+ * Generic interrupt handler for Broadcom MIPS boards
+ */
+
+#include <linux/autoconf.h>
+
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+/*
+ * MIPS IRQ Source
+ * -------- ------
+ * 0 Software (ignored)
+ * 1 Software (ignored)
+ * 2 Combined hardware interrupt (hw0)
+ * 3 Hardware
+ * 4 Hardware
+ * 5 Hardware
+ * 6 Hardware
+ * 7 R4k timer
+ */
+
+ .text
+ .set noreorder
+ .set noat
+ .align 5
+ NESTED(brcmIRQ, PT_SIZE, sp)
+ SAVE_ALL
+ CLI
+ .set noreorder
+ .set at
+
+ jal plat_irq_dispatch
+ move a0, sp
+
+ j ret_from_irq
+ nop
+
+ END(brcmIRQ)
diff --git a/target/linux/brcm63xx/files/arch/mips/bcm963xx/irq.c b/target/linux/brcm63xx/files/arch/mips/bcm963xx/irq.c
new file mode 100644
index 0000000000..962cd374dd
--- /dev/null
+++ b/target/linux/brcm63xx/files/arch/mips/bcm963xx/irq.c
@@ -0,0 +1,258 @@
+/*
+<:copyright-gpl
+ Copyright 2002 Broadcom Corp. All Rights Reserved.
+
+ This program is free software; you can distribute it and/or modify it
+ under the terms of the GNU General Public License (Version 2) as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+:>
+*/
+/*
+ * Interrupt control functions for Broadcom 963xx MIPS boards
+ */
+
+#include <asm/atomic.h>
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/signal.h>
+#include <6348_map_part.h>
+#include <6348_intr.h>
+#include <bcm_map_part.h>
+#include <bcm_intr.h>
+
+static void irq_dispatch_int(struct pt_regs *regs)
+{
+ unsigned int pendingIrqs;
+ static unsigned int irqBit;
+ static unsigned int isrNumber = 31;
+
+ pendingIrqs = PERF->IrqStatus & PERF->IrqMask;
+ if (!pendingIrqs) {
+ return;
+ }
+
+ while (1) {
+ irqBit <<= 1;
+ isrNumber++;
+ if (isrNumber == 32) {
+ isrNumber = 0;
+ irqBit = 0x1;
+ }
+ if (pendingIrqs & irqBit) {
+ PERF->IrqMask &= ~irqBit; // mask
+ do_IRQ(isrNumber + INTERNAL_ISR_TABLE_OFFSET);
+ break;
+ }
+ }
+}
+
+static void irq_dispatch_ext(uint32 irq)
+{
+ if (!(PERF->ExtIrqCfg & (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT)))) {
+ printk("**** Ext IRQ mask. Should not dispatch ****\n");
+ }
+ /* disable and clear interrupt in the controller */
+ PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT));
+ PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));
+ do_IRQ(irq);
+}
+
+
+extern void brcm_timer_interrupt(struct pt_regs *regs);
+
+asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+{
+ u32 cause;
+ while((cause = (read_c0_cause()& CAUSEF_IP))) {
+ if (cause & CAUSEF_IP7)
+ brcm_timer_interrupt(regs);
+ else if (cause & CAUSEF_IP2)
+ irq_dispatch_int(regs);
+ else if (cause & CAUSEF_IP3)
+ irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_0);
+ else if (cause & CAUSEF_IP4)
+ irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_1);
+ else if (cause & CAUSEF_IP5)
+ irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_2);
+ else if (cause & CAUSEF_IP6)
+ irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_3);
+ local_irq_disable();
+ }
+}
+
+
+void enable_brcm_irq(unsigned int irq)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if( irq >= INTERNAL_ISR_TABLE_OFFSET ) {
+ PERF->IrqMask |= (1 << (irq - INTERNAL_ISR_TABLE_OFFSET));
+ }
+ else if (irq >= INTERRUPT_ID_EXTERNAL_0 && irq <= INTERRUPT_ID_EXTERNAL_3) {
+ /* enable and clear interrupt in the controller */
+ PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT));
+ PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));
+ }
+ local_irq_restore(flags);
+}
+
+void disable_brcm_irq(unsigned int irq)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if( irq >= INTERNAL_ISR_TABLE_OFFSET ) {
+ PERF->IrqMask &= ~(1 << (irq - INTERNAL_ISR_TABLE_OFFSET));
+ }
+ else if (irq >= INTERRUPT_ID_EXTERNAL_0 && irq <= INTERRUPT_ID_EXTERNAL_3) {
+ /* disable interrupt in the controller */
+ PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));
+ }
+ local_irq_restore(flags);
+}
+
+void ack_brcm_irq(unsigned int irq)
+{
+ /* Already done in brcm_irq_dispatch */
+}
+
+unsigned int startup_brcm_irq(unsigned int irq)
+{
+ enable_brcm_irq(irq);
+
+ return 0; /* never anything pending */
+}
+
+unsigned int startup_brcm_none(unsigned int irq)
+{
+ return 0;
+}
+
+void end_brcm_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_brcm_irq(irq);
+}
+
+void end_brcm_none(unsigned int irq)
+{
+}
+
+static struct hw_interrupt_type brcm_irq_type = {
+ .typename = "MIPS",
+ .startup = startup_brcm_irq,
+ .shutdown = disable_brcm_irq,
+ .enable = enable_brcm_irq,
+ .disable = disable_brcm_irq,
+ .ack = ack_brcm_irq,
+ .end = end_brcm_irq,
+ .set_affinity = NULL
+};
+
+static struct hw_interrupt_type brcm_irq_no_end_type = {
+ .typename = "MIPS",
+ .startup = startup_brcm_none,
+ .shutdown = disable_brcm_irq,
+ .enable = enable_brcm_irq,
+ .disable = disable_brcm_irq,
+ .ack = ack_brcm_irq,
+ .end = end_brcm_none,
+ .set_affinity = NULL
+};
+
+void __init arch_init_irq(void)
+{
+ int i;
+
+ clear_c0_status(ST0_BEV);
+ change_c0_status(ST0_IM, (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4));
+
+ for (i = 0; i < NR_IRQS; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = 0;
+ irq_desc[i].depth = 1;
+ irq_desc[i].chip = &brcm_irq_type;
+ }
+}
+
+int request_external_irq(unsigned int irq,
+ FN_HANDLER handler,
+ unsigned long irqflags,
+ const char * devname,
+ void *dev_id)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT)); // Clear
+ PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT)); // Mask
+ PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_INSENS_SHFT)); // Edge insesnsitive
+ PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_LEVEL_SHFT)); // Level triggered
+ PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_SENSE_SHFT)); // Low level
+
+ local_irq_restore(flags);
+
+ return( request_irq(irq, handler, irqflags, devname, dev_id) );
+}
+
+/* VxWorks compatibility function(s). */
+
+unsigned int BcmHalMapInterrupt(FN_HANDLER pfunc, unsigned int param,
+ unsigned int interruptId)
+{
+ int nRet = -1;
+ char *devname;
+
+ devname = kmalloc(16, GFP_KERNEL);
+ if (devname)
+ sprintf( devname, "brcm_%d", interruptId );
+
+ /* Set the IRQ description to not automatically enable the interrupt at
+ * the end of an ISR. The driver that handles the interrupt must
+ * explicitly call BcmHalInterruptEnable or enable_brcm_irq. This behavior
+ * is consistent with interrupt handling on VxWorks.
+ */
+ irq_desc[interruptId].chip = &brcm_irq_no_end_type;
+
+ if( interruptId >= INTERNAL_ISR_TABLE_OFFSET )
+ {
+ printk("BcmHalMapInterrupt : internal IRQ\n");
+ nRet = request_irq( interruptId, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT, devname, (void *) param );
+ }
+ else if (interruptId >= INTERRUPT_ID_EXTERNAL_0 && interruptId <= INTERRUPT_ID_EXTERNAL_3)
+ {
+ printk("BcmHalMapInterrupt : external IRQ\n");
+ nRet = request_external_irq( interruptId, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT, devname, (void *) param );
+ }
+
+ return( nRet );
+}
+
+
+EXPORT_SYMBOL(enable_brcm_irq);
+EXPORT_SYMBOL(disable_brcm_irq);
+EXPORT_SYMBOL(request_external_irq);
+EXPORT_SYMBOL(BcmHalMapInterrupt);
+
diff --git a/target/linux/brcm63xx/files/arch/mips/bcm963xx/prom.c b/target/linux/brcm63xx/files/arch/mips/bcm963xx/prom.c
new file mode 100644
index 0000000000..e02d31c9ed
--- /dev/null
+++ b/target/linux/brcm63xx/files/arch/mips/bcm963xx/prom.c
@@ -0,0 +1,73 @@
+/*
+ Copyright 2004 Broadcom Corp. All Rights Reserved.
+ Copyright 2007 OpenWrt,org, Florian Fainelli <florian@openwrt.org>
+
+ This program is free software; you can distribute it and/or modify it
+ under the terms of the GNU General Public License (Version 2) as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+*/
+/*
+ * prom.c: PROM library initialization code.
+ *
+ */
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/bootmem.h>
+#include <linux/blkdev.h>
+
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
+#include <asm/time.h>
+#include <asm/mach-bcm963xx/bootloaders.h>
+#include <asm/mach-bcm963xx/6348_map_part.h>
+
+#include "../cfe/cfe_private.h"
+
+extern void __init detect_bootloader(void);
+extern void serial_init(void);
+extern int boot_loader_type;
+
+#define MACH_BCM MACH_BCM96348
+
+const char *get_system_type(void)
+{
+ return "Broadcom BCM963xx";
+}
+
+void __init prom_init(void)
+{
+ serial_init();
+
+ printk("%s prom init\n", get_system_type() );
+
+ PERF->IrqMask = 0;
+
+ /* Detect the bootloader */
+ detect_bootloader();
+
+ /* Do further initialisations depending on the bootloader */
+ if (boot_loader_type == BOOT_LOADER_CFE || boot_loader_type == BOOT_LOADER_CFE2) {
+ cfe_setup(fw_arg0, fw_arg1, fw_arg2, fw_arg3);
+ }
+ /* Register 16MB RAM minus the ADSL SDRAM by default */
+ add_memory_region(0, (0x01000000 - ADSL_SDRAM_IMAGE_SIZE), BOOT_MEM_RAM);
+
+ mips_machgroup = MACH_GROUP_BRCM;
+ mips_machtype = MACH_BCM;
+}
+
+void __init prom_free_prom_memory(void)
+{
+ /* We do not have any memory to free */
+}
diff --git a/target/linux/brcm63xx/files/arch/mips/bcm963xx/ser_init.c b/target/linux/brcm63xx/files/arch/mips/bcm963xx/ser_init.c
new file mode 100644
index 0000000000..bb745aec6e
--- /dev/null
+++ b/target/linux/brcm63xx/files/arch/mips/bcm963xx/ser_init.c
@@ -0,0 +1,181 @@
+/*
+<:copyright-gpl
+ Copyright 2004 Broadcom Corp. All Rights Reserved.
+
+ This program is free software; you can distribute it and/or modify it
+ under the terms of the GNU General Public License (Version 2) as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+:>
+*/
+/*
+ * Broadcom bcm63xx serial port initialization, also prepare for printk
+ * by registering with console_init
+ *
+ */
+
+#include <linux/autoconf.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/console.h>
+#include <linux/sched.h>
+
+#include <asm/addrspace.h>
+#include <asm/irq.h>
+#include <asm/reboot.h>
+#include <asm/gdb-stub.h>
+#include <asm/mc146818rtc.h>
+
+#include <bcm_map_part.h>
+#include <6348_map_part.h>
+#include <board.h>
+
+#define SER63XX_DEFAULT_BAUD 115200
+#define BD_BCM63XX_TIMER_CLOCK_INPUT (FPERIPH)
+#define stUart ((volatile Uart * const) UART_BASE)
+
+// Transmit interrupts
+#define TXINT (TXFIFOEMT | TXUNDERR | TXOVFERR)
+// Receive interrupts
+#define RXINT (RXFIFONE | RXOVFERR)
+
+/* --------------------------------------------------------------------------
+ Name: serial_init
+ Purpose: Initalize the UART
+-------------------------------------------------------------------------- */
+void __init serial_init(void)
+{
+ u32 tmpVal = SER63XX_DEFAULT_BAUD;
+ ULONG clockFreqHz;
+
+#if defined(CONFIG_BCM96345)
+ // Make sure clock is ticking
+ PERF->blkEnables |= UART_CLK_EN;
+#endif
+
+ /* Dissable channel's receiver and transmitter. */
+ stUart->control &= ~(BRGEN|TXEN|RXEN);
+
+ /*--------------------------------------------------------------------*/
+ /* Write the table value to the clock select register. */
+ /* DPullen - this is the equation to use: */
+ /* value = clockFreqHz / baud / 32-1; */
+ /* (snmod) Actually you should also take into account any necessary */
+ /* rounding. Divide by 16, look at lsb, if 0, divide by 2 */
+ /* and subtract 1. If 1, just divide by 2 */
+ /*--------------------------------------------------------------------*/
+ clockFreqHz = BD_BCM63XX_TIMER_CLOCK_INPUT;
+ tmpVal = (clockFreqHz / tmpVal) / 16;
+ if( tmpVal & 0x01 )
+ tmpVal /= 2; //Rounding up, so sub is already accounted for
+ else
+ tmpVal = (tmpVal / 2) - 1; // Rounding down so we must sub 1
+ stUart->baudword = tmpVal;
+
+ /* Finally, re-enable the transmitter and receiver. */
+ stUart->control |= (BRGEN|TXEN|RXEN);
+
+ stUart->config = (BITS8SYM | ONESTOP);
+ // Set the FIFO interrupt depth ... stUart->fifocfg = 0xAA;
+ stUart->fifoctl = RSTTXFIFOS | RSTRXFIFOS;
+ stUart->intMask = 0;
+ stUart->intMask = RXINT | TXINT;
+}
+
+
+/* prom_putc()
+ * Output a character to the UART
+ */
+void prom_putc(char c)
+{
+ /* Wait for Tx uffer to empty */
+ while (! (READ16(stUart->intStatus) & TXFIFOEMT));
+ /* Send character */
+ stUart->Data = c;
+}
+
+/* prom_puts()
+ * Write a string to the UART
+ */
+void prom_puts(const char *s)
+{
+ while (*s) {
+ if (*s == '\n') {
+ prom_putc('\r');
+ }
+ prom_putc(*s++);
+ }
+}
+
+
+/* prom_getc_nowait()
+ * Returns a character from the UART
+ * Returns -1 if no characters available or corrupted
+ */
+int prom_getc_nowait(void)
+{
+ uint16 uStatus;
+ int cData = -1;
+
+ uStatus = READ16(stUart->intStatus);
+
+ if (uStatus & RXFIFONE) { /* Do we have a character? */
+ cData = READ16(stUart->Data) & 0xff; /* Read character */
+ if (uStatus & (RXFRAMERR | RXPARERR)) { /* If we got an error, throw it away */
+ cData = -1;
+ }
+ }
+
+ return cData;
+}
+
+/* prom_getc()
+ * Returns a charcter from the serial port
+ * Will block until it receives a valid character
+*/
+char prom_getc(void)
+{
+ int cData = -1;
+
+ /* Loop until we get a valid character */
+ while(cData == -1) {
+ cData = prom_getc_nowait();
+ }
+ return (char) cData;
+}
+
+/* prom_testc()
+ * Returns 0 if no characters available
+ */
+int prom_testc(void)
+{
+ uint16 uStatus;
+
+ uStatus = READ16(stUart->intStatus);
+
+ return (uStatus & RXFIFONE);
+}
+
+#if defined (CONFIG_REMOTE_DEBUG)
+/* Prevent other code from writing to the serial port */
+void _putc(char c) { }
+void _puts(const char *ptr) { }
+#else
+/* Low level outputs call prom routines */
+void _putc(char c) {
+ prom_putc(c);
+}
+void _puts(const char *ptr) {
+ prom_puts(ptr);
+}
+#endif
diff --git a/target/linux/brcm63xx/files/arch/mips/bcm963xx/setup.c b/target/linux/brcm63xx/files/arch/mips/bcm963xx/setup.c
new file mode 100644
index 0000000000..70c6ebe601
--- /dev/null
+++ b/target/linux/brcm63xx/files/arch/mips/bcm963xx/setup.c
@@ -0,0 +1,472 @@
+/*
+<:copyright-gpl
+ Copyright 2002 Broadcom Corp. All Rights Reserved.
+
+ This program is free software; you can distribute it and/or modify it
+ under the terms of the GNU General Public License (Version 2) as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+:>
+*/
+/*
+ * Generic setup routines for Broadcom 963xx MIPS boards
+ */
+
+#include <linux/autoconf.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/console.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/bootmem.h>
+
+#include <asm/addrspace.h>
+#include <asm/bcache.h>
+#include <asm/irq.h>
+#include <asm/time.h>
+#include <asm/reboot.h>
+#include <asm/gdb-stub.h>
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
+#include <asm/mach-bcm963xx/bootloaders.h>
+
+extern void brcm_time_init(void);
+extern int boot_loader_type;
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <bcm_map_part.h>
+#include <6348_map_part.h>
+#include <bcmpci.h>
+
+static volatile MpiRegisters * mpi = (MpiRegisters *)(MPI_BASE);
+
+/* This function should be in a board specific directory. For now,
+ * assume that all boards that include this file use a Broadcom chip
+ * with a soft reset bit in the PLL control register.
+ */
+static void brcm_machine_restart(char *command)
+{
+ const unsigned long ulSoftReset = 0x00000001;
+ unsigned long *pulPllCtrl = (unsigned long *) 0xfffe0008;
+ *pulPllCtrl |= ulSoftReset;
+}
+
+static void brcm_machine_halt(void)
+{
+ printk("System halted\n");
+ while (1);
+}
+
+static void mpi_SetLocalPciConfigReg(uint32 reg, uint32 value)
+{
+ /* write index then value */
+ mpi->pcicfgcntrl = PCI_CFG_REG_WRITE_EN + reg;;
+ mpi->pcicfgdata = value;
+}
+
+static uint32 mpi_GetLocalPciConfigReg(uint32 reg)
+{
+ /* write index then get value */
+ mpi->pcicfgcntrl = PCI_CFG_REG_WRITE_EN + reg;;
+ return mpi->pcicfgdata;
+}
+
+/*
+ * mpi_ResetPcCard: Set/Reset the PcCard
+ */
+static void mpi_ResetPcCard(int cardtype, BOOL bReset)
+{
+ if (cardtype == MPI_CARDTYPE_NONE) {
+ return;
+ }
+
+ if (cardtype == MPI_CARDTYPE_CARDBUS) {
+ bReset = ! bReset;
+ }
+
+ if (bReset) {
+ mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 & ~PCCARD_CARD_RESET);
+ } else {
+ mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 | PCCARD_CARD_RESET);
+ }
+}
+
+/*
+ * mpi_ConfigCs: Configure an MPI/EBI chip select
+ */
+static void mpi_ConfigCs(uint32 cs, uint32 base, uint32 size, uint32 flags)
+{
+ mpi->cs[cs].base = ((base & 0x1FFFFFFF) | size);
+ mpi->cs[cs].config = flags;
+}
+
+/*
+ * mpi_InitPcmciaSpace
+ */
+static void mpi_InitPcmciaSpace(void)
+{
+ // ChipSelect 4 controls PCMCIA Memory accesses
+ mpi_ConfigCs(PCMCIA_COMMON_BASE, pcmciaMem, EBI_SIZE_1M, (EBI_WORD_WIDE|EBI_ENABLE));
+ // ChipSelect 5 controls PCMCIA Attribute accesses
+ mpi_ConfigCs(PCMCIA_ATTRIBUTE_BASE, pcmciaAttr, EBI_SIZE_1M, (EBI_WORD_WIDE|EBI_ENABLE));
+ // ChipSelect 6 controls PCMCIA I/O accesses
+ mpi_ConfigCs(PCMCIA_IO_BASE, pcmciaIo, EBI_SIZE_64K, (EBI_WORD_WIDE|EBI_ENABLE));
+
+ mpi->pcmcia_cntl2 = ((PCMCIA_ATTR_ACTIVE << RW_ACTIVE_CNT_BIT) |
+ (PCMCIA_ATTR_INACTIVE << INACTIVE_CNT_BIT) |
+ (PCMCIA_ATTR_CE_SETUP << CE_SETUP_CNT_BIT) |
+ (PCMCIA_ATTR_CE_HOLD << CE_HOLD_CNT_BIT));
+
+ mpi->pcmcia_cntl2 |= (PCMCIA_HALFWORD_EN | PCMCIA_BYTESWAP_DIS);
+}
+
+/*
+ * cardtype_vcc_detect: PC Card's card detect and voltage sense connection
+ *
+ * CD1#/ CD2#/ VS1#/ VS2#/ Card Initial Vcc
+ * CCD1# CCD2# CVS1 CVS2 Type
+ *
+ * GND GND open open 16-bit 5 vdc
+ *
+ * GND GND GND open 16-bit 3.3 vdc
+ *
+ * GND GND open GND 16-bit x.x vdc
+ *
+ * GND GND GND GND 16-bit 3.3 & x.x vdc
+ *
+ *====================================================================
+ *
+ * CVS1 GND CCD1# open CardBus 3.3 vdc
+ *
+ * GND CVS2 open CCD2# CardBus x.x vdc
+ *
+ * GND CVS1 CCD2# open CardBus y.y vdc
+ *
+ * GND CVS2 GND CCD2# CardBus 3.3 & x.x vdc
+ *
+ * CVS2 GND open CCD1# CardBus x.x & y.y vdc
+ *
+ * GND CVS1 CCD2# open CardBus 3.3, x.x & y.y vdc
+ *
+ */
+static int cardtype_vcc_detect(void)
+{
+ uint32 data32;
+ int cardtype;
+
+ cardtype = MPI_CARDTYPE_NONE;
+ mpi->pcmcia_cntl1 = 0x0000A000; // Turn on the output enables and drive
+ // the CVS pins to 0.
+ data32 = mpi->pcmcia_cntl1;
+ switch (data32 & 0x00000003) // Test CD1# and CD2#, see if card is plugged in.
+ {
+ case 0x00000003: // No Card is in the slot.
+ printk("mpi: No Card is in the PCMCIA slot\n");
+ break;
+
+ case 0x00000002: // Partial insertion, No CD2#.
+ printk("mpi: Card in the PCMCIA slot partial insertion, no CD2 signal\n");
+ break;
+
+ case 0x00000001: // Partial insertion, No CD1#.
+ printk("mpi: Card in the PCMCIA slot partial insertion, no CD1 signal\n");
+ break;
+
+ case 0x00000000:
+ mpi->pcmcia_cntl1 = 0x0000A0C0; // Turn off the CVS output enables and
+ // float the CVS pins.
+ mdelay(1);
+ data32 = mpi->pcmcia_cntl1;
+ // Read the Register.
+ switch (data32 & 0x0000000C) // See what is on the CVS pins.
+ {
+ case 0x00000000: // CVS1 and CVS2 are tied to ground, only 1 option.
+ printk("mpi: Detected 3.3 & x.x 16-bit PCMCIA card\n");
+ cardtype = MPI_CARDTYPE_PCMCIA;
+ break;
+
+ case 0x00000004: // CVS1 is open or tied to CCD1/CCD2 and CVS2 is tied to ground.
+ // 2 valid voltage options.
+ switch (data32 & 0x00000003) // Test the values of CCD1 and CCD2.
+ {
+ case 0x00000003: // CCD1 and CCD2 are tied to 1 of the CVS pins.
+ // This is not a valid combination.
+ printk("mpi: Unknown card plugged into slot\n");
+ break;
+
+ case 0x00000002: // CCD2 is tied to either CVS1 or CVS2.
+ mpi->pcmcia_cntl1 = 0x0000A080; // Drive CVS1 to a 0.
+ mdelay(1);
+ data32 = mpi->pcmcia_cntl1;
+ if (data32 & 0x00000002) { // CCD2 is tied to CVS2, not valid.
+ printk("mpi: Unknown card plugged into slot\n");
+ } else { // CCD2 is tied to CVS1.
+ printk("mpi: Detected 3.3, x.x and y.y Cardbus card\n");
+ cardtype = MPI_CARDTYPE_CARDBUS;
+ }
+ break;
+
+ case 0x00000001: // CCD1 is tied to either CVS1 or CVS2.
+ // This is not a valid combination.
+ printk("mpi: Unknown card plugged into slot\n");
+ break;
+
+ case 0x00000000: // CCD1 and CCD2 are tied to ground.
+ printk("mpi: Detected x.x vdc 16-bit PCMCIA card\n");
+ cardtype = MPI_CARDTYPE_PCMCIA;
+ break;
+ }
+ break;
+
+ case 0x00000008: // CVS2 is open or tied to CCD1/CCD2 and CVS1 is tied to ground.
+ // 2 valid voltage options.
+ switch (data32 & 0x00000003) // Test the values of CCD1 and CCD2.
+ {
+ case 0x00000003: // CCD1 and CCD2 are tied to 1 of the CVS pins.
+ // This is not a valid combination.
+ printk("mpi: Unknown card plugged into slot\n");
+ break;
+
+ case 0x00000002: // CCD2 is tied to either CVS1 or CVS2.
+ mpi->pcmcia_cntl1 = 0x0000A040; // Drive CVS2 to a 0.
+ mdelay(1);
+ data32 = mpi->pcmcia_cntl1;
+ if (data32 & 0x00000002) { // CCD2 is tied to CVS1, not valid.
+ printk("mpi: Unknown card plugged into slot\n");
+ } else {// CCD2 is tied to CVS2.
+ printk("mpi: Detected 3.3 and x.x Cardbus card\n");
+ cardtype = MPI_CARDTYPE_CARDBUS;
+ }
+ break;
+
+ case 0x00000001: // CCD1 is tied to either CVS1 or CVS2.
+ // This is not a valid combination.
+ printk("mpi: Unknown card plugged into slot\n");
+ break;
+
+ case 0x00000000: // CCD1 and CCD2 are tied to ground.
+ cardtype = MPI_CARDTYPE_PCMCIA;
+ printk("mpi: Detected 3.3 vdc 16-bit PCMCIA card\n");
+ break;
+ }
+ break;
+
+ case 0x0000000C: // CVS1 and CVS2 are open or tied to CCD1/CCD2.
+ // 5 valid voltage options.
+
+ switch (data32 & 0x00000003) // Test the values of CCD1 and CCD2.
+ {
+ case 0x00000003: // CCD1 and CCD2 are tied to 1 of the CVS pins.
+ // This is not a valid combination.
+ printk("mpi: Unknown card plugged into slot\n");
+ break;
+
+ case 0x00000002: // CCD2 is tied to either CVS1 or CVS2.
+ // CCD1 is tied to ground.
+ mpi->pcmcia_cntl1 = 0x0000A040; // Drive CVS2 to a 0.
+ mdelay(1);
+ data32 = mpi->pcmcia_cntl1;
+ if (data32 & 0x00000002) { // CCD2 is tied to CVS1.
+ printk("mpi: Detected y.y vdc Cardbus card\n");
+ } else { // CCD2 is tied to CVS2.
+ printk("mpi: Detected x.x vdc Cardbus card\n");
+ }
+ cardtype = MPI_CARDTYPE_CARDBUS;
+ break;
+
+ case 0x00000001: // CCD1 is tied to either CVS1 or CVS2.
+ // CCD2 is tied to ground.
+
+ mpi->pcmcia_cntl1 = 0x0000A040; // Drive CVS2 to a 0.
+ mdelay(1);
+ data32 = mpi->pcmcia_cntl1;
+ if (data32 & 0x00000001) {// CCD1 is tied to CVS1.
+ printk("mpi: Detected 3.3 vdc Cardbus card\n");
+ } else { // CCD1 is tied to CVS2.
+ printk("mpi: Detected x.x and y.y Cardbus card\n");
+ }
+ cardtype = MPI_CARDTYPE_CARDBUS;
+ break;
+
+ case 0x00000000: // CCD1 and CCD2 are tied to ground.
+ cardtype = MPI_CARDTYPE_PCMCIA;
+ printk("mpi: Detected 5 vdc 16-bit PCMCIA card\n");
+ break;
+ }
+ break;
+
+ default:
+ printk("mpi: Unknown card plugged into slot\n");
+ break;
+
+ }
+ }
+ return cardtype;
+}
+
+/*
+ * mpi_DetectPcCard: Detect the plugged in PC-Card
+ * Return: < 0 => Unknown card detected
+ * 0 => No card detected
+ * 1 => 16-bit card detected
+ * 2 => 32-bit CardBus card detected
+ */
+static int mpi_DetectPcCard(void)
+{
+ int cardtype;
+
+ cardtype = cardtype_vcc_detect();
+ switch(cardtype) {
+ case MPI_CARDTYPE_PCMCIA:
+ mpi->pcmcia_cntl1 &= ~0x0000e000; // disable enable bits
+ //mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 & ~PCCARD_CARD_RESET);
+ mpi->pcmcia_cntl1 |= (PCMCIA_ENABLE | PCMCIA_GPIO_ENABLE);
+ mpi_InitPcmciaSpace();
+ mpi_ResetPcCard(cardtype, FALSE);
+ // Hold card in reset for 10ms
+ mdelay(10);
+ mpi_ResetPcCard(cardtype, TRUE);
+ // Let card come out of reset
+ mdelay(100);
+ break;
+ case MPI_CARDTYPE_CARDBUS:
+ // 8 => CardBus Enable
+ // 1 => PCI Slot Number
+ // C => Float VS1 & VS2
+ mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 & 0xFFFF0000) |
+ CARDBUS_ENABLE |
+ (CARDBUS_SLOT << 8)|
+ VS2_OEN |
+ VS1_OEN;
+ /* access to this memory window will be to/from CardBus */
+ mpi->l2pmremap1 |= CARDBUS_MEM;
+
+ // Need to reset the Cardbus Card. There's no CardManager to do this,
+ // and we need to be ready for PCI configuration.
+ mpi_ResetPcCard(cardtype, FALSE);
+ // Hold card in reset for 10ms
+ mdelay(10);
+ mpi_ResetPcCard(cardtype, TRUE);
+ // Let card come out of reset
+ mdelay(100);
+ break;
+ default:
+ break;
+ }
+ return cardtype;
+}
+
+static int mpi_init(void)
+{
+ unsigned long data;
+ unsigned int chipid, chiprev, sdramsize;
+
+ printk("Broadcom BCM963xx MPI\n");
+ chipid = (PERF->RevID & 0xFFFF0000) >> 16;
+ chiprev = (PERF->RevID & 0xFF);
+
+ if (boot_loader_type == BOOT_LOADER_CFE)
+ sdramsize = boot_mem_map.map[0].size;
+ else
+ sdramsize = 0x01000000;
+ /*
+ * Init the pci interface
+ */
+ data = GPIO->GPIOMode; // GPIO mode register
+ data |= GROUP2_PCI | GROUP1_MII_PCCARD; // PCI internal arbiter + Cardbus
+ GPIO->GPIOMode = data; // PCI internal arbiter
+
+ /*
+ * In the BCM6348 CardBus support is defaulted to Slot 0
+ * because there is no external IDSEL for CardBus. To disable
+ * the CardBus and allow a standard PCI card in Slot 0
+ * set the cbus_idsel field to 0x1f.
+ */
+ /*
+ uData = mpi->pcmcia_cntl1;
+ uData |= CARDBUS_IDSEL;
+ mpi->pcmcia_cntl1 = uData;
+ */
+ // Setup PCI I/O Window range. Give 64K to PCI I/O
+ mpi->l2piorange = ~(BCM_PCI_IO_SIZE_64KB-1);
+ // UBUS to PCI I/O base address
+ mpi->l2piobase = BCM_PCI_IO_BASE & BCM_PCI_ADDR_MASK;
+ // UBUS to PCI I/O Window remap
+ mpi->l2pioremap = (BCM_PCI_IO_BASE | MEM_WINDOW_EN);
+
+ // enable PCI related GPIO pins and data swap between system and PCI bus
+ mpi->locbuscntrl = (EN_PCI_GPIO | DIR_U2P_NOSWAP);
+
+ /* Enable 6348 BusMaster and Memory access mode */
+ data = mpi_GetLocalPciConfigReg(PCI_COMMAND);
+ data |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ mpi_SetLocalPciConfigReg(PCI_COMMAND, data);
+
+ /* Configure two 16 MByte PCI to System memory regions. */
+ /* These memory regions are used when PCI device is a bus master */
+ /* Accesses to the SDRAM from PCI bus will be "byte swapped" for this region */
+ mpi_SetLocalPciConfigReg(PCI_BASE_ADDRESS_3, BCM_HOST_MEM_SPACE1);
+ mpi->sp0remap = 0x0;
+
+ /* Accesses to the SDRAM from PCI bus will not be "byte swapped" for this region */
+ mpi_SetLocalPciConfigReg(PCI_BASE_ADDRESS_4, BCM_HOST_MEM_SPACE2);
+ mpi->sp1remap = 0x0;
+ mpi->pcimodesel |= (PCI_BAR2_NOSWAP | 0x40);
+
+ if ((chipid == 0x6348) && (chiprev == 0xb0)) {
+ mpi->sp0range = ~(sdramsize-1);
+ mpi->sp1range = ~(sdramsize-1);
+ }
+ /*
+ * Change 6348 PCI Cfg Reg. offset 0x40 to PCI memory read retry count infinity
+ * by set 0 in bit 8~15. This resolve read Bcm4306 srom return 0xffff in
+ * first read.
+ */
+ data = mpi_GetLocalPciConfigReg(BRCM_PCI_CONFIG_TIMER);
+ data &= ~BRCM_PCI_CONFIG_TIMER_RETRY_MASK;
+ data |= 0x00000080;
+ mpi_SetLocalPciConfigReg(BRCM_PCI_CONFIG_TIMER, data);
+
+ /* enable pci interrupt */
+ mpi->locintstat |= (EXT_PCI_INT << 16);
+
+ mpi_DetectPcCard();
+
+ ioport_resource.start = BCM_PCI_IO_BASE;
+ ioport_resource.end = BCM_PCI_IO_BASE + BCM_PCI_IO_SIZE_64KB;
+
+#if defined(CONFIG_USB)
+ PERF->blkEnables |= USBH_CLK_EN;
+ mdelay(100);
+ *USBH_NON_OHCI = NON_OHCI_BYTE_SWAP;
+#endif
+
+ return 0;
+}
+
+void __init plat_mem_setup(void)
+{
+ _machine_restart = brcm_machine_restart;
+ _machine_halt = brcm_machine_halt;
+ pm_power_off = brcm_machine_halt;
+
+ board_time_init = brcm_time_init;
+
+ /* mpi initialization */
+ mpi_init();
+}
diff --git a/target/linux/brcm63xx/files/arch/mips/bcm963xx/time.c b/target/linux/brcm63xx/files/arch/mips/bcm963xx/time.c
new file mode 100644
index 0000000000..8b82ada371
--- /dev/null
+++ b/target/linux/brcm63xx/files/arch/mips/bcm963xx/time.c
@@ -0,0 +1,116 @@
+/*
+<:copyright-gpl
+ Copyright 2004 Broadcom Corp. All Rights Reserved.
+
+ This program is free software; you can distribute it and/or modify it
+ under the terms of the GNU General Public License (Version 2) as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+:>
+*/
+/*
+ * Setup time for Broadcom 963xx MIPS boards
+ */
+
+#include <linux/autoconf.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+
+#include <asm/mipsregs.h>
+#include <asm/ptrace.h>
+#include <asm/div64.h>
+#include <asm/time.h>
+
+#include <6348_map_part.h>
+#include <6348_intr.h>
+#include <bcm_map_part.h>
+#include <bcm_intr.h>
+
+static unsigned long r4k_offset; /* Amount to increment compare reg each time */
+static unsigned long r4k_cur; /* What counter should be at next timer irq */
+
+/* *********************************************************************
+ * calculateCpuSpeed()
+ * Calculate the BCM6348 CPU speed by reading the PLL strap register
+ * and applying the following formula:
+ * cpu_clk = (.25 * 64MHz freq) * (N1 + 1) * (N2 + 2) / (M1_CPU + 1)
+ * Input parameters:
+ * none
+ * Return value:
+ * none
+ ********************************************************************* */
+
+static inline unsigned long __init calculateCpuSpeed(void)
+{
+ u32 pllStrap = PERF->PllStrap;
+ int n1 = (pllStrap & PLL_N1_MASK) >> PLL_N1_SHFT;
+ int n2 = (pllStrap & PLL_N2_MASK) >> PLL_N2_SHFT;
+ int m1cpu = (pllStrap & PLL_M1_CPU_MASK) >> PLL_M1_CPU_SHFT;
+
+ return (16 * (n1 + 1) * (n2 + 2) / (m1cpu + 1)) * 1000000;
+}
+
+
+static inline unsigned long __init cal_r4koff(void)
+{
+ mips_hpt_frequency = calculateCpuSpeed() / 2;
+ return (mips_hpt_frequency / HZ);
+}
+
+
+/*
+ * There are a lot of conceptually broken versions of the MIPS timer interrupt
+ * handler floating around. This one is rather different, but the algorithm
+ * is provably more robust.
+ */
+irqreturn_t brcm_timer_interrupt(struct pt_regs *regs)
+{
+ int irq = MIPS_TIMER_INT;
+
+ irq_enter();
+ kstat_this_cpu.irqs[irq]++;
+
+ timer_interrupt(irq, regs);
+ irq_exit();
+ return IRQ_HANDLED;
+}
+
+
+void __init brcm_time_init(void)
+{
+ unsigned int est_freq, flags;
+ local_irq_save(flags);
+
+ printk("calculating r4koff... ");
+ r4k_offset = cal_r4koff();
+ printk("%08lx(%d)\n", r4k_offset, (int)r4k_offset);
+
+ est_freq = 2 * r4k_offset * HZ;
+ est_freq += 5000; /* round */
+ est_freq -= est_freq % 10000;
+ printk("CPU frequency %d.%02d MHz\n", est_freq / 1000000,
+ (est_freq % 1000000) * 100 / 1000000);
+ local_irq_restore(flags);
+}
+
+
+void __init plat_timer_setup(struct irqaction *irq)
+{
+ r4k_cur = (read_c0_count() + r4k_offset);
+ write_c0_compare(r4k_cur);
+ set_c0_status(IE_IRQ5);
+}
diff --git a/target/linux/brcm63xx/files/arch/mips/bcm963xx/wdt.c b/target/linux/brcm63xx/files/arch/mips/bcm963xx/wdt.c
new file mode 100644
index 0000000000..0ea36a67f0
--- /dev/null
+++ b/target/linux/brcm63xx/files/arch/mips/bcm963xx/wdt.c
@@ -0,0 +1,246 @@
+/*
+ * Watchdog driver for the BCM963xx devices
+ *
+ * Copyright (C) 2007 OpenWrt.org
+ * Florian Fainelli <florian@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.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/notifier.h>
+#include <linux/watchdog.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/completion.h>
+#include <linux/ioport.h>
+
+typedef struct bcm963xx_timer {
+ unsigned short unused0;
+ unsigned char timer_mask;
+#define TIMER0EN 0x01
+#define TIMER1EN 0x02
+#define TIMER2EN 0x04
+ unsigned char timer_ints;
+#define TIMER0 0x01
+#define TIMER1 0x02
+#define TIMER2 0x04
+#define WATCHDOG 0x08
+ unsigned long timer_ctl0;
+ unsigned long timer_ctl1;
+ unsigned long timer_ctl2;
+#define TIMERENABLE 0x80000000
+#define RSTCNTCLR 0x40000000
+ unsigned long timer_cnt0;
+ unsigned long timer_cnt1;
+ unsigned long timer_cnt2;
+ unsigned long wdt_def_count;
+
+ /* Write 0xff00 0x00ff to Start timer
+ * Write 0xee00 0x00ee to Stop and re-load default count
+ * Read from this register returns current watch dog count
+ */
+ unsigned long wdt_ctl;
+
+ /* Number of 40-MHz ticks for WD Reset pulse to last */
+ unsigned long wdt_rst_count;
+} bcm963xx_timer;
+
+static struct bcm963xx_wdt_device {
+ struct completion stop;
+ volatile int running;
+ struct timer_list timer;
+ volatile int queue;
+ int default_ticks;
+ unsigned long inuse;
+} bcm963xx_wdt_device;
+
+static int ticks = 1000;
+
+#define WDT_BASE 0xfffe0200
+#define WDT ((volatile bcm963xx_timer * const) WDT_BASE)
+
+#define BCM963XX_INTERVAL (HZ/10+1)
+
+static void bcm963xx_wdt_trigger(unsigned long unused)
+{
+ if (bcm963xx_wdt_device.running)
+ ticks--;
+
+ /* Load the default ticking value into the reset counter register */
+ WDT->wdt_rst_count = bcm963xx_wdt_device.default_ticks;
+
+ if (bcm963xx_wdt_device.queue && ticks) {
+ bcm963xx_wdt_device.timer.expires = jiffies + BCM963XX_INTERVAL;
+ add_timer(&bcm963xx_wdt_device.timer);
+ }
+ else {
+ complete(&bcm963xx_wdt_device.stop);
+ }
+}
+
+static void bcm963xx_wdt_reset(void)
+{
+ ticks = bcm963xx_wdt_device.default_ticks;
+ /* Also reload default count */
+ WDT->wdt_def_count = ticks;
+ WDT->wdt_ctl = 0xee00;
+ WDT->wdt_ctl = 0x00ee;
+}
+
+static void bcm963xx_wdt_start(void)
+{
+ if (!bcm963xx_wdt_device.queue) {
+ bcm963xx_wdt_device.queue;
+ /* Enable the watchdog by writing 0xff00 ,then 0x00ff to the control register */
+ WDT->wdt_ctl = 0xff00;
+ WDT->wdt_ctl = 0x00ff;
+ bcm963xx_wdt_device.timer.expires = jiffies + BCM963XX_INTERVAL;
+ add_timer(&bcm963xx_wdt_device.timer);
+ }
+ bcm963xx_wdt_device.running++;
+}
+
+static int bcm963xx_wdt_stop(void)
+{
+ if (bcm963xx_wdt_device.running)
+ bcm963xx_wdt_device.running = 0;
+
+ ticks = bcm963xx_wdt_device.default_ticks;
+
+ /* Stop the watchdog by writing 0xee00 then 0x00ee to the control register */
+ WDT->wdt_ctl = 0xee00;
+ WDT->wdt_ctl = 0x00ee;
+
+ return -EIO;
+}
+
+static int bcm963xx_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(0, &bcm963xx_wdt_device.inuse))
+ return -EBUSY;
+ return nonseekable_open(inode, file);
+}
+
+static int bcm963xx_wdt_release(struct inode *inode, struct file *file)
+{
+ clear_bit(0, &bcm963xx_wdt_device.inuse);
+ return 0;
+}
+
+static int bcm963xx_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ unsigned int value;
+
+ static struct watchdog_info ident = {
+ .options = WDIOF_CARDRESET,
+ .identity = "BCM963xx WDT",
+ };
+
+ switch (cmd) {
+ case WDIOC_KEEPALIVE:
+ bcm963xx_wdt_reset();
+ break;
+ case WDIOC_GETSTATUS:
+ /* Reading from the control register will return the current value */
+ value = WDT->wdt_ctl;
+ if ( copy_to_user(argp, &value, sizeof(int)) )
+ return -EFAULT;
+ break;
+ case WDIOC_GETSUPPORT:
+ if ( copy_to_user(argp, &ident, sizeof(ident)) )
+ return -EFAULT;
+ break;
+ case WDIOC_SETOPTIONS:
+ if ( copy_from_user(&value, argp, sizeof(int)) )
+ return -EFAULT;
+ switch(value) {
+ case WDIOS_ENABLECARD:
+ bcm963xx_wdt_start();
+ break;
+ case WDIOS_DISABLECARD:
+ bcm963xx_wdt_stop();
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int bcm963xx_wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+ if (!count)
+ return -EIO;
+ bcm963xx_wdt_reset();
+ return count;
+}
+
+static const struct file_operations bcm963xx_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = bcm963xx_wdt_write,
+ .ioctl = bcm963xx_wdt_ioctl,
+ .open = bcm963xx_wdt_open,
+ .release = bcm963xx_wdt_release,
+};
+
+static struct miscdevice bcm963xx_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &bcm963xx_wdt_fops,
+};
+
+static void __exit bcm963xx_wdt_exit(void)
+{
+ if (bcm963xx_wdt_device.queue ){
+ bcm963xx_wdt_device.queue = 0;
+ wait_for_completion(&bcm963xx_wdt_device.stop);
+ }
+ misc_deregister(&bcm963xx_wdt_miscdev);
+}
+
+static int __init bcm963xx_wdt_init(void)
+{
+ int ret = 0;
+
+ printk("Broadcom BCM963xx Watchdog timer\n");
+
+ ret = misc_register(&bcm963xx_wdt_miscdev);
+ if (ret) {
+ printk(KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n", WATCHDOG_MINOR, ret);
+ return ret;
+ }
+ init_completion(&bcm963xx_wdt_device.stop);
+ bcm963xx_wdt_device.queue = 0;
+
+ clear_bit(0, &bcm963xx_wdt_device.inuse);
+
+ init_timer(&bcm963xx_wdt_device.timer);
+ bcm963xx_wdt_device.timer.function = bcm963xx_wdt_trigger;
+ bcm963xx_wdt_device.timer.data = 0;
+
+ bcm963xx_wdt_device.default_ticks = ticks;
+ return ret;
+}
+
+
+module_init(bcm963xx_wdt_init);
+module_exit(bcm963xx_wdt_exit);
+
+MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
+MODULE_DESCRIPTION("Broadcom BCM963xx Watchdog driver");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/brcm63xx/files/arch/mips/cfe/Makefile b/target/linux/brcm63xx/files/arch/mips/cfe/Makefile
new file mode 100644
index 0000000000..d9f046adf3
--- /dev/null
+++ b/target/linux/brcm63xx/files/arch/mips/cfe/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Broadcom Common Firmware Environment support
+#
+
+obj-y += cfe.o
diff --git a/target/linux/brcm63xx/files/arch/mips/cfe/cfe.c b/target/linux/brcm63xx/files/arch/mips/cfe/cfe.c
new file mode 100644
index 0000000000..6d16111e1c
--- /dev/null
+++ b/target/linux/brcm63xx/files/arch/mips/cfe/cfe.c
@@ -0,0 +1,533 @@
+/*
+ * Broadcom Common Firmware Environment (CFE) support
+ *
+ * Copyright 2000, 2001, 2002
+ * Broadcom Corporation. All rights reserved.
+ *
+ * Copyright (C) 2006 Michael Buesch
+ *
+ * Original Authors: Mitch Lichtenberg, Chris Demetriou
+ *
+ * This software is furnished under license and may be used and copied only
+ * in accordance with the following terms and conditions. Subject to these
+ * conditions, you may download, copy, install, use, modify and distribute
+ * modified or unmodified copies of this software in source and/or binary
+ * form. No title or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce and
+ * retain this copyright notice and list of conditions as they appear in
+ * the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or logo of
+ * Broadcom Corporation. The "Broadcom Corporation" name may not be
+ * used to endorse or promote products derived from this software
+ * without the prior written permission of Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
+ * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
+ * LIABLE FOR 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), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <asm/cfe.h>
+
+#include "cfe_private.h"
+
+
+static cfe_uint_t cfe_handle;
+static int (*cfe_trampoline)(long handle, long iocb);
+
+
+#include <linux/kernel.h>
+
+void __init cfe_setup(unsigned long fwarg0, unsigned long fwarg1,
+ unsigned long fwarg2, unsigned long fwarg3)
+{
+ if (fwarg3 == 0x80300000) {
+ /* WRT54G workaround */
+ fwarg3 = CFE_EPTSEAL;
+ fwarg2 = 0xBFC00500;
+ }
+ if (fwarg3 != CFE_EPTSEAL) {
+ /* We are not booted from CFE */
+ return;
+ }
+ if (fwarg1 == 0) {
+ /* We are on the boot CPU */
+ cfe_handle = (cfe_uint_t)fwarg0;
+ cfe_trampoline = CFE_TO_PTR(fwarg2);
+ }
+}
+
+int cfe_vprintk(const char *fmt, va_list args)
+{
+ static char buffer[1024];
+ static DEFINE_SPINLOCK(lock);
+ static const char pfx[] = "CFE-console: ";
+ static const size_t pfx_len = sizeof(pfx) - 1;
+ unsigned long flags;
+ int len, cnt, pos;
+ int handle;
+ int res;
+
+ if (!cfe_present())
+ return -ENODEV;
+
+ spin_lock_irqsave(&lock, flags);
+ handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
+ if (CFE_ISERR(handle)) {
+ len = -EIO;
+ goto out;
+ }
+ strcpy(buffer, pfx);
+ len = vscnprintf(buffer + pfx_len,
+ sizeof(buffer) - pfx_len - 2,
+ fmt, args);
+ len += pfx_len;
+ /* The CFE console requires CR-LF line-ends.
+ * Add a CR, if we only terminate lines with a LF.
+ * This does only fix CR-LF at the end of the string.
+ * So for multiple lines, use multiple cfe_vprintk calls.
+ */
+ if (len > 1 &&
+ buffer[len - 1] == '\n' && buffer[len - 2] != '\r') {
+ buffer[len - 1] = '\r';
+ buffer[len] = '\n';
+ len += 1;
+ }
+ cnt = len;
+ pos = 0;
+ while (cnt > 0) {
+ res = cfe_write(handle, buffer + pos, len - pos);
+ if (CFE_ISERR(res)) {
+ len = -EIO;
+ goto out;
+ }
+ cnt -= res;
+ pos += res;
+ }
+out:
+ spin_unlock_irqrestore(&lock, flags);
+
+ return len;
+}
+
+int cfe_printk(const char *fmt, ...)
+{
+ va_list args;
+ int res;
+
+ va_start(args, fmt);
+ res = cfe_vprintk(fmt, args);
+ va_end(args);
+
+ return res;
+}
+
+static int cfe_iocb_dispatch(struct cfe_iocb *iocb)
+{
+ if (!cfe_present())
+ return CFE_ERR_UNSUPPORTED;
+ return cfe_trampoline((long)cfe_handle, (long)iocb);
+}
+
+int cfe_present(void)
+{
+ return (cfe_trampoline != NULL);
+}
+
+int cfe_close(int handle)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_DEV_CLOSE;
+ iocb.handle = handle;
+
+ err = cfe_iocb_dispatch(&iocb);
+
+ return (CFE_ISERR(err)) ? err : iocb.status;
+}
+
+int cfe_cpu_start(int cpu, void (*fn)(void), long sp, long gp, long a1)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_FW_CPUCTL;
+ iocb.psize = sizeof(struct cfe_iocb_cpuctl);
+ iocb.cpuctl.number = cpu;
+ iocb.cpuctl.command = CFE_CPU_CMD_START;
+ iocb.cpuctl.gp = gp;
+ iocb.cpuctl.sp = sp;
+ iocb.cpuctl.a1 = a1;
+ iocb.cpuctl.start_addr = (long)fn;
+
+ err = cfe_iocb_dispatch(&iocb);
+
+ return (CFE_ISERR(err)) ? err : iocb.status;
+}
+
+int cfe_cpu_stop(int cpu)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_FW_CPUCTL;
+ iocb.psize = sizeof(struct cfe_iocb_cpuctl);
+ iocb.cpuctl.number = cpu;
+ iocb.cpuctl.command = CFE_CPU_CMD_STOP;
+
+ err = cfe_iocb_dispatch(&iocb);
+
+ return (CFE_ISERR(err)) ? err : iocb.status;
+}
+
+int cfe_enumenv(int idx, char *name, int namelen, char *val, int vallen)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_ENV_ENUM;
+ iocb.psize = sizeof(struct cfe_iocb_envbuf);
+ iocb.envbuf.index = idx;
+ iocb.envbuf.name = PTR_TO_CFE(name);
+ iocb.envbuf.name_len = namelen;
+ iocb.envbuf.val = PTR_TO_CFE(val);
+ iocb.envbuf.val_len = vallen;
+
+ err = cfe_iocb_dispatch(&iocb);
+
+ return (CFE_ISERR(err)) ? err : iocb.status;
+}
+
+int cfe_enumdev(int idx, char *name, int namelen)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+
+ iocb.fcode = CFE_CMD_DEV_ENUM;
+ iocb.psize = sizeof(struct cfe_iocb_envbuf);
+ iocb.envbuf.index = idx;
+ iocb.envbuf.name = PTR_TO_CFE(name);
+ iocb.envbuf.name_len = namelen;
+
+ err = cfe_iocb_dispatch(&iocb);
+
+ return (CFE_ISERR(err)) ? err : iocb.status;
+}
+
+int cfe_enummem(int idx, int flags, u64 *start, u64 *length,
+ u64 *type)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+
+ iocb.fcode = CFE_CMD_FW_MEMENUM;
+ iocb.flags = flags;
+ iocb.psize = sizeof(struct cfe_iocb_meminfo);
+ iocb.meminfo.index = idx;
+
+ err = cfe_iocb_dispatch(&iocb);
+ if (CFE_ISERR(err))
+ return err;
+ if (!CFE_ISERR(iocb.status)) {
+ *start = iocb.meminfo.addr;
+ *length = iocb.meminfo.size;
+ *type = iocb.meminfo.type;
+ }
+
+ return iocb.status;
+}
+
+int cfe_exit(int warm, int status)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+printk("CFE REBOOT\n");
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_FW_RESTART;
+ if (warm)
+ iocb.flags = CFE_FLG_WARMSTART;
+ iocb.psize = sizeof(struct cfe_iocb_exitstat);
+ iocb.exitstat.status = status;
+
+printk("CALL\n");
+ err = cfe_iocb_dispatch(&iocb);
+printk("DONE\n");
+
+ return (CFE_ISERR(err)) ? err : iocb.status;
+}
+
+int cfe_flushcache(int flags)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_FW_FLUSHCACHE;
+ iocb.flags = flags;
+
+ err = cfe_iocb_dispatch(&iocb);
+
+ return (CFE_ISERR(err)) ? err : iocb.status;
+}
+
+int cfe_getdevinfo(char *name)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_DEV_GETINFO;
+ iocb.psize = sizeof(struct cfe_iocb_buf);
+ iocb.buffer.ptr = PTR_TO_CFE(name);
+ iocb.buffer.length = strlen(name);
+
+ err = cfe_iocb_dispatch(&iocb);
+ if (CFE_ISERR(err))
+ return err;
+ if (CFE_ISERR(iocb.status))
+ return iocb.status;
+
+ return iocb.buffer.devflags;
+}
+
+int cfe_getenv(char *name, char *dest, int destlen)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ dest[0] = '\0';
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_ENV_GET;
+ iocb.psize = sizeof(struct cfe_iocb_envbuf);
+ iocb.envbuf.name = PTR_TO_CFE(name);
+ iocb.envbuf.name_len = strlen(name);
+ iocb.envbuf.val = PTR_TO_CFE(dest);
+ iocb.envbuf.val_len = destlen;
+
+ err = cfe_iocb_dispatch(&iocb);
+
+ return (CFE_ISERR(err)) ? err : iocb.status;
+}
+
+int cfe_getfwinfo(struct cfe_fwinfo *info)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_FW_GETINFO;
+ iocb.psize = sizeof(struct cfe_iocb_fwinfo);
+
+ err = cfe_iocb_dispatch(&iocb);
+ if (CFE_ISERR(err))
+ return err;
+ if (CFE_ISERR(iocb.status))
+ return err;
+
+ info->version = iocb.fwinfo.version;
+ info->totalmem = iocb.fwinfo.totalmem;
+ info->flags = iocb.fwinfo.flags;
+ info->boardid = iocb.fwinfo.boardid;
+ info->bootarea_va = iocb.fwinfo.bootarea_va;
+ info->bootarea_pa = iocb.fwinfo.bootarea_pa;
+ info->bootarea_size = iocb.fwinfo.bootarea_size;
+
+ return iocb.status;
+}
+
+int cfe_getstdhandle(int handletype)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_DEV_GETHANDLE;
+ iocb.flags = handletype;
+
+ err = cfe_iocb_dispatch(&iocb);
+ if (CFE_ISERR(err))
+ return err;
+ if (CFE_ISERR(iocb.status))
+ return iocb.status;
+
+ return iocb.handle;
+}
+
+int cfe_getticks(s64 *ticks)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_FW_GETTIME;
+ iocb.psize = sizeof(struct cfe_iocb_time);
+
+ err = cfe_iocb_dispatch(&iocb);
+ if (CFE_ISERR(err))
+ return err;
+ if (!CFE_ISERR(iocb.status))
+ *ticks = iocb.time.ticks;
+
+ return iocb.status;
+}
+
+int cfe_inpstat(int handle)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_DEV_INPSTAT;
+ iocb.handle = handle;
+ iocb.psize = sizeof(struct cfe_iocb_inpstat);
+
+ err = cfe_iocb_dispatch(&iocb);
+ if (CFE_ISERR(err))
+ return err;
+ if (CFE_ISERR(iocb.status))
+ return iocb.status;
+
+ return iocb.inpstat.status;
+}
+
+int cfe_ioctl(int handle, unsigned int ioctlnum,
+ unsigned char *buffer, int length,
+ int *retlen, u64 offset)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_DEV_IOCTL;
+ iocb.handle = handle;
+ iocb.psize = sizeof(struct cfe_iocb_buf);
+ iocb.buffer.offset = offset;
+ iocb.buffer.ioctlcmd = ioctlnum;
+ iocb.buffer.ptr = PTR_TO_CFE(buffer);
+ iocb.buffer.length = length;
+
+ err = cfe_iocb_dispatch(&iocb);
+ if (CFE_ISERR(err))
+ return err;
+ if (CFE_ISERR(iocb.status))
+ return iocb.status;
+ if (retlen)
+ *retlen = iocb.buffer.retlen;
+
+ return iocb.status;
+}
+
+int cfe_open(char *name)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_DEV_OPEN;
+ iocb.psize = sizeof(struct cfe_iocb_buf);
+ iocb.buffer.ptr = PTR_TO_CFE(name);
+ iocb.buffer.length = strlen(name);
+
+ err = cfe_iocb_dispatch(&iocb);
+ if (CFE_ISERR(err))
+ return err;
+ if (CFE_ISERR(iocb.status))
+ return iocb.status;
+
+ return iocb.handle;
+}
+
+int cfe_read(int handle, unsigned char *buffer, int length)
+{
+ return cfe_readblk(handle, 0, buffer, length);
+}
+
+int cfe_readblk(int handle, s64 offset, unsigned char *buffer, int length)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_DEV_READ;
+ iocb.handle = handle;
+ iocb.psize = sizeof(struct cfe_iocb_buf);
+ iocb.buffer.offset = offset;
+ iocb.buffer.ptr = PTR_TO_CFE(buffer);
+ iocb.buffer.length = length;
+
+ err = cfe_iocb_dispatch(&iocb);
+ if (CFE_ISERR(err))
+ return err;
+ if (CFE_ISERR(iocb.status))
+ return iocb.status;
+
+ return iocb.buffer.retlen;
+}
+
+int cfe_setenv(char *name, char *val)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_ENV_SET;
+ iocb.psize = sizeof(struct cfe_iocb_envbuf);
+ iocb.envbuf.name = PTR_TO_CFE(name);
+ iocb.envbuf.name_len = strlen(name);
+ iocb.envbuf.val = PTR_TO_CFE(val);
+ iocb.envbuf.val_len = strlen(val);
+
+ err = cfe_iocb_dispatch(&iocb);
+
+ return (CFE_ISERR(err)) ? err : iocb.status;
+}
+
+int cfe_write(int handle, unsigned char *buffer, int length)
+{
+ return cfe_writeblk(handle, 0, buffer, length);
+}
+
+int cfe_writeblk(int handle, s64 offset, unsigned char *buffer, int length)
+{
+ struct cfe_iocb iocb;
+ int err;
+
+ memset(&iocb, 0, sizeof(iocb));
+ iocb.fcode = CFE_CMD_DEV_WRITE;
+ iocb.handle = handle;
+ iocb.psize = sizeof(struct cfe_iocb_buf);
+ iocb.buffer.offset = offset;
+ iocb.buffer.ptr = PTR_TO_CFE(buffer);
+ iocb.buffer.length = length;
+
+ err = cfe_iocb_dispatch(&iocb);
+ if (CFE_ISERR(err))
+ return err;
+ if (CFE_ISERR(iocb.status))
+ return iocb.status;
+
+ return iocb.buffer.retlen;
+}
diff --git a/target/linux/brcm63xx/files/arch/mips/cfe/cfe_private.h b/target/linux/brcm63xx/files/arch/mips/cfe/cfe_private.h
new file mode 100644
index 0000000000..0a604d3bbd
--- /dev/null
+++ b/target/linux/brcm63xx/files/arch/mips/cfe/cfe_private.h
@@ -0,0 +1,176 @@
+/*
+ * Broadcom Common Firmware Environment (CFE) support
+ *
+ * Copyright 2000, 2001, 2002
+ * Broadcom Corporation. All rights reserved.
+ *
+ * Copyright (C) 2006 Michael Buesch
+ *
+ * Original Authors: Mitch Lichtenberg, Chris Demetriou
+ *
+ * This software is furnished under license and may be used and copied only
+ * in accordance with the following terms and conditions. Subject to these
+ * conditions, you may download, copy, install, use, modify and distribute
+ * modified or unmodified copies of this software in source and/or binary
+ * form. No title or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce and
+ * retain this copyright notice and list of conditions as they appear in
+ * the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or logo of
+ * Broadcom Corporation. The "Broadcom Corporation" name may not be
+ * used to endorse or promote products derived from this software
+ * without the prior written permission of Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
+ * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
+ * LIABLE FOR 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), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LINUX_CFE_PRIVATE_H_
+#define LINUX_CFE_PRIVATE_H_
+
+#ifndef __ASSEMBLY__
+
+/* Seal indicating CFE's presence, passed to the kernel. */
+#define CFE_EPTSEAL 0x43464531
+
+#define CFE_CMD_FW_GETINFO 0
+#define CFE_CMD_FW_RESTART 1
+#define CFE_CMD_FW_BOOT 2
+#define CFE_CMD_FW_CPUCTL 3
+#define CFE_CMD_FW_GETTIME 4
+#define CFE_CMD_FW_MEMENUM 5
+#define CFE_CMD_FW_FLUSHCACHE 6
+
+#define CFE_CMD_DEV_GETHANDLE 9
+#define CFE_CMD_DEV_ENUM 10
+#define CFE_CMD_DEV_OPEN 11
+#define CFE_CMD_DEV_INPSTAT 12
+#define CFE_CMD_DEV_READ 13
+#define CFE_CMD_DEV_WRITE 14
+#define CFE_CMD_DEV_IOCTL 15
+#define CFE_CMD_DEV_CLOSE 16
+#define CFE_CMD_DEV_GETINFO 17
+
+#define CFE_CMD_ENV_ENUM 20
+#define CFE_CMD_ENV_GET 22
+#define CFE_CMD_ENV_SET 23
+#define CFE_CMD_ENV_DEL 24
+
+#define CFE_CMD_MAX 32
+
+#define CFE_CMD_VENDOR_USE 0x8000 /* codes above this are for customer use */
+
+typedef u64 cfe_uint_t;
+typedef s64 cfe_int_t;
+typedef s64 cfe_ptr_t;
+
+/* Cast a pointer from native to CFE-API pointer and back */
+#define CFE_TO_PTR(p) ((void *)(unsigned long)(p))
+#define PTR_TO_CFE(p) ((cfe_ptr_t)(unsigned long)(p))
+
+struct cfe_iocb_buf {
+ cfe_uint_t offset; /* offset on device (bytes) */
+ cfe_ptr_t ptr; /* pointer to a buffer */
+ cfe_uint_t length; /* length of this buffer */
+ cfe_uint_t retlen; /* returned length (for read ops) */
+ union {
+ cfe_uint_t ioctlcmd; /* IOCTL command (used only for IOCTLs) */
+ cfe_uint_t devflags; /* Returned device info flags */
+ };
+};
+
+struct cfe_iocb_inpstat {
+ cfe_uint_t status; /* 1 means input available */
+};
+
+struct cfe_iocb_envbuf {
+ cfe_int_t index; /* 0-based enumeration index */
+ cfe_ptr_t name; /* name string buffer */
+ cfe_int_t name_len; /* size of name buffer */
+ cfe_ptr_t val; /* value string buffer */
+ cfe_int_t val_len; /* size of value string buffer */
+};
+
+struct cfe_iocb_cpuctl {
+ cfe_uint_t number; /* cpu number to control */
+ cfe_uint_t command; /* command to issue to CPU */
+ cfe_uint_t start_addr; /* CPU start address */
+ cfe_uint_t gp; /* starting GP value */
+ cfe_uint_t sp; /* starting SP value */
+ cfe_uint_t a1; /* starting A1 value */
+};
+
+struct cfe_iocb_time {
+ cfe_int_t ticks; /* current time in ticks */
+};
+
+struct cfe_iocb_exitstat {
+ cfe_int_t status;
+};
+
+struct cfe_iocb_meminfo {
+ cfe_int_t index; /* 0-based enumeration index */
+ cfe_int_t type; /* type of memory block */
+ cfe_uint_t addr; /* physical start address */
+ cfe_uint_t size; /* block size */
+};
+
+struct cfe_iocb_fwinfo {
+ cfe_int_t version; /* major, minor, eco version */
+ cfe_int_t totalmem; /* total installed mem */
+ cfe_int_t flags; /* various flags */
+ cfe_int_t boardid; /* board ID */
+ cfe_int_t bootarea_va; /* VA of boot area */
+ cfe_int_t bootarea_pa; /* PA of boot area */
+ cfe_int_t bootarea_size; /* size of boot area */
+ cfe_int_t reserved1;
+ cfe_int_t reserved2;
+ cfe_int_t reserved3;
+};
+
+/* CFE I/O Control Block */
+struct cfe_iocb {
+ cfe_uint_t fcode; /* IOCB function code */
+ cfe_int_t status; /* return status */
+ cfe_int_t handle; /* file/device handle */
+ cfe_uint_t flags; /* flags for this IOCB */
+ cfe_uint_t psize; /* size of parameter list */
+ union {
+ struct cfe_iocb_buf buffer; /* buffer parameters */
+ struct cfe_iocb_inpstat inpstat; /* input status parameters */
+ struct cfe_iocb_envbuf envbuf; /* environment function parameters */
+ struct cfe_iocb_cpuctl cpuctl; /* CPU control parameters */
+ struct cfe_iocb_time time; /* timer parameters */
+ struct cfe_iocb_meminfo meminfo; /* memory arena info parameters */
+ struct cfe_iocb_fwinfo fwinfo; /* firmware information */
+ struct cfe_iocb_exitstat exitstat; /* Exit Status */
+ };
+};
+
+
+#include <linux/init.h>
+
+void __init cfe_setup(unsigned long fwarg0, unsigned long fwarg1,
+ unsigned long fwarg2, unsigned long fwarg3);
+
+#else /* __ASSEMBLY__ */
+
+ .macro cfe_early_init
+#ifdef CONFIG_CFE
+ jal cfe_setup
+#endif
+ .endm
+
+#endif /* __ASSEMBLY__ */
+#endif /* LINUX_CFE_PRIVATE_H_ */
diff --git a/target/linux/brcm63xx/files/arch/mips/pci/fixup-bcm96348.c b/target/linux/brcm63xx/files/arch/mips/pci/fixup-bcm96348.c
new file mode 100644
index 0000000000..ae71ebc73b
--- /dev/null
+++ b/target/linux/brcm63xx/files/arch/mips/pci/fixup-bcm96348.c
@@ -0,0 +1,95 @@
+/*
+<:copyright-gpl
+ Copyright 2002 Broadcom Corp. All Rights Reserved.
+
+ This program is free software; you can distribute it and/or modify it
+ under the terms of the GNU General Public License (Version 2) as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+:>
+*/
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+#include <bcmpci.h>
+#include <bcm_intr.h>
+#include <bcm_map_part.h>
+#include <6348_intr.h>
+#include <6348_map_part.h>
+
+static volatile MpiRegisters * mpi = (MpiRegisters *)(MPI_BASE);
+
+static char irq_tab_bcm96348[] __initdata = {
+ [0] = INTERRUPT_ID_MPI,
+ [1] = INTERRUPT_ID_MPI,
+#if defined(CONFIG_USB)
+ [USB_HOST_SLOT] = INTERRUPT_ID_USBH
+#endif
+};
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return irq_tab_bcm96348[slot];
+}
+
+static void bcm96348_fixup(struct pci_dev *dev)
+{
+ uint32 memaddr;
+ uint32 size;
+
+ memaddr = pci_resource_start(dev, 0);
+ size = pci_resource_len(dev, 0);
+
+ switch (PCI_SLOT(dev->devfn)) {
+ case 0:
+ // UBUS to PCI address range
+ // Memory Window 1. Mask determines which bits are decoded.
+ mpi->l2pmrange1 = ~(size-1);
+ // UBUS to PCI Memory base address. This is akin to the ChipSelect base
+ // register.
+ mpi->l2pmbase1 = memaddr & BCM_PCI_ADDR_MASK;
+ // UBUS to PCI Remap Address. Replaces the masked address bits in the
+ // range register with this setting.
+ // Also, enable direct I/O and direct Memory accesses
+ mpi->l2pmremap1 = (memaddr | MEM_WINDOW_EN);
+ break;
+
+ case 1:
+ // Memory Window 2
+ mpi->l2pmrange2 = ~(size-1);
+ // UBUS to PCI Memory base address.
+ mpi->l2pmbase2 = memaddr & BCM_PCI_ADDR_MASK;
+ // UBUS to PCI Remap Address
+ mpi->l2pmremap2 = (memaddr | MEM_WINDOW_EN);
+ break;
+
+#if defined(CONFIG_USB)
+ case USB_HOST_SLOT:
+ dev->resource[0].start = USB_HOST_BASE;
+ dev->resource[0].end = USB_HOST_BASE+USB_BAR0_MEM_SIZE-1;
+ break;
+#endif
+ }
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_ANY_ID,
+ bcm96348_fixup);
+
+/*struct pci_fixup pcibios_fixups[] = {
+ { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, bcm96348_fixup },
+ {0}
+};*/
diff --git a/target/linux/brcm63xx/files/arch/mips/pci/ops-bcm96348.c b/target/linux/brcm63xx/files/arch/mips/pci/ops-bcm96348.c
new file mode 100644
index 0000000000..ee1647121e
--- /dev/null
+++ b/target/linux/brcm63xx/files/arch/mips/pci/ops-bcm96348.c
@@ -0,0 +1,278 @@
+/*
+<:copyright-gpl
+ Copyright 2002 Broadcom Corp. All Rights Reserved.
+
+ This program is free software; you can distribute it and/or modify it
+ under the terms of the GNU General Public License (Version 2) as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+:>
+*/
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/addrspace.h>
+
+#include <bcm_intr.h>
+#include <bcm_map_part.h>
+#include <6348_intr.h>
+#include <6348_map_part.h>
+#include <bcmpci.h>
+
+#include <linux/delay.h>
+
+#if defined(CONFIG_USB)
+#if 0
+#define DPRINT(x...) printk(x)
+#else
+#define DPRINT(x...)
+#endif
+
+static int
+pci63xx_int_read(unsigned int devfn, int where, u32 * value, int size);
+static int
+pci63xx_int_write(unsigned int devfn, int where, u32 * value, int size);
+
+static bool usb_mem_size_rd = FALSE;
+static uint32 usb_mem_base = 0;
+static uint32 usb_cfg_space_cmd_reg = 0;
+#endif
+static bool pci_mem_size_rd = FALSE;
+
+static volatile MpiRegisters * mpi = (MpiRegisters *)(MPI_BASE);
+
+static void mpi_SetupPciConfigAccess(uint32 addr)
+{
+ mpi->l2pcfgctl = (DIR_CFG_SEL | DIR_CFG_USEREG | addr) & ~CONFIG_TYPE;
+}
+
+static void mpi_ClearPciConfigAccess(void)
+{
+ mpi->l2pcfgctl = 0x00000000;
+}
+
+#if defined(CONFIG_USB)
+/* --------------------------------------------------------------------------
+ Name: pci63xx_int_write
+Abstract: PCI Config write on internal device(s)
+ -------------------------------------------------------------------------- */
+static int
+pci63xx_int_write(unsigned int devfn, int where, u32 * value, int size)
+{
+ if (PCI_SLOT(devfn) != USB_HOST_SLOT) {
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ switch (size) {
+ case 1:
+ DPRINT("W => Slot: %d Where: %2X Len: %d Data: %02X\n",
+ PCI_SLOT(devfn), where, size, *value);
+ break;
+ case 2:
+ DPRINT("W => Slot: %d Where: %2X Len: %d Data: %04X\n",
+ PCI_SLOT(devfn), where, size, *value);
+ switch (where) {
+ case PCI_COMMAND:
+ usb_cfg_space_cmd_reg = *value;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 4:
+ DPRINT("W => Slot: %d Where: %2X Len: %d Data: %08lX\n",
+ PCI_SLOT(devfn), where, size, *value);
+ switch (where) {
+ case PCI_BASE_ADDRESS_0:
+ if (*value == 0xffffffff) {
+ usb_mem_size_rd = TRUE;
+ } else {
+ usb_mem_base = *value;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/* --------------------------------------------------------------------------
+ Name: pci63xx_int_read
+Abstract: PCI Config read on internal device(s)
+ -------------------------------------------------------------------------- */
+static int
+pci63xx_int_read(unsigned int devfn, int where, u32 * value, int size)
+{
+ uint32 retValue = 0xFFFFFFFF;
+
+ if (PCI_SLOT(devfn) != USB_HOST_SLOT) {
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ // For now, this is specific to the USB Host controller. We can
+ // make it more general if we have to...
+ // Emulate PCI Config accesses
+ switch (where) {
+ case PCI_VENDOR_ID:
+ case PCI_DEVICE_ID:
+ retValue = PCI_VENDOR_ID_BROADCOM | 0x63000000;
+ break;
+ case PCI_COMMAND:
+ case PCI_STATUS:
+ retValue = (0x0006 << 16) | usb_cfg_space_cmd_reg;
+ break;
+ case PCI_CLASS_REVISION:
+ case PCI_CLASS_DEVICE:
+ retValue = (PCI_CLASS_SERIAL_USB << 16) | (0x10 << 8) | 0x01;
+ break;
+ case PCI_BASE_ADDRESS_0:
+ if (usb_mem_size_rd) {
+ retValue = USB_BAR0_MEM_SIZE;
+ } else {
+ if (usb_mem_base != 0)
+ retValue = usb_mem_base;
+ else
+ retValue = USB_HOST_BASE;
+ }
+ usb_mem_size_rd = FALSE;
+ break;
+ case PCI_CACHE_LINE_SIZE:
+ case PCI_LATENCY_TIMER:
+ retValue = 0;
+ break;
+ case PCI_HEADER_TYPE:
+ retValue = PCI_HEADER_TYPE_NORMAL;
+ break;
+ case PCI_SUBSYSTEM_VENDOR_ID:
+ retValue = PCI_VENDOR_ID_BROADCOM;
+ break;
+ case PCI_SUBSYSTEM_ID:
+ retValue = 0x6300;
+ break;
+ case PCI_INTERRUPT_LINE:
+ retValue = INTERRUPT_ID_USBH;
+ break;
+ default:
+ break;
+ }
+
+ switch (size) {
+ case 1:
+ *value = (retValue >> ((where & 3) << 3)) & 0xff;
+ DPRINT("R <= Slot: %d Where: %2X Len: %d Data: %02X\n",
+ PCI_SLOT(devfn), where, size, *value);
+ break;
+ case 2:
+ *value = (retValue >> ((where & 3) << 3)) & 0xffff;
+ DPRINT("R <= Slot: %d Where: %2X Len: %d Data: %04X\n",
+ PCI_SLOT(devfn), where, size, *value);
+ break;
+ case 4:
+ *value = retValue;
+ DPRINT("R <= Slot: %d Where: %2X Len: %d Data: %08lX\n",
+ PCI_SLOT(devfn), where, size, *value);
+ break;
+ default:
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+#endif
+
+static int bcm96348_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 * val)
+{
+ volatile unsigned char *ioBase = (unsigned char *)(mpi->l2piobase | KSEG1);
+ uint32 data;
+
+#if defined(CONFIG_USB)
+ if (PCI_SLOT(devfn) == USB_HOST_SLOT)
+ return pci63xx_int_read(devfn, where, val, size);
+#endif
+
+ mpi_SetupPciConfigAccess(BCM_PCI_CFG(PCI_SLOT(devfn), PCI_FUNC(devfn), where));
+ data = *(uint32 *)ioBase;
+ switch(size) {
+ case 1:
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ break;
+ case 2:
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ break;
+ case 4:
+ *val = data;
+ /* Special case for reading PCI device range */
+ if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5)) {
+ if (pci_mem_size_rd) {
+ /* bcm6348 PCI memory window minimum size is 64K */
+ *val &= PCI_SIZE_64K;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ pci_mem_size_rd = FALSE;
+ mpi_ClearPciConfigAccess();
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int bcm96348_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ volatile unsigned char *ioBase = (unsigned char *)(mpi->l2piobase | KSEG1);
+ uint32 data;
+
+#if defined(CONFIG_USB)
+ if (PCI_SLOT(devfn) == USB_HOST_SLOT)
+ return pci63xx_int_write(devfn, where, &val, size);
+#endif
+ mpi_SetupPciConfigAccess(BCM_PCI_CFG(PCI_SLOT(devfn), PCI_FUNC(devfn), where));
+ data = *(uint32 *)ioBase;
+ switch(size) {
+ case 1:
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ break;
+ case 2:
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ break;
+ case 4:
+ data = val;
+ /* Special case for reading PCI device range */
+ if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5)) {
+ if (val == 0xffffffff)
+ pci_mem_size_rd = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ *(uint32 *)ioBase = data;
+ udelay(500);
+ mpi_ClearPciConfigAccess();
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops bcm96348_pci_ops = {
+ .read = bcm96348_pcibios_read,
+ .write = bcm96348_pcibios_write
+};
diff --git a/target/linux/brcm63xx/files/arch/mips/pci/pci-bcm96348.c b/target/linux/brcm63xx/files/arch/mips/pci/pci-bcm96348.c
new file mode 100644
index 0000000000..bea3b7ba08
--- /dev/null
+++ b/target/linux/brcm63xx/files/arch/mips/pci/pci-bcm96348.c
@@ -0,0 +1,62 @@
+/*
+<:copyright-gpl
+ Copyright 2002 Broadcom Corp. All Rights Reserved.
+
+ This program is free software; you can distribute it and/or modify it
+ under the terms of the GNU General Public License (Version 2) as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+:>
+*/
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <bcmpci.h>
+
+static struct resource bcm_pci_io_resource = {
+ .name = "bcm96348 pci IO space",
+ .start = BCM_PCI_IO_BASE,
+ .end = BCM_PCI_IO_BASE + BCM_PCI_IO_SIZE_64KB - 1,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource bcm_pci_mem_resource = {
+ .name = "bcm96348 pci memory space",
+ .start = BCM_PCI_MEM_BASE,
+ .end = BCM_PCI_MEM_BASE + BCM_PCI_MEM_SIZE_16MB - 1,
+ .flags = IORESOURCE_MEM
+};
+
+extern struct pci_ops bcm96348_pci_ops;
+
+struct pci_controller bcm96348_controller = {
+ .pci_ops = &bcm96348_pci_ops,
+ .io_resource = &bcm_pci_io_resource,
+ .mem_resource = &bcm_pci_mem_resource,
+};
+
+static __init int bcm96348_pci_init(void)
+{
+ /* Avoid ISA compat ranges. */
+ PCIBIOS_MIN_IO = 0x00000000;
+ PCIBIOS_MIN_MEM = 0x00000000;
+
+ /* Set I/O resource limits. */
+ ioport_resource.end = 0x1fffffff;
+ iomem_resource.end = 0xffffffff;
+
+ register_pci_controller(&bcm96348_controller);
+ return 0;
+}
+
+arch_initcall(bcm96348_pci_init);