diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2012-12-15 05:52:10 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2013-02-01 04:00:22 -0500 |
commit | 0f3a05cb43e731b8cf861dee30e7e4bddd6c5ccc (patch) | |
tree | e19550e56ab9cf95a99d6aa31502099950cdbce3 /arch/mips/pmcs-msp71xx | |
parent | 7034228792cc561e79ff8600f02884bd4c80e287 (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/Kconfig | 48 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/Makefile | 14 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/Platform | 7 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/gpio.c | 216 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/gpio_extended.c | 146 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/msp_elb.c | 46 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/msp_eth.c | 187 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/msp_hwbutton.c | 165 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/msp_irq.c | 164 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/msp_irq_cic.c | 216 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/msp_irq_per.c | 134 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/msp_irq_slp.c | 106 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/msp_pci.c | 50 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/msp_prom.c | 503 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/msp_serial.c | 154 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/msp_setup.c | 245 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/msp_smp.c | 77 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/msp_smtc.c | 105 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/msp_time.c | 101 | ||||
-rw-r--r-- | arch/mips/pmcs-msp71xx/msp_usb.c | 263 |
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 @@ | |||
1 | choice | ||
2 | prompt "PMC-Sierra MSP SOC type" | ||
3 | depends on PMC_MSP | ||
4 | |||
5 | config PMC_MSP4200_EVAL | ||
6 | bool "PMC-Sierra MSP4200 Eval Board" | ||
7 | select IRQ_MSP_SLP | ||
8 | select HW_HAS_PCI | ||
9 | |||
10 | config PMC_MSP4200_GW | ||
11 | bool "PMC-Sierra MSP4200 VoIP Gateway" | ||
12 | select IRQ_MSP_SLP | ||
13 | select HW_HAS_PCI | ||
14 | |||
15 | config 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 | |||
21 | config 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 | |||
29 | config 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 | |||
35 | endchoice | ||
36 | |||
37 | config MSP_HAS_USB | ||
38 | boolean | ||
39 | depends on PMC_MSP | ||
40 | |||
41 | config MSP_ETH | ||
42 | boolean | ||
43 | select MSP_HAS_MAC | ||
44 | depends on PMC_MSP | ||
45 | |||
46 | config 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 | # | ||
4 | obj-y += msp_prom.o msp_setup.o msp_irq.o \ | ||
5 | msp_time.o msp_serial.o msp_elb.o | ||
6 | obj-$(CONFIG_HAVE_GPIO_LIB) += gpio.o gpio_extended.o | ||
7 | obj-$(CONFIG_PMC_MSP7120_GW) += msp_hwbutton.o | ||
8 | obj-$(CONFIG_IRQ_MSP_SLP) += msp_irq_slp.o | ||
9 | obj-$(CONFIG_IRQ_MSP_CIC) += msp_irq_cic.o msp_irq_per.o | ||
10 | obj-$(CONFIG_PCI) += msp_pci.o | ||
11 | obj-$(CONFIG_MSP_HAS_MAC) += msp_eth.o | ||
12 | obj-$(CONFIG_MSP_HAS_USB) += msp_usb.o | ||
13 | obj-$(CONFIG_MIPS_MT_SMP) += msp_smp.o | ||
14 | obj-$(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 | # | ||
4 | platform-$(CONFIG_PMC_MSP) += pmcs-msp71xx/ | ||
5 | cflags-$(CONFIG_PMC_MSP) += -I$(srctree)/arch/mips/include/asm/mach-pmcs-msp71xx \ | ||
6 | -mno-branch-likely | ||
7 | load-$(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 | |||
30 | static 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 | */ | ||
39 | struct 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 | */ | ||
53 | static 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 | */ | ||
69 | static 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 | */ | ||
95 | static 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 | */ | ||
124 | static 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 | */ | ||
139 | static 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 | */ | ||
151 | int 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 | } | ||
172 | EXPORT_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 | */ | ||
200 | static 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 | |||
208 | void __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 | */ | ||
34 | struct 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 | */ | ||
46 | static 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 | */ | ||
64 | static 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 | */ | ||
83 | static 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 | */ | ||
101 | static 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 | */ | ||
134 | static 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 | |||
140 | void __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 | |||
33 | static 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 | |||
46 | subsys_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 | |||
45 | static 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 | |||
58 | static 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 | }; | ||
70 | static 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 | |||
84 | static 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 | ||
110 | static 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 | |||
123 | static 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 | |||
138 | static 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 | ||
156 | int __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 | } | ||
187 | subsys_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 | */ | ||
43 | struct 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 | ||
54 | extern void msp_restart(char *); | ||
55 | |||
56 | static 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 | |||
70 | static void softreset_release(void *data) | ||
71 | { | ||
72 | printk(KERN_WARNING "SOFTRESET switch was released\n"); | ||
73 | |||
74 | /* Do nothing */ | ||
75 | } | ||
76 | |||
77 | static 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 | |||
84 | static 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 | |||
92 | static 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 | |||
102 | static 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 | |||
113 | static 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 | |||
137 | static 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 | |||
156 | static 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 | |||
165 | subsys_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 */ | ||
23 | extern void msp_slp_irq_init(void); | ||
24 | extern void msp_slp_irq_dispatch(void); | ||
25 | |||
26 | /* CIC based systems */ | ||
27 | extern void msp_cic_irq_init(void); | ||
28 | extern void msp_cic_irq_dispatch(void); | ||
29 | |||
30 | /* VSMP support init */ | ||
31 | extern void msp_vsmp_int_init(void); | ||
32 | |||
33 | /* vectored interrupt implementation */ | ||
34 | |||
35 | /* SW0/1 interrupts are used for SMP/SMTC */ | ||
36 | static inline void mac0_int_dispatch(void) { do_IRQ(MSP_INT_MAC0); } | ||
37 | static inline void mac1_int_dispatch(void) { do_IRQ(MSP_INT_MAC1); } | ||
38 | static inline void mac2_int_dispatch(void) { do_IRQ(MSP_INT_SAR); } | ||
39 | static inline void usb_int_dispatch(void) { do_IRQ(MSP_INT_USB); } | ||
40 | static 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 | |||
54 | asmlinkage 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 | |||
109 | static struct irqaction cic_cascade_msp = { | ||
110 | .handler = no_action, | ||
111 | .name = "MSP CIC cascade", | ||
112 | .flags = IRQF_NO_THREAD, | ||
113 | }; | ||
114 | |||
115 | static struct irqaction per_cascade_msp = { | ||
116 | .handler = no_action, | ||
117 | .name = "MSP PER cascade", | ||
118 | .flags = IRQF_NO_THREAD, | ||
119 | }; | ||
120 | |||
121 | void __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 | */ | ||
26 | extern void msp_per_irq_init(void); | ||
27 | extern 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) \ | ||
39 | do { \ | ||
40 | local_irq_save(flags); \ | ||
41 | mtflags = dmt(); \ | ||
42 | } while (0) | ||
43 | |||
44 | #define UNLOCK_VPE(flags, mtflags) \ | ||
45 | do { \ | ||
46 | emt(mtflags); \ | ||
47 | local_irq_restore(flags);\ | ||
48 | } while (0) | ||
49 | |||
50 | #define LOCK_CORE(flags, mtflags) \ | ||
51 | do { \ | ||
52 | local_irq_save(flags); \ | ||
53 | mtflags = dvpe(); \ | ||
54 | } while (0) | ||
55 | |||
56 | #define UNLOCK_CORE(flags, mtflags) \ | ||
57 | do { \ | ||
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 */ | ||
69 | static 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 | |||
79 | static 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 | |||
102 | static 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 | } | ||
114 | static 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 | ||
129 | static 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 | |||
157 | static 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 | |||
168 | void __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 */ | ||
197 | void 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 | |||
35 | static DEFINE_SPINLOCK(per_lock); | ||
36 | #endif | ||
37 | |||
38 | /* ensure writes to per are completed */ | ||
39 | |||
40 | static 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 | |||
50 | static 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 | |||
63 | static 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 | |||
76 | static 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 | ||
88 | static 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 | |||
97 | static 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 | |||
107 | void __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 | |||
122 | void 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 | |||
23 | static 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 | |||
34 | static 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 | */ | ||
49 | static 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 | |||
60 | static 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 | |||
67 | void __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 | |||
83 | void 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 | |||
32 | extern void msp_pci_init(void); | ||
33 | |||
34 | static 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 | |||
50 | subsys_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 */ | ||
54 | int prom_argc; | ||
55 | char **prom_argv, **prom_envp; | ||
56 | int *prom_vec; | ||
57 | |||
58 | /* debug flag */ | ||
59 | int init_debug = 1; | ||
60 | |||
61 | /* memory blocks */ | ||
62 | struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS]; | ||
63 | |||
64 | /* default feature sets */ | ||
65 | static 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 */ | ||
77 | static 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 | |||
86 | static 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 | } | ||
108 | EXPORT_SYMBOL(str2eaddr); | ||
109 | |||
110 | static 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 */ | ||
123 | const 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 | |||
140 | int 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 | } | ||
167 | EXPORT_SYMBOL(get_ethernet_addr); | ||
168 | |||
169 | static 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 | |||
181 | static 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 | |||
194 | unsigned 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 | |||
204 | char identify_pci(void) | ||
205 | { | ||
206 | return test_feature(PCI_KEY); | ||
207 | } | ||
208 | EXPORT_SYMBOL(identify_pci); | ||
209 | |||
210 | char identify_pcimux(void) | ||
211 | { | ||
212 | return test_feature(PCIMUX_KEY); | ||
213 | } | ||
214 | |||
215 | char identify_sec(void) | ||
216 | { | ||
217 | return test_feature(SEC_KEY); | ||
218 | } | ||
219 | EXPORT_SYMBOL(identify_sec); | ||
220 | |||
221 | char identify_spad(void) | ||
222 | { | ||
223 | return test_feature(SPAD_KEY); | ||
224 | } | ||
225 | EXPORT_SYMBOL(identify_spad); | ||
226 | |||
227 | char identify_tdm(void) | ||
228 | { | ||
229 | return test_feature(TDM_KEY); | ||
230 | } | ||
231 | EXPORT_SYMBOL(identify_tdm); | ||
232 | |||
233 | char identify_zsp(void) | ||
234 | { | ||
235 | return test_feature(ZSP_KEY); | ||
236 | } | ||
237 | EXPORT_SYMBOL(identify_zsp); | ||
238 | |||
239 | static 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 | |||
252 | char identify_enet(unsigned long interface_num) | ||
253 | { | ||
254 | return identify_enetfeature(ENET_KEY, interface_num); | ||
255 | } | ||
256 | EXPORT_SYMBOL(identify_enet); | ||
257 | |||
258 | char identify_enetTxD(unsigned long interface_num) | ||
259 | { | ||
260 | return identify_enetfeature(ENETTXD_KEY, interface_num); | ||
261 | } | ||
262 | EXPORT_SYMBOL(identify_enetTxD); | ||
263 | |||
264 | unsigned long identify_family(void) | ||
265 | { | ||
266 | unsigned long deviceid; | ||
267 | |||
268 | deviceid = get_deviceid(); | ||
269 | |||
270 | return deviceid & CPU_DEVID_FAMILY; | ||
271 | } | ||
272 | EXPORT_SYMBOL(identify_family); | ||
273 | |||
274 | unsigned long identify_revision(void) | ||
275 | { | ||
276 | unsigned long deviceid; | ||
277 | |||
278 | deviceid = get_deviceid(); | ||
279 | |||
280 | return deviceid & CPU_DEVID_REVISION; | ||
281 | } | ||
282 | EXPORT_SYMBOL(identify_revision); | ||
283 | |||
284 | /* PROM environment functions */ | ||
285 | char *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 */ | ||
307 | void __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 */ | ||
327 | static 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 | |||
339 | void __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 | |||
358 | void __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 | |||
420 | struct 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 | |||
42 | struct msp_uart_data { | ||
43 | int last_lcr; | ||
44 | }; | ||
45 | |||
46 | static 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 | |||
57 | static 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 | |||
64 | static 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 | |||
91 | void __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 | |||
28 | extern void msp_serial_setup(void); | ||
29 | extern 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 | */ | ||
37 | void 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 | |||
108 | void 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 | |||
127 | void 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 | |||
138 | void msp_power_off(void) | ||
139 | { | ||
140 | msp_halt(); | ||
141 | } | ||
142 | |||
143 | void __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 | |||
150 | extern struct plat_smp_ops msp_smtc_smp_ops; | ||
151 | |||
152 | void __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 | |||
30 | static void ipi_resched_dispatch(void) | ||
31 | { | ||
32 | do_IRQ(MIPS_CPU_IPI_RESCHED_IRQ); | ||
33 | } | ||
34 | |||
35 | static void ipi_call_dispatch(void) | ||
36 | { | ||
37 | do_IRQ(MIPS_CPU_IPI_CALL_IRQ); | ||
38 | } | ||
39 | |||
40 | static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) | ||
41 | { | ||
42 | return IRQ_HANDLED; | ||
43 | } | ||
44 | |||
45 | static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) | ||
46 | { | ||
47 | smp_call_function_interrupt(); | ||
48 | |||
49 | return IRQ_HANDLED; | ||
50 | } | ||
51 | |||
52 | static struct irqaction irq_resched = { | ||
53 | .handler = ipi_resched_interrupt, | ||
54 | .flags = IRQF_PERCPU, | ||
55 | .name = "IPI_resched" | ||
56 | }; | ||
57 | |||
58 | static struct irqaction irq_call = { | ||
59 | .handler = ipi_call_interrupt, | ||
60 | .flags = IRQF_PERCPU, | ||
61 | .name = "IPI_call" | ||
62 | }; | ||
63 | |||
64 | void __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 | |||
70 | void __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 | |||
18 | static 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 | |||
24 | static 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 | */ | ||
36 | static 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 | */ | ||
51 | static 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 | */ | ||
60 | static 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 | |||
69 | static 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 | |||
80 | static 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 | |||
91 | static void __init msp_smtc_prepare_cpus(unsigned int max_cpus) | ||
92 | { | ||
93 | smtc_prepare_cpus(max_cpus); | ||
94 | } | ||
95 | |||
96 | struct 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 | |||
43 | static struct irqaction timer_vpe1; | ||
44 | static int tim_installed; | ||
45 | |||
46 | void __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 | |||
91 | unsigned 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) | ||
41 | static 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 | |||
64 | static u64 msp_usbhost0_dma_mask = 0xffffffffUL; | ||
65 | |||
66 | static 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 | ||
81 | static u64 msp_usbhost1_dma_mask = 0xffffffffUL; | ||
82 | |||
83 | static 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 | |||
106 | static 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) | ||
122 | static 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 | |||
145 | static u64 msp_usbdev_dma_mask = 0xffffffffUL; | ||
146 | |||
147 | /* This may need to be converted to a mspusb_device, too. */ | ||
148 | static 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 | ||
162 | static 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. */ | ||
186 | static 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 | |||
202 | static 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 | |||
262 | subsys_initcall(msp_usb_setup); | ||
263 | #endif /* CONFIG_USB_EHCI_HCD || CONFIG_USB_GADGET */ | ||