linux-mips
[Top] [All Lists]

[PATCH 2/5] mips: PMC MSP71xx mips common

To: linux-mips@linux-mips.org
Subject: [PATCH 2/5] mips: PMC MSP71xx mips common
From: Marc St-Jean <stjeanma@pmc-sierra.com>
Date: Fri, 23 Feb 2007 13:56:04 -0600
Original-recipient: rfc822;linux-mips@linux-mips.org
Sender: linux-mips-bounce@linux-mips.org
[PATCH 2/5] mips: PMC MSP71xx mips common

Patch to add mips common support for the PMC-Sierra
MSP71xx devices.

These 5 patches along with the previously posted serial patch
will boot the PMC-Sierra MSP7120 Residential Gateway board.

Signed-off-by: Marc St-Jean <Marc_St-Jean@pmc-sierra.com>
---
 arch/mips/Kconfig           |   82 +++++++++++++++++++++
 arch/mips/Makefile          |    8 ++
 arch/mips/kernel/head.S     |    8 ++
 arch/mips/kernel/traps.c    |   19 +++-
 include/asm-mips/bootinfo.h |   12 +++
 include/asm-mips/mipsregs.h |   30 +++++++
 include/asm-mips/regops.h   |  168 ++++++++++++++++++++++++++++++++++++++++++++
 include/asm-mips/war.h      |   11 ++
 8 files changed, 331 insertions(+), 7 deletions(-)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 5da6b0d..d512389 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -504,6 +504,25 @@ config MACH_VR41XX
        select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
        select GENERIC_HARDIRQS_NO__DO_IRQ
 
+config PMC_MSP
+       bool "PMC-Sierra MSP chipsets"
+       depends on EXPERIMENTAL
+       select DMA_NONCOHERENT
+       select SWAP_IO_SPACE
+       select SYS_HAS_CPU_MIPS32_R1
+       select SYS_HAS_CPU_MIPS32_R2
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_BIG_ENDIAN
+       select SYS_SUPPORTS_KGDB
+       select IRQ_CPU
+       select SERIAL_8250
+       select SERIAL_8250_CONSOLE
+       help
+         This adds support for the PMC-Sierra family of Multi-Service
+         Processor System-On-A-Chips.  These parts include a number
+         of integrated peripherals, interfaces and DSPs in addition to
+         a variety of MIPS cores.
+
 config PMC_YOSEMITE
        bool "PMC-Sierra Yosemite eval board"
        select DMA_COHERENT
@@ -815,6 +834,59 @@ config TOSHIBA_RBTX4938
 
 endchoice
 
+choice
+       prompt "PMC-Sierra MSP SOC type"
+       depends on PMC_MSP
+
+config PMC_MSP4200_EVAL
+       bool "PMC-Sierra MSP4200 Eval Board"
+       select IRQ_MSP_SLP
+       select HW_HAS_PCI
+
+config PMC_MSP4200_GW
+       bool "PMC-Sierra MSP4200 VoIP Gateway"
+       select IRQ_MSP_SLP
+       select HW_HAS_PCI
+
+config PMC_MSP7120_EVAL
+       bool "PMC-Sierra MSP7120 Eval Board"
+       select SYS_SUPPORTS_MULTITHREADING
+       select IRQ_MSP_CIC
+       select HW_HAS_PCI
+       select MSP_USB
+
+config PMC_MSP7120_GW
+       bool "PMC-Sierra MSP7120 Residential Gateway"
+       select SYS_SUPPORTS_MULTITHREADING
+       select IRQ_MSP_CIC
+       select HW_HAS_PCI
+       select MSP_USB
+       
+config PMC_MSP7120_FPGA
+       bool "PMC-Sierra MSP7120 FPGA"
+       select SYS_SUPPORTS_MULTITHREADING
+       select IRQ_MSP_CIC
+       select HW_HAS_PCI
+       select MSP_USB
+       
+endchoice
+
+menu "Options for PMC-Sierra MSP chipsets"
+       depends on PMC_MSP
+
+config PMC_MSP_EMBEDDED_ROOTFS
+       bool "Root filesystem embedded in kernel image"
+       select MTD
+       select MTD_BLOCK
+       select MTD_PMC_MSP_RAMROOT
+       select MTD_RAM
+
+config PMC_MSP_UNCACHED
+       bool "Run uncached"
+       select MIPS_UNCACHED
+       
+endmenu
+
 source "arch/mips/ddb5xxx/Kconfig"
 source "arch/mips/gt64120/ev64120/Kconfig"
 source "arch/mips/jazz/Kconfig"
@@ -971,6 +1043,15 @@ config IRQ_CPU_RM9K
 config IRQ_MV64340
        bool
 
+config IRQ_MSP_SLP
+       bool
+
+config IRQ_MSP_CIC
+       bool
+
+config MSP_USB
+       bool
+
 config DDB5XXX_COMMON
        bool
        select SYS_SUPPORTS_KGDB
@@ -1086,6 +1167,7 @@ config MIPS_L1_CACHE_SHIFT
        int
        default "4" if MACH_DECSTATION || SNI_RM
        default "7" if SGI_IP27
+       default "4" if PMC_MSP4200_EVAL
        default "5"
 
 config HAVE_STD_PC_SERIAL_PORT
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 92bca6a..fc406f7 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -367,6 +367,14 @@ cflags-$(CONFIG_PMC_YOSEMITE)      += 
-Iinclude/asm-mips/mach-yosemite
 load-$(CONFIG_PMC_YOSEMITE)    += 0xffffffff80100000
 
 #
+# PMC-Sierra MSP SOCs
+#
+core-$(CONFIG_PMC_MSP)         += arch/mips/pmc-sierra/msp71xx/
+cflags-$(CONFIG_PMC_MSP)       += -Iinclude/asm-mips/pmc-sierra/msp71xx \
+                                       -mno-branch-likely
+load-$(CONFIG_PMC_MSP)         += 0xffffffff80100000
+
+#
 # Qemu simulating MIPS32 4Kc
 #
 core-$(CONFIG_QEMU)            += arch/mips/qemu/
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index 6f57ca4..d7451b1 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -130,10 +130,18 @@
        .endm
 
        /*
+        * Reserverd space not required for PMC boards, although we need to
+        * jump to kernel start.
+        */
+#ifdef CONFIG_PMC_MSP
+       jal     kernel_entry
+#else
+       /*
         * Reserved space for exception handlers.
         * Necessary for machines which link their kernels at KSEG0.
         */
        .fill   0x400
+#endif /* CONFIG_PMC_MSP */
 
 EXPORT(stext)                                  # used for profiling
 EXPORT(_stext)
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 18f56a9..610e169 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -70,6 +70,7 @@ extern asmlinkage void handle_reserved(void);
 extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
        struct mips_fpu_struct *ctx, int has_fpu);
 
+void (*board_watchpoint_handler)(struct pt_regs *regs);
 void (*board_be_init)(void);
 int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
 void (*board_nmi_handler_setup)(void);
@@ -860,13 +861,17 @@ asmlinkage void do_mdmx(struct pt_regs *regs)
 
 asmlinkage void do_watch(struct pt_regs *regs)
 {
-       /*
-        * We use the watch exception where available to detect stack
-        * overflows.
-        */
-       dump_tlb_all();
-       show_regs(regs);
-       panic("Caught WATCH exception - probably caused by stack overflow.");
+       if (board_watchpoint_handler) {
+               (*board_watchpoint_handler)(regs);
+       } else {
+               /*
+                * We use the watch exception where available to detect stack
+                * overflows.
+                */
+               dump_tlb_all();
+               show_regs(regs);
+               panic("Caught WATCH exception - probably caused by stack 
overflow.");
+       }
 }
 
 asmlinkage void do_mcheck(struct pt_regs *regs)
diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h
index c7c945b..ab29fd4 100644
--- a/include/asm-mips/bootinfo.h
+++ b/include/asm-mips/bootinfo.h
@@ -213,6 +213,18 @@
 #define MACH_GROUP_NEC_EMMA2RH 25      /* NEC EMMA2RH (was 23)         */
 #define  MACH_NEC_MARKEINS     0       /* NEC EMMA2RH Mark-eins        */
 
+/*
+ * Valid machtype for group PMC-MSP
+ */
+#define MACH_GROUP_MSP         23      /* PMC-Sierra MSP boards/CPUs    */
+#define MACH_MSP4200_EVAL       0      /* PMC-Sierra MSP4200 Evaluation board 
*/
+#define MACH_MSP4200_GW         1      /* PMC-Sierra MSP4200 Gateway demo 
board */
+#define MACH_MSP4200_FPGA       2      /* PMC-Sierra MSP4200 Emulation board */
+#define MACH_MSP7120_EVAL       3      /* PMC-Sierra MSP7120 Evaluation board 
*/
+#define MACH_MSP7120_GW         4      /* PMC-Sierra MSP7120 Residential 
Gateway board */
+#define MACH_MSP7120_FPGA       5      /* PMC-Sierra MSP7120 Emulation board */
+#define MACH_MSP_OTHER        255      /* PMC-Sierra unknown board type */
+
 #define CL_SIZE                        COMMAND_LINE_SIZE
 
 const char *get_system_type(void);
diff --git a/include/asm-mips/mipsregs.h b/include/asm-mips/mipsregs.h
index 9985cb7..bd683b6 100644
--- a/include/asm-mips/mipsregs.h
+++ b/include/asm-mips/mipsregs.h
@@ -15,6 +15,7 @@
 
 #include <linux/linkage.h>
 #include <asm/hazards.h>
+#include <asm/war.h>
 
 /*
  * The following macros are especially useful for __asm__
@@ -1292,10 +1293,39 @@ static inline void tlb_probe(void)
 
 static inline void tlb_read(void)
 {
+#if MIPS34K_MISSED_ITLB_WAR
+       int res = 0;
+
+       __asm__ __volatile__(
+       "       .set    push                                            \n"
+       "       .set    noreorder                                       \n"
+       "       .set    noat                                            \n"
+       "       .set    mips32r2                                        \n"
+       "       .word   0x41610001              # dvpe $1               \n"
+       "       move    %0, $1                                          \n"
+       "       ehb                                                     \n"
+       "       .set    pop                                             \n"
+       : "=r" (res));
+
+       instruction_hazard();
+#endif
+
        __asm__ __volatile__(
                ".set noreorder\n\t"
                "tlbr\n\t"
                ".set reorder");
+
+#if MIPS34K_MISSED_ITLB_WAR
+       if ((res & _ULCAST_(1)))
+               __asm__ __volatile__(
+               "       .set    push                                            
\n"
+               "       .set    noreorder                                       
\n"
+               "       .set    noat                                            
\n"
+               "       .set    mips32r2                                        
\n"
+               "       .word   0x41600021              # evpe                  
\n"
+               "       ehb                                                     
\n"
+               "       .set    pop                                             
\n");
+#endif
 }
 
 static inline void tlb_write_indexed(void)
diff --git a/include/asm-mips/war.h b/include/asm-mips/war.h
index 13a3502..74c08e6 100644
--- a/include/asm-mips/war.h
+++ b/include/asm-mips/war.h
@@ -196,6 +196,14 @@
 #endif
 
 /*
+ * 34K core erratum: "Problems Executing the TLBR Instruction"
+ */
+#if defined(CONFIG_PMC_MSP7120_EVAL) || defined(CONFIG_PMC_MSP7120_GW) || \
+       defined(CONFIG_PMC_MSP7120_FPGA)
+#define MIPS34K_MISSED_ITLB_WAR                1
+#endif
+
+/*
  * Workarounds default to off
  */
 #ifndef ICACHE_REFILLS_WORKAROUND_WAR
@@ -234,5 +242,8 @@
 #ifndef R10000_LLSC_WAR
 #define R10000_LLSC_WAR                        0
 #endif
+#ifndef MIPS34K_MISSED_ITLB_WAR
+#define MIPS34K_MISSED_ITLB_WAR                0
+#endif
 
 #endif /* _ASM_WAR_H */
diff --git a/include/asm-mips/regops.h b/include/asm-mips/regops.h
new file mode 100644
index 0000000..fbfc940
--- /dev/null
+++ b/include/asm-mips/regops.h
@@ -0,0 +1,168 @@
+/*
+ * $Id: regops.h,v 1.2 2006/05/08 22:00:34 ramsayji Exp $
+ *
+ * VPE/SMP-safe functions to access registers.  They use ll/sc instructions, so
+ * it is your responsibility to ensure these are available on your platform
+ * before including this file.
+ *
+ * In addition, there is a bug on the R10000 chips which has a workaround.  If
+ * you are affected by this bug, make sure to define the symbol
+ * 'R10000_LLSC_WAR' to be non-zero.  If you are using this header from within
+ * linux, you may include <asm/war.h> before including this file to have this
+ * defined appropriately for you.
+ *
+ * Copyright 2005 PMC-Sierra, Inc.
+ *
+ *  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.
+ */
+
+#ifndef __ASM_REGOPS_H__
+#define __ASM_REGOPS_H__
+
+#ifndef R10000_LLSC_WAR
+#define R10000_LLSC_WAR 0
+#endif
+
+#if R10000_LLSC_WAR == 1
+#define __beqz "beqzl  "
+#else
+#define __beqz "beqz   "
+#endif
+
+#ifndef _LINUX_TYPES_H
+typedef unsigned int uint32_t;
+#endif
+
+/*
+ * Sets all the masked bits to the corresponding value bits
+ */
+static inline void set_value_reg32( volatile uint32_t * const addr,
+                                       uint32_t const mask,
+                                       uint32_t const value )
+{
+       uint32_t temp;
+
+       __asm__ __volatile__(
+       "       .set    mips3                           \n"
+       "1:     ll      %0, %1  # set_value_reg32       \n"
+       "       and     %0, %2                          \n"
+       "       or      %0, %3                          \n"
+       "       sc      %0, %1                          \n"
+       "       "__beqz"%0, 1b                          \n"
+       "       .set    mips0                           \n"
+       : "=&r" (temp), "=m" (*addr)
+       : "ir" (~mask), "ir" (value), "m" (*addr) );
+}
+
+/*
+ * Sets all the masked bits to '1'
+ */
+static inline void set_reg32( volatile uint32_t * const addr,
+                               uint32_t const mask )
+{
+       uint32_t temp;
+
+       __asm__ __volatile__(
+       "       .set    mips3                           \n"
+       "1:     ll      %0, %1          # set_reg32     \n"
+       "       or      %0, %2                          \n"
+       "       sc      %0, %1                          \n"
+       "       "__beqz"%0, 1b                          \n"
+       "       .set    mips0                           \n"
+       : "=&r" (temp), "=m" (*addr)
+       : "ir" (mask), "m" (*addr) );
+}
+
+/*
+ * Sets all the masked bits to '0'
+ */
+static inline void clear_reg32( volatile uint32_t * const addr,
+                               uint32_t const mask )
+{
+       uint32_t temp;
+
+       __asm__ __volatile__(
+       "       .set    mips3                           \n"
+       "1:     ll      %0, %1          # clear_reg32   \n"
+       "       and     %0, %2                          \n"
+       "       sc      %0, %1                          \n"
+       "       "__beqz"%0, 1b                          \n"
+       "       .set    mips0                           \n"
+       : "=&r" (temp), "=m" (*addr)
+       : "ir" (~mask), "m" (*addr) );
+}
+
+/*
+ * Toggles all masked bits from '0' to '1' and '1' to '0'
+ */
+static inline void toggle_reg32( volatile uint32_t * const addr,
+                               uint32_t const mask )
+{
+       uint32_t temp;
+
+       __asm__ __volatile__(
+       "       .set    mips3                           \n"
+       "1:     ll      %0, %1          # toggle_reg32  \n"
+       "       xor     %0, %2                          \n"
+       "       sc      %0, %1                          \n"
+       "       "__beqz"%0, 1b                          \n"
+       "       .set    mips0                           \n"
+       : "=&r" (temp), "=m" (*addr)
+       : "ir" (mask), "m" (*addr) );
+}
+
+/* For special strange cases only:
+ *
+ * If you need custom processing within a ll/sc loop, use the following macros
+ * VERY CAREFULLY:
+ *
+ *   uint32_t tmp;                      <-- Define a variable to hold the data
+ *
+ *   custom_reg32_start(address, tmp); <-- Reads the address and puts the value
+ *                                             in the 'tmp' variable given
+ *
+ *     < From here on out, you are (basicly) atomic, so don't do anything too
+ *     < fancy!
+ *     < Also, this code may loop if the end of this block fails to write
+ *     < everything back safely due do the other CPU, so do NOT do anything
+ *     < with side-effects!
+ *
+ *   custom_reg32_stop(address, tmp);  <-- Writes back 'tmp' safely. 
+ *
+ */
+#define custom_reg32_read(address, tmp)                                \
+       __asm__ __volatile__(                                   \
+       "       .set    mips3                           \n"     \
+       "1:     ll      %0, %1  #custom_reg32_read      \n"     \
+       "       .set    mips0                           \n"     \
+       : "=r" (tmp), "=m" (*address)                           \
+       : "m" (*address) )
+
+#define custom_reg32_write(address, tmp)                       \
+       __asm__ __volatile__(                                   \
+       "       .set    mips3                           \n"     \
+       "       sc      %0, %1  #custom_reg32_write     \n"     \
+       "       "__beqz"%0, 1b                          \n"     \
+       "       .set    mips0                           \n"     \
+       : "=&r" (tmp), "=m" (*address)                          \
+       : "0" (tmp), "m" (*address) )
+
+#endif  /* __ASM_REGOPS_H__ */

<Prev in Thread] Current Thread [Next in Thread>