aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMarc St-Jean <stjeanma@pmc-sierra.com>2007-06-14 17:54:47 -0400
committerRalf Baechle <ralf@linux-mips.org>2007-07-10 12:33:02 -0400
commit35832e26f95ba14a6b6f0519441c5cb64cca6bf9 (patch)
treedb3c05782a2140b19917344fb640070a655d75fd /arch
parenta4b156d47d204904fa104c3e585b4c67b89195f3 (diff)
[MIPS] PMC MSP71xx core platform
Patch to add core platform support for the PMC-Sierra MSP71xx devices. Signed-off-by: Marc St-Jean <Marc_St-Jean@pmc-sierra.com> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/mips/pmc-sierra/msp71xx/Makefile11
-rw-r--r--arch/mips/pmc-sierra/msp71xx/msp_elb.c46
-rw-r--r--arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c179
-rw-r--r--arch/mips/pmc-sierra/msp71xx/msp_irq.c124
-rw-r--r--arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c134
-rw-r--r--arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c109
-rw-r--r--arch/mips/pmc-sierra/msp71xx/msp_prom.c566
-rw-r--r--arch/mips/pmc-sierra/msp71xx/msp_setup.c256
-rw-r--r--arch/mips/pmc-sierra/msp71xx/msp_time.c94
-rw-r--r--arch/mips/pmc-sierra/msp71xx/msp_usb.c150
10 files changed, 1669 insertions, 0 deletions
diff --git a/arch/mips/pmc-sierra/msp71xx/Makefile b/arch/mips/pmc-sierra/msp71xx/Makefile
new file mode 100644
index 000000000000..4bba79c1cc79
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/Makefile
@@ -0,0 +1,11 @@
1#
2# Makefile for the PMC-Sierra MSP SOCs
3#
4obj-y += msp_prom.o msp_setup.o msp_irq.o \
5 msp_time.o msp_serial.o msp_elb.o
6obj-$(CONFIG_PMC_MSP7120_GW) += msp_hwbutton.o
7obj-$(CONFIG_IRQ_MSP_SLP) += msp_irq_slp.o
8obj-$(CONFIG_IRQ_MSP_CIC) += msp_irq_cic.o
9obj-$(CONFIG_PCI) += msp_pci.o
10obj-$(CONFIG_MSPETH) += msp_eth.o
11obj-$(CONFIG_USB_MSP71XX) += msp_usb.o
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_elb.c b/arch/mips/pmc-sierra/msp71xx/msp_elb.c
new file mode 100644
index 000000000000..3e9641007216
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_elb.c
@@ -0,0 +1,46 @@
1/*
2 * Sets up the proper Chip Select configuration registers. It is assumed that
3 * PMON sets up the ADDR and MASK registers properly.
4 *
5 * Copyright 2005-2006 PMC-Sierra, Inc.
6 * Author: Marc St-Jean, Marc_St-Jean@pmc-sierra.com
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
14 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
16 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
19 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28
29#include <linux/kernel.h>
30#include <linux/init.h>
31#include <msp_regs.h>
32
33static int __init msp_elb_setup(void)
34{
35#if defined(CONFIG_PMC_MSP7120_GW) \
36 || defined(CONFIG_PMC_MSP7120_EVAL)
37 /*
38 * Force all CNFG to be identical and equal to CS0,
39 * according to OPS doc
40 */
41 *CS1_CNFG_REG = *CS2_CNFG_REG = *CS3_CNFG_REG = *CS0_CNFG_REG;
42#endif
43 return 0;
44}
45
46subsys_initcall(msp_elb_setup);
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c b/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c
new file mode 100644
index 000000000000..6fa85728158b
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c
@@ -0,0 +1,179 @@
1/*
2 * Sets up interrupt handlers for various hardware switches which are
3 * connected to interrupt lines.
4 *
5 * Copyright 2005-2207 PMC-Sierra, Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
13 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
15 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
16 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
17 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
18 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27
28#include <linux/kernel.h>
29#include <linux/init.h>
30#include <linux/interrupt.h>
31
32#include <msp_int.h>
33#include <msp_regs.h>
34#include <msp_regops.h>
35#ifdef CONFIG_PMCTWILED
36#include <msp_led_macros.h>
37#endif
38
39/* For hwbutton_interrupt->initial_state */
40#define HWBUTTON_HI 0x1
41#define HWBUTTON_LO 0x2
42
43/*
44 * This struct describes a hardware button
45 */
46struct hwbutton_interrupt {
47 char *name; /* Name of button */
48 int irq; /* Actual LINUX IRQ */
49 int eirq; /* Extended IRQ number (0-7) */
50 int initial_state; /* The "normal" state of the switch */
51 void (*handle_hi)(void *); /* Handler: switch input has gone HI */
52 void (*handle_lo)(void *); /* Handler: switch input has gone LO */
53 void *data; /* Optional data to pass to handler */
54};
55
56#ifdef CONFIG_PMC_MSP7120_GW
57extern void msp_restart(char *);
58
59static void softreset_push(void *data)
60{
61 printk(KERN_WARNING "SOFTRESET switch was pushed\n");
62
63 /*
64 * In the future you could move this to the release handler,
65 * timing the difference between the 'push' and 'release', and only
66 * doing this ungraceful restart if the button has been down for
67 * a certain amount of time; otherwise doing a graceful restart.
68 */
69
70 msp_restart(NULL);
71}
72
73static void softreset_release(void *data)
74{
75 printk(KERN_WARNING "SOFTRESET switch was released\n");
76
77 /* Do nothing */
78}
79
80static void standby_on(void *data)
81{
82 printk(KERN_WARNING "STANDBY switch was set to ON (not implemented)\n");
83
84 /* TODO: Put board in standby mode */
85#ifdef CONFIG_PMCTWILED
86 msp_led_turn_off(MSP_LED_PWRSTANDBY_GREEN);
87 msp_led_turn_on(MSP_LED_PWRSTANDBY_RED);
88#endif
89}
90
91static void standby_off(void *data)
92{
93 printk(KERN_WARNING
94 "STANDBY switch was set to OFF (not implemented)\n");
95
96 /* TODO: Take out of standby mode */
97#ifdef CONFIG_PMCTWILED
98 msp_led_turn_on(MSP_LED_PWRSTANDBY_GREEN);
99 msp_led_turn_off(MSP_LED_PWRSTANDBY_RED);
100#endif
101}
102
103static struct hwbutton_interrupt softreset_sw = {
104 .name = "Softreset button",
105 .irq = MSP_INT_EXT0,
106 .eirq = 0,
107 .initial_state = HWBUTTON_HI,
108 .handle_hi = softreset_release,
109 .handle_lo = softreset_push,
110 .data = NULL,
111};
112
113static struct hwbutton_interrupt standby_sw = {
114 .name = "Standby switch",
115 .irq = MSP_INT_EXT1,
116 .eirq = 1,
117 .initial_state = HWBUTTON_HI,
118 .handle_hi = standby_off,
119 .handle_lo = standby_on,
120 .data = NULL,
121};
122#endif /* CONFIG_PMC_MSP7120_GW */
123
124static irqreturn_t hwbutton_handler(int irq, void *data)
125{
126 struct hwbutton_interrupt *hirq = data;
127 unsigned long cic_ext = *CIC_EXT_CFG_REG;
128
129 if (irq != hirq->irq)
130 return IRQ_NONE;
131
132 if (CIC_EXT_IS_ACTIVE_HI(cic_ext, hirq->eirq)) {
133 /* Interrupt: pin is now HI */
134 CIC_EXT_SET_ACTIVE_LO(cic_ext, hirq->eirq);
135 hirq->handle_hi(hirq->data);
136 } else {
137 /* Interrupt: pin is now LO */
138 CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);
139 hirq->handle_lo(hirq->data);
140 }
141
142 /*
143 * Invert the POLARITY of this level interrupt to ack the interrupt
144 * Thus next state change will invoke the opposite message
145 */
146 *CIC_EXT_CFG_REG = cic_ext;
147
148 return IRQ_HANDLED;
149}
150
151static int msp_hwbutton_register(struct hwbutton_interrupt *hirq)
152{
153 unsigned long cic_ext;
154
155 if (hirq->handle_hi == NULL || hirq->handle_lo == NULL)
156 return -EINVAL;
157
158 cic_ext = *CIC_EXT_CFG_REG;
159 CIC_EXT_SET_TRIGGER_LEVEL(cic_ext, hirq->eirq);
160 if (hirq->initial_state == HWBUTTON_HI)
161 CIC_EXT_SET_ACTIVE_LO(cic_ext, hirq->eirq);
162 else
163 CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);
164 *CIC_EXT_CFG_REG = cic_ext;
165
166 return request_irq(hirq->irq, hwbutton_handler, SA_INTERRUPT,
167 hirq->name, (void *)hirq);
168}
169
170static int __init msp_hwbutton_setup(void)
171{
172#ifdef CONFIG_PMC_MSP7120_GW
173 msp_hwbutton_register(&softreset_sw);
174 msp_hwbutton_register(&standby_sw);
175#endif
176 return 0;
177}
178
179subsys_initcall(msp_hwbutton_setup);
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq.c b/arch/mips/pmc-sierra/msp71xx/msp_irq.c
new file mode 100644
index 000000000000..734d598a2e3a
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_irq.c
@@ -0,0 +1,124 @@
1/*
2 * IRQ vector handles
3 *
4 * Copyright (C) 1995, 1996, 1997, 2003 by Ralf Baechle
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/irq.h>
14#include <linux/interrupt.h>
15#include <linux/ptrace.h>
16#include <linux/time.h>
17
18#include <asm/irq_cpu.h>
19
20#include <msp_int.h>
21
22extern void msp_int_handle(void);
23
24/* SLP bases systems */
25extern void msp_slp_irq_init(void);
26extern void msp_slp_irq_dispatch(void);
27
28/* CIC based systems */
29extern void msp_cic_irq_init(void);
30extern void msp_cic_irq_dispatch(void);
31
32/*
33 * The PMC-Sierra MSP interrupts are arranged in a 3 level cascaded
34 * hierarchical system. The first level are the direct MIPS interrupts
35 * and are assigned the interrupt range 0-7. The second level is the SLM
36 * interrupt controller and is assigned the range 8-39. The third level
37 * comprises the Peripherial block, the PCI block, the PCI MSI block and
38 * the SLP. The PCI interrupts and the SLP errors are handled by the
39 * relevant subsystems so the core interrupt code needs only concern
40 * itself with the Peripheral block. These are assigned interrupts in
41 * the range 40-71.
42 */
43
44asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
45{
46 u32 pending;
47
48 pending = read_c0_status() & read_c0_cause();
49
50 /*
51 * jump to the correct interrupt routine
52 * These are arranged in priority order and the timer
53 * comes first!
54 */
55
56#ifdef CONFIG_IRQ_MSP_CIC /* break out the CIC stuff for now */
57 if (pending & C_IRQ4) /* do the peripherals first, that's the timer */
58 msp_cic_irq_dispatch();
59
60 else if (pending & C_IRQ0)
61 do_IRQ(MSP_INT_MAC0);
62
63 else if (pending & C_IRQ1)
64 do_IRQ(MSP_INT_MAC1);
65
66 else if (pending & C_IRQ2)
67 do_IRQ(MSP_INT_USB);
68
69 else if (pending & C_IRQ3)
70 do_IRQ(MSP_INT_SAR);
71
72 else if (pending & C_IRQ5)
73 do_IRQ(MSP_INT_SEC);
74
75#else
76 if (pending & C_IRQ5)
77 do_IRQ(MSP_INT_TIMER);
78
79 else if (pending & C_IRQ0)
80 do_IRQ(MSP_INT_MAC0);
81
82 else if (pending & C_IRQ1)
83 do_IRQ(MSP_INT_MAC1);
84
85 else if (pending & C_IRQ3)
86 do_IRQ(MSP_INT_VE);
87
88 else if (pending & C_IRQ4)
89 msp_slp_irq_dispatch();
90#endif
91
92 else if (pending & C_SW0) /* do software after hardware */
93 do_IRQ(MSP_INT_SW0);
94
95 else if (pending & C_SW1)
96 do_IRQ(MSP_INT_SW1);
97}
98
99static struct irqaction cascade_msp = {
100 .handler = no_action,
101 .name = "MSP cascade"
102};
103
104
105void __init arch_init_irq(void)
106{
107 /* initialize the 1st-level CPU based interrupt controller */
108 mips_cpu_irq_init();
109
110#ifdef CONFIG_IRQ_MSP_CIC
111 msp_cic_irq_init();
112
113 /* setup the cascaded interrupts */
114 setup_irq(MSP_INT_CIC, &cascade_msp);
115 setup_irq(MSP_INT_PER, &cascade_msp);
116#else
117 /* setup the 2nd-level SLP register based interrupt controller */
118 msp_slp_irq_init();
119
120 /* setup the cascaded SLP/PER interrupts */
121 setup_irq(MSP_INT_SLP, &cascade_msp);
122 setup_irq(MSP_INT_PER, &cascade_msp);
123#endif
124}
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c b/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c
new file mode 100644
index 000000000000..5175357d0a25
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c
@@ -0,0 +1,134 @@
1/*
2 * This file define the irq handler for MSP SLM subsystem interrupts.
3 *
4 * Copyright 2005-2007 PMC-Sierra, Inc, derived from irq_cpu.c
5 * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.com
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13#include <linux/init.h>
14#include <linux/interrupt.h>
15#include <linux/kernel.h>
16#include <linux/bitops.h>
17
18#include <asm/system.h>
19
20#include <msp_cic_int.h>
21#include <msp_regs.h>
22
23/*
24 * NOTE: We are only enabling support for VPE0 right now.
25 */
26
27static inline void unmask_msp_cic_irq(unsigned int irq)
28{
29
30 /* check for PER interrupt range */
31 if (irq < MSP_PER_INTBASE)
32 *CIC_VPE0_MSK_REG |= (1 << (irq - MSP_CIC_INTBASE));
33 else
34 *PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE));
35}
36
37static inline void mask_msp_cic_irq(unsigned int irq)
38{
39 /* check for PER interrupt range */
40 if (irq < MSP_PER_INTBASE)
41 *CIC_VPE0_MSK_REG &= ~(1 << (irq - MSP_CIC_INTBASE));
42 else
43 *PER_INT_MSK_REG &= ~(1 << (irq - MSP_PER_INTBASE));
44}
45
46/*
47 * While we ack the interrupt interrupts are disabled and thus we don't need
48 * to deal with concurrency issues. Same for msp_cic_irq_end.
49 */
50static inline void ack_msp_cic_irq(unsigned int irq)
51{
52 mask_msp_cic_irq(irq);
53
54 /*
55 * only really necessary for 18, 16-14 and sometimes 3:0 (since
56 * these can be edge sensitive) but it doesn't hurt for the others.
57 */
58
59 /* check for PER interrupt range */
60 if (irq < MSP_PER_INTBASE)
61 *CIC_STS_REG = (1 << (irq - MSP_CIC_INTBASE));
62 else
63 *PER_INT_STS_REG = (1 << (irq - MSP_PER_INTBASE));
64}
65
66static struct irq_chip msp_cic_irq_controller = {
67 .name = "MSP_CIC",
68 .ack = ack_msp_cic_irq,
69 .mask = ack_msp_cic_irq,
70 .mask_ack = ack_msp_cic_irq,
71 .unmask = unmask_msp_cic_irq,
72};
73
74
75void __init msp_cic_irq_init(void)
76{
77 int i;
78
79 /* Mask/clear interrupts. */
80 *CIC_VPE0_MSK_REG = 0x00000000;
81 *PER_INT_MSK_REG = 0x00000000;
82 *CIC_STS_REG = 0xFFFFFFFF;
83 *PER_INT_STS_REG = 0xFFFFFFFF;
84
85#if defined(CONFIG_PMC_MSP7120_GW) || \
86 defined(CONFIG_PMC_MSP7120_EVAL)
87 /*
88 * The MSP7120 RG and EVBD boards use IRQ[6:4] for PCI.
89 * These inputs map to EXT_INT_POL[6:4] inside the CIC.
90 * They are to be active low, level sensitive.
91 */
92 *CIC_EXT_CFG_REG &= 0xFFFF8F8F;
93#endif
94
95 /* initialize all the IRQ descriptors */
96 for (i = MSP_CIC_INTBASE; i < MSP_PER_INTBASE + 32; i++)
97 set_irq_chip_and_handler(i, &msp_cic_irq_controller,
98 handle_level_irq);
99}
100
101void msp_cic_irq_dispatch(void)
102{
103 u32 pending;
104 int intbase;
105
106 intbase = MSP_CIC_INTBASE;
107 pending = *CIC_STS_REG & *CIC_VPE0_MSK_REG;
108
109 /* check for PER interrupt */
110 if (pending == (1 << (MSP_INT_PER - MSP_CIC_INTBASE))) {
111 intbase = MSP_PER_INTBASE;
112 pending = *PER_INT_STS_REG & *PER_INT_MSK_REG;
113 }
114
115 /* check for spurious interrupt */
116 if (pending == 0x00000000) {
117 printk(KERN_ERR
118 "Spurious %s interrupt? status %08x, mask %08x\n",
119 (intbase == MSP_CIC_INTBASE) ? "CIC" : "PER",
120 (intbase == MSP_CIC_INTBASE) ?
121 *CIC_STS_REG : *PER_INT_STS_REG,
122 (intbase == MSP_CIC_INTBASE) ?
123 *CIC_VPE0_MSK_REG : *PER_INT_MSK_REG);
124 return;
125 }
126
127 /* check for the timer and dispatch it first */
128 if ((intbase == MSP_CIC_INTBASE) &&
129 (pending & (1 << (MSP_INT_VPE0_TIMER - MSP_CIC_INTBASE))))
130 do_IRQ(MSP_INT_VPE0_TIMER);
131 else
132 do_IRQ(ffs(pending) + intbase - 1);
133}
134
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c b/arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c
new file mode 100644
index 000000000000..f5f1b8d2bb9a
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c
@@ -0,0 +1,109 @@
1/*
2 * This file define the irq handler for MSP SLM subsystem interrupts.
3 *
4 * Copyright 2005-2006 PMC-Sierra, Inc, derived from irq_cpu.c
5 * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.com
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13#include <linux/init.h>
14#include <linux/interrupt.h>
15#include <linux/kernel.h>
16#include <linux/bitops.h>
17
18#include <asm/mipsregs.h>
19#include <asm/system.h>
20
21#include <msp_slp_int.h>
22#include <msp_regs.h>
23
24static inline void unmask_msp_slp_irq(unsigned int irq)
25{
26 /* check for PER interrupt range */
27 if (irq < MSP_PER_INTBASE)
28 *SLP_INT_MSK_REG |= (1 << (irq - MSP_SLP_INTBASE));
29 else
30 *PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE));
31}
32
33static inline void mask_msp_slp_irq(unsigned int irq)
34{
35 /* check for PER interrupt range */
36 if (irq < MSP_PER_INTBASE)
37 *SLP_INT_MSK_REG &= ~(1 << (irq - MSP_SLP_INTBASE));
38 else
39 *PER_INT_MSK_REG &= ~(1 << (irq - MSP_PER_INTBASE));
40}
41
42/*
43 * While we ack the interrupt interrupts are disabled and thus we don't need
44 * to deal with concurrency issues. Same for msp_slp_irq_end.
45 */
46static inline void ack_msp_slp_irq(unsigned int irq)
47{
48 mask_slp_irq(irq);
49
50 /*
51 * only really necessary for 18, 16-14 and sometimes 3:0 (since
52 * these can be edge sensitive) but it doesn't hurt for the others.
53 */
54
55 /* check for PER interrupt range */
56 if (irq < MSP_PER_INTBASE)
57 *SLP_INT_STS_REG = (1 << (irq - MSP_SLP_INTBASE));
58 else
59 *PER_INT_STS_REG = (1 << (irq - MSP_PER_INTBASE));
60}
61
62static struct irq_chip msp_slp_irq_controller = {
63 .name = "MSP_SLP",
64 .ack = ack_msp_slp_irq,
65 .mask = ack_msp_slp_irq,
66 .mask_ack = ack_msp_slp_irq,
67 .unmask = unmask_msp_slp_irq,
68};
69
70void __init msp_slp_irq_init(void)
71{
72 int i;
73
74 /* Mask/clear interrupts. */
75 *SLP_INT_MSK_REG = 0x00000000;
76 *PER_INT_MSK_REG = 0x00000000;
77 *SLP_INT_STS_REG = 0xFFFFFFFF;
78 *PER_INT_STS_REG = 0xFFFFFFFF;
79
80 /* initialize all the IRQ descriptors */
81 for (i = MSP_SLP_INTBASE; i < MSP_PER_INTBASE + 32; i++)
82 set_irq_chip_and_handler(i, &msp_slp_irq_controller
83 handle_level_irq);
84}
85
86void msp_slp_irq_dispatch(void)
87{
88 u32 pending;
89 int intbase;
90
91 intbase = MSP_SLP_INTBASE;
92 pending = *SLP_INT_STS_REG & *SLP_INT_MSK_REG;
93
94 /* check for PER interrupt */
95 if (pending == (1 << (MSP_INT_PER - MSP_SLP_INTBASE))) {
96 intbase = MSP_PER_INTBASE;
97 pending = *PER_INT_STS_REG & *PER_INT_MSK_REG;
98 }
99
100 /* check for spurious interrupt */
101 if (pending == 0x00000000) {
102 printk(KERN_ERR "Spurious %s interrupt?\n",
103 (intbase == MSP_SLP_INTBASE) ? "SLP" : "PER");
104 return;
105 }
106
107 /* dispatch the irq */
108 do_IRQ(ffs(pending) + intbase - 1);
109}
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_prom.c b/arch/mips/pmc-sierra/msp71xx/msp_prom.c
new file mode 100644
index 000000000000..e5bd5481d8db
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_prom.c
@@ -0,0 +1,566 @@
1/*
2 * BRIEF MODULE DESCRIPTION
3 * PROM library initialisation code, assuming a version of
4 * pmon is the boot code.
5 *
6 * Copyright 2000,2001 MontaVista Software Inc.
7 * Author: MontaVista Software, Inc.
8 * ppopov@mvista.com or source@mvista.com
9 *
10 * This file was derived from Carsten Langgaard's
11 * arch/mips/mips-boards/xx files.
12 *
13 * Carsten Langgaard, carstenl@mips.com
14 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
15 *
16 * This program is free software; you can redistribute it and/or modify it
17 * under the terms of the GNU General Public License as published by the
18 * Free Software Foundation; either version 2 of the License, or (at your
19 * option) any later version.
20 *
21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
24 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * You should have received a copy of the GNU General Public License along
33 * with this program; if not, write to the Free Software Foundation, Inc.,
34 * 675 Mass Ave, Cambridge, MA 02139, USA.
35 */
36
37#include <linux/module.h>
38#include <linux/kernel.h>
39#include <linux/init.h>
40#include <linux/string.h>
41#include <linux/interrupt.h>
42#include <linux/mm.h>
43#ifdef CONFIG_CRAMFS
44#include <linux/cramfs_fs.h>
45#endif
46#ifdef CONFIG_SQUASHFS
47#include <linux/squashfs_fs.h>
48#endif
49
50#include <asm/addrspace.h>
51#include <asm/bootinfo.h>
52#include <asm-generic/sections.h>
53#include <asm/page.h>
54
55#include <msp_prom.h>
56#include <msp_regs.h>
57
58/* global PROM environment variables and pointers */
59int prom_argc;
60char **prom_argv, **prom_envp;
61int *prom_vec;
62
63/* debug flag */
64int init_debug = 1;
65
66/* memory blocks */
67struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
68
69/* default feature sets */
70static char msp_default_features[] =
71#if defined(CONFIG_PMC_MSP4200_EVAL) \
72 || defined(CONFIG_PMC_MSP4200_GW)
73 "ERER";
74#elif defined(CONFIG_PMC_MSP7120_EVAL) \
75 || defined(CONFIG_PMC_MSP7120_GW)
76 "EMEMSP";
77#elif defined(CONFIG_PMC_MSP7120_FPGA)
78 "EMEM";
79#endif
80
81/* conversion functions */
82static inline unsigned char str2hexnum(unsigned char c)
83{
84 if (c >= '0' && c <= '9')
85 return c - '0';
86 if (c >= 'a' && c <= 'f')
87 return c - 'a' + 10;
88 return 0; /* foo */
89}
90
91static inline int str2eaddr(unsigned char *ea, unsigned char *str)
92{
93 int index = 0;
94 unsigned char num = 0;
95
96 while (*str != '\0') {
97 if ((*str == '.') || (*str == ':')) {
98 ea[index++] = num;
99 num = 0;
100 str++;
101 } else {
102 num = num << 4;
103 num |= str2hexnum(*str++);
104 }
105 }
106
107 if (index == 5) {
108 ea[index++] = num;
109 return 0;
110 } else
111 return -1;
112}
113EXPORT_SYMBOL(str2eaddr);
114
115static inline unsigned long str2hex(unsigned char *str)
116{
117 int value = 0;
118
119 while (*str) {
120 value = value << 4;
121 value |= str2hexnum(*str++);
122 }
123
124 return value;
125}
126
127/* function to query the system information */
128const char *get_system_type(void)
129{
130#if defined(CONFIG_PMC_MSP4200_EVAL)
131 return "PMC-Sierra MSP4200 Eval Board";
132#elif defined(CONFIG_PMC_MSP4200_GW)
133 return "PMC-Sierra MSP4200 VoIP Gateway";
134#elif defined(CONFIG_PMC_MSP7120_EVAL)
135 return "PMC-Sierra MSP7120 Eval Board";
136#elif defined(CONFIG_PMC_MSP7120_GW)
137 return "PMC-Sierra MSP7120 Residential Gateway";
138#elif defined(CONFIG_PMC_MSP7120_FPGA)
139 return "PMC-Sierra MSP7120 FPGA";
140#else
141 #error "What is the type of *your* MSP?"
142#endif
143}
144
145int get_ethernet_addr(char *ethaddr_name, char *ethernet_addr)
146{
147 char *ethaddr_str;
148
149 ethaddr_str = prom_getenv(ethaddr_name);
150 if (!ethaddr_str) {
151 printk(KERN_WARNING "%s not set in boot prom\n", ethaddr_name);
152 return -1;
153 }
154
155 if (str2eaddr(ethernet_addr, ethaddr_str) == -1) {
156 printk(KERN_WARNING "%s badly formatted-<%s>\n",
157 ethaddr_name, ethaddr_str);
158 return -1;
159 }
160
161 if (init_debug > 1) {
162 int i;
163 printk(KERN_DEBUG "get_ethernet_addr: for %s ", ethaddr_name);
164 for (i = 0; i < 5; i++)
165 printk(KERN_DEBUG "%02x:",
166 (unsigned char)*(ethernet_addr+i));
167 printk(KERN_DEBUG "%02x\n", *(ethernet_addr+i));
168 }
169
170 return 0;
171}
172EXPORT_SYMBOL(get_ethernet_addr);
173
174static char *get_features(void)
175{
176 char *feature = prom_getenv(FEATURES);
177
178 if (feature == NULL) {
179 /* default features based on MACHINE_TYPE */
180 feature = msp_default_features;
181 }
182
183 return feature;
184}
185
186static char test_feature(char c)
187{
188 char *feature = get_features();
189
190 while (*feature) {
191 if (*feature++ == c)
192 return *feature;
193 feature++;
194 }
195
196 return FEATURE_NOEXIST;
197}
198
199unsigned long get_deviceid(void)
200{
201 char *deviceid = prom_getenv(DEVICEID);
202
203 if (deviceid == NULL)
204 return *DEV_ID_REG;
205 else
206 return str2hex(deviceid);
207}
208
209char identify_pci(void)
210{
211 return test_feature(PCI_KEY);
212}
213EXPORT_SYMBOL(identify_pci);
214
215char identify_pcimux(void)
216{
217 return test_feature(PCIMUX_KEY);
218}
219
220char identify_sec(void)
221{
222 return test_feature(SEC_KEY);
223}
224EXPORT_SYMBOL(identify_sec);
225
226char identify_spad(void)
227{
228 return test_feature(SPAD_KEY);
229}
230EXPORT_SYMBOL(identify_spad);
231
232char identify_tdm(void)
233{
234 return test_feature(TDM_KEY);
235}
236EXPORT_SYMBOL(identify_tdm);
237
238char identify_zsp(void)
239{
240 return test_feature(ZSP_KEY);
241}
242EXPORT_SYMBOL(identify_zsp);
243
244static char identify_enetfeature(char key, unsigned long interface_num)
245{
246 char *feature = get_features();
247
248 while (*feature) {
249 if (*feature++ == key && interface_num-- == 0)
250 return *feature;
251 feature++;
252 }
253
254 return FEATURE_NOEXIST;
255}
256
257char identify_enet(unsigned long interface_num)
258{
259 return identify_enetfeature(ENET_KEY, interface_num);
260}
261EXPORT_SYMBOL(identify_enet);
262
263char identify_enetTxD(unsigned long interface_num)
264{
265 return identify_enetfeature(ENETTXD_KEY, interface_num);
266}
267EXPORT_SYMBOL(identify_enetTxD);
268
269unsigned long identify_family(void)
270{
271 unsigned long deviceid;
272
273 deviceid = get_deviceid();
274
275 return deviceid & CPU_DEVID_FAMILY;
276}
277EXPORT_SYMBOL(identify_family);
278
279unsigned long identify_revision(void)
280{
281 unsigned long deviceid;
282
283 deviceid = get_deviceid();
284
285 return deviceid & CPU_DEVID_REVISION;
286}
287EXPORT_SYMBOL(identify_revision);
288
289/* PROM environment functions */
290char *prom_getenv(char *env_name)
291{
292 /*
293 * Return a pointer to the given environment variable. prom_envp
294 * points to a null terminated array of pointers to variables.
295 * Environment variables are stored in the form of "memsize=64"
296 */
297
298 char **var = prom_envp;
299 int i = strlen(env_name);
300
301 while (*var) {
302 if (strncmp(env_name, *var, i) == 0) {
303 return (*var + strlen(env_name) + 1);
304 }
305 var++;
306 }
307
308 return NULL;
309}
310
311/* PROM commandline functions */
312char *prom_getcmdline(void)
313{
314 return &(arcs_cmdline[0]);
315}
316EXPORT_SYMBOL(prom_getcmdline);
317
318void __init prom_init_cmdline(void)
319{
320 char *cp;
321 int actr;
322
323 actr = 1; /* Always ignore argv[0] */
324
325 cp = &(arcs_cmdline[0]);
326 while (actr < prom_argc) {
327 strcpy(cp, prom_argv[actr]);
328 cp += strlen(prom_argv[actr]);
329 *cp++ = ' ';
330 actr++;
331 }
332 if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
333 --cp;
334 *cp = '\0';
335}
336
337/* memory allocation functions */
338static int __init prom_memtype_classify(unsigned int type)
339{
340 switch (type) {
341 case yamon_free:
342 return BOOT_MEM_RAM;
343 case yamon_prom:
344 return BOOT_MEM_ROM_DATA;
345 default:
346 return BOOT_MEM_RESERVED;
347 }
348}
349
350void __init prom_meminit(void)
351{
352 struct prom_pmemblock *p;
353
354 p = prom_getmdesc();
355
356 while (p->size) {
357 long type;
358 unsigned long base, size;
359
360 type = prom_memtype_classify(p->type);
361 base = p->base;
362 size = p->size;
363
364 add_memory_region(base, size, type);
365 p++;
366 }
367}
368
369void __init prom_free_prom_memory(void)
370{
371 int argc;
372 char **argv;
373 char **envp;
374 char *ptr;
375 int len = 0;
376 int i;
377 unsigned long addr;
378
379 /*
380 * preserve environment variables and command line from pmon/bbload
381 * first preserve the command line
382 */
383 for (argc = 0; argc < prom_argc; argc++) {
384 len += sizeof(char *); /* length of pointer */
385 len += strlen(prom_argv[argc]) + 1; /* length of string */
386 }
387 len += sizeof(char *); /* plus length of null pointer */
388
389 argv = kmalloc(len, GFP_KERNEL);
390 ptr = (char *) &argv[prom_argc + 1]; /* strings follow array */
391
392 for (argc = 0; argc < prom_argc; argc++) {
393 argv[argc] = ptr;
394 strcpy(ptr, prom_argv[argc]);
395 ptr += strlen(prom_argv[argc]) + 1;
396 }
397 argv[prom_argc] = NULL; /* end array with null pointer */
398 prom_argv = argv;
399
400 /* next preserve the environment variables */
401 len = 0;
402 i = 0;
403 for (envp = prom_envp; *envp != NULL; envp++) {
404 i++; /* count number of environment variables */
405 len += sizeof(char *); /* length of pointer */
406 len += strlen(*envp) + 1; /* length of string */
407 }
408 len += sizeof(char *); /* plus length of null pointer */
409
410 envp = kmalloc(len, GFP_KERNEL);
411 ptr = (char *) &envp[i+1];
412
413 for (argc = 0; argc < i; argc++) {
414 envp[argc] = ptr;
415 strcpy(ptr, prom_envp[argc]);
416 ptr += strlen(prom_envp[argc]) + 1;
417 }
418 envp[i] = NULL; /* end array with null pointer */
419 prom_envp = envp;
420
421 for (i = 0; i < boot_mem_map.nr_map; i++) {
422 if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
423 continue;
424
425 addr = boot_mem_map.map[i].addr;
426 free_init_pages("prom memory",
427 addr, addr + boot_mem_map.map[i].size);
428 }
429}
430
431struct prom_pmemblock *__init prom_getmdesc(void)
432{
433 static char memsz_env[] __initdata = "memsize";
434 static char heaptop_env[] __initdata = "heaptop";
435 char *str;
436 unsigned int memsize;
437 unsigned int heaptop;
438#ifdef CONFIG_MTD_PMC_MSP_RAMROOT
439 void *ramroot_start;
440 unsigned long ramroot_size;
441#endif
442 int i;
443
444 str = prom_getenv(memsz_env);
445 if (!str) {
446 ppfinit("memsize not set in boot prom, "
447 "set to default (32Mb)\n");
448 memsize = 0x02000000;
449 } else {
450 memsize = simple_strtol(str, NULL, 0);
451
452 if (memsize == 0) {
453 /* if memsize is a bad size, use reasonable default */
454 memsize = 0x02000000;
455 }
456
457 /* convert to physical address (removing caching bits, etc) */
458 memsize = CPHYSADDR(memsize);
459 }
460
461 str = prom_getenv(heaptop_env);
462 if (!str) {
463 heaptop = CPHYSADDR((u32)&_text);
464 ppfinit("heaptop not set in boot prom, "
465 "set to default 0x%08x\n", heaptop);
466 } else {
467 heaptop = simple_strtol(str, NULL, 16);
468 if (heaptop == 0) {
469 /* heaptop conversion bad, might have 0xValue */
470 heaptop = simple_strtol(str, NULL, 0);
471
472 if (heaptop == 0) {
473 /* heaptop still bad, use reasonable default */
474 heaptop = CPHYSADDR((u32)&_text);
475 }
476 }
477
478 /* convert to physical address (removing caching bits, etc) */
479 heaptop = CPHYSADDR((u32)heaptop);
480 }
481
482 /* the base region */
483 i = 0;
484 mdesc[i].type = BOOT_MEM_RESERVED;
485 mdesc[i].base = 0x00000000;
486 mdesc[i].size = PAGE_ALIGN(0x300 + 0x80);
487 /* jtag interrupt vector + sizeof vector */
488
489 /* PMON data */
490 if (heaptop > mdesc[i].base + mdesc[i].size) {
491 i++; /* 1 */
492 mdesc[i].type = BOOT_MEM_ROM_DATA;
493 mdesc[i].base = mdesc[i-1].base + mdesc[i-1].size;
494 mdesc[i].size = heaptop - mdesc[i].base;
495 }
496
497 /* end of PMON data to start of kernel -- probably zero .. */
498 if (heaptop != CPHYSADDR((u32)_text)) {
499 i++; /* 2 */
500 mdesc[i].type = BOOT_MEM_RAM;
501 mdesc[i].base = heaptop;
502 mdesc[i].size = CPHYSADDR((u32)_text) - mdesc[i].base;
503 }
504
505 /* kernel proper */
506 i++; /* 3 */
507 mdesc[i].type = BOOT_MEM_RESERVED;
508 mdesc[i].base = CPHYSADDR((u32)_text);
509#ifdef CONFIG_MTD_PMC_MSP_RAMROOT
510 if (get_ramroot(&ramroot_start, &ramroot_size)) {
511 /*
512 * Rootfs in RAM -- follows kernel
513 * Combine rootfs image with kernel block so a
514 * page (4k) isn't wasted between memory blocks
515 */
516 mdesc[i].size = CPHYSADDR(PAGE_ALIGN(
517 (u32)ramroot_start + ramroot_size)) - mdesc[i].base;
518 } else
519#endif
520 mdesc[i].size = CPHYSADDR(PAGE_ALIGN(
521 (u32)_end)) - mdesc[i].base;
522
523 /* Remainder of RAM -- under memsize */
524 i++; /* 5 */
525 mdesc[i].type = yamon_free;
526 mdesc[i].base = mdesc[i-1].base + mdesc[i-1].size;
527 mdesc[i].size = memsize - mdesc[i].base;
528
529 return &mdesc[0];
530}
531
532/* rootfs functions */
533#ifdef CONFIG_MTD_PMC_MSP_RAMROOT
534bool get_ramroot(void **start, unsigned long *size)
535{
536 extern char _end[];
537
538 /* Check for start following the end of the kernel */
539 void *check_start = (void *)_end;
540
541 /* Check for supported rootfs types */
542#ifdef CONFIG_CRAMFS
543 if (*(__u32 *)check_start == CRAMFS_MAGIC) {
544 /* Get CRAMFS size */
545 *start = check_start;
546 *size = PAGE_ALIGN(((struct cramfs_super *)
547 check_start)->size);
548
549 return true;
550 }
551#endif
552#ifdef CONFIG_SQUASHFS
553 if (*((unsigned int *)check_start) == SQUASHFS_MAGIC) {
554 /* Get SQUASHFS size */
555 *start = check_start;
556 *size = PAGE_ALIGN(((struct squashfs_super_block *)
557 check_start)->bytes_used);
558
559 return true;
560 }
561#endif
562
563 return false;
564}
565EXPORT_SYMBOL(get_ramroot);
566#endif
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_setup.c b/arch/mips/pmc-sierra/msp71xx/msp_setup.c
new file mode 100644
index 000000000000..8f69b789be90
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_setup.c
@@ -0,0 +1,256 @@
1/*
2 * The generic setup file for PMC-Sierra MSP processors
3 *
4 * Copyright 2005-2007 PMC-Sierra, Inc,
5 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13#include <asm/bootinfo.h>
14#include <asm/cacheflush.h>
15#include <asm/r4kcache.h>
16#include <asm/reboot.h>
17#include <asm/time.h>
18
19#include <msp_prom.h>
20#include <msp_regs.h>
21
22#if defined(CONFIG_PMC_MSP7120_GW)
23#include <msp_regops.h>
24#include <msp_gpio.h>
25#define MSP_BOARD_RESET_GPIO 9
26#endif
27
28extern void msp_timer_init(void);
29extern void msp_serial_setup(void);
30extern void pmctwiled_setup(void);
31
32#if defined(CONFIG_PMC_MSP7120_EVAL) || \
33 defined(CONFIG_PMC_MSP7120_GW) || \
34 defined(CONFIG_PMC_MSP7120_FPGA)
35/*
36 * Performs the reset for MSP7120-based boards
37 */
38void msp7120_reset(void)
39{
40 void *start, *end, *iptr;
41 register int i;
42
43 /* Diasble all interrupts */
44 local_irq_disable();
45#ifdef CONFIG_SYS_SUPPORTS_MULTITHREADING
46 dvpe();
47#endif
48
49 /* Cache the reset code of this function */
50 __asm__ __volatile__ (
51 " .set push \n"
52 " .set mips3 \n"
53 " la %0,startpoint \n"
54 " la %1,endpoint \n"
55 " .set pop \n"
56 : "=r" (start), "=r" (end)
57 :
58 );
59
60 for (iptr = (void *)((unsigned int)start & ~(L1_CACHE_BYTES - 1));
61 iptr < end; iptr += L1_CACHE_BYTES)
62 cache_op(Fill, iptr);
63
64 __asm__ __volatile__ (
65 "startpoint: \n"
66 );
67
68 /* Put the DDRC into self-refresh mode */
69 DDRC_INDIRECT_WRITE(DDRC_CTL(10), 0xb, 1 << 16);
70
71 /*
72 * IMPORTANT!
73 * DO NOT do anything from here on out that might even
74 * think about fetching from RAM - i.e., don't call any
75 * non-inlined functions, and be VERY sure that any inline
76 * functions you do call do NOT access any sort of RAM
77 * anywhere!
78 */
79
80 /* Wait a bit for the DDRC to settle */
81 for (i = 0; i < 100000000; i++);
82
83#if defined(CONFIG_PMC_MSP7120_GW)
84 /*
85 * Set GPIO 9 HI, (tied to board reset logic)
86 * GPIO 9 is the 4th GPIO of register 3
87 *
88 * NOTE: We cannot use the higher-level msp_gpio_mode()/out()
89 * as GPIO char driver may not be enabled and it would look up
90 * data inRAM!
91 */
92 set_value_reg32(GPIO_CFG3_REG,
93 basic_mode_mask(MSP_BOARD_RESET_GPIO),
94 basic_mode(MSP_GPIO_OUTPUT, MSP_BOARD_RESET_GPIO));
95 set_reg32(GPIO_DATA3_REG,
96 basic_data_mask(MSP_BOARD_RESET_GPIO));
97
98 /*
99 * In case GPIO9 doesn't reset the board (jumper configurable!)
100 * fallback to device reset below.
101 */
102#endif
103 /* Set bit 1 of the MSP7120 reset register */
104 *RST_SET_REG = 0x00000001;
105
106 __asm__ __volatile__ (
107 "endpoint: \n"
108 );
109}
110#endif
111
112void msp_restart(char *command)
113{
114 printk(KERN_WARNING "Now rebooting .......\n");
115
116#if defined(CONFIG_PMC_MSP7120_EVAL) || \
117 defined(CONFIG_PMC_MSP7120_GW) || \
118 defined(CONFIG_PMC_MSP7120_FPGA)
119 msp7120_reset();
120#else
121 /* No chip-specific reset code, just jump to the ROM reset vector */
122 set_c0_status(ST0_BEV | ST0_ERL);
123 change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
124 flush_cache_all();
125 write_c0_wired(0);
126
127 __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
128#endif
129}
130
131void msp_halt(void)
132{
133 printk(KERN_WARNING "\n** You can safely turn off the power\n");
134 while (1)
135 /* If possible call official function to get CPU WARs */
136 if (cpu_wait)
137 (*cpu_wait)();
138 else
139 __asm__(".set\tmips3\n\t" "wait\n\t" ".set\tmips0");
140}
141
142void msp_power_off(void)
143{
144 msp_halt();
145}
146
147void __init plat_mem_setup(void)
148{
149 _machine_restart = msp_restart;
150 _machine_halt = msp_halt;
151 pm_power_off = msp_power_off;
152
153 board_time_init = msp_timer_init;
154}
155
156void __init prom_init(void)
157{
158 unsigned long family;
159 unsigned long revision;
160
161 prom_argc = fw_arg0;
162 prom_argv = (char **)fw_arg1;
163 prom_envp = (char **)fw_arg2;
164
165 /*
166 * Someday we can use this with PMON2000 to get a
167 * platform call prom routines for output etc. without
168 * having to use grody hacks. For now it's unused.
169 *
170 * struct callvectors *cv = (struct callvectors *) fw_arg3;
171 */
172 family = identify_family();
173 revision = identify_revision();
174
175 switch (family) {
176 case FAMILY_FPGA:
177 if (FPGA_IS_MSP4200(revision)) {
178 /* Old-style revision ID */
179 mips_machgroup = MACH_GROUP_MSP;
180 mips_machtype = MACH_MSP4200_FPGA;
181 } else {
182 mips_machgroup = MACH_GROUP_MSP;
183 mips_machtype = MACH_MSP_OTHER;
184 }
185 break;
186
187 case FAMILY_MSP4200:
188 mips_machgroup = MACH_GROUP_MSP;
189#if defined(CONFIG_PMC_MSP4200_EVAL)
190 mips_machtype = MACH_MSP4200_EVAL;
191#elif defined(CONFIG_PMC_MSP4200_GW)
192 mips_machtype = MACH_MSP4200_GW;
193#else
194 mips_machtype = MACH_MSP_OTHER;
195#endif
196 break;
197
198 case FAMILY_MSP4200_FPGA:
199 mips_machgroup = MACH_GROUP_MSP;
200 mips_machtype = MACH_MSP4200_FPGA;
201 break;
202
203 case FAMILY_MSP7100:
204 mips_machgroup = MACH_GROUP_MSP;
205#if defined(CONFIG_PMC_MSP7120_EVAL)
206 mips_machtype = MACH_MSP7120_EVAL;
207#elif defined(CONFIG_PMC_MSP7120_GW)
208 mips_machtype = MACH_MSP7120_GW;
209#else
210 mips_machtype = MACH_MSP_OTHER;
211#endif
212 break;
213
214 case FAMILY_MSP7100_FPGA:
215 mips_machgroup = MACH_GROUP_MSP;
216 mips_machtype = MACH_MSP7120_FPGA;
217 break;
218
219 default:
220 /* we don't recognize the machine */
221 mips_machgroup = MACH_GROUP_UNKNOWN;
222 mips_machtype = MACH_UNKNOWN;
223 break;
224 }
225
226 /* make sure we have the right initialization routine - sanity */
227 if (mips_machgroup != MACH_GROUP_MSP) {
228 ppfinit("Unknown machine group in a "
229 "MSP initialization routine\n");
230 panic("***Bogosity factor five***, exiting\n");
231 }
232
233 prom_init_cmdline();
234
235 prom_meminit();
236
237 /*
238 * Sub-system setup follows.
239 * Setup functions can either be called here or using the
240 * subsys_initcall mechanism (i.e. see msp_pci_setup). The
241 * order in which they are called can be changed by using the
242 * link order in arch/mips/pmc-sierra/msp71xx/Makefile.
243 *
244 * NOTE: Please keep sub-system specific initialization code
245 * in separate specific files.
246 */
247 msp_serial_setup();
248
249#ifdef CONFIG_PMCTWILED
250 /*
251 * Setup LED states before the subsys_initcall loads other
252 * dependant drivers/modules.
253 */
254 pmctwiled_setup();
255#endif
256}
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_time.c b/arch/mips/pmc-sierra/msp71xx/msp_time.c
new file mode 100644
index 000000000000..2a2beac5a4f8
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_time.c
@@ -0,0 +1,94 @@
1/*
2 * Setting up the clock on MSP SOCs. No RTC typically.
3 *
4 * Carsten Langgaard, carstenl@mips.com
5 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
6 *
7 * ########################################################################
8 *
9 * This program is free software; you can distribute it and/or modify it
10 * under the terms of the GNU General Public License (Version 2) as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
21 *
22 * ########################################################################
23 */
24
25#include <linux/init.h>
26#include <linux/kernel_stat.h>
27#include <linux/sched.h>
28#include <linux/spinlock.h>
29#include <linux/module.h>
30#include <linux/ptrace.h>
31
32#include <asm/mipsregs.h>
33#include <asm/time.h>
34
35#include <msp_prom.h>
36#include <msp_int.h>
37#include <msp_regs.h>
38
39void __init msp_timer_init(void)
40{
41 char *endp, *s;
42 unsigned long cpu_rate = 0;
43
44 if (cpu_rate == 0) {
45 s = prom_getenv("clkfreqhz");
46 cpu_rate = simple_strtoul(s, &endp, 10);
47 if (endp != NULL && *endp != 0) {
48 printk(KERN_ERR
49 "Clock rate in Hz parse error: %s\n", s);
50 cpu_rate = 0;
51 }
52 }
53
54 if (cpu_rate == 0) {
55 s = prom_getenv("clkfreq");
56 cpu_rate = 1000 * simple_strtoul(s, &endp, 10);
57 if (endp != NULL && *endp != 0) {
58 printk(KERN_ERR
59 "Clock rate in MHz parse error: %s\n", s);
60 cpu_rate = 0;
61 }
62 }
63
64 if (cpu_rate == 0) {
65#if defined(CONFIG_PMC_MSP7120_EVAL) \
66 || defined(CONFIG_PMC_MSP7120_GW)
67 cpu_rate = 400000000;
68#elif defined(CONFIG_PMC_MSP7120_FPGA)
69 cpu_rate = 25000000;
70#else
71 cpu_rate = 150000000;
72#endif
73 printk(KERN_ERR
74 "Failed to determine CPU clock rate, "
75 "assuming %ld hz ...\n", cpu_rate);
76 }
77
78 printk(KERN_WARNING "Clock rate set to %ld\n", cpu_rate);
79
80 /* timer frequency is 1/2 clock rate */
81 mips_hpt_frequency = cpu_rate/2;
82}
83
84
85void __init plat_timer_setup(struct irqaction *irq)
86{
87#ifdef CONFIG_IRQ_MSP_CIC
88 /* we are using the vpe0 counter for timer interrupts */
89 setup_irq(MSP_INT_VPE0_TIMER, irq);
90#else
91 /* we are using the mips counter for timer interrupts */
92 setup_irq(MSP_INT_TIMER, irq);
93#endif
94}
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_usb.c b/arch/mips/pmc-sierra/msp71xx/msp_usb.c
new file mode 100644
index 000000000000..21f9c70b6923
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_usb.c
@@ -0,0 +1,150 @@
1/*
2 * The setup file for USB related hardware on PMC-Sierra MSP processors.
3 *
4 * Copyright 2006-2007 PMC-Sierra, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 *
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
12 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
14 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
15 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
16 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
17 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
18 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
20 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
27#include <linux/dma-mapping.h>
28#include <linux/init.h>
29#include <linux/ioport.h>
30#include <linux/platform_device.h>
31
32#include <asm/mipsregs.h>
33
34#include <msp_regs.h>
35#include <msp_int.h>
36#include <msp_prom.h>
37
38#if defined(CONFIG_USB_EHCI_HCD)
39static struct resource msp_usbhost_resources [] = {
40 [0] = {
41 .start = MSP_USB_BASE_START,
42 .end = MSP_USB_BASE_END,
43 .flags = IORESOURCE_MEM,
44 },
45 [1] = {
46 .start = MSP_INT_USB,
47 .end = MSP_INT_USB,
48 .flags = IORESOURCE_IRQ,
49 },
50};
51
52static u64 msp_usbhost_dma_mask = DMA_32BIT_MASK;
53
54static struct platform_device msp_usbhost_device = {
55 .name = "pmcmsp-ehci",
56 .id = 0,
57 .dev = {
58 .dma_mask = &msp_usbhost_dma_mask,
59 .coherent_dma_mask = DMA_32BIT_MASK,
60 },
61 .num_resources = ARRAY_SIZE (msp_usbhost_resources),
62 .resource = msp_usbhost_resources,
63};
64#endif /* CONFIG_USB_EHCI_HCD */
65
66#if defined(CONFIG_USB_GADGET)
67static struct resource msp_usbdev_resources [] = {
68 [0] = {
69 .start = MSP_USB_BASE,
70 .end = MSP_USB_BASE_END,
71 .flags = IORESOURCE_MEM,
72 },
73 [1] = {
74 .start = MSP_INT_USB,
75 .end = MSP_INT_USB,
76 .flags = IORESOURCE_IRQ,
77 },
78};
79
80static u64 msp_usbdev_dma_mask = DMA_32BIT_MASK;
81
82static struct platform_device msp_usbdev_device = {
83 .name = "msp71xx_udc",
84 .id = 0,
85 .dev = {
86 .dma_mask = &msp_usbdev_dma_mask,
87 .coherent_dma_mask = DMA_32BIT_MASK,
88 },
89 .num_resources = ARRAY_SIZE (msp_usbdev_resources),
90 .resource = msp_usbdev_resources,
91};
92#endif /* CONFIG_USB_GADGET */
93
94#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_GADGET)
95static struct platform_device *msp_devs[1];
96#endif
97
98
99static int __init msp_usb_setup(void)
100{
101#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_GADGET)
102 char *strp;
103 char envstr[32];
104 unsigned int val = 0;
105 int result = 0;
106
107 /*
108 * construct environment name usbmode
109 * set usbmode <host/device> as pmon environment var
110 */
111 snprintf((char *)&envstr[0], sizeof(envstr), "usbmode");
112
113#if defined(CONFIG_USB_EHCI_HCD)
114 /* default to host mode */
115 val = 1;
116#endif
117
118 /* get environment string */
119 strp = prom_getenv((char *)&envstr[0]);
120 if (strp) {
121 if (!strcmp(strp, "device"))
122 val = 0;
123 }
124
125 if (val) {
126#if defined(CONFIG_USB_EHCI_HCD)
127 /* get host mode device */
128 msp_devs[0] = &msp_usbhost_device;
129 ppfinit("platform add USB HOST done %s.\n",
130 msp_devs[0]->name);
131
132 result = platform_add_devices(msp_devs, ARRAY_SIZE (msp_devs));
133#endif /* CONFIG_USB_EHCI_HCD */
134 }
135#if defined(CONFIG_USB_GADGET)
136 else {
137 /* get device mode structure */
138 msp_devs[0] = &msp_usbdev_device;
139 ppfinit("platform add USB DEVICE done %s.\n",
140 msp_devs[0]->name);
141
142 result = platform_add_devices(msp_devs, ARRAY_SIZE (msp_devs));
143 }
144#endif /* CONFIG_USB_GADGET */
145#endif /* CONFIG_USB_EHCI_HCD || CONFIG_USB_GADGET */
146
147 return result;
148}
149
150subsys_initcall(msp_usb_setup);