diff options
Diffstat (limited to 'target/linux/rdc/files-2.6.24/arch/x86/mach-rdc')
5 files changed, 645 insertions, 0 deletions
diff --git a/target/linux/rdc/files-2.6.24/arch/x86/mach-rdc/Makefile b/target/linux/rdc/files-2.6.24/arch/x86/mach-rdc/Makefile new file mode 100644 index 000000000..5961bc791 --- /dev/null +++ b/target/linux/rdc/files-2.6.24/arch/x86/mach-rdc/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the RDC321x specific parts of the kernel +# +obj-$(CONFIG_X86_RDC) := gpio.o platform.o wdt.o + diff --git a/target/linux/rdc/files-2.6.24/arch/x86/mach-rdc/gpio.c b/target/linux/rdc/files-2.6.24/arch/x86/mach-rdc/gpio.c new file mode 100644 index 000000000..dbd03270f --- /dev/null +++ b/target/linux/rdc/files-2.6.24/arch/x86/mach-rdc/gpio.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2007, OpenWrt.org, Florian Fainelli <florian@openwrt.org> + * RDC321x architecture specific GPIO support + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/autoconf.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/types.h> +#include <linux/module.h> +#include <linux/delay.h> + +#include <asm/mach-rdc/rdc321x_defs.h> + +static inline int rdc_gpio_is_valid(unsigned gpio) +{ + return (gpio <= RDC_MAX_GPIO); +} + +static unsigned int rdc_gpio_read(unsigned gpio) +{ + unsigned int val; + + val = 0x80000000 | (7 << 11) | ((gpio&0x20?0x84:0x48)); + outl(val, RDC3210_CFGREG_ADDR); + udelay(10); + val = inl(RDC3210_CFGREG_DATA); + val |= (0x1 << (gpio & 0x1F)); + outl(val, RDC3210_CFGREG_DATA); + udelay(10); + val = 0x80000000 | (7 << 11) | ((gpio&0x20?0x88:0x4C)); + outl(val, RDC3210_CFGREG_ADDR); + udelay(10); + val = inl(RDC3210_CFGREG_DATA); + + return val; +} + +static void rdc_gpio_write(unsigned int val) +{ + if (val) { + outl(val, RDC3210_CFGREG_DATA); + udelay(10); + } +} + +int rdc_gpio_get_value(unsigned gpio) +{ + if (rdc_gpio_is_valid(gpio)) + return (int)rdc_gpio_read(gpio); + else + return -EINVAL; +} +EXPORT_SYMBOL(rdc_gpio_get_value); + +void rdc_gpio_set_value(unsigned gpio, int value) +{ + unsigned int val; + + if (!rdc_gpio_is_valid(gpio)) + return; + + val = rdc_gpio_read(gpio); + + if (value) + val &= ~(0x1 << (gpio & 0x1F)); + else + val |= (0x1 << (gpio & 0x1F)); + + rdc_gpio_write(val); +} +EXPORT_SYMBOL(rdc_gpio_set_value); + +int rdc_gpio_direction_input(unsigned gpio) +{ + return 0; +} +EXPORT_SYMBOL(rdc_gpio_direction_input); + +int rdc_gpio_direction_output(unsigned gpio, int value) +{ + return 0; +} +EXPORT_SYMBOL(rdc_gpio_direction_output); + + diff --git a/target/linux/rdc/files-2.6.24/arch/x86/mach-rdc/platform.c b/target/linux/rdc/files-2.6.24/arch/x86/mach-rdc/platform.c new file mode 100644 index 000000000..86981f844 --- /dev/null +++ b/target/linux/rdc/files-2.6.24/arch/x86/mach-rdc/platform.c @@ -0,0 +1,263 @@ +/* + * + * Generic RDC321x platform devices + * + * Copyright (C) 2007-2008 OpenWrt.org + * Copyright (C) 2007 Florian Fainelli <florian@openwrt.org> + * Copyright (C) 2008 Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/version.h> +#include <linux/leds.h> +#include <linux/gpio_keys.h> +#include <linux/input.h> +#include <linux/mtd/map.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/physmap.h> +#include <linux/root_dev.h> +#include <asm/gpio.h> + +/* Flash */ +#ifdef CONFIG_MTD_RDC3210 +static struct resource rdc_flash_resource[] = { + [0] = { + .start = (u32)-CONFIG_MTD_RDC3210_SIZE, + .end = (u32)-1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device rdc_flash_device = { + .name = "rdc321x-flash", + .id = -1, + .num_resources = ARRAY_SIZE(rdc_flash_resource), + .resource = rdc_flash_resource, +}; +#else +static struct mtd_partition rdc_flash_parts[15]; + +static struct resource rdc_flash_resource = { + .end = (u32)-1, + .flags = IORESOURCE_MEM, +}; + +static struct physmap_flash_data rdc_flash_data = { + .parts = rdc_flash_parts, +}; + +static struct platform_device rdc_flash_device = { + .name = "physmap-flash", + .id = -1, + .resource = &rdc_flash_resource, + .num_resources = 1, + .dev.platform_data = &rdc_flash_data, +}; +#endif + +/* LEDS */ +static struct gpio_led default_leds[] = { + { .name = "rdc321x:dmz", .gpio = 1, }, +}; + +static struct gpio_led_platform_data rdc321x_led_data = { + .num_leds = ARRAY_SIZE(default_leds), + .leds = default_leds, +}; + +static struct platform_device rdc321x_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &rdc321x_led_data, + } +}; + +/* Watchdog */ +static struct platform_device rdc321x_wdt = { + .name = "rdc321x-wdt", + .id = -1, + .num_resources = 0, +}; + +/* Button */ +static struct gpio_keys_button rdc321x_gpio_btn[] = { + { + .gpio = 0, + .code = BTN_0, + .desc = "Reset", + .active_low = 1, + } +}; + +static struct gpio_keys_platform_data rdc321x_gpio_btn_data = { + .buttons = rdc321x_gpio_btn, + .nbuttons = ARRAY_SIZE(rdc321x_gpio_btn), +}; + +static struct platform_device rdc321x_button = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &rdc321x_gpio_btn_data, + } +}; + +static struct platform_device *rdc321x_devs[] = { + &rdc_flash_device, + &rdc321x_leds, + &rdc321x_wdt, + &rdc321x_button +}; + +static int probe_flash_start(struct map_info *the_map) +{ + struct mtd_info *res; + + the_map->virt = ioremap(the_map->phys, the_map->size); + if (the_map->virt == NULL) + return 1; + for (the_map->bankwidth = 32; the_map->bankwidth; the_map->bankwidth + >>= 1) { + res = do_map_probe("cfi_probe", the_map); + if (res == NULL) + res = do_map_probe("jedec_probe", the_map); + if (res != NULL) + break; + } + iounmap(the_map->virt); + if (res != NULL) + the_map->phys = (u32)-(s32)(the_map->size = res->size); + return res == NULL; +} + +static __init int rdc_board_setup(void) +{ +#ifndef CONFIG_MTD_RDC3210 + struct map_info rdc_map_info; + u32 the_header[4]; + + ROOT_DEV = 0; + rdc_map_info.name = rdc_flash_device.name; + rdc_map_info.phys = 0xff000000; + rdc_map_info.size = 0x1000000; + rdc_map_info.bankwidth = 2; + rdc_map_info.set_vpp = NULL; + simple_map_init(&rdc_map_info); + while (probe_flash_start(&rdc_map_info)) { + rdc_map_info.phys++; + if (--rdc_map_info.size) + panic("Not to be or to be: That" + " is not the question."); + } + rdc_flash_resource.start = rdc_map_info.phys; + rdc_flash_data.width = rdc_map_info.bankwidth; + rdc_map_info.virt = (u32)ioremap_nocache(rdc_map_info.phys, 0x10); + if (rdc_map_info.virt == NULL) + panic("Something's rotten in Denmark!"); + the_header[0] = ((u32 *)rdc_map_info.virt)[0]; + the_header[1] = ((u32 *)rdc_map_info.virt)[1]; + the_header[2] = ((u32 *)rdc_map_info.virt)[2]; + the_header[3] = ((u32 *)rdc_map_info.virt)[3]; + iounmap(rdc_map_info.virt); + if (!memcmp(the_header, "GMTK", 4)) { /* Gemtek */ + /* TODO */ + } else if (!memcmp(the_header, "CSYS", 4)) { /* Sitecom */ + /* TODO */ + } else if (!memcmp(((u8 *)the_header) + 14, "Li", 2)) { /* AMIT */ + rdc_flash_parts[0].name = "kernel_parthdr"; + rdc_flash_parts[0].offset = 0; + rdc_flash_parts[0].size = 0x10; + rdc_flash_parts[1].name = "kernel"; + rdc_flash_parts[1].offset = 0x10; + rdc_flash_parts[1].size = 0xffff0; + rdc_flash_parts[2].name = "rootfs_parthdr"; + rdc_flash_parts[2].offset = 0x100000; + rdc_flash_parts[2].size = 0x10; + rdc_flash_parts[3].name = "rootfs"; + rdc_flash_parts[3].offset = 0x100010; + rdc_flash_parts[3].size = rdc_map_info.size - 0x160010; + rdc_flash_parts[4].name = "config_parthdr"; + rdc_flash_parts[4].offset = rdc_map_info.size - 0x60000; + rdc_flash_parts[4].size = 0x10; + rdc_flash_parts[5].name = "config"; + rdc_flash_parts[5].offset = rdc_map_info.size - 0x5fff0; + rdc_flash_parts[5].size = 0xfff0; + rdc_flash_parts[6].name = "recoveryfs_parthdr"; + rdc_flash_parts[6].offset = rdc_map_info.size - 0x50000; + rdc_flash_parts[6].size = 0x10; + rdc_flash_parts[7].name = "recoveryfs"; + rdc_flash_parts[7].offset = rdc_map_info.size - 0x4fff0; + rdc_flash_parts[7].size = 0x3fff0; + rdc_flash_parts[8].name = "recovery_parthdr"; + rdc_flash_parts[8].offset = rdc_map_info.size - 0x10000; + rdc_flash_parts[8].size = 0x10; + rdc_flash_parts[9].name = "recovery"; + rdc_flash_parts[9].offset = rdc_map_info.size - 0xfff0; + rdc_flash_parts[9].size = 0x7ff0; + rdc_flash_parts[10].name = "productinfo_parthdr"; + rdc_flash_parts[10].offset = rdc_map_info.size - 0x8000; + rdc_flash_parts[10].size = 0x10; + rdc_flash_parts[11].name = "productinfo"; + rdc_flash_parts[11].offset = rdc_map_info.size - 0x7ff0; + rdc_flash_parts[11].size = 0x1ff0; + rdc_flash_parts[12].name = "bootloader_parthdr"; + rdc_flash_parts[12].offset = rdc_map_info.size - 0x6000; + rdc_flash_parts[12].size = 0x10; + rdc_flash_parts[13].name = "bootloader"; + rdc_flash_parts[13].offset = rdc_map_info.size - 0x5ff0; + rdc_flash_parts[13].size = 0x5ff0; + rdc_flash_parts[14].name = "everything"; + rdc_flash_parts[14].offset = 0; + rdc_flash_parts[14].size = rdc_map_info.size; + rdc_flash_data.nr_parts = 15; + } else { /* ZyXEL */ + rdc_flash_parts[0].name = "kernel"; + rdc_flash_parts[0].offset = 0; + rdc_flash_parts[0].size = 0x100000; + rdc_flash_parts[1].name = "rootfs"; + rdc_flash_parts[1].offset = 0x100000; + rdc_flash_parts[1].size = rdc_map_info.size - 0x140000; + rdc_flash_parts[2].name = "linux"; + rdc_flash_parts[2].offset = 0; + rdc_flash_parts[2].size = rdc_map_info.size - 0x40000; + rdc_flash_parts[3].name = "config"; + rdc_flash_parts[3].offset = rdc_map_info.size - 0x40000; + rdc_flash_parts[3].size = 0x10000; + rdc_flash_parts[4].name = "productinfo"; + rdc_flash_parts[4].offset = rdc_map_info.size - 0x30000; + rdc_flash_parts[4].size = 0x10000; + rdc_flash_parts[5].name = "bootloader"; + rdc_flash_parts[5].offset = rdc_map_info.size - 0x20000; + rdc_flash_parts[5].size = 0x20000; + rdc_flash_data.nr_parts = 6; + } +#endif + return platform_add_devices(rdc321x_devs, ARRAY_SIZE(rdc321x_devs)); +} + +#ifdef CONFIG_MTD_RDC3210 +arch_initcall(rdc_board_setup); +#else +late_initcall(rdc_board_setup); +#endif diff --git a/target/linux/rdc/files-2.6.24/arch/x86/mach-rdc/setup.c b/target/linux/rdc/files-2.6.24/arch/x86/mach-rdc/setup.c new file mode 100644 index 000000000..ad206c3d0 --- /dev/null +++ b/target/linux/rdc/files-2.6.24/arch/x86/mach-rdc/setup.c @@ -0,0 +1,14 @@ +/* + * Machine specific setup for generic + */ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <asm/arch_hooks.h> +#include <asm/io.h> +#include <asm/setup.h> + +char * __init machine_specific_memory_setup(void) +{ + return "RDC R-321x"; +} diff --git a/target/linux/rdc/files-2.6.24/arch/x86/mach-rdc/wdt.c b/target/linux/rdc/files-2.6.24/arch/x86/mach-rdc/wdt.c new file mode 100644 index 000000000..13b69f68a --- /dev/null +++ b/target/linux/rdc/files-2.6.24/arch/x86/mach-rdc/wdt.c @@ -0,0 +1,272 @@ +/* + * RDC321x watchdog driver + * + * Copyright (C) 2007 Florian Fainelli <florian@openwrt.org> + * + * This driver is highly inspired from the cpu5_wdt driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/miscdevice.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/timer.h> +#include <linux/completion.h> +#include <linux/jiffies.h> +#include <linux/platform_device.h> +#include <linux/watchdog.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + +#include <asm/mach-rdc/rdc321x_defs.h> + +#define RDC_WDT_MASK 0x80000000 /* Mask */ +#define RDC_WDT_EN 0x00800000 /* Enable bit */ +#define RDC_WDT_WTI 0x00200000 /* Generate a CPU reset/NMI/WDT irq when WDT timeout is reached */ +#define RDC_WDT_RST 0x00100000 /* Reset bit */ +#define RDC_WDT_WIF 0x00040000 /* WDT IRQ Flag */ +#define RDC_WDT_IRT 0x00000100 /* IRQ Routing table */ +#define RDC_WDT_CNT 0x00000001 /* WDT count */ + +#define RDC_CLS_TMR 0x80003844 /* Clear timer */ + +#define RDC_WDT_INTERVAL (HZ/10+1) + +int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +static int ticks = 1000; + +/* some device data */ + +static struct { + struct completion stop; + volatile int running; + struct timer_list timer; + volatile int queue; + int default_ticks; + unsigned long inuse; +} rdc321x_wdt_device; + +/* generic helper functions */ + +static void rdc321x_wdt_trigger(unsigned long unused) +{ + if( rdc321x_wdt_device.running ) + ticks--; + + /* keep watchdog alive */ + outl(RDC_WDT_EN|inl(RDC3210_CFGREG_DATA), RDC3210_CFGREG_DATA); + + /* requeue?? */ + if (rdc321x_wdt_device.queue && ticks) + mod_timer(&rdc321x_wdt_device.timer, jiffies + RDC_WDT_INTERVAL); + else { + /* ticks doesn't matter anyway */ + complete(&rdc321x_wdt_device.stop); + } + +} + +static void rdc321x_wdt_reset(void) +{ + ticks = rdc321x_wdt_device.default_ticks; +} + +static void rdc321x_wdt_start(void) +{ + if (!rdc321x_wdt_device.queue) { + rdc321x_wdt_device.queue = 1; + + /* Clear the timer */ + outl(RDC_CLS_TMR, RDC3210_CFGREG_ADDR); + + /* Enable watchdog and set the timeout to 81.92 us */ + outl(RDC_WDT_EN|RDC_WDT_CNT, RDC3210_CFGREG_DATA); + + mod_timer(&rdc321x_wdt_device.timer, jiffies + RDC_WDT_INTERVAL); + } + + /* if process dies, counter is not decremented */ + rdc321x_wdt_device.running++; +} + +static int rdc321x_wdt_stop(void) +{ + if (rdc321x_wdt_device.running) + rdc321x_wdt_device.running = 0; + + ticks = rdc321x_wdt_device.default_ticks; + + return -EIO; +} + +/* filesystem operations */ + +static int rdc321x_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &rdc321x_wdt_device.inuse)) + return -EBUSY; + + return nonseekable_open(inode, file); +} + +static int rdc321x_wdt_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &rdc321x_wdt_device.inuse); + return 0; +} + +static int rdc321x_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + unsigned int value; + static struct watchdog_info ident = + { + .options = WDIOF_CARDRESET, + .identity = "RDC321x WDT", + }; + + switch(cmd) { + case WDIOC_KEEPALIVE: + rdc321x_wdt_reset(); + break; + case WDIOC_GETSTATUS: + /* Read the value from the DATA register */ + value = inl(RDC3210_CFGREG_DATA); + if ( copy_to_user(argp, &value, sizeof(int)) ) + return -EFAULT; + break; + case WDIOC_GETSUPPORT: + if ( copy_to_user(argp, &ident, sizeof(ident)) ) + return -EFAULT; + break; + case WDIOC_SETOPTIONS: + if ( copy_from_user(&value, argp, sizeof(int)) ) + return -EFAULT; + switch(value) { + case WDIOS_ENABLECARD: + rdc321x_wdt_start(); + break; + case WDIOS_DISABLECARD: + return rdc321x_wdt_stop(); + default: + return -EINVAL; + } + break; + default: + return -ENOTTY; + } + return 0; +} + +static ssize_t rdc321x_wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + if ( !count ) + return -EIO; + + rdc321x_wdt_reset(); + + return count; +} + +static const struct file_operations rdc321x_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .ioctl = rdc321x_wdt_ioctl, + .open = rdc321x_wdt_open, + .write = rdc321x_wdt_write, + .release = rdc321x_wdt_release, +}; + +static struct miscdevice rdc321x_wdt_misc = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &rdc321x_wdt_fops, +}; + +static int __devinit rdc321x_wdt_probe(struct platform_device *pdev) +{ + int err; + + if ( (err = misc_register(&rdc321x_wdt_misc)) < 0 ) { + printk(KERN_ERR PFX "misc_register failed\n"); + return err; + } + + /* Reset the watchdog */ + outl(RDC_WDT_RST, RDC3210_CFGREG_DATA); + + init_completion(&rdc321x_wdt_device.stop); + rdc321x_wdt_device.queue = 0; + + clear_bit(0, &rdc321x_wdt_device.inuse); + + setup_timer(&rdc321x_wdt_device.timer, rdc321x_wdt_trigger, 0); + + rdc321x_wdt_device.default_ticks = ticks; + + printk(KERN_INFO PFX "init success\n"); + + return 0; +} + +static int rdc321x_wdt_remove(struct platform_device *pdev) +{ + if (rdc321x_wdt_device.queue) { + rdc321x_wdt_device.queue = 0; + wait_for_completion(&rdc321x_wdt_device.stop); + } + + misc_deregister(&rdc321x_wdt_misc); + + return 0; +} + +static struct platform_driver rdc321x_wdt_driver = { + .probe = rdc321x_wdt_probe, + .remove = rdc321x_wdt_remove, + .driver = { + .owner = THIS_MODULE, + .name = "rdc321x-wdt", + }, +}; + +static int __init rdc321x_wdt_init(void) +{ + return platform_driver_register(&rdc321x_wdt_driver); +} + +static void __exit rdc321x_wdt_exit(void) +{ + platform_driver_unregister(&rdc321x_wdt_driver); +} + +module_init(rdc321x_wdt_init); +module_exit(rdc321x_wdt_exit); + +MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); +MODULE_DESCRIPTION("RDC321x watchdog driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |