aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Fainelli <florian.fainelli@telecomint.eu>2008-01-30 07:33:36 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:33:36 -0500
commit5e3a77e9a9b7bfc1f69f51fe6d34aa649887980c (patch)
tree2ec08958a77752beb57ee8e823a4baac509be8dd
parent0acf8e3447b893ff921863c2a4258e210d584452 (diff)
x86: add support for the RDC R-321x SoC
This patch adds support for the RDC R-321x system-on-chip, also known as R-861x-(G). It uses the generic GPIO API and has support for the on-chip hardware watchdog. Build-fix from: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Florian Fainelli <florian.fainelli@telecomint.eu> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/Kconfig14
-rw-r--r--arch/x86/Makefile5
-rw-r--r--arch/x86/mach-rdc321x/Makefile5
-rw-r--r--arch/x86/mach-rdc321x/gpio.c91
-rw-r--r--arch/x86/mach-rdc321x/platform.c68
-rw-r--r--arch/x86/mach-rdc321x/wdt.c275
-rw-r--r--include/asm-x86/mach-rdc321x/gpio.h56
-rw-r--r--include/asm-x86/mach-rdc321x/rdc321x_defs.h6
-rw-r--r--include/asm-x86/timex.h2
9 files changed, 521 insertions, 1 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 32e267186035..92dc919c7640 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -291,6 +291,18 @@ config X86_ES7000
291 Only choose this option if you have such a system, otherwise you 291 Only choose this option if you have such a system, otherwise you
292 should say N here. 292 should say N here.
293 293
294config X86_RDC321X
295 bool "RDC R-321x SoC"
296 depends on X86_32
297 select M486
298 select X86_REBOOTFIXUPS
299 select GENERIC_GPIO
300 select LEDS_GPIO
301 help
302 This option is needed for RDC R-321x system-on-chip, also known
303 as R-8610-(G).
304 If you don't have one of these chips, you should say N here.
305
294config X86_VSMP 306config X86_VSMP
295 bool "Support for ScaleMP vSMP" 307 bool "Support for ScaleMP vSMP"
296 depends on X86_64 && PCI 308 depends on X86_64 && PCI
@@ -637,7 +649,7 @@ config X86_REBOOTFIXUPS
637 system. 649 system.
638 650
639 Currently, the only fixup is for the Geode machines using 651 Currently, the only fixup is for the Geode machines using
640 CS5530A and CS5536 chipsets. 652 CS5530A and CS5536 chipsets and the RDC R-321x SoC.
641 653
642 Say Y if you want to enable the fixup. Currently, it's safe to 654 Say Y if you want to enable the fixup. Currently, it's safe to
643 enable this option even if you don't need it. 655 enable this option even if you don't need it.
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index e2ffccfd6af6..b08f18261df6 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -139,6 +139,11 @@ mflags-$(CONFIG_X86_ES7000) := -Iinclude/asm-x86/mach-es7000
139fcore-$(CONFIG_X86_ES7000) := arch/x86/mach-es7000/ 139fcore-$(CONFIG_X86_ES7000) := arch/x86/mach-es7000/
140mcore-$(CONFIG_X86_ES7000) := arch/x86/mach-default/ 140mcore-$(CONFIG_X86_ES7000) := arch/x86/mach-default/
141 141
142# RDC R-321x subarch support
143mflags-$(CONFIG_X86_RDC321X) := -Iinclude/asm-x86/mach-rdc321x
144mcore-$(CONFIG_X86_RDC321X) := arch/x86/mach-default
145core-$(CONFIG_X86_RDC321X) += arch/x86/mach-rdc321x/
146
142# default subarch .h files 147# default subarch .h files
143mflags-y += -Iinclude/asm-x86/mach-default 148mflags-y += -Iinclude/asm-x86/mach-default
144 149
diff --git a/arch/x86/mach-rdc321x/Makefile b/arch/x86/mach-rdc321x/Makefile
new file mode 100644
index 000000000000..1faac8125e3d
--- /dev/null
+++ b/arch/x86/mach-rdc321x/Makefile
@@ -0,0 +1,5 @@
1#
2# Makefile for the RDC321x specific parts of the kernel
3#
4obj-$(CONFIG_X86_RDC321X) := gpio.o platform.o wdt.o
5
diff --git a/arch/x86/mach-rdc321x/gpio.c b/arch/x86/mach-rdc321x/gpio.c
new file mode 100644
index 000000000000..031269163bd6
--- /dev/null
+++ b/arch/x86/mach-rdc321x/gpio.c
@@ -0,0 +1,91 @@
1/*
2 * Copyright (C) 2007, OpenWrt.org, Florian Fainelli <florian@openwrt.org>
3 * RDC321x architecture specific GPIO support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 */
10
11#include <linux/autoconf.h>
12#include <linux/init.h>
13#include <linux/io.h>
14#include <linux/types.h>
15#include <linux/module.h>
16#include <linux/delay.h>
17
18#include <asm/mach-rdc321x/rdc321x_defs.h>
19
20static inline int rdc_gpio_is_valid(unsigned gpio)
21{
22 return (gpio <= RDC_MAX_GPIO);
23}
24
25static unsigned int rdc_gpio_read(unsigned gpio)
26{
27 unsigned int val;
28
29 val = 0x80000000 | (7 << 11) | ((gpio&0x20?0x84:0x48));
30 outl(val, RDC3210_CFGREG_ADDR);
31 udelay(10);
32 val = inl(RDC3210_CFGREG_DATA);
33 val |= (0x1 << (gpio & 0x1F));
34 outl(val, RDC3210_CFGREG_DATA);
35 udelay(10);
36 val = 0x80000000 | (7 << 11) | ((gpio&0x20?0x88:0x4C));
37 outl(val, RDC3210_CFGREG_ADDR);
38 udelay(10);
39 val = inl(RDC3210_CFGREG_DATA);
40
41 return val;
42}
43
44static void rdc_gpio_write(unsigned int val)
45{
46 if (val) {
47 outl(val, RDC3210_CFGREG_DATA);
48 udelay(10);
49 }
50}
51
52int rdc_gpio_get_value(unsigned gpio)
53{
54 if (rdc_gpio_is_valid(gpio))
55 return (int)rdc_gpio_read(gpio);
56 else
57 return -EINVAL;
58}
59EXPORT_SYMBOL(rdc_gpio_get_value);
60
61void rdc_gpio_set_value(unsigned gpio, int value)
62{
63 unsigned int val;
64
65 if (!rdc_gpio_is_valid(gpio))
66 return;
67
68 val = rdc_gpio_read(gpio);
69
70 if (value)
71 val &= ~(0x1 << (gpio & 0x1F));
72 else
73 val |= (0x1 << (gpio & 0x1F));
74
75 rdc_gpio_write(val);
76}
77EXPORT_SYMBOL(rdc_gpio_set_value);
78
79int rdc_gpio_direction_input(unsigned gpio)
80{
81 return 0;
82}
83EXPORT_SYMBOL(rdc_gpio_direction_input);
84
85int rdc_gpio_direction_output(unsigned gpio, int value)
86{
87 return 0;
88}
89EXPORT_SYMBOL(rdc_gpio_direction_output);
90
91
diff --git a/arch/x86/mach-rdc321x/platform.c b/arch/x86/mach-rdc321x/platform.c
new file mode 100644
index 000000000000..dda6024a5862
--- /dev/null
+++ b/arch/x86/mach-rdc321x/platform.c
@@ -0,0 +1,68 @@
1/*
2 * Generic RDC321x platform devices
3 *
4 * Copyright (C) 2007 Florian Fainelli <florian@openwrt.org>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#include <linux/init.h>
24#include <linux/kernel.h>
25#include <linux/list.h>
26#include <linux/device.h>
27#include <linux/platform_device.h>
28#include <linux/version.h>
29#include <linux/leds.h>
30
31#include <asm/gpio.h>
32
33/* LEDS */
34static struct gpio_led default_leds[] = {
35 { .name = "rdc:dmz", .gpio = 1, },
36};
37
38static struct gpio_led_platform_data rdc321x_led_data = {
39 .num_leds = ARRAY_SIZE(default_leds),
40 .leds = default_leds,
41};
42
43static struct platform_device rdc321x_leds = {
44 .name = "leds-gpio",
45 .id = -1,
46 .dev = {
47 .platform_data = &rdc321x_led_data,
48 }
49};
50
51/* Watchdog */
52static struct platform_device rdc321x_wdt = {
53 .name = "rdc321x-wdt",
54 .id = -1,
55 .num_resources = 0,
56};
57
58static struct platform_device *rdc321x_devs[] = {
59 &rdc321x_leds,
60 &rdc321x_wdt
61};
62
63static int __init rdc_board_setup(void)
64{
65 return platform_add_devices(rdc321x_devs, ARRAY_SIZE(rdc321x_devs));
66}
67
68arch_initcall(rdc_board_setup);
diff --git a/arch/x86/mach-rdc321x/wdt.c b/arch/x86/mach-rdc321x/wdt.c
new file mode 100644
index 000000000000..ec5625ae7061
--- /dev/null
+++ b/arch/x86/mach-rdc321x/wdt.c
@@ -0,0 +1,275 @@
1/*
2 * RDC321x watchdog driver
3 *
4 * Copyright (C) 2007 Florian Fainelli <florian@openwrt.org>
5 *
6 * This driver is highly inspired from the cpu5_wdt driver
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 */
23
24#include <linux/module.h>
25#include <linux/moduleparam.h>
26#include <linux/types.h>
27#include <linux/errno.h>
28#include <linux/miscdevice.h>
29#include <linux/fs.h>
30#include <linux/init.h>
31#include <linux/ioport.h>
32#include <linux/timer.h>
33#include <linux/completion.h>
34#include <linux/jiffies.h>
35#include <linux/platform_device.h>
36#include <linux/watchdog.h>
37#include <linux/io.h>
38#include <linux/uaccess.h>
39
40#include <asm/mach-rdc321x/rdc321x_defs.h>
41
42#define RDC_WDT_MASK 0x80000000 /* Mask */
43#define RDC_WDT_EN 0x00800000 /* Enable bit */
44#define RDC_WDT_WTI 0x00200000 /* Generate CPU reset/NMI/WDT on timeout */
45#define RDC_WDT_RST 0x00100000 /* Reset bit */
46#define RDC_WDT_WIF 0x00040000 /* WDT IRQ Flag */
47#define RDC_WDT_IRT 0x00000100 /* IRQ Routing table */
48#define RDC_WDT_CNT 0x00000001 /* WDT count */
49
50#define RDC_CLS_TMR 0x80003844 /* Clear timer */
51
52#define RDC_WDT_INTERVAL (HZ/10+1)
53
54int nowayout = WATCHDOG_NOWAYOUT;
55module_param(nowayout, int, 0);
56MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
57
58static int ticks = 1000;
59
60/* some device data */
61
62static struct {
63 struct completion stop;
64 volatile int running;
65 struct timer_list timer;
66 volatile int queue;
67 int default_ticks;
68 unsigned long inuse;
69} rdc321x_wdt_device;
70
71/* generic helper functions */
72
73static void rdc321x_wdt_trigger(unsigned long unused)
74{
75 if (rdc321x_wdt_device.running)
76 ticks--;
77
78 /* keep watchdog alive */
79 outl(RDC_WDT_EN|inl(RDC3210_CFGREG_DATA), RDC3210_CFGREG_DATA);
80
81 /* requeue?? */
82 if (rdc321x_wdt_device.queue && ticks)
83 mod_timer(&rdc321x_wdt_device.timer,
84 jiffies + RDC_WDT_INTERVAL);
85 else {
86 /* ticks doesn't matter anyway */
87 complete(&rdc321x_wdt_device.stop);
88 }
89
90}
91
92static void rdc321x_wdt_reset(void)
93{
94 ticks = rdc321x_wdt_device.default_ticks;
95}
96
97static void rdc321x_wdt_start(void)
98{
99 if (!rdc321x_wdt_device.queue) {
100 rdc321x_wdt_device.queue = 1;
101
102 /* Clear the timer */
103 outl(RDC_CLS_TMR, RDC3210_CFGREG_ADDR);
104
105 /* Enable watchdog and set the timeout to 81.92 us */
106 outl(RDC_WDT_EN|RDC_WDT_CNT, RDC3210_CFGREG_DATA);
107
108 mod_timer(&rdc321x_wdt_device.timer,
109 jiffies + RDC_WDT_INTERVAL);
110 }
111
112 /* if process dies, counter is not decremented */
113 rdc321x_wdt_device.running++;
114}
115
116static int rdc321x_wdt_stop(void)
117{
118 if (rdc321x_wdt_device.running)
119 rdc321x_wdt_device.running = 0;
120
121 ticks = rdc321x_wdt_device.default_ticks;
122
123 return -EIO;
124}
125
126/* filesystem operations */
127
128static int rdc321x_wdt_open(struct inode *inode, struct file *file)
129{
130 if (test_and_set_bit(0, &rdc321x_wdt_device.inuse))
131 return -EBUSY;
132
133 return nonseekable_open(inode, file);
134}
135
136static int rdc321x_wdt_release(struct inode *inode, struct file *file)
137{
138 clear_bit(0, &rdc321x_wdt_device.inuse);
139 return 0;
140}
141
142static int rdc321x_wdt_ioctl(struct inode *inode, struct file *file,
143 unsigned int cmd, unsigned long arg)
144{
145 void __user *argp = (void __user *)arg;
146 unsigned int value;
147 static struct watchdog_info ident = {
148 .options = WDIOF_CARDRESET,
149 .identity = "RDC321x WDT",
150 };
151
152 switch (cmd) {
153 case WDIOC_KEEPALIVE:
154 rdc321x_wdt_reset();
155 break;
156 case WDIOC_GETSTATUS:
157 /* Read the value from the DATA register */
158 value = inl(RDC3210_CFGREG_DATA);
159 if (copy_to_user(argp, &value, sizeof(int)))
160 return -EFAULT;
161 break;
162 case WDIOC_GETSUPPORT:
163 if (copy_to_user(argp, &ident, sizeof(ident)))
164 return -EFAULT;
165 break;
166 case WDIOC_SETOPTIONS:
167 if (copy_from_user(&value, argp, sizeof(int)))
168 return -EFAULT;
169 switch (value) {
170 case WDIOS_ENABLECARD:
171 rdc321x_wdt_start();
172 break;
173 case WDIOS_DISABLECARD:
174 return rdc321x_wdt_stop();
175 default:
176 return -EINVAL;
177 }
178 break;
179 default:
180 return -ENOTTY;
181 }
182 return 0;
183}
184
185static ssize_t rdc321x_wdt_write(struct file *file, const char __user *buf,
186 size_t count, loff_t *ppos)
187{
188 if (!count)
189 return -EIO;
190
191 rdc321x_wdt_reset();
192
193 return count;
194}
195
196static const struct file_operations rdc321x_wdt_fops = {
197 .owner = THIS_MODULE,
198 .llseek = no_llseek,
199 .ioctl = rdc321x_wdt_ioctl,
200 .open = rdc321x_wdt_open,
201 .write = rdc321x_wdt_write,
202 .release = rdc321x_wdt_release,
203};
204
205static struct miscdevice rdc321x_wdt_misc = {
206 .minor = WATCHDOG_MINOR,
207 .name = "watchdog",
208 .fops = &rdc321x_wdt_fops,
209};
210
211static int __devinit rdc321x_wdt_probe(struct platform_device *pdev)
212{
213 int err;
214
215 err = misc_register(&rdc321x_wdt_misc);
216 if (err < 0) {
217 printk(KERN_ERR PFX "watchdog misc_register failed\n");
218 return err;
219 }
220
221 /* Reset the watchdog */
222 outl(RDC_WDT_RST, RDC3210_CFGREG_DATA);
223
224 init_completion(&rdc321x_wdt_device.stop);
225 rdc321x_wdt_device.queue = 0;
226
227 clear_bit(0, &rdc321x_wdt_device.inuse);
228
229 setup_timer(&rdc321x_wdt_device.timer, rdc321x_wdt_trigger, 0);
230
231 rdc321x_wdt_device.default_ticks = ticks;
232
233 printk(KERN_INFO PFX "watchdog init success\n");
234
235 return 0;
236}
237
238static int rdc321x_wdt_remove(struct platform_device *pdev)
239{
240 if (rdc321x_wdt_device.queue) {
241 rdc321x_wdt_device.queue = 0;
242 wait_for_completion(&rdc321x_wdt_device.stop);
243 }
244
245 misc_deregister(&rdc321x_wdt_misc);
246
247 return 0;
248}
249
250static struct platform_driver rdc321x_wdt_driver = {
251 .probe = rdc321x_wdt_probe,
252 .remove = rdc321x_wdt_remove,
253 .driver = {
254 .owner = THIS_MODULE,
255 .name = "rdc321x-wdt",
256 },
257};
258
259static int __init rdc321x_wdt_init(void)
260{
261 return platform_driver_register(&rdc321x_wdt_driver);
262}
263
264static void __exit rdc321x_wdt_exit(void)
265{
266 platform_driver_unregister(&rdc321x_wdt_driver);
267}
268
269module_init(rdc321x_wdt_init);
270module_exit(rdc321x_wdt_exit);
271
272MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
273MODULE_DESCRIPTION("RDC321x watchdog driver");
274MODULE_LICENSE("GPL");
275MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/include/asm-x86/mach-rdc321x/gpio.h b/include/asm-x86/mach-rdc321x/gpio.h
new file mode 100644
index 000000000000..db31b929b990
--- /dev/null
+++ b/include/asm-x86/mach-rdc321x/gpio.h
@@ -0,0 +1,56 @@
1#ifndef _RDC321X_GPIO_H
2#define _RDC321X_GPIO_H
3
4extern int rdc_gpio_get_value(unsigned gpio);
5extern void rdc_gpio_set_value(unsigned gpio, int value);
6extern int rdc_gpio_direction_input(unsigned gpio);
7extern int rdc_gpio_direction_output(unsigned gpio, int value);
8
9
10/* Wrappers for the arch-neutral GPIO API */
11
12static inline int gpio_request(unsigned gpio, const char *label)
13{
14 /* Not yet implemented */
15 return 0;
16}
17
18static inline void gpio_free(unsigned gpio)
19{
20 /* Not yet implemented */
21}
22
23static inline int gpio_direction_input(unsigned gpio)
24{
25 return rdc_gpio_direction_input(gpio);
26}
27
28static inline int gpio_direction_output(unsigned gpio, int value)
29{
30 return rdc_gpio_direction_output(gpio, value);
31}
32
33static inline int gpio_get_value(unsigned gpio)
34{
35 return rdc_gpio_get_value(gpio);
36}
37
38static inline void gpio_set_value(unsigned gpio, int value)
39{
40 rdc_gpio_set_value(gpio, value);
41}
42
43static inline int gpio_to_irq(unsigned gpio)
44{
45 return gpio;
46}
47
48static inline int irq_to_gpio(unsigned irq)
49{
50 return irq;
51}
52
53/* For cansleep */
54#include <asm-generic/gpio.h>
55
56#endif /* _RDC321X_GPIO_H_ */
diff --git a/include/asm-x86/mach-rdc321x/rdc321x_defs.h b/include/asm-x86/mach-rdc321x/rdc321x_defs.h
new file mode 100644
index 000000000000..838ba8f64fd3
--- /dev/null
+++ b/include/asm-x86/mach-rdc321x/rdc321x_defs.h
@@ -0,0 +1,6 @@
1#define PFX "rdc321x: "
2
3/* General purpose configuration and data registers */
4#define RDC3210_CFGREG_ADDR 0x0CF8
5#define RDC3210_CFGREG_DATA 0x0CFC
6#define RDC_MAX_GPIO 0x3A
diff --git a/include/asm-x86/timex.h b/include/asm-x86/timex.h
index 39a21ab030f0..27cfd6c599ba 100644
--- a/include/asm-x86/timex.h
+++ b/include/asm-x86/timex.h
@@ -7,6 +7,8 @@
7 7
8#ifdef CONFIG_X86_ELAN 8#ifdef CONFIG_X86_ELAN
9# define PIT_TICK_RATE 1189200 /* AMD Elan has different frequency! */ 9# define PIT_TICK_RATE 1189200 /* AMD Elan has different frequency! */
10#elif defined(CONFIG_X86_RDC321X)
11# define PIT_TICK_RATE 1041667 /* Underlying HZ for R8610 */
10#else 12#else
11# define PIT_TICK_RATE 1193182 /* Underlying HZ */ 13# define PIT_TICK_RATE 1193182 /* Underlying HZ */
12#endif 14#endif