aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/pmcs-msp71xx
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2012-12-15 05:52:10 -0500
committerRalf Baechle <ralf@linux-mips.org>2013-02-01 04:00:22 -0500
commit0f3a05cb43e731b8cf861dee30e7e4bddd6c5ccc (patch)
treee19550e56ab9cf95a99d6aa31502099950cdbce3 /arch/mips/pmcs-msp71xx
parent7034228792cc561e79ff8600f02884bd4c80e287 (diff)
MIPS: MSP71xx: Move code.
Now that Yosemite's gone we can move the MSP71xx code one level up. Shane McDonald <mcdonald.shane@gmail.com>'s https://patchwork.linux-mips.org/patch/4736/ has been folded into this patch. Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/pmcs-msp71xx')
-rw-r--r--arch/mips/pmcs-msp71xx/Kconfig48
-rw-r--r--arch/mips/pmcs-msp71xx/Makefile14
-rw-r--r--arch/mips/pmcs-msp71xx/Platform7
-rw-r--r--arch/mips/pmcs-msp71xx/gpio.c216
-rw-r--r--arch/mips/pmcs-msp71xx/gpio_extended.c146
-rw-r--r--arch/mips/pmcs-msp71xx/msp_elb.c46
-rw-r--r--arch/mips/pmcs-msp71xx/msp_eth.c187
-rw-r--r--arch/mips/pmcs-msp71xx/msp_hwbutton.c165
-rw-r--r--arch/mips/pmcs-msp71xx/msp_irq.c164
-rw-r--r--arch/mips/pmcs-msp71xx/msp_irq_cic.c216
-rw-r--r--arch/mips/pmcs-msp71xx/msp_irq_per.c134
-rw-r--r--arch/mips/pmcs-msp71xx/msp_irq_slp.c106
-rw-r--r--arch/mips/pmcs-msp71xx/msp_pci.c50
-rw-r--r--arch/mips/pmcs-msp71xx/msp_prom.c503
-rw-r--r--arch/mips/pmcs-msp71xx/msp_serial.c154
-rw-r--r--arch/mips/pmcs-msp71xx/msp_setup.c245
-rw-r--r--arch/mips/pmcs-msp71xx/msp_smp.c77
-rw-r--r--arch/mips/pmcs-msp71xx/msp_smtc.c105
-rw-r--r--arch/mips/pmcs-msp71xx/msp_time.c101
-rw-r--r--arch/mips/pmcs-msp71xx/msp_usb.c263
20 files changed, 2947 insertions, 0 deletions
diff --git a/arch/mips/pmcs-msp71xx/Kconfig b/arch/mips/pmcs-msp71xx/Kconfig
new file mode 100644
index 000000000000..3482b8c8640c
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/Kconfig
@@ -0,0 +1,48 @@
1choice
2 prompt "PMC-Sierra MSP SOC type"
3 depends on PMC_MSP
4
5config PMC_MSP4200_EVAL
6 bool "PMC-Sierra MSP4200 Eval Board"
7 select IRQ_MSP_SLP
8 select HW_HAS_PCI
9
10config PMC_MSP4200_GW
11 bool "PMC-Sierra MSP4200 VoIP Gateway"
12 select IRQ_MSP_SLP
13 select HW_HAS_PCI
14
15config PMC_MSP7120_EVAL
16 bool "PMC-Sierra MSP7120 Eval Board"
17 select SYS_SUPPORTS_MULTITHREADING
18 select IRQ_MSP_CIC
19 select HW_HAS_PCI
20
21config PMC_MSP7120_GW
22 bool "PMC-Sierra MSP7120 Residential Gateway"
23 select SYS_SUPPORTS_MULTITHREADING
24 select IRQ_MSP_CIC
25 select HW_HAS_PCI
26 select MSP_HAS_USB
27 select MSP_ETH
28
29config PMC_MSP7120_FPGA
30 bool "PMC-Sierra MSP7120 FPGA"
31 select SYS_SUPPORTS_MULTITHREADING
32 select IRQ_MSP_CIC
33 select HW_HAS_PCI
34
35endchoice
36
37config MSP_HAS_USB
38 boolean
39 depends on PMC_MSP
40
41config MSP_ETH
42 boolean
43 select MSP_HAS_MAC
44 depends on PMC_MSP
45
46config MSP_HAS_MAC
47 boolean
48 depends on PMC_MSP
diff --git a/arch/mips/pmcs-msp71xx/Makefile b/arch/mips/pmcs-msp71xx/Makefile
new file mode 100644
index 000000000000..cefba7733b73
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/Makefile
@@ -0,0 +1,14 @@
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_HAVE_GPIO_LIB) += gpio.o gpio_extended.o
7obj-$(CONFIG_PMC_MSP7120_GW) += msp_hwbutton.o
8obj-$(CONFIG_IRQ_MSP_SLP) += msp_irq_slp.o
9obj-$(CONFIG_IRQ_MSP_CIC) += msp_irq_cic.o msp_irq_per.o
10obj-$(CONFIG_PCI) += msp_pci.o
11obj-$(CONFIG_MSP_HAS_MAC) += msp_eth.o
12obj-$(CONFIG_MSP_HAS_USB) += msp_usb.o
13obj-$(CONFIG_MIPS_MT_SMP) += msp_smp.o
14obj-$(CONFIG_MIPS_MT_SMTC) += msp_smtc.o
diff --git a/arch/mips/pmcs-msp71xx/Platform b/arch/mips/pmcs-msp71xx/Platform
new file mode 100644
index 000000000000..7af0734a5007
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/Platform
@@ -0,0 +1,7 @@
1#
2# PMC-Sierra MSP SOCs
3#
4platform-$(CONFIG_PMC_MSP) += pmcs-msp71xx/
5cflags-$(CONFIG_PMC_MSP) += -I$(srctree)/arch/mips/include/asm/mach-pmcs-msp71xx \
6 -mno-branch-likely
7load-$(CONFIG_PMC_MSP) += 0xffffffff80100000
diff --git a/arch/mips/pmcs-msp71xx/gpio.c b/arch/mips/pmcs-msp71xx/gpio.c
new file mode 100644
index 000000000000..aaccbe524386
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/gpio.c
@@ -0,0 +1,216 @@
1/*
2 * Generic PMC MSP71xx GPIO handling. These base gpio are controlled by two
3 * types of registers. The data register sets the output level when in output
4 * mode and when in input mode will contain the value at the input. The config
5 * register sets the various modes for each gpio.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * @author Patrick Glass <patrickglass@gmail.com>
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/gpio.h>
18#include <linux/spinlock.h>
19#include <linux/io.h>
20
21#define MSP71XX_CFG_OFFSET(gpio) (4 * (gpio))
22#define CONF_MASK 0x0F
23#define MSP71XX_GPIO_INPUT 0x01
24#define MSP71XX_GPIO_OUTPUT 0x08
25
26#define MSP71XX_GPIO_BASE 0x0B8400000L
27
28#define to_msp71xx_gpio_chip(c) container_of(c, struct msp71xx_gpio_chip, chip)
29
30static spinlock_t gpio_lock;
31
32/*
33 * struct msp71xx_gpio_chip - container for gpio chip and registers
34 * @chip: chip structure for the specified gpio bank
35 * @data_reg: register for reading and writing the gpio pin value
36 * @config_reg: register to set the mode for the gpio pin bank
37 * @out_drive_reg: register to set the output drive mode for the gpio pin bank
38 */
39struct msp71xx_gpio_chip {
40 struct gpio_chip chip;
41 void __iomem *data_reg;
42 void __iomem *config_reg;
43 void __iomem *out_drive_reg;
44};
45
46/*
47 * msp71xx_gpio_get() - return the chip's gpio value
48 * @chip: chip structure which controls the specified gpio
49 * @offset: gpio whose value will be returned
50 *
51 * It will return 0 if gpio value is low and other if high.
52 */
53static int msp71xx_gpio_get(struct gpio_chip *chip, unsigned offset)
54{
55 struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip);
56
57 return __raw_readl(msp_chip->data_reg) & (1 << offset);
58}
59
60/*
61 * msp71xx_gpio_set() - set the output value for the gpio
62 * @chip: chip structure who controls the specified gpio
63 * @offset: gpio whose value will be assigned
64 * @value: logic level to assign to the gpio initially
65 *
66 * This will set the gpio bit specified to the desired value. It will set the
67 * gpio pin low if value is 0 otherwise it will be high.
68 */
69static void msp71xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
70{
71 struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip);
72 unsigned long flags;
73 u32 data;
74
75 spin_lock_irqsave(&gpio_lock, flags);
76
77 data = __raw_readl(msp_chip->data_reg);
78 if (value)
79 data |= (1 << offset);
80 else
81 data &= ~(1 << offset);
82 __raw_writel(data, msp_chip->data_reg);
83
84 spin_unlock_irqrestore(&gpio_lock, flags);
85}
86
87/*
88 * msp71xx_set_gpio_mode() - declare the mode for a gpio
89 * @chip: chip structure which controls the specified gpio
90 * @offset: gpio whose value will be assigned
91 * @mode: desired configuration for the gpio (see datasheet)
92 *
93 * It will set the gpio pin config to the @mode value passed in.
94 */
95static int msp71xx_set_gpio_mode(struct gpio_chip *chip,
96 unsigned offset, int mode)
97{
98 struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip);
99 const unsigned bit_offset = MSP71XX_CFG_OFFSET(offset);
100 unsigned long flags;
101 u32 cfg;
102
103 spin_lock_irqsave(&gpio_lock, flags);
104
105 cfg = __raw_readl(msp_chip->config_reg);
106 cfg &= ~(CONF_MASK << bit_offset);
107 cfg |= (mode << bit_offset);
108 __raw_writel(cfg, msp_chip->config_reg);
109
110 spin_unlock_irqrestore(&gpio_lock, flags);
111
112 return 0;
113}
114
115/*
116 * msp71xx_direction_output() - declare the direction mode for a gpio
117 * @chip: chip structure which controls the specified gpio
118 * @offset: gpio whose value will be assigned
119 * @value: logic level to assign to the gpio initially
120 *
121 * This call will set the mode for the @gpio to output. It will set the
122 * gpio pin low if value is 0 otherwise it will be high.
123 */
124static int msp71xx_direction_output(struct gpio_chip *chip,
125 unsigned offset, int value)
126{
127 msp71xx_gpio_set(chip, offset, value);
128
129 return msp71xx_set_gpio_mode(chip, offset, MSP71XX_GPIO_OUTPUT);
130}
131
132/*
133 * msp71xx_direction_input() - declare the direction mode for a gpio
134 * @chip: chip structure which controls the specified gpio
135 * @offset: gpio whose to which the value will be assigned
136 *
137 * This call will set the mode for the @gpio to input.
138 */
139static int msp71xx_direction_input(struct gpio_chip *chip, unsigned offset)
140{
141 return msp71xx_set_gpio_mode(chip, offset, MSP71XX_GPIO_INPUT);
142}
143
144/*
145 * msp71xx_set_output_drive() - declare the output drive for the gpio line
146 * @gpio: gpio pin whose output drive you wish to modify
147 * @value: zero for active drain 1 for open drain drive
148 *
149 * This call will set the output drive mode for the @gpio to output.
150 */
151int msp71xx_set_output_drive(unsigned gpio, int value)
152{
153 unsigned long flags;
154 u32 data;
155
156 if (gpio > 15 || gpio < 0)
157 return -EINVAL;
158
159 spin_lock_irqsave(&gpio_lock, flags);
160
161 data = __raw_readl((void __iomem *)(MSP71XX_GPIO_BASE + 0x190));
162 if (value)
163 data |= (1 << gpio);
164 else
165 data &= ~(1 << gpio);
166 __raw_writel(data, (void __iomem *)(MSP71XX_GPIO_BASE + 0x190));
167
168 spin_unlock_irqrestore(&gpio_lock, flags);
169
170 return 0;
171}
172EXPORT_SYMBOL(msp71xx_set_output_drive);
173
174#define MSP71XX_GPIO_BANK(name, dr, cr, base_gpio, num_gpio) \
175{ \
176 .chip = { \
177 .label = name, \
178 .direction_input = msp71xx_direction_input, \
179 .direction_output = msp71xx_direction_output, \
180 .get = msp71xx_gpio_get, \
181 .set = msp71xx_gpio_set, \
182 .base = base_gpio, \
183 .ngpio = num_gpio \
184 }, \
185 .data_reg = (void __iomem *)(MSP71XX_GPIO_BASE + dr), \
186 .config_reg = (void __iomem *)(MSP71XX_GPIO_BASE + cr), \
187 .out_drive_reg = (void __iomem *)(MSP71XX_GPIO_BASE + 0x190), \
188}
189
190/*
191 * struct msp71xx_gpio_banks[] - container array of gpio banks
192 * @chip: chip structure for the specified gpio bank
193 * @data_reg: register for reading and writing the gpio pin value
194 * @config_reg: register to set the mode for the gpio pin bank
195 *
196 * This array structure defines the gpio banks for the PMC MIPS Processor.
197 * We specify the bank name, the data register, the config register, base
198 * starting gpio number, and the number of gpios exposed by the bank.
199 */
200static struct msp71xx_gpio_chip msp71xx_gpio_banks[] = {
201
202 MSP71XX_GPIO_BANK("GPIO_1_0", 0x170, 0x180, 0, 2),
203 MSP71XX_GPIO_BANK("GPIO_5_2", 0x174, 0x184, 2, 4),
204 MSP71XX_GPIO_BANK("GPIO_9_6", 0x178, 0x188, 6, 4),
205 MSP71XX_GPIO_BANK("GPIO_15_10", 0x17C, 0x18C, 10, 6),
206};
207
208void __init msp71xx_init_gpio(void)
209{
210 int i;
211
212 spin_lock_init(&gpio_lock);
213
214 for (i = 0; i < ARRAY_SIZE(msp71xx_gpio_banks); i++)
215 gpiochip_add(&msp71xx_gpio_banks[i].chip);
216}
diff --git a/arch/mips/pmcs-msp71xx/gpio_extended.c b/arch/mips/pmcs-msp71xx/gpio_extended.c
new file mode 100644
index 000000000000..2a99f360fae4
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/gpio_extended.c
@@ -0,0 +1,146 @@
1/*
2 * Generic PMC MSP71xx EXTENDED (EXD) GPIO handling. The extended gpio is
3 * a set of hardware registers that have no need for explicit locking as
4 * it is handled by unique method of writing individual set/clr bits.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * @author Patrick Glass <patrickglass@gmail.com>
11 */
12
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/gpio.h>
17#include <linux/io.h>
18
19#define MSP71XX_DATA_OFFSET(gpio) (2 * (gpio))
20#define MSP71XX_READ_OFFSET(gpio) (MSP71XX_DATA_OFFSET(gpio) + 1)
21#define MSP71XX_CFG_OUT_OFFSET(gpio) (MSP71XX_DATA_OFFSET(gpio) + 16)
22#define MSP71XX_CFG_IN_OFFSET(gpio) (MSP71XX_CFG_OUT_OFFSET(gpio) + 1)
23
24#define MSP71XX_EXD_GPIO_BASE 0x0BC000000L
25
26#define to_msp71xx_exd_gpio_chip(c) \
27 container_of(c, struct msp71xx_exd_gpio_chip, chip)
28
29/*
30 * struct msp71xx_exd_gpio_chip - container for gpio chip and registers
31 * @chip: chip structure for the specified gpio bank
32 * @reg: register for control and data of gpio pin
33 */
34struct msp71xx_exd_gpio_chip {
35 struct gpio_chip chip;
36 void __iomem *reg;
37};
38
39/*
40 * msp71xx_exd_gpio_get() - return the chip's gpio value
41 * @chip: chip structure which controls the specified gpio
42 * @offset: gpio whose value will be returned
43 *
44 * It will return 0 if gpio value is low and other if high.
45 */
46static int msp71xx_exd_gpio_get(struct gpio_chip *chip, unsigned offset)
47{
48 struct msp71xx_exd_gpio_chip *msp71xx_chip =
49 to_msp71xx_exd_gpio_chip(chip);
50 const unsigned bit = MSP71XX_READ_OFFSET(offset);
51
52 return __raw_readl(msp71xx_chip->reg) & (1 << bit);
53}
54
55/*
56 * msp71xx_exd_gpio_set() - set the output value for the gpio
57 * @chip: chip structure who controls the specified gpio
58 * @offset: gpio whose value will be assigned
59 * @value: logic level to assign to the gpio initially
60 *
61 * This will set the gpio bit specified to the desired value. It will set the
62 * gpio pin low if value is 0 otherwise it will be high.
63 */
64static void msp71xx_exd_gpio_set(struct gpio_chip *chip,
65 unsigned offset, int value)
66{
67 struct msp71xx_exd_gpio_chip *msp71xx_chip =
68 to_msp71xx_exd_gpio_chip(chip);
69 const unsigned bit = MSP71XX_DATA_OFFSET(offset);
70
71 __raw_writel(1 << (bit + (value ? 1 : 0)), msp71xx_chip->reg);
72}
73
74/*
75 * msp71xx_exd_direction_output() - declare the direction mode for a gpio
76 * @chip: chip structure which controls the specified gpio
77 * @offset: gpio whose value will be assigned
78 * @value: logic level to assign to the gpio initially
79 *
80 * This call will set the mode for the @gpio to output. It will set the
81 * gpio pin low if value is 0 otherwise it will be high.
82 */
83static int msp71xx_exd_direction_output(struct gpio_chip *chip,
84 unsigned offset, int value)
85{
86 struct msp71xx_exd_gpio_chip *msp71xx_chip =
87 to_msp71xx_exd_gpio_chip(chip);
88
89 msp71xx_exd_gpio_set(chip, offset, value);
90 __raw_writel(1 << MSP71XX_CFG_OUT_OFFSET(offset), msp71xx_chip->reg);
91 return 0;
92}
93
94/*
95 * msp71xx_exd_direction_input() - declare the direction mode for a gpio
96 * @chip: chip structure which controls the specified gpio
97 * @offset: gpio whose to which the value will be assigned
98 *
99 * This call will set the mode for the @gpio to input.
100 */
101static int msp71xx_exd_direction_input(struct gpio_chip *chip, unsigned offset)
102{
103 struct msp71xx_exd_gpio_chip *msp71xx_chip =
104 to_msp71xx_exd_gpio_chip(chip);
105
106 __raw_writel(1 << MSP71XX_CFG_IN_OFFSET(offset), msp71xx_chip->reg);
107 return 0;
108}
109
110#define MSP71XX_EXD_GPIO_BANK(name, exd_reg, base_gpio, num_gpio) \
111{ \
112 .chip = { \
113 .label = name, \
114 .direction_input = msp71xx_exd_direction_input, \
115 .direction_output = msp71xx_exd_direction_output, \
116 .get = msp71xx_exd_gpio_get, \
117 .set = msp71xx_exd_gpio_set, \
118 .base = base_gpio, \
119 .ngpio = num_gpio, \
120 }, \
121 .reg = (void __iomem *)(MSP71XX_EXD_GPIO_BASE + exd_reg), \
122}
123
124/*
125 * struct msp71xx_exd_gpio_banks[] - container array of gpio banks
126 * @chip: chip structure for the specified gpio bank
127 * @reg: register for reading and writing the gpio pin value
128 *
129 * This array structure defines the extended gpio banks for the
130 * PMC MIPS Processor. We specify the bank name, the data/config
131 * register,the base starting gpio number, and the number of
132 * gpios exposed by the bank of gpios.
133 */
134static struct msp71xx_exd_gpio_chip msp71xx_exd_gpio_banks[] = {
135
136 MSP71XX_EXD_GPIO_BANK("GPIO_23_16", 0x188, 16, 8),
137 MSP71XX_EXD_GPIO_BANK("GPIO_27_24", 0x18C, 24, 4),
138};
139
140void __init msp71xx_init_gpio_extended(void)
141{
142 int i;
143
144 for (i = 0; i < ARRAY_SIZE(msp71xx_exd_gpio_banks); i++)
145 gpiochip_add(&msp71xx_exd_gpio_banks[i].chip);
146}
diff --git a/arch/mips/pmcs-msp71xx/msp_elb.c b/arch/mips/pmcs-msp71xx/msp_elb.c
new file mode 100644
index 000000000000..3e9641007216
--- /dev/null
+++ b/arch/mips/pmcs-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/pmcs-msp71xx/msp_eth.c b/arch/mips/pmcs-msp71xx/msp_eth.c
new file mode 100644
index 000000000000..c584df393de2
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/msp_eth.c
@@ -0,0 +1,187 @@
1/*
2 * The setup file for ethernet related hardware on PMC-Sierra MSP processors.
3 *
4 * Copyright 2010 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/init.h>
28#include <linux/kernel.h>
29#include <linux/ioport.h>
30#include <linux/platform_device.h>
31#include <linux/delay.h>
32#include <msp_regs.h>
33#include <msp_int.h>
34#include <msp_gpio_macros.h>
35
36
37#define MSP_ETHERNET_GPIO0 14
38#define MSP_ETHERNET_GPIO1 15
39#define MSP_ETHERNET_GPIO2 16
40
41#ifdef CONFIG_MSP_HAS_TSMAC
42#define MSP_TSMAC_SIZE 0x10020
43#define MSP_TSMAC_ID "pmc_tsmac"
44
45static struct resource msp_tsmac0_resources[] = {
46 [0] = {
47 .start = MSP_MAC0_BASE,
48 .end = MSP_MAC0_BASE + MSP_TSMAC_SIZE - 1,
49 .flags = IORESOURCE_MEM,
50 },
51 [1] = {
52 .start = MSP_INT_MAC0,
53 .end = MSP_INT_MAC0,
54 .flags = IORESOURCE_IRQ,
55 },
56};
57
58static struct resource msp_tsmac1_resources[] = {
59 [0] = {
60 .start = MSP_MAC1_BASE,
61 .end = MSP_MAC1_BASE + MSP_TSMAC_SIZE - 1,
62 .flags = IORESOURCE_MEM,
63 },
64 [1] = {
65 .start = MSP_INT_MAC1,
66 .end = MSP_INT_MAC1,
67 .flags = IORESOURCE_IRQ,
68 },
69};
70static struct resource msp_tsmac2_resources[] = {
71 [0] = {
72 .start = MSP_MAC2_BASE,
73 .end = MSP_MAC2_BASE + MSP_TSMAC_SIZE - 1,
74 .flags = IORESOURCE_MEM,
75 },
76 [1] = {
77 .start = MSP_INT_SAR,
78 .end = MSP_INT_SAR,
79 .flags = IORESOURCE_IRQ,
80 },
81};
82
83
84static struct platform_device tsmac_device[] = {
85 [0] = {
86 .name = MSP_TSMAC_ID,
87 .id = 0,
88 .num_resources = ARRAY_SIZE(msp_tsmac0_resources),
89 .resource = msp_tsmac0_resources,
90 },
91 [1] = {
92 .name = MSP_TSMAC_ID,
93 .id = 1,
94 .num_resources = ARRAY_SIZE(msp_tsmac1_resources),
95 .resource = msp_tsmac1_resources,
96 },
97 [2] = {
98 .name = MSP_TSMAC_ID,
99 .id = 2,
100 .num_resources = ARRAY_SIZE(msp_tsmac2_resources),
101 .resource = msp_tsmac2_resources,
102 },
103};
104#define msp_eth_devs tsmac_device
105
106#else
107/* If it is not TSMAC assume MSP_ETH (100Mbps) */
108#define MSP_ETH_ID "pmc_mspeth"
109#define MSP_ETH_SIZE 0xE0
110static struct resource msp_eth0_resources[] = {
111 [0] = {
112 .start = MSP_MAC0_BASE,
113 .end = MSP_MAC0_BASE + MSP_ETH_SIZE - 1,
114 .flags = IORESOURCE_MEM,
115 },
116 [1] = {
117 .start = MSP_INT_MAC0,
118 .end = MSP_INT_MAC0,
119 .flags = IORESOURCE_IRQ,
120 },
121};
122
123static struct resource msp_eth1_resources[] = {
124 [0] = {
125 .start = MSP_MAC1_BASE,
126 .end = MSP_MAC1_BASE + MSP_ETH_SIZE - 1,
127 .flags = IORESOURCE_MEM,
128 },
129 [1] = {
130 .start = MSP_INT_MAC1,
131 .end = MSP_INT_MAC1,
132 .flags = IORESOURCE_IRQ,
133 },
134};
135
136
137
138static struct platform_device mspeth_device[] = {
139 [0] = {
140 .name = MSP_ETH_ID,
141 .id = 0,
142 .num_resources = ARRAY_SIZE(msp_eth0_resources),
143 .resource = msp_eth0_resources,
144 },
145 [1] = {
146 .name = MSP_ETH_ID,
147 .id = 1,
148 .num_resources = ARRAY_SIZE(msp_eth1_resources),
149 .resource = msp_eth1_resources,
150 },
151
152};
153#define msp_eth_devs mspeth_device
154
155#endif
156int __init msp_eth_setup(void)
157{
158 int i, ret = 0;
159
160 /* Configure the GPIO and take the ethernet PHY out of reset */
161 msp_gpio_pin_mode(MSP_GPIO_OUTPUT, MSP_ETHERNET_GPIO0);
162 msp_gpio_pin_hi(MSP_ETHERNET_GPIO0);
163
164#ifdef CONFIG_MSP_HAS_TSMAC
165 /* 3 phys on boards with TSMAC */
166 msp_gpio_pin_mode(MSP_GPIO_OUTPUT, MSP_ETHERNET_GPIO1);
167 msp_gpio_pin_hi(MSP_ETHERNET_GPIO1);
168
169 msp_gpio_pin_mode(MSP_GPIO_OUTPUT, MSP_ETHERNET_GPIO2);
170 msp_gpio_pin_hi(MSP_ETHERNET_GPIO2);
171#endif
172 for (i = 0; i < ARRAY_SIZE(msp_eth_devs); i++) {
173 ret = platform_device_register(&msp_eth_devs[i]);
174 printk(KERN_INFO "device: %d, return value = %d\n", i, ret);
175 if (ret) {
176 platform_device_unregister(&msp_eth_devs[i]);
177 break;
178 }
179 }
180
181 if (ret)
182 printk(KERN_WARNING "Could not initialize "
183 "MSPETH device structures.\n");
184
185 return ret;
186}
187subsys_initcall(msp_eth_setup);
diff --git a/arch/mips/pmcs-msp71xx/msp_hwbutton.c b/arch/mips/pmcs-msp71xx/msp_hwbutton.c
new file mode 100644
index 000000000000..bb57ed9ea2bd
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/msp_hwbutton.c
@@ -0,0 +1,165 @@
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
36/* For hwbutton_interrupt->initial_state */
37#define HWBUTTON_HI 0x1
38#define HWBUTTON_LO 0x2
39
40/*
41 * This struct describes a hardware button
42 */
43struct hwbutton_interrupt {
44 char *name; /* Name of button */
45 int irq; /* Actual LINUX IRQ */
46 int eirq; /* Extended IRQ number (0-7) */
47 int initial_state; /* The "normal" state of the switch */
48 void (*handle_hi)(void *); /* Handler: switch input has gone HI */
49 void (*handle_lo)(void *); /* Handler: switch input has gone LO */
50 void *data; /* Optional data to pass to handler */
51};
52
53#ifdef CONFIG_PMC_MSP7120_GW
54extern void msp_restart(char *);
55
56static void softreset_push(void *data)
57{
58 printk(KERN_WARNING "SOFTRESET switch was pushed\n");
59
60 /*
61 * In the future you could move this to the release handler,
62 * timing the difference between the 'push' and 'release', and only
63 * doing this ungraceful restart if the button has been down for
64 * a certain amount of time; otherwise doing a graceful restart.
65 */
66
67 msp_restart(NULL);
68}
69
70static void softreset_release(void *data)
71{
72 printk(KERN_WARNING "SOFTRESET switch was released\n");
73
74 /* Do nothing */
75}
76
77static void standby_on(void *data)
78{
79 printk(KERN_WARNING "STANDBY switch was set to ON (not implemented)\n");
80
81 /* TODO: Put board in standby mode */
82}
83
84static void standby_off(void *data)
85{
86 printk(KERN_WARNING
87 "STANDBY switch was set to OFF (not implemented)\n");
88
89 /* TODO: Take out of standby mode */
90}
91
92static struct hwbutton_interrupt softreset_sw = {
93 .name = "Softreset button",
94 .irq = MSP_INT_EXT0,
95 .eirq = 0,
96 .initial_state = HWBUTTON_HI,
97 .handle_hi = softreset_release,
98 .handle_lo = softreset_push,
99 .data = NULL,
100};
101
102static struct hwbutton_interrupt standby_sw = {
103 .name = "Standby switch",
104 .irq = MSP_INT_EXT1,
105 .eirq = 1,
106 .initial_state = HWBUTTON_HI,
107 .handle_hi = standby_off,
108 .handle_lo = standby_on,
109 .data = NULL,
110};
111#endif /* CONFIG_PMC_MSP7120_GW */
112
113static irqreturn_t hwbutton_handler(int irq, void *data)
114{
115 struct hwbutton_interrupt *hirq = data;
116 unsigned long cic_ext = *CIC_EXT_CFG_REG;
117
118 if (CIC_EXT_IS_ACTIVE_HI(cic_ext, hirq->eirq)) {
119 /* Interrupt: pin is now HI */
120 CIC_EXT_SET_ACTIVE_LO(cic_ext, hirq->eirq);
121 hirq->handle_hi(hirq->data);
122 } else {
123 /* Interrupt: pin is now LO */
124 CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);
125 hirq->handle_lo(hirq->data);
126 }
127
128 /*
129 * Invert the POLARITY of this level interrupt to ack the interrupt
130 * Thus next state change will invoke the opposite message
131 */
132 *CIC_EXT_CFG_REG = cic_ext;
133
134 return IRQ_HANDLED;
135}
136
137static int msp_hwbutton_register(struct hwbutton_interrupt *hirq)
138{
139 unsigned long cic_ext;
140
141 if (hirq->handle_hi == NULL || hirq->handle_lo == NULL)
142 return -EINVAL;
143
144 cic_ext = *CIC_EXT_CFG_REG;
145 CIC_EXT_SET_TRIGGER_LEVEL(cic_ext, hirq->eirq);
146 if (hirq->initial_state == HWBUTTON_HI)
147 CIC_EXT_SET_ACTIVE_LO(cic_ext, hirq->eirq);
148 else
149 CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);
150 *CIC_EXT_CFG_REG = cic_ext;
151
152 return request_irq(hirq->irq, hwbutton_handler, 0,
153 hirq->name, hirq);
154}
155
156static int __init msp_hwbutton_setup(void)
157{
158#ifdef CONFIG_PMC_MSP7120_GW
159 msp_hwbutton_register(&softreset_sw);
160 msp_hwbutton_register(&standby_sw);
161#endif
162 return 0;
163}
164
165subsys_initcall(msp_hwbutton_setup);
diff --git a/arch/mips/pmcs-msp71xx/msp_irq.c b/arch/mips/pmcs-msp71xx/msp_irq.c
new file mode 100644
index 000000000000..9da5619c00a5
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/msp_irq.c
@@ -0,0 +1,164 @@
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
22/* SLP bases systems */
23extern void msp_slp_irq_init(void);
24extern void msp_slp_irq_dispatch(void);
25
26/* CIC based systems */
27extern void msp_cic_irq_init(void);
28extern void msp_cic_irq_dispatch(void);
29
30/* VSMP support init */
31extern void msp_vsmp_int_init(void);
32
33/* vectored interrupt implementation */
34
35/* SW0/1 interrupts are used for SMP/SMTC */
36static inline void mac0_int_dispatch(void) { do_IRQ(MSP_INT_MAC0); }
37static inline void mac1_int_dispatch(void) { do_IRQ(MSP_INT_MAC1); }
38static inline void mac2_int_dispatch(void) { do_IRQ(MSP_INT_SAR); }
39static inline void usb_int_dispatch(void) { do_IRQ(MSP_INT_USB); }
40static inline void sec_int_dispatch(void) { do_IRQ(MSP_INT_SEC); }
41
42/*
43 * The PMC-Sierra MSP interrupts are arranged in a 3 level cascaded
44 * hierarchical system. The first level are the direct MIPS interrupts
45 * and are assigned the interrupt range 0-7. The second level is the SLM
46 * interrupt controller and is assigned the range 8-39. The third level
47 * comprises the Peripherial block, the PCI block, the PCI MSI block and
48 * the SLP. The PCI interrupts and the SLP errors are handled by the
49 * relevant subsystems so the core interrupt code needs only concern
50 * itself with the Peripheral block. These are assigned interrupts in
51 * the range 40-71.
52 */
53
54asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
55{
56 u32 pending;
57
58 pending = read_c0_status() & read_c0_cause();
59
60 /*
61 * jump to the correct interrupt routine
62 * These are arranged in priority order and the timer
63 * comes first!
64 */
65
66#ifdef CONFIG_IRQ_MSP_CIC /* break out the CIC stuff for now */
67 if (pending & C_IRQ4) /* do the peripherals first, that's the timer */
68 msp_cic_irq_dispatch();
69
70 else if (pending & C_IRQ0)
71 do_IRQ(MSP_INT_MAC0);
72
73 else if (pending & C_IRQ1)
74 do_IRQ(MSP_INT_MAC1);
75
76 else if (pending & C_IRQ2)
77 do_IRQ(MSP_INT_USB);
78
79 else if (pending & C_IRQ3)
80 do_IRQ(MSP_INT_SAR);
81
82 else if (pending & C_IRQ5)
83 do_IRQ(MSP_INT_SEC);
84
85#else
86 if (pending & C_IRQ5)
87 do_IRQ(MSP_INT_TIMER);
88
89 else if (pending & C_IRQ0)
90 do_IRQ(MSP_INT_MAC0);
91
92 else if (pending & C_IRQ1)
93 do_IRQ(MSP_INT_MAC1);
94
95 else if (pending & C_IRQ3)
96 do_IRQ(MSP_INT_VE);
97
98 else if (pending & C_IRQ4)
99 msp_slp_irq_dispatch();
100#endif
101
102 else if (pending & C_SW0) /* do software after hardware */
103 do_IRQ(MSP_INT_SW0);
104
105 else if (pending & C_SW1)
106 do_IRQ(MSP_INT_SW1);
107}
108
109static struct irqaction cic_cascade_msp = {
110 .handler = no_action,
111 .name = "MSP CIC cascade",
112 .flags = IRQF_NO_THREAD,
113};
114
115static struct irqaction per_cascade_msp = {
116 .handler = no_action,
117 .name = "MSP PER cascade",
118 .flags = IRQF_NO_THREAD,
119};
120
121void __init arch_init_irq(void)
122{
123 /* assume we'll be using vectored interrupt mode except in UP mode*/
124#ifdef CONFIG_MIPS_MT
125 BUG_ON(!cpu_has_vint);
126#endif
127 /* initialize the 1st-level CPU based interrupt controller */
128 mips_cpu_irq_init();
129
130#ifdef CONFIG_IRQ_MSP_CIC
131 msp_cic_irq_init();
132#ifdef CONFIG_MIPS_MT
133 set_vi_handler(MSP_INT_CIC, msp_cic_irq_dispatch);
134 set_vi_handler(MSP_INT_MAC0, mac0_int_dispatch);
135 set_vi_handler(MSP_INT_MAC1, mac1_int_dispatch);
136 set_vi_handler(MSP_INT_SAR, mac2_int_dispatch);
137 set_vi_handler(MSP_INT_USB, usb_int_dispatch);
138 set_vi_handler(MSP_INT_SEC, sec_int_dispatch);
139#ifdef CONFIG_MIPS_MT_SMP
140 msp_vsmp_int_init();
141#elif defined CONFIG_MIPS_MT_SMTC
142 /*Set hwmask for all platform devices */
143 irq_hwmask[MSP_INT_MAC0] = C_IRQ0;
144 irq_hwmask[MSP_INT_MAC1] = C_IRQ1;
145 irq_hwmask[MSP_INT_USB] = C_IRQ2;
146 irq_hwmask[MSP_INT_SAR] = C_IRQ3;
147 irq_hwmask[MSP_INT_SEC] = C_IRQ5;
148
149#endif /* CONFIG_MIPS_MT_SMP */
150#endif /* CONFIG_MIPS_MT */
151 /* setup the cascaded interrupts */
152 setup_irq(MSP_INT_CIC, &cic_cascade_msp);
153 setup_irq(MSP_INT_PER, &per_cascade_msp);
154
155#else
156 /* setup the 2nd-level SLP register based interrupt controller */
157 /* VSMP /SMTC support support is not enabled for SLP */
158 msp_slp_irq_init();
159
160 /* setup the cascaded SLP/PER interrupts */
161 setup_irq(MSP_INT_SLP, &cic_cascade_msp);
162 setup_irq(MSP_INT_PER, &per_cascade_msp);
163#endif
164}
diff --git a/arch/mips/pmcs-msp71xx/msp_irq_cic.c b/arch/mips/pmcs-msp71xx/msp_irq_cic.c
new file mode 100644
index 000000000000..e49b499f66db
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/msp_irq_cic.c
@@ -0,0 +1,216 @@
1/*
2 * Copyright 2010 PMC-Sierra, Inc, derived from irq_cpu.c
3 *
4 * This file define the irq handler for MSP CIC subsystem interrupts.
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
12#include <linux/init.h>
13#include <linux/interrupt.h>
14#include <linux/kernel.h>
15#include <linux/bitops.h>
16#include <linux/irq.h>
17
18#include <asm/mipsregs.h>
19
20#include <msp_cic_int.h>
21#include <msp_regs.h>
22
23/*
24 * External API
25 */
26extern void msp_per_irq_init(void);
27extern void msp_per_irq_dispatch(void);
28
29
30/*
31 * Convenience Macro. Should be somewhere generic.
32 */
33#define get_current_vpe() \
34 ((read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE)
35
36#ifdef CONFIG_SMP
37
38#define LOCK_VPE(flags, mtflags) \
39do { \
40 local_irq_save(flags); \
41 mtflags = dmt(); \
42} while (0)
43
44#define UNLOCK_VPE(flags, mtflags) \
45do { \
46 emt(mtflags); \
47 local_irq_restore(flags);\
48} while (0)
49
50#define LOCK_CORE(flags, mtflags) \
51do { \
52 local_irq_save(flags); \
53 mtflags = dvpe(); \
54} while (0)
55
56#define UNLOCK_CORE(flags, mtflags) \
57do { \
58 evpe(mtflags); \
59 local_irq_restore(flags);\
60} while (0)
61
62#else
63
64#define LOCK_VPE(flags, mtflags)
65#define UNLOCK_VPE(flags, mtflags)
66#endif
67
68/* ensure writes to cic are completed */
69static inline void cic_wmb(void)
70{
71 const volatile void __iomem *cic_mem = CIC_VPE0_MSK_REG;
72 volatile u32 dummy_read;
73
74 wmb();
75 dummy_read = __raw_readl(cic_mem);
76 dummy_read++;
77}
78
79static void unmask_cic_irq(struct irq_data *d)
80{
81 volatile u32 *cic_msk_reg = CIC_VPE0_MSK_REG;
82 int vpe;
83#ifdef CONFIG_SMP
84 unsigned int mtflags;
85 unsigned long flags;
86
87 /*
88 * Make sure we have IRQ affinity. It may have changed while
89 * we were processing the IRQ.
90 */
91 if (!cpumask_test_cpu(smp_processor_id(), d->affinity))
92 return;
93#endif
94
95 vpe = get_current_vpe();
96 LOCK_VPE(flags, mtflags);
97 cic_msk_reg[vpe] |= (1 << (d->irq - MSP_CIC_INTBASE));
98 UNLOCK_VPE(flags, mtflags);
99 cic_wmb();
100}
101
102static void mask_cic_irq(struct irq_data *d)
103{
104 volatile u32 *cic_msk_reg = CIC_VPE0_MSK_REG;
105 int vpe = get_current_vpe();
106#ifdef CONFIG_SMP
107 unsigned long flags, mtflags;
108#endif
109 LOCK_VPE(flags, mtflags);
110 cic_msk_reg[vpe] &= ~(1 << (d->irq - MSP_CIC_INTBASE));
111 UNLOCK_VPE(flags, mtflags);
112 cic_wmb();
113}
114static void msp_cic_irq_ack(struct irq_data *d)
115{
116 mask_cic_irq(d);
117 /*
118 * Only really necessary for 18, 16-14 and sometimes 3:0
119 * (since these can be edge sensitive) but it doesn't
120 * hurt for the others
121 */
122 *CIC_STS_REG = (1 << (d->irq - MSP_CIC_INTBASE));
123 smtc_im_ack_irq(d->irq);
124}
125
126/*Note: Limiting to VSMP . Not tested in SMTC */
127
128#ifdef CONFIG_MIPS_MT_SMP
129static int msp_cic_irq_set_affinity(struct irq_data *d,
130 const struct cpumask *cpumask, bool force)
131{
132 int cpu;
133 unsigned long flags;
134 unsigned int mtflags;
135 unsigned long imask = (1 << (irq - MSP_CIC_INTBASE));
136 volatile u32 *cic_mask = (volatile u32 *)CIC_VPE0_MSK_REG;
137
138 /* timer balancing should be disabled in kernel code */
139 BUG_ON(irq == MSP_INT_VPE0_TIMER || irq == MSP_INT_VPE1_TIMER);
140
141 LOCK_CORE(flags, mtflags);
142 /* enable if any of each VPE's TCs require this IRQ */
143 for_each_online_cpu(cpu) {
144 if (cpumask_test_cpu(cpu, cpumask))
145 cic_mask[cpu] |= imask;
146 else
147 cic_mask[cpu] &= ~imask;
148
149 }
150
151 UNLOCK_CORE(flags, mtflags);
152 return 0;
153
154}
155#endif
156
157static struct irq_chip msp_cic_irq_controller = {
158 .name = "MSP_CIC",
159 .irq_mask = mask_cic_irq,
160 .irq_mask_ack = msp_cic_irq_ack,
161 .irq_unmask = unmask_cic_irq,
162 .irq_ack = msp_cic_irq_ack,
163#ifdef CONFIG_MIPS_MT_SMP
164 .irq_set_affinity = msp_cic_irq_set_affinity,
165#endif
166};
167
168void __init msp_cic_irq_init(void)
169{
170 int i;
171 /* Mask/clear interrupts. */
172 *CIC_VPE0_MSK_REG = 0x00000000;
173 *CIC_VPE1_MSK_REG = 0x00000000;
174 *CIC_STS_REG = 0xFFFFFFFF;
175 /*
176 * The MSP7120 RG and EVBD boards use IRQ[6:4] for PCI.
177 * These inputs map to EXT_INT_POL[6:4] inside the CIC.
178 * They are to be active low, level sensitive.
179 */
180 *CIC_EXT_CFG_REG &= 0xFFFF8F8F;
181
182 /* initialize all the IRQ descriptors */
183 for (i = MSP_CIC_INTBASE ; i < MSP_CIC_INTBASE + 32 ; i++) {
184 irq_set_chip_and_handler(i, &msp_cic_irq_controller,
185 handle_level_irq);
186#ifdef CONFIG_MIPS_MT_SMTC
187 /* Mask of CIC interrupt */
188 irq_hwmask[i] = C_IRQ4;
189#endif
190 }
191
192 /* Initialize the PER interrupt sub-system */
193 msp_per_irq_init();
194}
195
196/* CIC masked by CIC vector processing before dispatch called */
197void msp_cic_irq_dispatch(void)
198{
199 volatile u32 *cic_msk_reg = (volatile u32 *)CIC_VPE0_MSK_REG;
200 u32 cic_mask;
201 u32 pending;
202 int cic_status = *CIC_STS_REG;
203 cic_mask = cic_msk_reg[get_current_vpe()];
204 pending = cic_status & cic_mask;
205 if (pending & (1 << (MSP_INT_VPE0_TIMER - MSP_CIC_INTBASE))) {
206 do_IRQ(MSP_INT_VPE0_TIMER);
207 } else if (pending & (1 << (MSP_INT_VPE1_TIMER - MSP_CIC_INTBASE))) {
208 do_IRQ(MSP_INT_VPE1_TIMER);
209 } else if (pending & (1 << (MSP_INT_PER - MSP_CIC_INTBASE))) {
210 msp_per_irq_dispatch();
211 } else if (pending) {
212 do_IRQ(ffs(pending) + MSP_CIC_INTBASE - 1);
213 } else{
214 spurious_interrupt();
215 }
216}
diff --git a/arch/mips/pmcs-msp71xx/msp_irq_per.c b/arch/mips/pmcs-msp71xx/msp_irq_per.c
new file mode 100644
index 000000000000..d1fd530479d4
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/msp_irq_per.c
@@ -0,0 +1,134 @@
1/*
2 * Copyright 2010 PMC-Sierra, Inc, derived from irq_cpu.c
3 *
4 * This file define the irq handler for MSP PER subsystem interrupts.
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
12#include <linux/init.h>
13#include <linux/interrupt.h>
14#include <linux/kernel.h>
15#include <linux/spinlock.h>
16#include <linux/bitops.h>
17
18#include <asm/mipsregs.h>
19
20#include <msp_cic_int.h>
21#include <msp_regs.h>
22
23
24/*
25 * Convenience Macro. Should be somewhere generic.
26 */
27#define get_current_vpe() \
28 ((read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE)
29
30#ifdef CONFIG_SMP
31/*
32 * The PER registers must be protected from concurrent access.
33 */
34
35static DEFINE_SPINLOCK(per_lock);
36#endif
37
38/* ensure writes to per are completed */
39
40static inline void per_wmb(void)
41{
42 const volatile void __iomem *per_mem = PER_INT_MSK_REG;
43 volatile u32 dummy_read;
44
45 wmb();
46 dummy_read = __raw_readl(per_mem);
47 dummy_read++;
48}
49
50static inline void unmask_per_irq(struct irq_data *d)
51{
52#ifdef CONFIG_SMP
53 unsigned long flags;
54 spin_lock_irqsave(&per_lock, flags);
55 *PER_INT_MSK_REG |= (1 << (d->irq - MSP_PER_INTBASE));
56 spin_unlock_irqrestore(&per_lock, flags);
57#else
58 *PER_INT_MSK_REG |= (1 << (d->irq - MSP_PER_INTBASE));
59#endif
60 per_wmb();
61}
62
63static inline void mask_per_irq(struct irq_data *d)
64{
65#ifdef CONFIG_SMP
66 unsigned long flags;
67 spin_lock_irqsave(&per_lock, flags);
68 *PER_INT_MSK_REG &= ~(1 << (d->irq - MSP_PER_INTBASE));
69 spin_unlock_irqrestore(&per_lock, flags);
70#else
71 *PER_INT_MSK_REG &= ~(1 << (d->irq - MSP_PER_INTBASE));
72#endif
73 per_wmb();
74}
75
76static inline void msp_per_irq_ack(struct irq_data *d)
77{
78 mask_per_irq(d);
79 /*
80 * In the PER interrupt controller, only bits 11 and 10
81 * are write-to-clear, (SPI TX complete, SPI RX complete).
82 * It does nothing for any others.
83 */
84 *PER_INT_STS_REG = (1 << (d->irq - MSP_PER_INTBASE));
85}
86
87#ifdef CONFIG_SMP
88static int msp_per_irq_set_affinity(struct irq_data *d,
89 const struct cpumask *affinity, bool force)
90{
91 /* WTF is this doing ????? */
92 unmask_per_irq(d);
93 return 0;
94}
95#endif
96
97static struct irq_chip msp_per_irq_controller = {
98 .name = "MSP_PER",
99 .irq_enable = unmask_per_irq,
100 .irq_disable = mask_per_irq,
101 .irq_ack = msp_per_irq_ack,
102#ifdef CONFIG_SMP
103 .irq_set_affinity = msp_per_irq_set_affinity,
104#endif
105};
106
107void __init msp_per_irq_init(void)
108{
109 int i;
110 /* Mask/clear interrupts. */
111 *PER_INT_MSK_REG = 0x00000000;
112 *PER_INT_STS_REG = 0xFFFFFFFF;
113 /* initialize all the IRQ descriptors */
114 for (i = MSP_PER_INTBASE; i < MSP_PER_INTBASE + 32; i++) {
115 irq_set_chip(i, &msp_per_irq_controller);
116#ifdef CONFIG_MIPS_MT_SMTC
117 irq_hwmask[i] = C_IRQ4;
118#endif
119 }
120}
121
122void msp_per_irq_dispatch(void)
123{
124 u32 per_mask = *PER_INT_MSK_REG;
125 u32 per_status = *PER_INT_STS_REG;
126 u32 pending;
127
128 pending = per_status & per_mask;
129 if (pending) {
130 do_IRQ(ffs(pending) + MSP_PER_INTBASE - 1);
131 } else {
132 spurious_interrupt();
133 }
134}
diff --git a/arch/mips/pmcs-msp71xx/msp_irq_slp.c b/arch/mips/pmcs-msp71xx/msp_irq_slp.c
new file mode 100644
index 000000000000..5f66a76311c3
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/msp_irq_slp.c
@@ -0,0 +1,106 @@
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
20#include <msp_slp_int.h>
21#include <msp_regs.h>
22
23static inline void unmask_msp_slp_irq(struct irq_data *d)
24{
25 unsigned int irq = d->irq;
26
27 /* check for PER interrupt range */
28 if (irq < MSP_PER_INTBASE)
29 *SLP_INT_MSK_REG |= (1 << (irq - MSP_SLP_INTBASE));
30 else
31 *PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE));
32}
33
34static inline void mask_msp_slp_irq(struct irq_data *d)
35{
36 unsigned int irq = d->irq;
37
38 /* check for PER interrupt range */
39 if (irq < MSP_PER_INTBASE)
40 *SLP_INT_MSK_REG &= ~(1 << (irq - MSP_SLP_INTBASE));
41 else
42 *PER_INT_MSK_REG &= ~(1 << (irq - MSP_PER_INTBASE));
43}
44
45/*
46 * While we ack the interrupt interrupts are disabled and thus we don't need
47 * to deal with concurrency issues. Same for msp_slp_irq_end.
48 */
49static inline void ack_msp_slp_irq(struct irq_data *d)
50{
51 unsigned int irq = d->irq;
52
53 /* check for PER interrupt range */
54 if (irq < MSP_PER_INTBASE)
55 *SLP_INT_STS_REG = (1 << (irq - MSP_SLP_INTBASE));
56 else
57 *PER_INT_STS_REG = (1 << (irq - MSP_PER_INTBASE));
58}
59
60static struct irq_chip msp_slp_irq_controller = {
61 .name = "MSP_SLP",
62 .irq_ack = ack_msp_slp_irq,
63 .irq_mask = mask_msp_slp_irq,
64 .irq_unmask = unmask_msp_slp_irq,
65};
66
67void __init msp_slp_irq_init(void)
68{
69 int i;
70
71 /* Mask/clear interrupts. */
72 *SLP_INT_MSK_REG = 0x00000000;
73 *PER_INT_MSK_REG = 0x00000000;
74 *SLP_INT_STS_REG = 0xFFFFFFFF;
75 *PER_INT_STS_REG = 0xFFFFFFFF;
76
77 /* initialize all the IRQ descriptors */
78 for (i = MSP_SLP_INTBASE; i < MSP_PER_INTBASE + 32; i++)
79 irq_set_chip_and_handler(i, &msp_slp_irq_controller,
80 handle_level_irq);
81}
82
83void msp_slp_irq_dispatch(void)
84{
85 u32 pending;
86 int intbase;
87
88 intbase = MSP_SLP_INTBASE;
89 pending = *SLP_INT_STS_REG & *SLP_INT_MSK_REG;
90
91 /* check for PER interrupt */
92 if (pending == (1 << (MSP_INT_PER - MSP_SLP_INTBASE))) {
93 intbase = MSP_PER_INTBASE;
94 pending = *PER_INT_STS_REG & *PER_INT_MSK_REG;
95 }
96
97 /* check for spurious interrupt */
98 if (pending == 0x00000000) {
99 printk(KERN_ERR "Spurious %s interrupt?\n",
100 (intbase == MSP_SLP_INTBASE) ? "SLP" : "PER");
101 return;
102 }
103
104 /* dispatch the irq */
105 do_IRQ(ffs(pending) + intbase - 1);
106}
diff --git a/arch/mips/pmcs-msp71xx/msp_pci.c b/arch/mips/pmcs-msp71xx/msp_pci.c
new file mode 100644
index 000000000000..428dea23c35c
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/msp_pci.c
@@ -0,0 +1,50 @@
1/*
2 * The setup file for PCI related hardware on PMC-Sierra MSP processors.
3 *
4 * Copyright 2005-2006 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/init.h>
28
29#include <msp_prom.h>
30#include <msp_regs.h>
31
32extern void msp_pci_init(void);
33
34static int __init msp_pci_setup(void)
35{
36#if 0 /* Linux 2.6 initialization code to be completed */
37 if (getdeviceid() & DEV_ID_SINGLE_PC) {
38 /* If single card mode */
39 slmRegs *sreg = (slmRegs *) SREG_BASE;
40
41 sreg->single_pc_enable = SINGLE_PCCARD;
42 }
43#endif
44
45 msp_pci_init();
46
47 return 0;
48}
49
50subsys_initcall(msp_pci_setup);
diff --git a/arch/mips/pmcs-msp71xx/msp_prom.c b/arch/mips/pmcs-msp71xx/msp_prom.c
new file mode 100644
index 000000000000..0edb89a63516
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/msp_prom.c
@@ -0,0 +1,503 @@
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#include <linux/slab.h>
44
45#include <asm/addrspace.h>
46#include <asm/bootinfo.h>
47#include <asm-generic/sections.h>
48#include <asm/page.h>
49
50#include <msp_prom.h>
51#include <msp_regs.h>
52
53/* global PROM environment variables and pointers */
54int prom_argc;
55char **prom_argv, **prom_envp;
56int *prom_vec;
57
58/* debug flag */
59int init_debug = 1;
60
61/* memory blocks */
62struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
63
64/* default feature sets */
65static char msp_default_features[] =
66#if defined(CONFIG_PMC_MSP4200_EVAL) \
67 || defined(CONFIG_PMC_MSP4200_GW)
68 "ERER";
69#elif defined(CONFIG_PMC_MSP7120_EVAL) \
70 || defined(CONFIG_PMC_MSP7120_GW)
71 "EMEMSP";
72#elif defined(CONFIG_PMC_MSP7120_FPGA)
73 "EMEM";
74#endif
75
76/* conversion functions */
77static inline unsigned char str2hexnum(unsigned char c)
78{
79 if (c >= '0' && c <= '9')
80 return c - '0';
81 if (c >= 'a' && c <= 'f')
82 return c - 'a' + 10;
83 return 0; /* foo */
84}
85
86static inline int str2eaddr(unsigned char *ea, unsigned char *str)
87{
88 int index = 0;
89 unsigned char num = 0;
90
91 while (*str != '\0') {
92 if ((*str == '.') || (*str == ':')) {
93 ea[index++] = num;
94 num = 0;
95 str++;
96 } else {
97 num = num << 4;
98 num |= str2hexnum(*str++);
99 }
100 }
101
102 if (index == 5) {
103 ea[index++] = num;
104 return 0;
105 } else
106 return -1;
107}
108EXPORT_SYMBOL(str2eaddr);
109
110static inline unsigned long str2hex(unsigned char *str)
111{
112 int value = 0;
113
114 while (*str) {
115 value = value << 4;
116 value |= str2hexnum(*str++);
117 }
118
119 return value;
120}
121
122/* function to query the system information */
123const char *get_system_type(void)
124{
125#if defined(CONFIG_PMC_MSP4200_EVAL)
126 return "PMC-Sierra MSP4200 Eval Board";
127#elif defined(CONFIG_PMC_MSP4200_GW)
128 return "PMC-Sierra MSP4200 VoIP Gateway";
129#elif defined(CONFIG_PMC_MSP7120_EVAL)
130 return "PMC-Sierra MSP7120 Eval Board";
131#elif defined(CONFIG_PMC_MSP7120_GW)
132 return "PMC-Sierra MSP7120 Residential Gateway";
133#elif defined(CONFIG_PMC_MSP7120_FPGA)
134 return "PMC-Sierra MSP7120 FPGA";
135#else
136 #error "What is the type of *your* MSP?"
137#endif
138}
139
140int get_ethernet_addr(char *ethaddr_name, char *ethernet_addr)
141{
142 char *ethaddr_str;
143
144 ethaddr_str = prom_getenv(ethaddr_name);
145 if (!ethaddr_str) {
146 printk(KERN_WARNING "%s not set in boot prom\n", ethaddr_name);
147 return -1;
148 }
149
150 if (str2eaddr(ethernet_addr, ethaddr_str) == -1) {
151 printk(KERN_WARNING "%s badly formatted-<%s>\n",
152 ethaddr_name, ethaddr_str);
153 return -1;
154 }
155
156 if (init_debug > 1) {
157 int i;
158 printk(KERN_DEBUG "get_ethernet_addr: for %s ", ethaddr_name);
159 for (i = 0; i < 5; i++)
160 printk(KERN_DEBUG "%02x:",
161 (unsigned char)*(ethernet_addr+i));
162 printk(KERN_DEBUG "%02x\n", *(ethernet_addr+i));
163 }
164
165 return 0;
166}
167EXPORT_SYMBOL(get_ethernet_addr);
168
169static char *get_features(void)
170{
171 char *feature = prom_getenv(FEATURES);
172
173 if (feature == NULL) {
174 /* default features based on MACHINE_TYPE */
175 feature = msp_default_features;
176 }
177
178 return feature;
179}
180
181static char test_feature(char c)
182{
183 char *feature = get_features();
184
185 while (*feature) {
186 if (*feature++ == c)
187 return *feature;
188 feature++;
189 }
190
191 return FEATURE_NOEXIST;
192}
193
194unsigned long get_deviceid(void)
195{
196 char *deviceid = prom_getenv(DEVICEID);
197
198 if (deviceid == NULL)
199 return *DEV_ID_REG;
200 else
201 return str2hex(deviceid);
202}
203
204char identify_pci(void)
205{
206 return test_feature(PCI_KEY);
207}
208EXPORT_SYMBOL(identify_pci);
209
210char identify_pcimux(void)
211{
212 return test_feature(PCIMUX_KEY);
213}
214
215char identify_sec(void)
216{
217 return test_feature(SEC_KEY);
218}
219EXPORT_SYMBOL(identify_sec);
220
221char identify_spad(void)
222{
223 return test_feature(SPAD_KEY);
224}
225EXPORT_SYMBOL(identify_spad);
226
227char identify_tdm(void)
228{
229 return test_feature(TDM_KEY);
230}
231EXPORT_SYMBOL(identify_tdm);
232
233char identify_zsp(void)
234{
235 return test_feature(ZSP_KEY);
236}
237EXPORT_SYMBOL(identify_zsp);
238
239static char identify_enetfeature(char key, unsigned long interface_num)
240{
241 char *feature = get_features();
242
243 while (*feature) {
244 if (*feature++ == key && interface_num-- == 0)
245 return *feature;
246 feature++;
247 }
248
249 return FEATURE_NOEXIST;
250}
251
252char identify_enet(unsigned long interface_num)
253{
254 return identify_enetfeature(ENET_KEY, interface_num);
255}
256EXPORT_SYMBOL(identify_enet);
257
258char identify_enetTxD(unsigned long interface_num)
259{
260 return identify_enetfeature(ENETTXD_KEY, interface_num);
261}
262EXPORT_SYMBOL(identify_enetTxD);
263
264unsigned long identify_family(void)
265{
266 unsigned long deviceid;
267
268 deviceid = get_deviceid();
269
270 return deviceid & CPU_DEVID_FAMILY;
271}
272EXPORT_SYMBOL(identify_family);
273
274unsigned long identify_revision(void)
275{
276 unsigned long deviceid;
277
278 deviceid = get_deviceid();
279
280 return deviceid & CPU_DEVID_REVISION;
281}
282EXPORT_SYMBOL(identify_revision);
283
284/* PROM environment functions */
285char *prom_getenv(char *env_name)
286{
287 /*
288 * Return a pointer to the given environment variable. prom_envp
289 * points to a null terminated array of pointers to variables.
290 * Environment variables are stored in the form of "memsize=64"
291 */
292
293 char **var = prom_envp;
294 int i = strlen(env_name);
295
296 while (*var) {
297 if (strncmp(env_name, *var, i) == 0) {
298 return (*var + strlen(env_name) + 1);
299 }
300 var++;
301 }
302
303 return NULL;
304}
305
306/* PROM commandline functions */
307void __init prom_init_cmdline(void)
308{
309 char *cp;
310 int actr;
311
312 actr = 1; /* Always ignore argv[0] */
313
314 cp = &(arcs_cmdline[0]);
315 while (actr < prom_argc) {
316 strcpy(cp, prom_argv[actr]);
317 cp += strlen(prom_argv[actr]);
318 *cp++ = ' ';
319 actr++;
320 }
321 if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
322 --cp;
323 *cp = '\0';
324}
325
326/* memory allocation functions */
327static int __init prom_memtype_classify(unsigned int type)
328{
329 switch (type) {
330 case yamon_free:
331 return BOOT_MEM_RAM;
332 case yamon_prom:
333 return BOOT_MEM_ROM_DATA;
334 default:
335 return BOOT_MEM_RESERVED;
336 }
337}
338
339void __init prom_meminit(void)
340{
341 struct prom_pmemblock *p;
342
343 p = prom_getmdesc();
344
345 while (p->size) {
346 long type;
347 unsigned long base, size;
348
349 type = prom_memtype_classify(p->type);
350 base = p->base;
351 size = p->size;
352
353 add_memory_region(base, size, type);
354 p++;
355 }
356}
357
358void __init prom_free_prom_memory(void)
359{
360 int argc;
361 char **argv;
362 char **envp;
363 char *ptr;
364 int len = 0;
365 int i;
366 unsigned long addr;
367
368 /*
369 * preserve environment variables and command line from pmon/bbload
370 * first preserve the command line
371 */
372 for (argc = 0; argc < prom_argc; argc++) {
373 len += sizeof(char *); /* length of pointer */
374 len += strlen(prom_argv[argc]) + 1; /* length of string */
375 }
376 len += sizeof(char *); /* plus length of null pointer */
377
378 argv = kmalloc(len, GFP_KERNEL);
379 ptr = (char *) &argv[prom_argc + 1]; /* strings follow array */
380
381 for (argc = 0; argc < prom_argc; argc++) {
382 argv[argc] = ptr;
383 strcpy(ptr, prom_argv[argc]);
384 ptr += strlen(prom_argv[argc]) + 1;
385 }
386 argv[prom_argc] = NULL; /* end array with null pointer */
387 prom_argv = argv;
388
389 /* next preserve the environment variables */
390 len = 0;
391 i = 0;
392 for (envp = prom_envp; *envp != NULL; envp++) {
393 i++; /* count number of environment variables */
394 len += sizeof(char *); /* length of pointer */
395 len += strlen(*envp) + 1; /* length of string */
396 }
397 len += sizeof(char *); /* plus length of null pointer */
398
399 envp = kmalloc(len, GFP_KERNEL);
400 ptr = (char *) &envp[i+1];
401
402 for (argc = 0; argc < i; argc++) {
403 envp[argc] = ptr;
404 strcpy(ptr, prom_envp[argc]);
405 ptr += strlen(prom_envp[argc]) + 1;
406 }
407 envp[i] = NULL; /* end array with null pointer */
408 prom_envp = envp;
409
410 for (i = 0; i < boot_mem_map.nr_map; i++) {
411 if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
412 continue;
413
414 addr = boot_mem_map.map[i].addr;
415 free_init_pages("prom memory",
416 addr, addr + boot_mem_map.map[i].size);
417 }
418}
419
420struct prom_pmemblock *__init prom_getmdesc(void)
421{
422 static char memsz_env[] __initdata = "memsize";
423 static char heaptop_env[] __initdata = "heaptop";
424 char *str;
425 unsigned int memsize;
426 unsigned int heaptop;
427 int i;
428
429 str = prom_getenv(memsz_env);
430 if (!str) {
431 ppfinit("memsize not set in boot prom, "
432 "set to default (32Mb)\n");
433 memsize = 0x02000000;
434 } else {
435 memsize = simple_strtol(str, NULL, 0);
436
437 if (memsize == 0) {
438 /* if memsize is a bad size, use reasonable default */
439 memsize = 0x02000000;
440 }
441
442 /* convert to physical address (removing caching bits, etc) */
443 memsize = CPHYSADDR(memsize);
444 }
445
446 str = prom_getenv(heaptop_env);
447 if (!str) {
448 heaptop = CPHYSADDR((u32)&_text);
449 ppfinit("heaptop not set in boot prom, "
450 "set to default 0x%08x\n", heaptop);
451 } else {
452 heaptop = simple_strtol(str, NULL, 16);
453 if (heaptop == 0) {
454 /* heaptop conversion bad, might have 0xValue */
455 heaptop = simple_strtol(str, NULL, 0);
456
457 if (heaptop == 0) {
458 /* heaptop still bad, use reasonable default */
459 heaptop = CPHYSADDR((u32)&_text);
460 }
461 }
462
463 /* convert to physical address (removing caching bits, etc) */
464 heaptop = CPHYSADDR((u32)heaptop);
465 }
466
467 /* the base region */
468 i = 0;
469 mdesc[i].type = BOOT_MEM_RESERVED;
470 mdesc[i].base = 0x00000000;
471 mdesc[i].size = PAGE_ALIGN(0x300 + 0x80);
472 /* jtag interrupt vector + sizeof vector */
473
474 /* PMON data */
475 if (heaptop > mdesc[i].base + mdesc[i].size) {
476 i++; /* 1 */
477 mdesc[i].type = BOOT_MEM_ROM_DATA;
478 mdesc[i].base = mdesc[i-1].base + mdesc[i-1].size;
479 mdesc[i].size = heaptop - mdesc[i].base;
480 }
481
482 /* end of PMON data to start of kernel -- probably zero .. */
483 if (heaptop != CPHYSADDR((u32)_text)) {
484 i++; /* 2 */
485 mdesc[i].type = BOOT_MEM_RAM;
486 mdesc[i].base = heaptop;
487 mdesc[i].size = CPHYSADDR((u32)_text) - mdesc[i].base;
488 }
489
490 /* kernel proper */
491 i++; /* 3 */
492 mdesc[i].type = BOOT_MEM_RESERVED;
493 mdesc[i].base = CPHYSADDR((u32)_text);
494 mdesc[i].size = CPHYSADDR(PAGE_ALIGN((u32)_end)) - mdesc[i].base;
495
496 /* Remainder of RAM -- under memsize */
497 i++; /* 5 */
498 mdesc[i].type = yamon_free;
499 mdesc[i].base = mdesc[i-1].base + mdesc[i-1].size;
500 mdesc[i].size = memsize - mdesc[i].base;
501
502 return &mdesc[0];
503}
diff --git a/arch/mips/pmcs-msp71xx/msp_serial.c b/arch/mips/pmcs-msp71xx/msp_serial.c
new file mode 100644
index 000000000000..d304be22b963
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/msp_serial.c
@@ -0,0 +1,154 @@
1/*
2 * The setup file for serial related hardware on PMC-Sierra MSP processors.
3 *
4 * Copyright 2005 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/serial.h>
28#include <linux/serial_core.h>
29#include <linux/serial_reg.h>
30#include <linux/slab.h>
31
32#include <asm/bootinfo.h>
33#include <asm/io.h>
34#include <asm/processor.h>
35#include <asm/serial.h>
36#include <linux/serial_8250.h>
37
38#include <msp_prom.h>
39#include <msp_int.h>
40#include <msp_regs.h>
41
42struct msp_uart_data {
43 int last_lcr;
44};
45
46static void msp_serial_out(struct uart_port *p, int offset, int value)
47{
48 struct msp_uart_data *d = p->private_data;
49
50 if (offset == UART_LCR)
51 d->last_lcr = value;
52
53 offset <<= p->regshift;
54 writeb(value, p->membase + offset);
55}
56
57static unsigned int msp_serial_in(struct uart_port *p, int offset)
58{
59 offset <<= p->regshift;
60
61 return readb(p->membase + offset);
62}
63
64static int msp_serial_handle_irq(struct uart_port *p)
65{
66 struct msp_uart_data *d = p->private_data;
67 unsigned int iir = readb(p->membase + (UART_IIR << p->regshift));
68
69 if (serial8250_handle_irq(p, iir)) {
70 return 1;
71 } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
72 /*
73 * The DesignWare APB UART has an Busy Detect (0x07) interrupt
74 * meaning an LCR write attempt occurred while the UART was
75 * busy. The interrupt must be cleared by reading the UART
76 * status register (USR) and the LCR re-written.
77 *
78 * Note: MSP reserves 0x20 bytes of address space for the UART
79 * and the USR is mapped in a separate block at an offset of
80 * 0xc0 from the start of the UART.
81 */
82 (void)readb(p->membase + 0xc0);
83 writeb(d->last_lcr, p->membase + (UART_LCR << p->regshift));
84
85 return 1;
86 }
87
88 return 0;
89}
90
91void __init msp_serial_setup(void)
92{
93 char *s;
94 char *endp;
95 struct uart_port up;
96 unsigned int uartclk;
97
98 memset(&up, 0, sizeof(up));
99
100 /* Check if clock was specified in environment */
101 s = prom_getenv("uartfreqhz");
102 if(!(s && *s && (uartclk = simple_strtoul(s, &endp, 10)) && *endp == 0))
103 uartclk = MSP_BASE_BAUD;
104 ppfinit("UART clock set to %d\n", uartclk);
105
106 /* Initialize first serial port */
107 up.mapbase = MSP_UART0_BASE;
108 up.membase = ioremap_nocache(up.mapbase, MSP_UART_REG_LEN);
109 up.irq = MSP_INT_UART0;
110 up.uartclk = uartclk;
111 up.regshift = 2;
112 up.iotype = UPIO_MEM;
113 up.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
114 up.type = PORT_16550A;
115 up.line = 0;
116 up.serial_out = msp_serial_out;
117 up.serial_in = msp_serial_in;
118 up.handle_irq = msp_serial_handle_irq;
119 up.private_data = kzalloc(sizeof(struct msp_uart_data), GFP_KERNEL);
120 if (!up.private_data) {
121 pr_err("failed to allocate uart private data\n");
122 return;
123 }
124 if (early_serial_setup(&up)) {
125 kfree(up.private_data);
126 pr_err("Early serial init of port 0 failed\n");
127 }
128
129 /* Initialize the second serial port, if one exists */
130 switch (mips_machtype) {
131 case MACH_MSP4200_EVAL:
132 case MACH_MSP4200_GW:
133 case MACH_MSP4200_FPGA:
134 case MACH_MSP7120_EVAL:
135 case MACH_MSP7120_GW:
136 case MACH_MSP7120_FPGA:
137 /* Enable UART1 on MSP4200 and MSP7120 */
138 *GPIO_CFG2_REG = 0x00002299;
139 break;
140
141 default:
142 return; /* No second serial port, good-bye. */
143 }
144
145 up.mapbase = MSP_UART1_BASE;
146 up.membase = ioremap_nocache(up.mapbase, MSP_UART_REG_LEN);
147 up.irq = MSP_INT_UART1;
148 up.line = 1;
149 up.private_data = (void*)UART1_STATUS_REG;
150 if (early_serial_setup(&up)) {
151 kfree(up.private_data);
152 pr_err("Early serial init of port 1 failed\n");
153 }
154}
diff --git a/arch/mips/pmcs-msp71xx/msp_setup.c b/arch/mips/pmcs-msp71xx/msp_setup.c
new file mode 100644
index 000000000000..1651cfdbfe7b
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/msp_setup.c
@@ -0,0 +1,245 @@
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/smp-ops.h>
18#include <asm/time.h>
19
20#include <msp_prom.h>
21#include <msp_regs.h>
22
23#if defined(CONFIG_PMC_MSP7120_GW)
24#include <msp_regops.h>
25#define MSP_BOARD_RESET_GPIO 9
26#endif
27
28extern void msp_serial_setup(void);
29extern void pmctwiled_setup(void);
30
31#if defined(CONFIG_PMC_MSP7120_EVAL) || \
32 defined(CONFIG_PMC_MSP7120_GW) || \
33 defined(CONFIG_PMC_MSP7120_FPGA)
34/*
35 * Performs the reset for MSP7120-based boards
36 */
37void msp7120_reset(void)
38{
39 void *start, *end, *iptr;
40 register int i;
41
42 /* Diasble all interrupts */
43 local_irq_disable();
44#ifdef CONFIG_SYS_SUPPORTS_MULTITHREADING
45 dvpe();
46#endif
47
48 /* Cache the reset code of this function */
49 __asm__ __volatile__ (
50 " .set push \n"
51 " .set mips3 \n"
52 " la %0,startpoint \n"
53 " la %1,endpoint \n"
54 " .set pop \n"
55 : "=r" (start), "=r" (end)
56 :
57 );
58
59 for (iptr = (void *)((unsigned int)start & ~(L1_CACHE_BYTES - 1));
60 iptr < end; iptr += L1_CACHE_BYTES)
61 cache_op(Fill, iptr);
62
63 __asm__ __volatile__ (
64 "startpoint: \n"
65 );
66
67 /* Put the DDRC into self-refresh mode */
68 DDRC_INDIRECT_WRITE(DDRC_CTL(10), 0xb, 1 << 16);
69
70 /*
71 * IMPORTANT!
72 * DO NOT do anything from here on out that might even
73 * think about fetching from RAM - i.e., don't call any
74 * non-inlined functions, and be VERY sure that any inline
75 * functions you do call do NOT access any sort of RAM
76 * anywhere!
77 */
78
79 /* Wait a bit for the DDRC to settle */
80 for (i = 0; i < 100000000; i++);
81
82#if defined(CONFIG_PMC_MSP7120_GW)
83 /*
84 * Set GPIO 9 HI, (tied to board reset logic)
85 * GPIO 9 is the 4th GPIO of register 3
86 *
87 * NOTE: We cannot use the higher-level msp_gpio_mode()/out()
88 * as GPIO char driver may not be enabled and it would look up
89 * data inRAM!
90 */
91 set_value_reg32(GPIO_CFG3_REG, 0xf000, 0x8000);
92 set_reg32(GPIO_DATA3_REG, 8);
93
94 /*
95 * In case GPIO9 doesn't reset the board (jumper configurable!)
96 * fallback to device reset below.
97 */
98#endif
99 /* Set bit 1 of the MSP7120 reset register */
100 *RST_SET_REG = 0x00000001;
101
102 __asm__ __volatile__ (
103 "endpoint: \n"
104 );
105}
106#endif
107
108void msp_restart(char *command)
109{
110 printk(KERN_WARNING "Now rebooting .......\n");
111
112#if defined(CONFIG_PMC_MSP7120_EVAL) || \
113 defined(CONFIG_PMC_MSP7120_GW) || \
114 defined(CONFIG_PMC_MSP7120_FPGA)
115 msp7120_reset();
116#else
117 /* No chip-specific reset code, just jump to the ROM reset vector */
118 set_c0_status(ST0_BEV | ST0_ERL);
119 change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
120 flush_cache_all();
121 write_c0_wired(0);
122
123 __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
124#endif
125}
126
127void msp_halt(void)
128{
129 printk(KERN_WARNING "\n** You can safely turn off the power\n");
130 while (1)
131 /* If possible call official function to get CPU WARs */
132 if (cpu_wait)
133 (*cpu_wait)();
134 else
135 __asm__(".set\tmips3\n\t" "wait\n\t" ".set\tmips0");
136}
137
138void msp_power_off(void)
139{
140 msp_halt();
141}
142
143void __init plat_mem_setup(void)
144{
145 _machine_restart = msp_restart;
146 _machine_halt = msp_halt;
147 pm_power_off = msp_power_off;
148}
149
150extern struct plat_smp_ops msp_smtc_smp_ops;
151
152void __init prom_init(void)
153{
154 unsigned long family;
155 unsigned long revision;
156
157 prom_argc = fw_arg0;
158 prom_argv = (char **)fw_arg1;
159 prom_envp = (char **)fw_arg2;
160
161 /*
162 * Someday we can use this with PMON2000 to get a
163 * platform call prom routines for output etc. without
164 * having to use grody hacks. For now it's unused.
165 *
166 * struct callvectors *cv = (struct callvectors *) fw_arg3;
167 */
168 family = identify_family();
169 revision = identify_revision();
170
171 switch (family) {
172 case FAMILY_FPGA:
173 if (FPGA_IS_MSP4200(revision)) {
174 /* Old-style revision ID */
175 mips_machtype = MACH_MSP4200_FPGA;
176 } else {
177 mips_machtype = MACH_MSP_OTHER;
178 }
179 break;
180
181 case FAMILY_MSP4200:
182#if defined(CONFIG_PMC_MSP4200_EVAL)
183 mips_machtype = MACH_MSP4200_EVAL;
184#elif defined(CONFIG_PMC_MSP4200_GW)
185 mips_machtype = MACH_MSP4200_GW;
186#else
187 mips_machtype = MACH_MSP_OTHER;
188#endif
189 break;
190
191 case FAMILY_MSP4200_FPGA:
192 mips_machtype = MACH_MSP4200_FPGA;
193 break;
194
195 case FAMILY_MSP7100:
196#if defined(CONFIG_PMC_MSP7120_EVAL)
197 mips_machtype = MACH_MSP7120_EVAL;
198#elif defined(CONFIG_PMC_MSP7120_GW)
199 mips_machtype = MACH_MSP7120_GW;
200#else
201 mips_machtype = MACH_MSP_OTHER;
202#endif
203 break;
204
205 case FAMILY_MSP7100_FPGA:
206 mips_machtype = MACH_MSP7120_FPGA;
207 break;
208
209 default:
210 /* we don't recognize the machine */
211 mips_machtype = MACH_UNKNOWN;
212 panic("***Bogosity factor five***, exiting");
213 break;
214 }
215
216 prom_init_cmdline();
217
218 prom_meminit();
219
220 /*
221 * Sub-system setup follows.
222 * Setup functions can either be called here or using the
223 * subsys_initcall mechanism (i.e. see msp_pci_setup). The
224 * order in which they are called can be changed by using the
225 * link order in arch/mips/pmc-sierra/msp71xx/Makefile.
226 *
227 * NOTE: Please keep sub-system specific initialization code
228 * in separate specific files.
229 */
230 msp_serial_setup();
231
232 if (register_vsmp_smp_ops()) {
233#ifdef CONFIG_MIPS_MT_SMTC
234 register_smp_ops(&msp_smtc_smp_ops);
235#endif
236 }
237
238#ifdef CONFIG_PMCTWILED
239 /*
240 * Setup LED states before the subsys_initcall loads other
241 * dependent drivers/modules.
242 */
243 pmctwiled_setup();
244#endif
245}
diff --git a/arch/mips/pmcs-msp71xx/msp_smp.c b/arch/mips/pmcs-msp71xx/msp_smp.c
new file mode 100644
index 000000000000..10170580a2de
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/msp_smp.c
@@ -0,0 +1,77 @@
1/*
2 * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc.
3 * Copyright (C) 2001 Ralf Baechle
4 * Copyright (C) 2010 PMC-Sierra, Inc.
5 *
6 * VSMP support for MSP platforms . Derived from malta vsmp support.
7 *
8 * This program is free software; you can distribute it and/or modify it
9 * under the terms of the GNU General Public License (Version 2) as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
20 *
21 */
22#include <linux/smp.h>
23#include <linux/interrupt.h>
24
25#ifdef CONFIG_MIPS_MT_SMP
26#define MIPS_CPU_IPI_RESCHED_IRQ 0 /* SW int 0 for resched */
27#define MIPS_CPU_IPI_CALL_IRQ 1 /* SW int 1 for call */
28
29
30static void ipi_resched_dispatch(void)
31{
32 do_IRQ(MIPS_CPU_IPI_RESCHED_IRQ);
33}
34
35static void ipi_call_dispatch(void)
36{
37 do_IRQ(MIPS_CPU_IPI_CALL_IRQ);
38}
39
40static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
41{
42 return IRQ_HANDLED;
43}
44
45static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
46{
47 smp_call_function_interrupt();
48
49 return IRQ_HANDLED;
50}
51
52static struct irqaction irq_resched = {
53 .handler = ipi_resched_interrupt,
54 .flags = IRQF_PERCPU,
55 .name = "IPI_resched"
56};
57
58static struct irqaction irq_call = {
59 .handler = ipi_call_interrupt,
60 .flags = IRQF_PERCPU,
61 .name = "IPI_call"
62};
63
64void __init arch_init_ipiirq(int irq, struct irqaction *action)
65{
66 setup_irq(irq, action);
67 irq_set_handler(irq, handle_percpu_irq);
68}
69
70void __init msp_vsmp_int_init(void)
71{
72 set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
73 set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
74 arch_init_ipiirq(MIPS_CPU_IPI_RESCHED_IRQ, &irq_resched);
75 arch_init_ipiirq(MIPS_CPU_IPI_CALL_IRQ, &irq_call);
76}
77#endif /* CONFIG_MIPS_MT_SMP */
diff --git a/arch/mips/pmcs-msp71xx/msp_smtc.c b/arch/mips/pmcs-msp71xx/msp_smtc.c
new file mode 100644
index 000000000000..c8dcc1c01e18
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/msp_smtc.c
@@ -0,0 +1,105 @@
1/*
2 * MSP71xx Platform-specific hooks for SMP operation
3 */
4#include <linux/irq.h>
5#include <linux/init.h>
6
7#include <asm/mipsmtregs.h>
8#include <asm/mipsregs.h>
9#include <asm/smtc.h>
10#include <asm/smtc_ipi.h>
11
12/* VPE/SMP Prototype implements platform interfaces directly */
13
14/*
15 * Cause the specified action to be performed on a targeted "CPU"
16 */
17
18static void msp_smtc_send_ipi_single(int cpu, unsigned int action)
19{
20 /* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */
21 smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
22}
23
24static void msp_smtc_send_ipi_mask(const struct cpumask *mask,
25 unsigned int action)
26{
27 unsigned int i;
28
29 for_each_cpu(i, mask)
30 msp_smtc_send_ipi_single(i, action);
31}
32
33/*
34 * Post-config but pre-boot cleanup entry point
35 */
36static void __cpuinit msp_smtc_init_secondary(void)
37{
38 int myvpe;
39
40 /* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */
41 myvpe = read_c0_tcbind() & TCBIND_CURVPE;
42 if (myvpe > 0)
43 change_c0_status(ST0_IM, STATUSF_IP0 | STATUSF_IP1 |
44 STATUSF_IP6 | STATUSF_IP7);
45 smtc_init_secondary();
46}
47
48/*
49 * Platform "CPU" startup hook
50 */
51static void __cpuinit msp_smtc_boot_secondary(int cpu,
52 struct task_struct *idle)
53{
54 smtc_boot_secondary(cpu, idle);
55}
56
57/*
58 * SMP initialization finalization entry point
59 */
60static void __cpuinit msp_smtc_smp_finish(void)
61{
62 smtc_smp_finish();
63}
64
65/*
66 * Hook for after all CPUs are online
67 */
68
69static void msp_smtc_cpus_done(void)
70{
71}
72
73/*
74 * Platform SMP pre-initialization
75 *
76 * As noted above, we can assume a single CPU for now
77 * but it may be multithreaded.
78 */
79
80static void __init msp_smtc_smp_setup(void)
81{
82 /*
83 * we won't get the definitive value until
84 * we've run smtc_prepare_cpus later, but
85 */
86
87 if (read_c0_config3() & (1 << 2))
88 smp_num_siblings = smtc_build_cpu_map(0);
89}
90
91static void __init msp_smtc_prepare_cpus(unsigned int max_cpus)
92{
93 smtc_prepare_cpus(max_cpus);
94}
95
96struct plat_smp_ops msp_smtc_smp_ops = {
97 .send_ipi_single = msp_smtc_send_ipi_single,
98 .send_ipi_mask = msp_smtc_send_ipi_mask,
99 .init_secondary = msp_smtc_init_secondary,
100 .smp_finish = msp_smtc_smp_finish,
101 .cpus_done = msp_smtc_cpus_done,
102 .boot_secondary = msp_smtc_boot_secondary,
103 .smp_setup = msp_smtc_smp_setup,
104 .prepare_cpus = msp_smtc_prepare_cpus,
105};
diff --git a/arch/mips/pmcs-msp71xx/msp_time.c b/arch/mips/pmcs-msp71xx/msp_time.c
new file mode 100644
index 000000000000..8f12ecc55ace
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/msp_time.c
@@ -0,0 +1,101 @@
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/cevt-r4k.h>
33#include <asm/mipsregs.h>
34#include <asm/time.h>
35
36#include <msp_prom.h>
37#include <msp_int.h>
38#include <msp_regs.h>
39
40#define get_current_vpe() \
41 ((read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE)
42
43static struct irqaction timer_vpe1;
44static int tim_installed;
45
46void __init plat_time_init(void)
47{
48 char *endp, *s;
49 unsigned long cpu_rate = 0;
50
51 if (cpu_rate == 0) {
52 s = prom_getenv("clkfreqhz");
53 cpu_rate = simple_strtoul(s, &endp, 10);
54 if (endp != NULL && *endp != 0) {
55 printk(KERN_ERR
56 "Clock rate in Hz parse error: %s\n", s);
57 cpu_rate = 0;
58 }
59 }
60
61 if (cpu_rate == 0) {
62 s = prom_getenv("clkfreq");
63 cpu_rate = 1000 * simple_strtoul(s, &endp, 10);
64 if (endp != NULL && *endp != 0) {
65 printk(KERN_ERR
66 "Clock rate in MHz parse error: %s\n", s);
67 cpu_rate = 0;
68 }
69 }
70
71 if (cpu_rate == 0) {
72#if defined(CONFIG_PMC_MSP7120_EVAL) \
73 || defined(CONFIG_PMC_MSP7120_GW)
74 cpu_rate = 400000000;
75#elif defined(CONFIG_PMC_MSP7120_FPGA)
76 cpu_rate = 25000000;
77#else
78 cpu_rate = 150000000;
79#endif
80 printk(KERN_ERR
81 "Failed to determine CPU clock rate, "
82 "assuming %ld hz ...\n", cpu_rate);
83 }
84
85 printk(KERN_WARNING "Clock rate set to %ld\n", cpu_rate);
86
87 /* timer frequency is 1/2 clock rate */
88 mips_hpt_frequency = cpu_rate/2;
89}
90
91unsigned int __cpuinit get_c0_compare_int(void)
92{
93 /* MIPS_MT modes may want timer for second VPE */
94 if ((get_current_vpe()) && !tim_installed) {
95 memcpy(&timer_vpe1, &c0_compare_irqaction, sizeof(timer_vpe1));
96 setup_irq(MSP_INT_VPE1_TIMER, &timer_vpe1);
97 tim_installed++;
98 }
99
100 return get_current_vpe() ? MSP_INT_VPE1_TIMER : MSP_INT_VPE0_TIMER;
101}
diff --git a/arch/mips/pmcs-msp71xx/msp_usb.c b/arch/mips/pmcs-msp71xx/msp_usb.c
new file mode 100644
index 000000000000..4dab915696e7
--- /dev/null
+++ b/arch/mips/pmcs-msp71xx/msp_usb.c
@@ -0,0 +1,263 @@
1/*
2 * The setup file for USB related hardware on PMC-Sierra MSP processors.
3 *
4 * Copyright 2006 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#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_GADGET)
27
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#include <msp_usb.h>
38
39
40#if defined(CONFIG_USB_EHCI_HCD)
41static struct resource msp_usbhost0_resources[] = {
42 [0] = { /* EHCI-HS operational and capabilities registers */
43 .start = MSP_USB0_HS_START,
44 .end = MSP_USB0_HS_END,
45 .flags = IORESOURCE_MEM,
46 },
47 [1] = {
48 .start = MSP_INT_USB,
49 .end = MSP_INT_USB,
50 .flags = IORESOURCE_IRQ,
51 },
52 [2] = { /* MSBus-to-AMBA bridge register space */
53 .start = MSP_USB0_MAB_START,
54 .end = MSP_USB0_MAB_END,
55 .flags = IORESOURCE_MEM,
56 },
57 [3] = { /* Identification and general hardware parameters */
58 .start = MSP_USB0_ID_START,
59 .end = MSP_USB0_ID_END,
60 .flags = IORESOURCE_MEM,
61 },
62};
63
64static u64 msp_usbhost0_dma_mask = 0xffffffffUL;
65
66static struct mspusb_device msp_usbhost0_device = {
67 .dev = {
68 .name = "pmcmsp-ehci",
69 .id = 0,
70 .dev = {
71 .dma_mask = &msp_usbhost0_dma_mask,
72 .coherent_dma_mask = 0xffffffffUL,
73 },
74 .num_resources = ARRAY_SIZE(msp_usbhost0_resources),
75 .resource = msp_usbhost0_resources,
76 },
77};
78
79/* MSP7140/MSP82XX has two USB2 hosts. */
80#ifdef CONFIG_MSP_HAS_DUAL_USB
81static u64 msp_usbhost1_dma_mask = 0xffffffffUL;
82
83static struct resource msp_usbhost1_resources[] = {
84 [0] = { /* EHCI-HS operational and capabilities registers */
85 .start = MSP_USB1_HS_START,
86 .end = MSP_USB1_HS_END,
87 .flags = IORESOURCE_MEM,
88 },
89 [1] = {
90 .start = MSP_INT_USB,
91 .end = MSP_INT_USB,
92 .flags = IORESOURCE_IRQ,
93 },
94 [2] = { /* MSBus-to-AMBA bridge register space */
95 .start = MSP_USB1_MAB_START,
96 .end = MSP_USB1_MAB_END,
97 .flags = IORESOURCE_MEM,
98 },
99 [3] = { /* Identification and general hardware parameters */
100 .start = MSP_USB1_ID_START,
101 .end = MSP_USB1_ID_END,
102 .flags = IORESOURCE_MEM,
103 },
104};
105
106static struct mspusb_device msp_usbhost1_device = {
107 .dev = {
108 .name = "pmcmsp-ehci",
109 .id = 1,
110 .dev = {
111 .dma_mask = &msp_usbhost1_dma_mask,
112 .coherent_dma_mask = 0xffffffffUL,
113 },
114 .num_resources = ARRAY_SIZE(msp_usbhost1_resources),
115 .resource = msp_usbhost1_resources,
116 },
117};
118#endif /* CONFIG_MSP_HAS_DUAL_USB */
119#endif /* CONFIG_USB_EHCI_HCD */
120
121#if defined(CONFIG_USB_GADGET)
122static struct resource msp_usbdev0_resources[] = {
123 [0] = { /* EHCI-HS operational and capabilities registers */
124 .start = MSP_USB0_HS_START,
125 .end = MSP_USB0_HS_END,
126 .flags = IORESOURCE_MEM,
127 },
128 [1] = {
129 .start = MSP_INT_USB,
130 .end = MSP_INT_USB,
131 .flags = IORESOURCE_IRQ,
132 },
133 [2] = { /* MSBus-to-AMBA bridge register space */
134 .start = MSP_USB0_MAB_START,
135 .end = MSP_USB0_MAB_END,
136 .flags = IORESOURCE_MEM,
137 },
138 [3] = { /* Identification and general hardware parameters */
139 .start = MSP_USB0_ID_START,
140 .end = MSP_USB0_ID_END,
141 .flags = IORESOURCE_MEM,
142 },
143};
144
145static u64 msp_usbdev_dma_mask = 0xffffffffUL;
146
147/* This may need to be converted to a mspusb_device, too. */
148static struct mspusb_device msp_usbdev0_device = {
149 .dev = {
150 .name = "msp71xx_udc",
151 .id = 0,
152 .dev = {
153 .dma_mask = &msp_usbdev_dma_mask,
154 .coherent_dma_mask = 0xffffffffUL,
155 },
156 .num_resources = ARRAY_SIZE(msp_usbdev0_resources),
157 .resource = msp_usbdev0_resources,
158 },
159};
160
161#ifdef CONFIG_MSP_HAS_DUAL_USB
162static struct resource msp_usbdev1_resources[] = {
163 [0] = { /* EHCI-HS operational and capabilities registers */
164 .start = MSP_USB1_HS_START,
165 .end = MSP_USB1_HS_END,
166 .flags = IORESOURCE_MEM,
167 },
168 [1] = {
169 .start = MSP_INT_USB,
170 .end = MSP_INT_USB,
171 .flags = IORESOURCE_IRQ,
172 },
173 [2] = { /* MSBus-to-AMBA bridge register space */
174 .start = MSP_USB1_MAB_START,
175 .end = MSP_USB1_MAB_END,
176 .flags = IORESOURCE_MEM,
177 },
178 [3] = { /* Identification and general hardware parameters */
179 .start = MSP_USB1_ID_START,
180 .end = MSP_USB1_ID_END,
181 .flags = IORESOURCE_MEM,
182 },
183};
184
185/* This may need to be converted to a mspusb_device, too. */
186static struct mspusb_device msp_usbdev1_device = {
187 .dev = {
188 .name = "msp71xx_udc",
189 .id = 0,
190 .dev = {
191 .dma_mask = &msp_usbdev_dma_mask,
192 .coherent_dma_mask = 0xffffffffUL,
193 },
194 .num_resources = ARRAY_SIZE(msp_usbdev1_resources),
195 .resource = msp_usbdev1_resources,
196 },
197};
198
199#endif /* CONFIG_MSP_HAS_DUAL_USB */
200#endif /* CONFIG_USB_GADGET */
201
202static int __init msp_usb_setup(void)
203{
204 char *strp;
205 char envstr[32];
206 struct platform_device *msp_devs[NUM_USB_DEVS];
207 unsigned int val;
208
209 /* construct environment name usbmode */
210 /* set usbmode <host/device> as pmon environment var */
211 /*
212 * Could this perhaps be integrated into the "features" env var?
213 * Use the features key "U", and follow with "H" for host-mode,
214 * "D" for device-mode. If it works for Ethernet, why not USB...
215 * -- hammtrev, 2007/03/22
216 */
217 snprintf((char *)&envstr[0], sizeof(envstr), "usbmode");
218
219 /* set default host mode */
220 val = 1;
221
222 /* get environment string */
223 strp = prom_getenv((char *)&envstr[0]);
224 if (strp) {
225 /* compare string */
226 if (!strcmp(strp, "device"))
227 val = 0;
228 }
229
230 if (val) {
231#if defined(CONFIG_USB_EHCI_HCD)
232 msp_devs[0] = &msp_usbhost0_device.dev;
233 ppfinit("platform add USB HOST done %s.\n", msp_devs[0]->name);
234#ifdef CONFIG_MSP_HAS_DUAL_USB
235 msp_devs[1] = &msp_usbhost1_device.dev;
236 ppfinit("platform add USB HOST done %s.\n", msp_devs[1]->name);
237#endif
238#else
239 ppfinit("%s: echi_hcd not supported\n", __FILE__);
240#endif /* CONFIG_USB_EHCI_HCD */
241 } else {
242#if defined(CONFIG_USB_GADGET)
243 /* get device mode structure */
244 msp_devs[0] = &msp_usbdev0_device.dev;
245 ppfinit("platform add USB DEVICE done %s.\n"
246 , msp_devs[0]->name);
247#ifdef CONFIG_MSP_HAS_DUAL_USB
248 msp_devs[1] = &msp_usbdev1_device.dev;
249 ppfinit("platform add USB DEVICE done %s.\n"
250 , msp_devs[1]->name);
251#endif
252#else
253 ppfinit("%s: usb_gadget not supported\n", __FILE__);
254#endif /* CONFIG_USB_GADGET */
255 }
256 /* add device */
257 platform_add_devices(msp_devs, ARRAY_SIZE(msp_devs));
258
259 return 0;
260}
261
262subsys_initcall(msp_usb_setup);
263#endif /* CONFIG_USB_EHCI_HCD || CONFIG_USB_GADGET */