diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-27 08:49:07 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-27 08:49:07 -0700 |
commit | b98adfccdf5f8dd34ae56a2d5adbe2c030bd4674 (patch) | |
tree | 1807a029520f550dd4f90c95ad0063bceb00d645 /drivers | |
parent | ba21fe71725f94792330ebc3034ef2b35a36276f (diff) | |
parent | 33573c0e3243aaa38b6ad96942de85a1b713c2ff (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6: (108 commits)
sh: Fix occasional flush_cache_4096() stack corruption.
sh: Calculate shm alignment at runtime.
sh: dma-mapping compile fixes.
sh: Initial vsyscall page support.
sh: Clean up PAGE_SIZE definition for assembly use.
sh: Selective flush_cache_mm() flushing.
sh: More intelligent entry_mask/way_size calculation.
sh: Support for L2 cache on newer SH-4A CPUs.
sh: Update kexec support for API changes.
sh: Optimized readsl()/writesl() support.
sh: Report movli.l/movco.l capabilities.
sh: CPU flags in AT_HWCAP in ELF auxvt.
sh: Add support for 4K stacks.
sh: Enable /proc/kcore support.
sh: stack debugging support.
sh: select CONFIG_EMBEDDED.
sh: machvec rework.
sh: Solution Engine SH7343 board support.
sh: SH7710VoIPGW board support.
sh: Enable verbose BUG() support.
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/Kconfig | 2 | ||||
-rw-r--r-- | drivers/char/watchdog/Kconfig | 8 | ||||
-rw-r--r-- | drivers/char/watchdog/shwdt.c | 110 | ||||
-rw-r--r-- | drivers/input/touchscreen/hp680_ts_input.c | 14 | ||||
-rw-r--r-- | drivers/net/stnic.c | 2 | ||||
-rw-r--r-- | drivers/rtc/Kconfig | 10 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-sh.c | 467 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 9 | ||||
-rw-r--r-- | drivers/serial/sh-sci.c | 1146 | ||||
-rw-r--r-- | drivers/serial/sh-sci.h | 90 | ||||
-rw-r--r-- | drivers/video/backlight/hp680_bl.c | 4 | ||||
-rw-r--r-- | drivers/video/console/Kconfig | 2 | ||||
-rw-r--r-- | drivers/video/hitfb.c | 229 | ||||
-rw-r--r-- | drivers/video/pvr2fb.c | 22 |
15 files changed, 1234 insertions, 882 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 6a3d3af45c5..1b21c3a911d 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -747,7 +747,7 @@ config NVRAM config RTC tristate "Enhanced Real Time Clock Support" - depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM + depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index fff89c2d88f..f114d7b5bb2 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -510,6 +510,14 @@ config SH_WDT To compile this driver as a module, choose M here: the module will be called shwdt. +config SH_WDT_MMAP + bool "Allow mmap of SH WDT" + default n + depends on SH_WDT + help + If you say Y here, user applications will be able to mmap the + WDT/CPG registers. +# # SPARC64 Architecture config WATCHDOG_CP1XXX diff --git a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c index 1355038f104..e5b8c64f1d6 100644 --- a/drivers/char/watchdog/shwdt.c +++ b/drivers/char/watchdog/shwdt.c @@ -27,7 +27,7 @@ #include <linux/notifier.h> #include <linux/ioport.h> #include <linux/fs.h> - +#include <linux/mm.h> #include <asm/io.h> #include <asm/uaccess.h> #include <asm/watchdog.h> @@ -125,7 +125,6 @@ static void sh_wdt_start(void) /** * sh_wdt_stop - Stop the Watchdog - * * Stops the watchdog. */ static void sh_wdt_stop(void) @@ -141,22 +140,20 @@ static void sh_wdt_stop(void) /** * sh_wdt_keepalive - Keep the Userspace Watchdog Alive - * * The Userspace watchdog got a KeepAlive: schedule the next heartbeat. */ -static void sh_wdt_keepalive(void) +static inline void sh_wdt_keepalive(void) { next_heartbeat = jiffies + (heartbeat * HZ); } /** * sh_wdt_set_heartbeat - Set the Userspace Watchdog heartbeat - * * Set the Userspace Watchdog heartbeat */ static int sh_wdt_set_heartbeat(int t) { - if ((t < 1) || (t > 3600)) /* arbitrary upper limit */ + if (unlikely((t < 1) || (t > 3600))) /* arbitrary upper limit */ return -EINVAL; heartbeat = t; @@ -165,7 +162,6 @@ static int sh_wdt_set_heartbeat(int t) /** * sh_wdt_ping - Ping the Watchdog - * * @data: Unused * * Clears overflow bit, resets timer counter. @@ -182,14 +178,13 @@ static void sh_wdt_ping(unsigned long data) sh_wdt_write_cnt(0); mod_timer(&timer, next_ping_period(clock_division_ratio)); - } else { - printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); - } + } else + printk(KERN_WARNING PFX "Heartbeat lost! Will not ping " + "the watchdog\n"); } /** * sh_wdt_open - Open the Device - * * @inode: inode of device * @file: file handle of device * @@ -209,7 +204,6 @@ static int sh_wdt_open(struct inode *inode, struct file *file) /** * sh_wdt_close - Close the Device - * * @inode: inode of device * @file: file handle of device * @@ -220,7 +214,8 @@ static int sh_wdt_close(struct inode *inode, struct file *file) if (shwdt_expect_close == 42) { sh_wdt_stop(); } else { - printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); + printk(KERN_CRIT PFX "Unexpected close, not " + "stopping watchdog!\n"); sh_wdt_keepalive(); } @@ -232,7 +227,6 @@ static int sh_wdt_close(struct inode *inode, struct file *file) /** * sh_wdt_write - Write to Device - * * @file: file handle of device * @buf: buffer to write * @count: length of buffer @@ -264,8 +258,56 @@ static ssize_t sh_wdt_write(struct file *file, const char *buf, } /** - * sh_wdt_ioctl - Query Device + * sh_wdt_mmap - map WDT/CPG registers into userspace + * @file: file structure for the device + * @vma: VMA to map the registers into + * + * A simple mmap() implementation for the corner cases where the counter + * needs to be mapped in userspace directly. Due to the relatively small + * size of the area, neighbouring registers not necessarily tied to the + * CPG will also be accessible through the register page, so this remains + * configurable for users that really know what they're doing. * + * Additionaly, the register page maps in the CPG register base relative + * to the nearest page-aligned boundary, which requires that userspace do + * the appropriate CPU subtype math for calculating the page offset for + * the counter value. + */ +static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma) +{ + int ret = -ENOSYS; + +#ifdef CONFIG_SH_WDT_MMAP + unsigned long addr; + + /* Only support the simple cases where we map in a register page. */ + if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff) + return -EINVAL; + + /* + * Pick WTCNT as the start, it's usually the first register after the + * FRQCR, and neither one are generally page-aligned out of the box. + */ + addr = WTCNT & ~(PAGE_SIZE - 1); + + vma->vm_flags |= VM_IO; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, + PAGE_SIZE, vma->vm_page_prot)) { + printk(KERN_ERR PFX "%s: io_remap_pfn_range failed\n", + __FUNCTION__); + return -EAGAIN; + } + + ret = 0; +#endif + + return ret; +} + +/** + * sh_wdt_ioctl - Query Device * @inode: inode of device * @file: file handle of device * @cmd: watchdog command @@ -326,7 +368,6 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file, /** * sh_wdt_notify_sys - Notifier Handler - * * @this: notifier block * @code: notifier event * @unused: unused @@ -337,9 +378,8 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file, static int sh_wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) { - if (code == SYS_DOWN || code == SYS_HALT) { + if (code == SYS_DOWN || code == SYS_HALT) sh_wdt_stop(); - } return NOTIFY_DONE; } @@ -351,10 +391,12 @@ static const struct file_operations sh_wdt_fops = { .ioctl = sh_wdt_ioctl, .open = sh_wdt_open, .release = sh_wdt_close, + .mmap = sh_wdt_mmap, }; static struct watchdog_info sh_wdt_info = { - .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | + WDIOF_MAGICCLOSE, .firmware_version = 1, .identity = "SH WDT", }; @@ -371,7 +413,6 @@ static struct miscdevice sh_wdt_miscdev = { /** * sh_wdt_init - Initialize module - * * Registers the device and notifier handler. Actual device * initialization is handled by sh_wdt_open(). */ @@ -381,15 +422,15 @@ static int __init sh_wdt_init(void) if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) { clock_division_ratio = WTCSR_CKS_4096; - printk(KERN_INFO PFX "clock_division_ratio value must be 0x5<=x<=0x7, using %d\n", - clock_division_ratio); + printk(KERN_INFO PFX "clock_division_ratio value must " + "be 0x5<=x<=0x7, using %d\n", clock_division_ratio); } - if (sh_wdt_set_heartbeat(heartbeat)) - { + rc = sh_wdt_set_heartbeat(heartbeat); + if (unlikely(rc)) { heartbeat = WATCHDOG_HEARTBEAT; - printk(KERN_INFO PFX "heartbeat value must be 1<=x<=3600, using %d\n", - heartbeat); + printk(KERN_INFO PFX "heartbeat value must " + "be 1<=x<=3600, using %d\n", heartbeat); } init_timer(&timer); @@ -397,15 +438,16 @@ static int __init sh_wdt_init(void) timer.data = 0; rc = register_reboot_notifier(&sh_wdt_notifier); - if (rc) { - printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", rc); + if (unlikely(rc)) { + printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", + rc); return rc; } rc = misc_register(&sh_wdt_miscdev); - if (rc) { - printk(KERN_ERR PFX "Can't register miscdev on minor=%d (err=%d)\n", - sh_wdt_miscdev.minor, rc); + if (unlikely(rc)) { + printk(KERN_ERR PFX "Can't register miscdev on " + "minor=%d (err=%d)\n", sh_wdt_miscdev.minor, rc); unregister_reboot_notifier(&sh_wdt_notifier); return rc; } @@ -418,7 +460,6 @@ static int __init sh_wdt_init(void) /** * sh_wdt_exit - Deinitialize module - * * Unregisters the device and notifier handler. Actual device * deinitialization is handled by sh_wdt_close(). */ @@ -434,14 +475,13 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); module_param(clock_division_ratio, int, 0); -MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7."); +MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). (default=" __MODULE_STRING(clock_division_ratio) ")"); module_param(heartbeat, int, 0); MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); module_init(sh_wdt_init); module_exit(sh_wdt_exit); - diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c index fa97e0f79e7..ee6c2f40cdf 100644 --- a/drivers/input/touchscreen/hp680_ts_input.c +++ b/drivers/input/touchscreen/hp680_ts_input.c @@ -15,7 +15,6 @@ #define HP680_TS_ABS_Y_MIN 80 #define HP680_TS_ABS_Y_MAX 910 -#define SCPCR 0xa4000116 #define PHDR 0xa400012e #define SCPDR 0xa4000136 @@ -77,19 +76,6 @@ static irqreturn_t hp680_ts_interrupt(int irq, void *dev, struct pt_regs *regs) static int __init hp680_ts_init(void) { - u8 scpdr; - u16 scpcr; - - scpdr = ctrl_inb(SCPDR); - scpdr |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y; - scpdr &= ~SCPDR_TS_SCAN_ENABLE; - ctrl_outb(scpdr, SCPDR); - - scpcr = ctrl_inw(SCPCR); - scpcr &= ~SCPCR_TS_MASK; - scpcr |= SCPCR_TS_ENABLE; - ctrl_outw(scpcr, SCPCR); - hp680_ts_dev = input_allocate_device(); if (!hp680_ts_dev) return -ENOMEM; diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c index 3fd7a4fee66..e6f90427160 100644 --- a/drivers/net/stnic.c +++ b/drivers/net/stnic.c @@ -19,7 +19,7 @@ #include <asm/system.h> #include <asm/io.h> -#include <asm/se/se.h> +#include <asm/se.h> #include <asm/machvec.h> #ifdef CONFIG_SH_STANDARD_BIOS #include <asm/sh_bios.h> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 7ff1d88094b..33a7b720539 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -238,6 +238,16 @@ config RTC_DRV_SA1100 To compile this driver as a module, choose M here: the module will be called rtc-sa1100. +config RTC_DRV_SH + tristate "SuperH On-Chip RTC" + depends on RTC_CLASS && SUPERH + help + Say Y here to enable support for the on-chip RTC found in + most SuperH processors. + + To compile this driver as a module, choose M here: the + module will be called rtc-sh. + config RTC_DRV_VR41XX tristate "NEC VR41XX" depends on RTC_CLASS && CPU_VR41XX diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index bbcfb09d81d..e72d467ab21 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o obj-$(CONFIG_RTC_DRV_AT91) += rtc-at91.o +obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c new file mode 100644 index 00000000000..d2ce0c8bb8f --- /dev/null +++ b/drivers/rtc/rtc-sh.c @@ -0,0 +1,467 @@ +/* + * SuperH On-Chip RTC Support + * + * Copyright (C) 2006 Paul Mundt + * + * Based on the old arch/sh/kernel/cpu/rtc.c by: + * + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/bcd.h> +#include <linux/rtc.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/seq_file.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <asm/io.h> + +#ifdef CONFIG_CPU_SH3 +#define rtc_reg_size sizeof(u16) +#define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */ +#elif defined(CONFIG_CPU_SH4) +#define rtc_reg_size sizeof(u32) +#define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */ +#endif + +#define RTC_REG(r) ((r) * rtc_reg_size) + +#define R64CNT RTC_REG(0) +#define RSECCNT RTC_REG(1) +#define RMINCNT RTC_REG(2) +#define RHRCNT RTC_REG(3) +#define RWKCNT RTC_REG(4) +#define RDAYCNT RTC_REG(5) +#define RMONCNT RTC_REG(6) +#define RYRCNT RTC_REG(7) +#define RSECAR RTC_REG(8) +#define RMINAR RTC_REG(9) +#define RHRAR RTC_REG(10) +#define RWKAR RTC_REG(11) +#define RDAYAR RTC_REG(12) +#define RMONAR RTC_REG(13) +#define RCR1 RTC_REG(14) +#define RCR2 RTC_REG(15) + +/* RCR1 Bits */ +#define RCR1_CF 0x80 /* Carry Flag */ +#define RCR1_CIE 0x10 /* Carry Interrupt Enable */ +#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */ +#define RCR1_AF 0x01 /* Alarm Flag */ + +/* RCR2 Bits */ +#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */ +#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */ +#define RCR2_RTCEN 0x08 /* ENable RTC */ +#define RCR2_ADJ 0x04 /* ADJustment (30-second) */ +#define RCR2_RESET 0x02 /* Reset bit */ +#define RCR2_START 0x01 /* Start bit */ + +struct sh_rtc { + void __iomem *regbase; + unsigned long regsize; + struct resource *res; + unsigned int alarm_irq, periodic_irq, carry_irq; + struct rtc_device *rtc_dev; + spinlock_t lock; +}; + +static irqreturn_t sh_rtc_interrupt(int irq, void *id, struct pt_regs *regs) +{ + struct platform_device *pdev = id; + struct sh_rtc *rtc = platform_get_drvdata(pdev); + unsigned int tmp, events = 0; + + spin_lock(&rtc->lock); + + tmp = readb(rtc->regbase + RCR1); + + if (tmp & RCR1_AF) + events |= RTC_AF | RTC_IRQF; + + tmp &= ~(RCR1_CF | RCR1_AF); + + writeb(tmp, rtc->regbase + RCR1); + + rtc_update_irq(&rtc->rtc_dev->class_dev, 1, events); + + spin_unlock(&rtc->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t sh_rtc_periodic(int irq, void *id, struct pt_regs *regs) +{ + struct sh_rtc *rtc = dev_get_drvdata(id); + + spin_lock(&rtc->lock); + + rtc_update_irq(&rtc->rtc_dev->class_dev, 1, RTC_PF | RTC_IRQF); + + spin_unlock(&rtc->lock); + + return IRQ_HANDLED; +} + +static inline void sh_rtc_setpie(struct device *dev, unsigned int enable) +{ + struct sh_rtc *rtc = dev_get_drvdata(dev); + unsigned int tmp; + + spin_lock_irq(&rtc->lock); + + tmp = readb(rtc->regbase + RCR2); + + if (enable) { + tmp &= ~RCR2_PESMASK; + tmp |= RCR2_PEF | (2 << 4); + } else + tmp &= ~(RCR2_PESMASK | RCR2_PEF); + + writeb(tmp, rtc->regbase + RCR2); + + spin_unlock_irq(&rtc->lock); +} + +static inline void sh_rtc_setaie(struct device *dev, unsigned int enable) +{ + struct sh_rtc *rtc = dev_get_drvdata(dev); + unsigned int tmp; + + spin_lock_irq(&rtc->lock); + + tmp = readb(rtc->regbase + RCR1); + + if (enable) + tmp |= RCR1_AIE; + else + tmp &= ~RCR1_AIE; + + writeb(tmp, rtc->regbase + RCR1); + + spin_unlock_irq(&rtc->lock); +} + +static int sh_rtc_open(struct device *dev) +{ + struct sh_rtc *rtc = dev_get_drvdata(dev); + unsigned int tmp; + int ret; + + tmp = readb(rtc->regbase + RCR1); + tmp &= ~RCR1_CF; + tmp |= RCR1_CIE; + writeb(tmp, rtc->regbase + RCR1); + + ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, SA_INTERRUPT, + "sh-rtc period", dev); + if (unlikely(ret)) { + dev_err(dev, "request period IRQ failed with %d, IRQ %d\n", + ret, rtc->periodic_irq); + return ret; + } + + ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, SA_INTERRUPT, + "sh-rtc carry", dev); + if (unlikely(ret)) { + dev_err(dev, "request carry IRQ failed with %d, IRQ %d\n", + ret, rtc->carry_irq); + free_irq(rtc->periodic_irq, dev); + goto err_bad_carry; + } + + ret = request_irq(rtc->alarm_irq, sh_rtc_interrupt, SA_INTERRUPT, + "sh-rtc alarm", dev); + if (unlikely(ret)) { + dev_err(dev, "request alarm IRQ failed with %d, IRQ %d\n", + ret, rtc->alarm_irq); + goto err_bad_alarm; + } + + return 0; + +err_bad_alarm: + free_irq(rtc->carry_irq, dev); +err_bad_carry: + free_irq(rtc->periodic_irq, dev); + + return ret; +} + +static void sh_rtc_release(struct device *dev) +{ + struct sh_rtc *rtc = dev_get_drvdata(dev); + + sh_rtc_setpie(dev, 0); + + free_irq(rtc->periodic_irq, dev); + free_irq(rtc->carry_irq, dev); + free_irq(rtc->alarm_irq, dev); +} + +static int sh_rtc_proc(struct device *dev, struct seq_file *seq) +{ + struct sh_rtc *rtc = dev_get_drvdata(dev); + unsigned int tmp; + + tmp = readb(rtc->regbase + RCR1); + seq_printf(seq, "alarm_IRQ\t: %s\n", + (tmp & RCR1_AIE) ? "yes" : "no"); + seq_printf(seq, "carry_IRQ\t: %s\n", + (tmp & RCR1_CIE) ? "yes" : "no"); + + tmp = readb(rtc->regbase + RCR2); + seq_printf(seq, "periodic_IRQ\t: %s\n", + (tmp & RCR2_PEF) ? "yes" : "no"); + + return 0; +} + +static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + unsigned int ret = -ENOIOCTLCMD; + + switch (cmd) { + case RTC_PIE_OFF: + case RTC_PIE_ON: + sh_rtc_setpie(dev, cmd == RTC_PIE_ON); + ret = 0; + break; + case RTC_AIE_OFF: + case RTC_AIE_ON: + sh_rtc_setaie(dev, cmd == RTC_AIE_ON); + ret = 0; + break; + } + + return ret; +} + +static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sh_rtc *rtc = platform_get_drvdata(pdev); + unsigned int sec128, sec2, yr, yr100, cf_bit; + + do { + unsigned int tmp; + + spin_lock_irq(&rtc->lock); + + tmp = readb(rtc->regbase + RCR1); + tmp &= ~RCR1_CF; /* Clear CF-bit */ + tmp |= RCR1_CIE; + writeb(tmp, rtc->regbase + RCR1); + + sec128 = readb(rtc->regbase + R64CNT); + + tm->tm_sec = BCD2BIN(readb(rtc->regbase + RSECCNT)); + tm->tm_min = BCD2BIN(readb(rtc->regbase + RMINCNT)); + tm->tm_hour = BCD2BIN(readb(rtc->regbase + RHRCNT)); + tm->tm_wday = BCD2BIN(readb(rtc->regbase + RWKCNT)); + tm->tm_mday = BCD2BIN(readb(rtc->regbase + RDAYCNT)); + tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT)); + +#if defined(CONFIG_CPU_SH4) + yr = readw(rtc->regbase + RYRCNT); + yr100 = BCD2BIN(yr >> 8); + yr &= 0xff; +#else + yr = readb(rtc->regbase + RYRCNT); + yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20); +#endif + + tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900; + + sec2 = readb(rtc->regbase + R64CNT); + cf_bit = readb(rtc->regbase + RCR1) & RCR1_CF; + + spin_unlock_irq(&rtc->lock); + } while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0); + +#if RTC_BIT_INVERTED != 0 + if ((sec128 & RTC_BIT_INVERTED)) + tm->tm_sec--; +#endif + + dev_dbg(&dev, "%s: tm is secs=%d, mins=%d, hours=%d, " + "mday=%d, mon=%d, year=%d, wday=%d\n", + __FUNCTION__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + + if (rtc_valid_tm(tm) < 0) + dev_err(dev, "invalid date\n"); + + return 0; +} + +static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sh_rtc *rtc = platform_get_drvdata(pdev); + unsigned int tmp; + int year; + + spin_lock_irq(&rtc->lock); + + /* Reset pre-scaler & stop RTC */ + tmp = readb(rtc->regbase + RCR2); + tmp |= RCR2_RESET; + writeb(tmp, rtc->regbase + RCR2); + + writeb(BIN2BCD(tm->tm_sec), rtc->regbase + RSECCNT); + writeb(BIN2BCD(tm->tm_min), rtc->regbase + RMINCNT); + writeb(BIN2BCD(tm->tm_hour), rtc->regbase + RHRCNT); + writeb(BIN2BCD(tm->tm_wday), rtc->regbase + RWKCNT); + writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT); + writeb(BIN2BCD(tm->tm_mon), rtc->regbase + RMONCNT); + +#ifdef CONFIG_CPU_SH3 + year = tm->tm_year % 100; + writeb(BIN2BCD(year), rtc->regbase + RYRCNT); +#else + year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) | + BIN2BCD(tm->tm_year % 100); + writew(year, rtc->regbase + RYRCNT); +#endif + + /* Start RTC */ + tmp = readb(rtc->regbase + RCR2); + tmp &= ~RCR2_RESET; + tmp |= RCR2_RTCEN | RCR2_START; + writeb(tmp, rtc->regbase + RCR2); + + spin_unlock_irq(&rtc->lock); + + return 0; +} + +static struct rtc_class_ops sh_rtc_ops = { + .open = sh_rtc_open, + .release = sh_rtc_release, + .ioctl = sh_rtc_ioctl, + .read_time = sh_rtc_read_time, + .set_time = sh_rtc_set_time, + .proc = sh_rtc_proc, +}; + +static int __devinit sh_rtc_probe(struct platform_device *pdev) +{ + struct sh_rtc *rtc; + struct resource *res; + int ret = -ENOENT; + + rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL); + if (unlikely(!rtc)) + return -ENOMEM; + + spin_lock_init(&rtc->lock); + + rtc->periodic_irq = platform_get_irq(pdev, 0); + if (unlikely(rtc->periodic_irq < 0)) { + dev_err(&pdev->dev, "No IRQ for period\n"); + goto err_badres; + } + + rtc->carry_irq = platform_get_irq(pdev, 1); + if (unlikely(rtc->carry_irq < 0)) { + dev_err(&pdev->dev, "No IRQ for carry\n"); + goto err_badres; + } + + rtc->alarm_irq = platform_get_irq(pdev, 2); + if (unlikely(rtc->alarm_irq < 0)) { + dev_err(&pdev->dev, "No IRQ for alarm\n"); + goto err_badres; + } + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (unlikely(res == NULL)) { + dev_err(&pdev->dev, "No IO resource\n"); + goto err_badres; + } + + rtc->regsize = res->end - res->start + 1; + + rtc->res = request_mem_region(res->start, rtc->regsize, pdev->name); + if (unlikely(!rtc->res)) { + ret = -EBUSY; + goto err_badres; + } + + rtc->regbase = (void __iomem *)rtc->res->start; + if (unlikely(!rtc->regbase)) { + ret = -EINVAL; + goto err_badmap; + } + + rtc->rtc_dev = rtc_device_register("sh", &pdev->dev, + &sh_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc->rtc_dev); + goto err_badmap; + } + + platform_set_drvdata(pdev, rtc); + + return 0; + +err_badmap: + release_resource(rtc->res); +err_badres: + kfree(rtc); + + return ret; +} + +static int __devexit sh_rtc_remove(struct platform_device *pdev) +{ + struct sh_rtc *rtc = platform_get_drvdata(pdev); + + if (likely(rtc->rtc_dev)) + rtc_device_unregister(rtc->rtc_dev); + + sh_rtc_setpie(&pdev->dev, 0); + sh_rtc_setaie(&pdev->dev, 0); + + release_resource(rtc->res); + + platform_set_drvdata(pdev, NULL); + + kfree(rtc); + + return 0; +} +static struct platform_driver sh_rtc_platform_driver = { + .driver = { + .name = "sh-rtc", + .owner = THIS_MODULE, + }, + .probe = sh_rtc_probe, + .remove = __devexit_p(sh_rtc_remove), +}; + +static int __init sh_rtc_init(void) +{ + return platform_driver_register(&sh_rtc_platform_driver); +} + +static void __exit sh_rtc_exit(void) +{ + platform_driver_unregister(&sh_rtc_platform_driver); +} + +module_init(sh_rtc_init); +module_exit(sh_rtc_exit); + +MODULE_DESCRIPTION("SuperH on-chip RTC driver"); +MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 5b48ac22c9c..261eaa44295 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -642,12 +642,17 @@ config V850E_UART_CONSOLE select SERIAL_CORE_CONSOLE config SERIAL_SH_SCI - tristate "SH SCI(F) serial port support" + tristate "SuperH SCI(F) serial port support" depends on SUPERH || H8300 select SERIAL_CORE +config SERIAL_SH_SCI_NR_UARTS + int "Maximum number of SCI(F) serial ports" + depends on SERIAL_SH_SCI + default "2" + config SERIAL_SH_SCI_CONSOLE - bool "Support for console on SH SCI(F)" + bool "Support for console on SuperH SCI(F)" depends on SERIAL_SH_SCI=y select SERIAL_CORE_CONSOLE diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index cbede06cac2..f336ba6778d 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -3,7 +3,7 @@ * * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) * - * Copyright (C) 2002, 2003, 2004 Paul Mundt + * Copyright (C) 2002 - 2006 Paul Mundt * * based off of the old drivers/char/sh-sci.c by: * @@ -20,10 +20,9 @@ #undef DEBUG +#include <linux/config.h> #include <linux/module.h> #include <linux/errno.h> -#include <linux/signal.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/tty.h> @@ -32,71 +31,77 @@ #include <linux/major.h> #include <linux/string.h> #include <linux/sysrq.h> -#include <linux/fcntl.h> -#include <linux/ptrace.h> #include <linux/ioport.h> #include <linux/mm.h> -#include <linux/slab.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/console.h> -#include <linux/bitops.h> -#include <linux/generic_serial.h> +#include <linux/platform_device.h> #ifdef CONFIG_CPU_FREQ #include <linux/notifier.h> #include <linux/cpufreq.h> #endif -#include <asm/system.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/uaccess.h> - #if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) #include <asm/clock.h> -#endif - -#ifdef CONFIG_SH_STANDARD_BIOS #include <asm/sh_bios.h> +#include <asm/kgdb.h> #endif +#include <asm/sci.h> + #if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif #include "sh-sci.h" -#ifdef CONFIG_SH_KGDB -#include <asm/kgdb.h> +struct sci_port { + struct uart_port port; + + /* Port type */ + unsigned int type; + + /* Port IRQs: ERI, RXI, TXI, BRI (optional) */ + unsigned int irqs[SCIx_NR_IRQS]; + + /* Port pin configuration */ + void (*init_pins)(struct uart_port *port, + unsigned int cflag); -static int kgdb_get_char(struct sci_port *port); -static void kgdb_put_char(struct sci_port *port, char c); -static void kgdb_handle_error(struct sci_port *port); + /* Port enable callback */ + void (*enable)(struct uart_port *port); + + /* Port disable callback */ + void (*disable)(struct uart_port *port); + + /* Break timer */ + struct timer_list break_timer; + int break_flag; +}; + +#ifdef CONFIG_SH_KGDB static struct sci_port *kgdb_sci_port; -#endif /* CONFIG_SH_KGDB */ +#endif #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE -static struct sci_port *serial_console_port = 0; -#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ +static struct sci_port *serial_console_port; +#endif /* Function prototypes */ static void sci_stop_tx(struct uart_port *port); -static void sci_start_tx(struct uart_port *port); -static void sci_start_rx(struct uart_port *port, unsigned int tty_start); -static void sci_stop_rx(struct uart_port *port); -static int sci_request_irq(struct sci_port *port); -static void sci_free_irq(struct sci_port *port); - -static struct sci_port sci_ports[]; -static struct uart_driver sci_uart_driver; -#define SCI_NPORTS sci_uart_driver.nr +#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS -#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) +static struct sci_port sci_ports[SCI_NPORTS]; +static struct uart_driver sci_uart_driver; -static void handle_error(struct uart_port *port) -{ /* Clear error flags */ +#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && \ + defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB) +static inline void handle_error(struct uart_port *port) +{ + /* Clear error flags */ sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); } @@ -106,8 +111,8 @@ static int get_char(struct uart_port *port) unsigned short status; int c; - local_irq_save(flags); - do { + spin_lock_irqsave(&port->lock, flags); + do { status = sci_in(port, SCxSR); if (status & SCxSR_ERRORS(port)) { handle_error(port); @@ -117,38 +122,19 @@ static int get_char(struct uart_port *port) c = sci_in(port, SCxRDR); sci_in(port, SCxSR); /* Dummy read */ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); - local_irq_restore(flags); + spin_unlock_irqrestore(&port->lock, flags); return c; } - -/* Taken from sh-stub.c of GDB 4.18 */ -static const char hexchars[] = "0123456789abcdef"; - -static __inline__ char highhex(int x) -{ - return hexchars[(x >> 4) & 0xf]; -} - -static __inline__ char lowhex(int x) -{ - return hexchars[x & 0xf]; -} - #endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */ -/* - * Send the packet in buffer. The host gets one chance to read it. - * This routine does not wait for a positive acknowledge. - */ - -#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE +#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || defined(CONFIG_SH_KGDB) static void put_char(struct uart_port *port, char c) { unsigned long flags; unsigned short status; - local_irq_save(flags); + spin_lock_irqsave(&port->lock, flags); do { status = sci_in(port, SCxSR); @@ -158,9 +144,11 @@ static void put_char(struct uart_port *port, char c) sci_in(port, SCxSR); /* Dummy read */ sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); - local_irq_restore(flags); + spin_unlock_irqrestore(&port->lock, flags); } +#endif +#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE static void put_string(struct sci_port *sci_port, const char *buffer, int count) { struct uart_port *port = &sci_port->port; @@ -213,96 +201,28 @@ static void put_string(struct sci_port *sci_port, const char *buffer, int count) } #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ - #ifdef CONFIG_SH_KGDB - -/* Is the SCI ready, ie is there a char waiting? */ -static int kgdb_is_char_ready(struct sci_port *port) -{ - unsigned short status = sci_in(port, SCxSR); - - if (status & (SCxSR_ERRORS(port) | SCxSR_BRK(port))) - kgdb_handle_error(port); - - return (status & SCxSR_RDxF(port)); -} - -/* Write a char */ -static void kgdb_put_char(struct sci_port *port, char c) -{ - unsigned short status; - - do - status = sci_in(port, SCxSR); - while (!(status & SCxSR_TDxE(port))); - - sci_out(port, SCxTDR, c); - sci_in(port, SCxSR); /* Dummy read */ - sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); -} - -/* Get a char if there is one, else ret -1 */ -static int kgdb_get_char(struct sci_port *port) -{ - int c; - - if (kgdb_is_char_ready(port) == 0) - c = -1; - else { - c = sci_in(port, SCxRDR); - sci_in(port, SCxSR); /* Dummy read */ - sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); - } - - return c; -} - -/* Called from kgdbstub.c to get a character, i.e. is blocking */ static int kgdb_sci_getchar(void) { - volatile int c; + int c; /* Keep trying to read a character, this could be neater */ - while ((c = kgdb_get_char(kgdb_sci_port)) < 0); + while ((c = get_char(kgdb_sci_port)) < 0) + cpu_relax(); return c; } -/* Called from kgdbstub.c to put a character, just a wrapper */ -static void kgdb_sci_putchar(int c) -{ - - kgdb_put_char(kgdb_sci_port, c); -} - -/* Clear any errors on the SCI */ -static void kgdb_handle_error(struct sci_port *port) +static inline void kgdb_sci_putchar(int c) { - sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); /* Clear error flags */ + put_char(kgdb_sci_port, c); } - -/* Breakpoint if there's a break sent on the serial port */ -static void kgdb_break_interrupt(int irq, void *ptr, struct pt_regs *regs) -{ - struct sci_port *port = ptr; - unsigned short status = sci_in(port, SCxSR); - - if (status & SCxSR_BRK(port)) { - - /* Break into the debugger if a break is detected */ - BREAKPOINT(); - - /* Clear */ - sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); - } -} - #endif /* CONFIG_SH_KGDB */ #if defined(__H8300S__) enum { sci_disable, sci_enable }; -static void h8300_sci_enable(struct uart_port* port, unsigned int ctrl) +static void h8300_sci_config(struct uart_port* port, unsigned int ctrl) { volatile unsigned char *mstpcrl=(volatile unsigned char *)MSTPCRL; int ch = (port->mapbase - SMR0) >> 3; @@ -314,32 +234,66 @@ static void h8300_sci_enable(struct uart_port* port, unsigned int ctrl) *mstpcrl &= ~mask; } } + +static inline void h8300_sci_enable(struct uart_port *port) +{ + h8300_sci_config(port, sci_enable); +} + +static inline void h8300_sci_disable(struct uart_port *port) +{ + h8300_sci_config(port, sci_disable); +} #endif -#if defined(SCI_ONLY) || defined(SCI_AND_SCIF) -#if defined(__H8300H__) || defined(__H8300S__) +#if defined(SCI_ONLY) || defined(SCI_AND_SCIF) && \ + defined(__H8300H__) || defined(__H8300S__) static void sci_init_pins_sci(struct uart_port* port, unsigned int cflag) { int ch = (port->mapbase - SMR0) >> 3; /* set DDR regs */ - H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].rx,H8300_GPIO_INPUT); - H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].tx,H8300_GPIO_OUTPUT); + H8300_GPIO_DDR(h8300_sci_pins[ch].port, + h8300_sci_pins[ch].rx, + H8300_GPIO_INPUT); + H8300_GPIO_DDR(h8300_sci_pins[ch].port, + h8300_sci_pins[ch].tx, + H8300_GPIO_OUTPUT); + /* tx mark output*/ H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx; } +#else +#define sci_init_pins_sci NULL +#endif + +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) +static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag) +{ + unsigned int fcr_val = 0; + + if (cflag & CRTSCTS) + fcr_val |= SCFCR_MCE; + + sci_out(port, SCFCR, fcr_val); +} +#else +#define sci_init_pins_irda NULL #endif + +#ifdef SCI_ONLY +#define sci_init_pins_scif NULL #endif #if defined(SCIF_ONLY) || defined(SCI_AND_SCIF) -#if defined(CONFIG_CPU_SUBTYPE_SH7300) +#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7710) /* SH7300 doesn't use RTS/CTS */ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) { sci_out(port, SCFCR, 0); } #elif defined(CONFIG_CPU_SH3) -/* For SH7705, SH7707, SH7709, SH7709A, SH7729 */ +/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) { unsigned int fcr_val = 0; @@ -366,20 +320,7 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) sci_out(port, SCFCR, fcr_val); } - -#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) -static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag) -{ - unsigned int fcr_val = 0; - - if (cflag & CRTSCTS) - fcr_val |= SCFCR_MCE; - - sci_out(port, SCFCR, fcr_val); -} -#endif #else - /* For SH7750 */ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) { @@ -388,7 +329,9 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) if (cflag & CRTSCTS) { fcr_val |= SCFCR_MCE; } else { -#ifdef CONFIG_CPU_SUBTYPE_SH7780 +#ifdef CONFIG_CPU_SUBTYPE_SH7343 + /* Nothing */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7780) ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */ #else ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */ @@ -396,10 +339,41 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) } sci_out(port, SCFCR, fcr_val); } +#endif + +#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780) +static inline int scif_txroom(struct uart_port *port) +{ + return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f); +} + +static inline int scif_rxroom(struct uart_port *port) +{ + return sci_in(port, SCRFDR) & 0x7f; +} +#else +static inline int scif_txroom(struct uart_port *port) +{ + return SCIF_TXROOM_MAX - (sci_in(port, SCFDR) >> 8); +} +static inline int scif_rxroom(struct uart_port *port) +{ + return sci_in(port, SCFDR) & SCIF_RFDC_MASK; +} #endif #endif /* SCIF_ONLY || SCI_AND_SCIF */ +static inline int sci_txroom(struct uart_port *port) +{ + return ((sci_in(port, SCxSR) & SCI_TDRE) != 0); +} + +static inline int sci_rxroom(struct uart_port *port) +{ + return ((sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0); +} + /* ********************************************************************** * * the interrupt related routines * * ********************************************************************** */ @@ -408,14 +382,12 @@ static void sci_transmit_chars(struct uart_port *port) { struct circ_buf *xmit = &port->info->xmit; unsigned int stopped = uart_tx_stopped(port); - unsigned long flags; unsigned short status; unsigned short ctrl; - int count, txroom; + int count; status = sci_in(port, SCxSR); if (!(status & SCxSR_TDxE(port))) { - local_irq_save(flags); ctrl = sci_in(port, SCSCR); if (uart_circ_empty(xmit)) { ctrl &= ~SCI_CTRL_FLAGS_TIE; @@ -423,25 +395,15 @@ static void sci_transmit_chars(struct uart_port *port) ctrl |= SCI_CTRL_FLAGS_TIE; } sci_out(port, SCSCR, ctrl); - local_irq_restore(flags); return; } -#if !defined(SCI_ONLY) - if (port->type == PORT_SCIF) { -#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780) - txroom = SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f); -#else - txroom = SCIF_TXROOM_MAX - (sci_in(port, SCFDR)>>8); -#endif - } else { - txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0; - } -#else - txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0; +#ifndef SCI_ONLY + if (port->type == PORT_SCIF) + count = scif_txroom(port); + else #endif - - count = txroom; + count = sci_txroom(port); do { unsigned char c; @@ -468,7 +430,6 @@ static void sci_transmit_chars(struct uart_port *port) if (uart_circ_empty(xmit)) { sci_stop_tx(port); } else { - local_irq_save(flags); ctrl = sci_in(port, SCSCR); #if !defined(SCI_ONLY) @@ -480,7 +441,6 @@ static void sci_transmit_chars(struct uart_port *port) ctrl |= SCI_CTRL_FLAGS_TIE; sci_out(port, SCSCR, ctrl); - local_irq_restore(flags); } } @@ -490,6 +450,7 @@ static void sci_transmit_chars(struct uart_port *port) static inline void sci_receive_chars(struct uart_port *port, struct pt_regs *regs) { + struct sci_port *sci_port = (struct sci_port *)port; struct tty_struct *tty = port->info->tty; int i, count, copied = 0; unsigned short status; @@ -501,18 +462,11 @@ static inline void sci_receive_chars(struct uart_port *port, while (1) { #if !defined(SCI_ONLY) - if (port->type == PORT_SCIF) { -#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780) - count = sci_in(port, SCRFDR) & 0x7f; -#else - count = sci_in(port, SCFDR)&SCIF_RFDC_MASK ; -#endif - } else { - count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0; - } -#else - count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0; + if (port->type == PORT_SCIF) + count = scif_rxroom(port); + else #endif + count = sci_rxroom(port); /* Don't copy more bytes than there is room for in the buffer */ count = tty_buffer_request_room(tty, count); @@ -523,11 +477,10 @@ static inline void sci_receive_chars(struct uart_port *port, if (port->type == PORT_SCI) { char c = sci_in(port, SCxRDR); - if(((struct sci_port *)port)->break_flag - || uart_handle_sysrq_char(port, c, regs)) { + if (uart_handle_sysrq_char(port, c, regs) || sci_port->break_flag) count = 0; - } else { - tty_insert_flip_char(tty, c, TTY_NORMAL); + else { + tty_insert_flip_char(tty, c, TTY_NORMAL); } } else { for (i=0; i<count; i++) { @@ -535,15 +488,17 @@ static inline void sci_receive_chars(struct uart_port *port, status = sci_in(port, SCxSR); #if defined(CONFIG_CPU_SH3) /* Skip "chars" during break */ - if (((struct sci_port *)port)->break_flag) { + if (sci_port->break_flag) { if ((c == 0) && (status & SCxSR_FER(port))) { count--; i--; continue; } + /* Nonzero => end-of-break */ pr_debug("scif: debounce<%02x>\n", c); - ((struct sci_port *)port)->break_flag = 0; + sci_port->break_flag = 0; + if (STEPFN(c)) { count--; i--; continue; @@ -600,15 +555,17 @@ static void sci_schedule_break_timer(struct sci_port *port) /* Ensure that two consecutive samples find the break over. */ static void sci_break_timer(unsigned long data) { - struct sci_port * port = (struct sci_port *)data; - if(sci_rxd_in(&port->port) == 0) { + struct sci_port *port = (struct sci_port *)data; + + if (sci_rxd_in(&port->port) == 0) { port->break_flag = 1; - sci_schedule_break_timer(port); - } else if(port->break_flag == 1){ + sci_schedule_break_timer(port); + } else if (port->break_flag == 1) { /* break is over. */ port->break_flag = 2; - sci_schedule_break_timer(port); - } else port->break_flag = 0; + sci_schedule_break_timer(port); + } else + port->break_flag = 0; } static inline int sci_handle_errors(struct uart_port *port) @@ -617,40 +574,41 @@ static inline int sci_handle_errors(struct uart_port *port) unsigned short status = sci_in(port, SCxSR); struct tty_struct *tty = port->info->tty; - if (status&SCxSR_ORER(port)) { + if (status & SCxSR_ORER(port)) { /* overrun error */ - if(tty_insert_flip_char(tty, 0, TTY_OVERRUN)) + if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) copied++; pr_debug("sci: overrun error\n"); } - if (status&SCxSR_FER(port)) { + if (status & SCxSR_FER(port)) { if (sci_rxd_in(port) == 0) { /* Notify of BREAK */ - struct sci_port * sci_port = (struct sci_port *)port; - if(!sci_port->break_flag) { - sci_port->break_flag = 1; - sci_schedule_break_timer((struct sci_port *)port); + struct sci_port *sci_port = (struct sci_port *)port; + + if (!sci_port->break_flag) { + sci_port->break_flag = 1; + sci_schedule_break_timer(sci_port); + /* Do sysrq handling. */ - if(uart_handle_break(port)) + if (uart_handle_break(port)) return 0; pr_debug("sci: BREAK detected\n"); - if(tty_insert_flip_char(tty, 0, TTY_BREAK)) + if (tty_insert_flip_char(tty, 0, TTY_BREAK)) copied++; } - } - else { + } else { /* frame error */ - if(tty_insert_flip_char(tty, 0, TTY_FRAME)) + if (tty_insert_flip_char(tty, 0, TTY_FRAME)) copied++; pr_debug("sci: frame error\n"); } } - if (status&SCxSR_PER(port)) { - if(tty_insert_flip_char(tty, 0, TTY_PARITY)) - copied++; + if (status & SCxSR_PER(port)) { /* parity error */ + if (tty_insert_flip_char(tty, 0, TTY_PARITY)) + copied++; pr_debug("sci: parity error\n"); } @@ -673,7 +631,7 @@ static inline int sci_handle_breaks(struct uart_port *port) s->break_flag = 1; #endif /* Notify of BREAK */ - if(tty_insert_flip_char(tty, 0, TTY_BREAK)) + if (tty_insert_flip_char(tty, 0, TTY_BREAK)) copied++; pr_debug("sci: BREAK detected\n"); } @@ -682,7 +640,7 @@ static inline int sci_handle_breaks(struct uart_port *port) /* XXX: Handle SCIF overrun error */ if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) { sci_out(port, SCLSR, 0); - if(tty_insert_flip_char(tty, 0, TTY_OVERRUN)) { + if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) { copied++; pr_debug("sci: overrun error\n"); } @@ -691,13 +649,12 @@ static inline int sci_handle_breaks(struct uart_port *port) if (copied) tty_flip_buffer_push(tty); + return copied; } -static irqreturn_t sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs) +static irqreturn_t sci_rx_interrupt(int irq, void *port, struct pt_regs *regs) { - struct uart_port *port = ptr; - /* I think sci_receive_chars has to be called irrespective * of whether the I_IXOFF is set, otherwise, how is the interrupt * to be disabled? @@ -711,7 +668,9 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs) { struct uart_port *port = ptr; + spin_lock_irq(&port->lock); sci_transmit_chars(port); + spin_unlock_irq(&port->lock); return IRQ_HANDLED; } @@ -755,6 +714,12 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs) /* Handle BREAKs */ sci_handle_breaks(port); + +#ifdef CONFIG_SH_KGDB + /* Break into the debugger if a break is detected */ + BREAKPOINT(); +#endif + sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); return IRQ_HANDLED; @@ -769,16 +734,16 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr, struct pt_regs *regs) scr_status = sci_in(port,SCSCR); /* Tx Interrupt */ - if ((ssr_status&0x0020) && (scr_status&0x0080)) + if ((ssr_status & 0x0020) && (scr_status & 0x0080)) sci_tx_interrupt(irq, ptr, regs); /* Rx Interrupt */ - if ((ssr_status&0x0002) && (scr_status&0x0040)) + if ((ssr_status & 0x0002) && (scr_status & 0x0040)) sci_rx_interrupt(irq, ptr, regs); /* Error Interrupt */ - if ((ssr_status&0x0080) && (scr_status&0x0400)) + if ((ssr_status & 0x0080) && (scr_status & 0x0400)) sci_er_interrupt(irq, ptr, regs); /* Break Interrupt */ - if ((ssr_status&0x0010) && (scr_status&0x0200)) + if ((ssr_status & 0x0010) && (scr_status & 0x0200)) sci_br_interrupt(irq, ptr, regs); return IRQ_HANDLED; @@ -789,7 +754,8 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr, struct pt_regs *regs) * Here we define a transistion notifier so that we can update all of our * ports' baud rate when the peripheral clock changes. */ -static int sci_notifier(struct notifier_block *self, unsigned long phase, void *p) +static int sci_notifier(struct notifier_block *self, + unsigned long phase, void *p) { struct cpufreq_freqs *freqs = p; int i; @@ -816,8 +782,9 @@ static int sci_notifier(struct notifier_block *self, unsigned long phase, void * clk_put(clk); } - printk("%s: got a postchange notification for cpu %d (old %d, new %d)\n", - __FUNCTION__, freqs->cpu, freqs->old, freqs->new); + printk(KERN_INFO "%s: got a postchange notification " + "for cpu %d (old %d, new %d)\n", + __FUNCTION__, freqs->cpu, freqs->old, freqs->new); } return NOTIFY_OK; @@ -841,8 +808,9 @@ static int sci_request_irq(struct sci_port *port) printk(KERN_ERR "sci: Cannot allocate irq.(IRQ=0)\n"); return -ENODEV; } - if (request_irq(port->irqs[0], sci_mpxed_interrupt, IRQF_DISABLED, - "sci", port)) { + + if (request_irq(port->irqs[0], sci_mpxed_interrupt, + SA_INTERRUPT, "sci", port)) { printk(KERN_ERR "sci: Cannot allocate irq.\n"); return -ENODEV; } @@ -850,8 +818,8 @@ static int sci_request_irq(struct sci_port *port) for (i = 0; i < ARRAY_SIZE(handlers); i++) { if (!port->irqs[i]) continue; - if (request_irq(port->irqs[i], handlers[i], IRQF_DISABLED, - desc[i], port)) { + if (request_irq(port->irqs[i], handlers[i], + SA_INTERRUPT, desc[i], port)) { printk(KERN_ERR "sci: Cannot allocate irq.\n"); return -ENODEV; } @@ -903,50 +871,42 @@ static unsigned int sci_get_mctrl(struct uart_port *port) static void sci_start_tx(struct uart_port *port) { - struct sci_port *s = &sci_ports[port->line]; + unsigned short ctrl; - disable_irq(s->irqs[SCIx_TXI_IRQ]); - sci_transmit_chars(port); - enable_irq(s->irqs[SCIx_TXI_IRQ]); + /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ + ctrl = sci_in(port, SCSCR); + ctrl |= SCI_CTRL_FLAGS_TIE; + sci_out(port, SCSCR, ctrl); } static void sci_stop_tx(struct uart_port *port) { - unsigned long flags; unsigned short ctrl; /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ - local_irq_save(flags); ctrl = sci_in(port, SCSCR); ctrl &= ~SCI_CTRL_FLAGS_TIE; sci_out(port, SCSCR, ctrl); - local_irq_restore(flags); } static void sci_start_rx(struct uart_port *port, unsigned int tty_start) { - unsigned long flags; unsigned short ctrl; /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ - local_irq_save(flags); ctrl = sci_in(port, SCSCR); ctrl |= SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE; sci_out(port, SCSCR, ctrl); - local_irq_restore(flags); } static void sci_stop_rx(struct uart_port *port) { - unsigned long flags; unsigned short ctrl; /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ - local_irq_save(flags); ctrl = sci_in(port, SCSCR); ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE); sci_out(port, SCSCR, ctrl); - local_irq_restore(flags); } static void sci_enable_ms(struct uart_port *port) @@ -963,9 +923,8 @@ static int sci_startup(struct uart_port *port) { struct sci_port *s = &sci_ports[port->line]; -#if defined(__H8300S__) - h8300_sci_enable(port, sci_enable); -#endif + if (s->enable) + s->enable(port); sci_request_irq(s); sci_start_tx(port); @@ -982,9 +941,8 @@ static void sci_shutdown(struct uart_port *port) sci_stop_tx(port); sci_free_irq(s); -#if defined(__H8300S__) - h8300_sci_enable(port, sci_disable); -#endif + if (s->disable) + s->disable(port); } static void sci_set_termios(struct uart_port *port, struct termios *termios, @@ -997,6 +955,23 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios, baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + switch (baud) { + case 0: + t = -1; + break; + default: + { +#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) + struct clk *clk = clk_get("module_clk"); + t = SCBRR_VALUE(baud, clk_get_rate(clk)); + clk_put(clk); +#else + t = SCBRR_VALUE(baud); +#endif + } + break; + } + spin_lock_irqsave(&port->lock, flags); do { @@ -1006,9 +981,8 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios, sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */ #if !defined(SCI_ONLY) - if (port->type == PORT_SCIF) { + if (port->type == PORT_SCIF) sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); - } #endif smr_val = sci_in(port, SCSMR) & 3; @@ -1025,23 +999,6 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios, sci_out(port, SCSMR, smr_val); - switch (baud) { - case 0: - t = -1; - break; - default: - { -#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) - struct clk *clk = clk_get("module_clk"); - t = SCBRR_VALUE(baud, clk_get_rate(clk)); - clk_put(clk); -#else - t = SCBRR_VALUE(baud); -#endif - } - break; - } - if (t > 0) { if(t >= 256) { sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); @@ -1092,11 +1049,23 @@ static void sci_config_port(struct uart_port *port, int flags) port->type = s->type; + switch (port->type) { + case PORT_SCI: + s->init_pins = sci_init_pins_sci; + break; + case PORT_SCIF: + s->init_pins = sci_init_pins_scif; + break; + case PORT_IRDA: + s->init_pins = sci_init_pins_irda; + break; + } + #if defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) if (port->mapbase == 0) port->mapbase = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF"); - port->membase = (void *)port->mapbase; + port->membase = (void __iomem *)port->mapbase; #endif } @@ -1132,412 +1101,61 @@ static struct uart_ops sci_uart_ops = { .verify_port = sci_verify_port, }; -static struct sci_port sci_ports[] = { -#if defined(CONFIG_CPU_SUBTYPE_SH7708) - { - .port = { - .membase = (void *)0xfffffe80, - .mapbase = 0xfffffe80, - .iotype = UPIO_MEM, - .irq = 25, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCI, - .irqs = SCI_IRQS, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH7705) - { - .port = { - .membase = (void *)SCIF0, - .mapbase = SCIF0, - .iotype = UPIO_MEM, - .irq = 55, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH3_IRDA_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)SCIF2, - .mapbase = SCIF2, - .iotype = UPIO_MEM, - .irq = 59, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCIF, - .irqs = SH3_SCIF_IRQS, - .init_pins = sci_init_pins_scif, - } -#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) - { - .port = { - .membase = (void *)0xfffffe80, - .mapbase = 0xfffffe80, - .iotype = UPIO_MEM, - .irq = 25, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCI, - .irqs = SCI_IRQS, - }, - { - .port = { - .membase = (void *)0xa4000150, - .mapbase = 0xa4000150, - .iotype = UPIO_MEM, - .irq = 59, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCIF, - .irqs = SH3_SCIF_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)0xa4000140, - .mapbase = 0xa4000140, - .iotype = UPIO_MEM, - .irq = 55, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - .type = PORT_IRDA, - .irqs = SH3_IRDA_IRQS, - .init_pins = sci_init_pins_irda, - } -#elif defined(CONFIG_CPU_SUBTYPE_SH7300) - { - .port = { - .membase = (void *)0xA4430000, - .mapbase = 0xA4430000, - .iotype = UPIO_MEM, - .irq = 25, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH7300_SCIF0_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH73180) - { - .port = { - .membase = (void *)0xffe00000, - .mapbase = 0xffe00000, - .iotype = UPIO_MEM, - .irq = 25, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH73180_SCIF_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH4_202) - { - .port = { - .membase = (void *)0xffe80000, - .mapbase = 0xffe80000, - .iotype = UPIO_MEM, - .irq = 43, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH4_SCIF_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) - { - .port = { - .membase = (void *)0xffe00000, - .mapbase = 0xffe00000, - .iotype = UPIO_MEM, - .irq = 25, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCI, - .irqs = SCI_IRQS, - }, - { - .port = { - .membase = (void *)0xffe80000, - .mapbase = 0xffe80000, - .iotype = UPIO_MEM, - .irq = 43, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCIF, - .irqs = SH4_SCIF_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH7760) - { - .port = { - .membase = (void *)0xfe600000, - .mapbase = 0xfe600000, - .iotype = UPIO_MEM, - .irq = 55, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH7760_SCIF0_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)0xfe610000, - .mapbase = 0xfe610000, - .iotype = UPIO_MEM, - .irq = 75, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCIF, - .irqs = SH7760_SCIF1_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)0xfe620000, - .mapbase = 0xfe620000, - .iotype = UPIO_MEM, - .irq = 79, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - .type = PORT_SCIF, - .irqs = SH7760_SCIF2_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) - { - .port = { - .membase = (void *)0xffe00000, - .mapbase = 0xffe00000, - .iotype = UPIO_MEM, - .irq = 26, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = STB1_SCIF1_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)0xffe80000, - .mapbase = 0xffe80000, - .iotype = UPIO_MEM, - .irq = 43, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCIF, - .irqs = SH4_SCIF_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) - { - .port = { - .iotype = UPIO_MEM, - .irq = 42, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH5_SCIF_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_H83007) || defined(CONFIG_H83068) - { - .port = { - .membase = (void *)0x00ffffb0, - .mapbase = 0x00ffffb0, - .iotype = UPIO_MEM, - .irq = 54, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCI, - .irqs = H8300H_SCI_IRQS0, - .init_pins = sci_init_pins_sci, - }, - { - .port = { - .membase = (void *)0x00ffffb8, - .mapbase = 0x00ffffb8, - .iotype = UPIO_MEM, - .irq = 58, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCI, - .irqs = H8300H_SCI_IRQS1, - .init_pins = sci_init_pins_sci, - }, - { - .port = { - .membase = (void *)0x00ffffc0, - .mapbase = 0x00ffffc0, - .iotype = UPIO_MEM, - .irq = 62, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - .type = PORT_SCI, - .irqs = H8300H_SCI_IRQS2, - .init_pins = sci_init_pins_sci, - }, -#elif defined(CONFIG_H8S2678) - { - .port = { - .membase = (void *)0x00ffff78, - .mapbase = 0x00ffff78, - .iotype = UPIO_MEM, - .irq = 90, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCI, - .irqs = H8S_SCI_IRQS0, - .init_pins = sci_init_pins_sci, - }, - { - .port = { - .membase = (void *)0x00ffff80, - .mapbase = 0x00ffff80, - .iotype = UPIO_MEM, - .irq = 94, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCI, - .irqs = H8S_SCI_IRQS1, - .init_pins = sci_init_pins_sci, - }, - { - .port = { - .membase = (void *)0x00ffff88, - .mapbase = 0x00ffff88, - .iotype = UPIO_MEM, - .irq = 98, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - .type = PORT_SCI, - .irqs = H8S_SCI_IRQS2, - .init_pins = sci_init_pins_sci, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH7770) - { - .port = { - .membase = (void *)0xff923000, - .mapbase = 0xff923000, - .iotype = UPIO_MEM, - .irq = 61, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH7770_SCIF0_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)0xff924000, - .mapbase = 0xff924000, - .iotype = UPIO_MEM, - .irq = 62, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCIF, - .irqs = SH7770_SCIF1_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)0xff925000, - .mapbase = 0xff925000, - .iotype = UPIO_MEM, - .irq = 63, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - .type = PORT_SCIF, - .irqs = SH7770_SCIF2_IRQS, - .init_pins = sci_init_pins_scif, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH7780) - { - .port = { - .membase = (void *)0xffe00000, - .mapbase = 0xffe00000, - .iotype = UPIO_MEM, - .irq = 43, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - .type = PORT_SCIF, - .irqs = SH7780_SCIF0_IRQS, - .init_pins = sci_init_pins_scif, - }, - { - .port = { - .membase = (void *)0xffe10000, - .mapbase = 0xffe10000, - .iotype = UPIO_MEM, - .irq = 79, - .ops = &sci_uart_ops, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - .type = PORT_SCIF, - .irqs = SH7780_SCIF1_IRQS, - .init_pins = sci_init_pins_scif, - }, +static void __init sci_init_ports(void) +{ + static int first = 1; + int i; + + if (!first) + return; + + first = 0; + + for (i = 0; i < SCI_NPORTS; i++) { + sci_ports[i].port.ops = &sci_uart_ops; + sci_ports[i].port.iotype = UPIO_MEM; + sci_ports[i].port.line = i; + sci_ports[i].port.fifosize = 1; + +#if defined(__H8300H__) || defined(__H8300S__) +#ifdef __H8300S__ + sci_ports[i].enable = h8300_sci_enable; + sci_ports[i].disable = h8300_sci_disable; +#endif + sci_ports[i].port.uartclk = CONFIG_CPU_CLOCK; +#elif defined(CONFIG_SUPERH64) + sci_ports[i].port.uartclk = current_cpu_data.module_clock * 16; #else -#error "CPU subtype not defined" + /* + * XXX: We should use a proper SCI/SCIF clock + */ + { + struct clk *clk = clk_get("module_clk"); + sci_ports[i].port.uartclk = clk_get_rate(clk) * 16; + clk_put(clk); + } #endif -}; + + sci_ports[i].break_timer.data = (unsigned long)&sci_ports[i]; + sci_ports[i].break_timer.function = sci_break_timer; + + init_timer(&sci_ports[i].break_timer); + } +} + +int __init early_sci_setup(struct uart_port *port) +{ + if (unlikely(port->line > SCI_NPORTS)) + return -ENODEV; + + sci_init_ports(); + + sci_ports[port->line].port.membase = port->membase; + sci_ports[port->line].port.mapbase = port->mapbase; + sci_ports[port->line].port.type = port->type; + + return 0; +} #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE /* @@ -1559,34 +1177,38 @@ static int __init serial_console_setup(struct console *co, char *options) int flow = 'n'; int ret; + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index >= SCI_NPORTS) + co->index = 0; + serial_console_port = &sci_ports[co->index]; port = &serial_console_port->port; - port->type = serial_console_port->type; - -#ifdef CONFIG_SUPERH64 - /* This is especially needed on sh64 to remap the SCIF */ - sci_config_port(port, 0); -#endif /* - * We need to set the initial uartclk here, since otherwise it will - * only ever be setup at sci_init() time. + * Also need to check port->type, we don't actually have any + * UPIO_PORT ports, but uart_report_port() handily misreports + * it anyways if we don't have a port available by the time this is + * called. */ -#if defined(__H8300H__) || defined(__H8300S__) - port->uartclk = CONFIG_CPU_CLOCK; + if (!port->type) + return -ENODEV; + if (!port->membase || !port->mapbase) + return -ENODEV; + + spin_lock_init(&port->lock); + + port->type = serial_console_port->type; + + if (port->flags & UPF_IOREMAP) + sci_config_port(port, 0); + + if (serial_console_port->enable) + serial_console_port->enable(port); -#if defined(__H8300S__) - h8300_sci_enable(port, sci_enable); -#endif -#elif defined(CONFIG_SUPERH64) - port->uartclk = current_cpu_data.module_clock * 16; -#else - { - struct clk *clk = clk_get("module_clk"); - port->uartclk = clk_get_rate(clk) * 16; - clk_put(clk); - } -#endif if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -1604,17 +1226,17 @@ static struct console serial_console = { .device = uart_console_device, .write = serial_console_write, .setup = serial_console_setup, - .flags = CON_PRINTBUFFER, + .flags = CON_PRINTBUFFER, .index = -1, .data = &sci_uart_driver, }; static int __init sci_console_init(void) { + sci_init_ports(); register_console(&serial_console); return 0; } - console_initcall(sci_console_init); #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ @@ -1649,6 +1271,8 @@ int __init kgdb_console_setup(struct console *co, char *options) int parity = 'n'; int flow = 'n'; + spin_lock_init(&port->lock); + if (co->index != kgdb_portnum) co->index = kgdb_portnum; @@ -1677,10 +1301,10 @@ static struct console kgdb_console = { /* Register the KGDB console so we get messages (d'oh!) */ static int __init kgdb_console_init(void) { + sci_init_ports(); register_console(&kgdb_console); return 0; } - console_initcall(kgdb_console_init); #endif /* CONFIG_SH_KGDB_CONSOLE */ @@ -1701,60 +1325,132 @@ static struct uart_driver sci_uart_driver = { .dev_name = "ttySC", .major = SCI_MAJOR, .minor = SCI_MINOR_START, + .nr = SCI_NPORTS, .cons = SCI_CONSOLE, }; -static int __init sci_init(void) +/* + * Register a set of serial devices attached to a platform device. The + * list is terminated with a zero flags entry, which means we expect + * all entries to have at least UPF_BOOT_AUTOCONF set. Platforms that need + * remapping (such as sh64) should also set UPF_IOREMAP. + */ +static int __devinit sci_probe(struct platform_device *dev) { - int chan, ret; + struct plat_sci_port *p = dev->dev.platform_data; + int i; - printk("%s", banner); + for (i = 0; p && p->flags != 0 && i < SCI_NPORTS; p++, i++) { + struct sci_port *sciport = &sci_ports[i]; - sci_uart_driver.nr = ARRAY_SIZE(sci_ports); + sciport->port.mapbase = p->mapbase; - ret = uart_register_driver(&sci_uart_driver); - if (ret == 0) { - for (chan = 0; chan < SCI_NPORTS; chan++) { - struct sci_port *sciport = &sci_ports[chan]; + /* + * For the simple (and majority of) cases where we don't need + * to do any remapping, just cast the cookie directly. + */ + if (p->mapbase && !p->membase && !(p->flags & UPF_IOREMAP)) + p->membase = (void __iomem *)p->mapbase; -#if defined(__H8300H__) || defined(__H8300S__) - sciport->port.uartclk = CONFIG_CPU_CLOCK; -#elif defined(CONFIG_SUPERH64) - sciport->port.uartclk = current_cpu_data.module_clock * 16; -#else - struct clk *clk = clk_get("module_clk"); - sciport->port.uartclk = clk_get_rate(clk) * 16; - clk_put(clk); -#endif - uart_add_one_port(&sci_uart_driver, &sciport->port); - sciport->break_timer.data = (unsigned long)sciport; - sciport->break_timer.function = sci_break_timer; - init_timer(&sciport->break_timer); - } + sciport->port.membase = p->membase; + + sciport->port.irq = p->irqs[SCIx_TXI_IRQ]; + sciport->port.flags = p->flags; + sciport->port.dev = &dev->dev; + + sciport->type = sciport->port.type = p->type; + + memcpy(&sciport->irqs, &p->irqs, sizeof(p->irqs)); + + uart_add_one_port(&sci_uart_driver, &sciport->port); } #ifdef CONFIG_CPU_FREQ cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); - printk("sci: CPU frequency notifier registered\n"); + dev_info(&dev->dev, "sci: CPU frequency notifier registered\n"); #endif #ifdef CONFIG_SH_STANDARD_BIOS sh_bios_gdb_detach(); #endif - return ret; + return 0; } -static void __exit sci_exit(void) +static int __devexit sci_remove(struct platform_device *dev) +{ + int i; + + for (i = 0; i < SCI_NPORTS; i++) + uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port); + + return 0; +} + +static int sci_suspend(struct platform_device *dev, pm_message_t state) { - int chan; + int i; + + for (i = 0; i < SCI_NPORTS; i++) { + struct sci_port *p = &sci_ports[i]; + + if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev) + uart_suspend_port(&sci_uart_driver, &p->port); + } - for (chan = 0; chan < SCI_NPORTS; chan++) - uart_remove_one_port(&sci_uart_driver, &sci_ports[chan].port); + return 0; +} +static int sci_resume(struct platform_device *dev) +{ + int i; + + for (i = 0; i < SCI_NPORTS; i++) { + struct sci_port *p = &sci_ports[i]; + + if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev) + uart_resume_port(&sci_uart_driver, &p->port); + } + + return 0; +} + +static struct platform_driver sci_driver = { + .probe = sci_probe, + .remove = __devexit_p(sci_remove), + .suspend = sci_suspend, + .resume = sci_resume, + .driver = { + .name = "sh-sci", + .owner = THIS_MODULE, + }, +}; + +static int __init sci_init(void) +{ + int ret; + + printk(banner); + + sci_init_ports(); + + ret = uart_register_driver(&sci_uart_driver); + if (likely(ret == 0)) { + ret = platform_driver_register(&sci_driver); + if (unlikely(ret)) + uart_unregister_driver(&sci_uart_driver); + } + + return ret; +} + +static void __exit sci_exit(void) +{ + platform_driver_unregister(&sci_driver); uart_unregister_driver(&sci_uart_driver); } module_init(sci_init); module_exit(sci_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index ab320fa3237..28643c4dc85 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -10,7 +10,9 @@ * Modified to support SH7300(SH-Mobile) SCIF. Takashi Kusuda (Jun 2003). * Modified to support H8/300 Series Yoshinori Sato (Feb 2004). */ +#include <linux/config.h> #include <linux/serial_core.h> +#include <asm/io.h> #if defined(__H8300H__) || defined(__H8300S__) #include <asm/gpio.h> @@ -22,40 +24,13 @@ #endif #endif -/* Offsets into the sci_port->irqs array */ -#define SCIx_ERI_IRQ 0 -#define SCIx_RXI_IRQ 1 -#define SCIx_TXI_IRQ 2 - -/* ERI, RXI, TXI, BRI */ -#define SCI_IRQS { 23, 24, 25, 0 } -#define SH3_SCIF_IRQS { 56, 57, 59, 58 } -#define SH3_IRDA_IRQS { 52, 53, 55, 54 } -#define SH4_SCIF_IRQS { 40, 41, 43, 42 } -#define STB1_SCIF1_IRQS {23, 24, 26, 25 } -#define SH7760_SCIF0_IRQS { 52, 53, 55, 54 } -#define SH7760_SCIF1_IRQS { 72, 73, 75, 74 } -#define SH7760_SCIF2_IRQS { 76, 77, 79, 78 } -#define SH7300_SCIF0_IRQS {80, 80, 80, 80 } -#define SH73180_SCIF_IRQS {80, 81, 83, 82 } -#define H8300H_SCI_IRQS0 {52, 53, 54, 0 } -#define H8300H_SCI_IRQS1 {56, 57, 58, 0 } -#define H8300H_SCI_IRQS2 {60, 61, 62, 0 } -#define H8S_SCI_IRQS0 {88, 89, 90, 0 } -#define H8S_SCI_IRQS1 {92, 93, 94, 0 } -#define H8S_SCI_IRQS2 {96, 97, 98, 0 } -#define SH5_SCIF_IRQS {39, 40, 42, 0 } -#define SH7770_SCIF0_IRQS {61, 61, 61, 61 } -#define SH7770_SCIF1_IRQS {62, 62, 62, 62 } -#define SH7770_SCIF2_IRQS {63, 63, 63, 63 } -#define SH7780_SCIF0_IRQS {40, 41, 43, 42 } -#define SH7780_SCIF1_IRQS {76, 77, 79, 78 } - #if defined(CONFIG_CPU_SUBTYPE_SH7708) # define SCSPTR 0xffffff7c /* 8 bit */ # define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ # define SCI_ONLY -#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) +#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) || \ + defined(CONFIG_CPU_SUBTYPE_SH7706) # define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */ # define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */ # define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ @@ -99,12 +74,23 @@ # define SCPDR 0xA4050136 /* 16 bit SCIF */ # define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */ # define SCIF_ONLY +#elif defined(CONFIG_CPU_SUBTYPE_SH7710) +# define SCSPTR0 0xA4400000 /* 16 bit SCIF */ +# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */ +# define SCIF_ONLY #elif defined(CONFIG_CPU_SUBTYPE_SH73180) # define SCPDR 0xA4050138 /* 16 bit SCIF */ # define SCSPTR2 SCPDR # define SCIF_ORER 0x0001 /* overrun error bit */ # define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1 */ # define SCIF_ONLY +#elif defined(CONFIG_CPU_SUBTYPE_SH7343) +# define SCSPTR0 0xffe00010 /* 16 bit SCIF */ +# define SCSPTR1 0xffe10010 /* 16 bit SCIF */ +# define SCSPTR2 0xffe20010 /* 16 bit SCIF */ +# define SCSPTR3 0xffe30010 /* 16 bit SCIF */ +# define SCSCR_INIT(port) 0x32 /* TIE=0,RIE=0,TE=1,RE=1,REIE=0,CKE=1 */ +# define SCIF_ONLY #elif defined(CONFIG_CPU_SUBTYPE_SH4_202) # define SCSPTR2 0xffe80020 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ @@ -145,7 +131,7 @@ #elif defined(CONFIG_CPU_SUBTYPE_SH7780) # define SCSPTR0 0xffe00024 /* 16 bit SCIF */ # define SCSPTR1 0xffe10024 /* 16 bit SCIF */ -# define SCIF_OPER 0x0001 /* Overrun error bit */ +# define SCIF_ORER 0x0001 /* Overrun error bit */ # define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ # define SCIF_ONLY #else @@ -273,15 +259,6 @@ */ #define SCI_EVENT_WRITE_WAKEUP 0 -struct sci_port { - struct uart_port port; - int type; - unsigned char irqs[4]; /* ERI, RXI, TXI, BRI */ - void (*init_pins)(struct uart_port *port, unsigned int cflag); - int break_flag; - struct timer_list break_timer; -}; - #define SCI_IN(size, offset) \ unsigned int addr = port->mapbase + (offset); \ if ((size) == 8) { \ @@ -336,7 +313,9 @@ struct sci_port { } #ifdef CONFIG_CPU_SH3 -#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) +#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \ + defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7710) #define SCIF_FNS(name, scif_offset, scif_size) \ CPU_SCIF_FNS(name, scif_offset, scif_size) #else @@ -362,7 +341,9 @@ struct sci_port { CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) #endif -#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) +#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \ + defined(CONFIG_CPU_SUBTYPE_SH7705) || \ + defined(CONFIG_CPU_SUBTYPE_SH7710) SCIF_FNS(SCSMR, 0x00, 16) SCIF_FNS(SCBRR, 0x04, 8) SCIF_FNS(SCSCR, 0x08, 16) @@ -447,7 +428,9 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inb(SCSPTR)&0x01 ? 1 : 0; /* SCI */ return 1; } -#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) +#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) || \ + defined(CONFIG_CPU_SUBTYPE_SH7706) static inline int sci_rxd_in(struct uart_port *port) { if (port->mapbase == 0xfffffe80) @@ -467,6 +450,13 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */ return 1; } +#elif defined(CONFIG_CPU_SUBTYPE_SH7710) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == SCSPTR0) + return ctrl_inw(SCSPTR0 + 0x10) & 0x01 ? 1 : 0; + return 1; +} #elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \ defined(CONFIG_CPU_SUBTYPE_SH7751) || \ defined(CONFIG_CPU_SUBTYPE_SH4_202) @@ -504,6 +494,19 @@ static inline int sci_rxd_in(struct uart_port *port) { return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCIF0 */ } +#elif defined(CONFIG_CPU_SUBTYPE_SH7343) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xffe00000) + return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xffe10000) + return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xffe20000) + return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xffe30000) + return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */ + return 1; +} #elif defined(CONFIG_CPU_SUBTYPE_ST40STB1) static inline int sci_rxd_in(struct uart_port *port) { @@ -587,4 +590,3 @@ static inline int sci_rxd_in(struct uart_port *port) #else /* Generic SH */ #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1) #endif - diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index ffc72ae3ada..fe1488374f6 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -20,7 +20,7 @@ #include <asm/cpu/dac.h> #include <asm/hp6xx/hp6xx.h> -#include <asm/hd64461/hd64461.h> +#include <asm/hd64461.h> #define HP680_MAX_INTENSITY 255 #define HP680_DEFAULT_INTENSITY 10 @@ -163,6 +163,6 @@ static void __exit hp680bl_exit(void) module_init(hp680bl_init); module_exit(hp680bl_exit); -MODULE_AUTHOR("Andriy Skulysh <askulysh@image.kiev.ua>"); +MODULE_AUTHOR("Andriy Skulysh <askulysh@gmail.com>"); MODULE_DESCRIPTION("HP Jornada 680 Backlight Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 4444bef68fb..aa3935df852 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -6,7 +6,7 @@ menu "Console display driver support" config VGA_CONSOLE bool "VGA text console" if EMBEDDED || !X86 - depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE + depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH default y help Saying Y here will allow you to use Linux in text mode through a diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c index 4cc6b454265..3afb472763c 100644 --- a/drivers/video/hitfb.c +++ b/drivers/video/hitfb.c @@ -4,7 +4,7 @@ * (C) 1999 Mihai Spatar * (C) 2000 YAEGASHI Takeshi * (C) 2003, 2004 Paul Mundt - * (C) 2003, 2004 Andriy Skulysh + * (C) 2003, 2004, 2006 Andriy Skulysh * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for @@ -20,18 +20,16 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/platform_device.h> #include <linux/fb.h> #include <asm/machvec.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/io.h> -#include <asm/hd64461/hd64461.h> - -#ifdef MACH_HP600 +#include <asm/hd64461.h> #include <asm/cpu/dac.h> #include <asm/hp6xx/hp6xx.h> -#endif #define WIDTH 640 @@ -45,7 +43,6 @@ static struct fb_var_screeninfo hitfb_var __initdata = { static struct fb_fix_screeninfo hitfb_fix __initdata = { .id = "Hitachi HD64461", .type = FB_TYPE_PACKED_PIXELS, - .ypanstep = 8, .accel = FB_ACCEL_NONE, }; @@ -73,26 +70,14 @@ static inline void hitfb_accel_set_dest(int truecolor, u16 dx, u16 dy, if (truecolor) saddr <<= 1; - fb_writew(width, HD64461_BBTDWR); - fb_writew(height, HD64461_BBTDHR); + fb_writew(width-1, HD64461_BBTDWR); + fb_writew(height-1, HD64461_BBTDHR); fb_writew(saddr & 0xffff, HD64461_BBTDSARL); fb_writew(saddr >> 16, HD64461_BBTDSARH); } -static inline void hitfb_accel_solidfill(int truecolor, u16 dx, u16 dy, - u16 width, u16 height, u16 color) -{ - hitfb_accel_set_dest(truecolor, dx, dy, width, height); - - fb_writew(0x00f0, HD64461_BBTROPR); - fb_writew(16, HD64461_BBTMDR); - fb_writew(color, HD64461_GRSCR); - - hitfb_accel_start(truecolor); -} - static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx, u16 dy, u16 width, u16 height, u16 rop, u32 mask_addr) @@ -100,6 +85,8 @@ static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx, u32 saddr, daddr; u32 maddr = 0; + height--; + width--; fb_writew(rop, HD64461_BBTROPR); if ((sy < dy) || ((sy == dy) && (sx <= dx))) { saddr = WIDTH * (sy + height) + sx + width; @@ -146,6 +133,7 @@ static void hitfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) if (rect->rop != ROP_COPY) cfb_fillrect(p, rect); else { + hitfb_accel_wait(); fb_writew(0x00f0, HD64461_BBTROPR); fb_writew(16, HD64461_BBTMDR); @@ -161,16 +149,15 @@ static void hitfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) rect->height); hitfb_accel_start(0); } - hitfb_accel_wait(); } } static void hitfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) { + hitfb_accel_wait(); hitfb_accel_bitblt(p->var.bits_per_pixel == 16, area->sx, area->sy, area->dx, area->dy, area->width, area->height, 0x00cc, 0); - hitfb_accel_wait(); } static int hitfb_pan_display(struct fb_var_screeninfo *var, @@ -182,7 +169,7 @@ static int hitfb_pan_display(struct fb_var_screeninfo *var, if (xoffset != 0) return -EINVAL; - fb_writew(yoffset, HD64461_LCDCBAR); + fb_writew((yoffset*info->fix.line_length)>>10, HD64461_LCDCBAR); return 0; } @@ -192,12 +179,6 @@ int hitfb_blank(int blank_mode, struct fb_info *info) unsigned short v; if (blank_mode) { -#ifdef MACH_HP600 - sh_dac_disable(DAC_LCD_BRIGHTNESS); - v = fb_readw(HD64461_GPBDR); - v |= HD64461_GPBDR_LCDOFF; - fb_writew(v, HD64461_GPBDR); -#endif v = fb_readw(HD64461_LDR1); v &= ~HD64461_LDR1_DON; fb_writew(v, HD64461_LDR1); @@ -213,19 +194,18 @@ int hitfb_blank(int blank_mode, struct fb_info *info) v = fb_readw(HD64461_STBCR); v &= ~HD64461_STBCR_SLCDST; fb_writew(v, HD64461_STBCR); -#ifdef MACH_HP600 - sh_dac_enable(DAC_LCD_BRIGHTNESS); - v = fb_readw(HD64461_GPBDR); - v &= ~HD64461_GPBDR_LCDOFF; - fb_writew(v, HD64461_GPBDR); -#endif - v = fb_readw(HD64461_LDR1); - v |= HD64461_LDR1_DON; - fb_writew(v, HD64461_LDR1); v = fb_readw(HD64461_LCDCCR); - v &= ~HD64461_LCDCCR_MOFF; + v &= ~(HD64461_LCDCCR_MOFF | HD64461_LCDCCR_STREQ); fb_writew(v, HD64461_LCDCCR); + + do { + v = fb_readw(HD64461_LCDCCR); + } while(v&HD64461_LCDCCR_STBACK); + + v = fb_readw(HD64461_LDR1); + v |= HD64461_LDR1_DON; + fb_writew(v, HD64461_LDR1); } return 0; } @@ -233,7 +213,7 @@ int hitfb_blank(int blank_mode, struct fb_info *info) static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { - if (regno >= info->cmap.len) + if (regno >= 256) return 1; switch (info->var.bits_per_pixel) { @@ -244,6 +224,8 @@ static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green, fb_writew(blue >> 10, HD64461_CPTWDR); break; case 16: + if (regno >= 16) + return 1; ((u32 *) (info->pseudo_palette))[regno] = ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); @@ -252,26 +234,113 @@ static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } +static int hitfb_sync(struct fb_info *info) +{ + hitfb_accel_wait(); + + return 0; +} + +static int hitfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + int maxy; + + var->xres = info->var.xres; + var->xres_virtual = info->var.xres; + var->yres = info->var.yres; + + if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16)) + var->bits_per_pixel = info->var.bits_per_pixel; + + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + + maxy = info->fix.smem_len / var->xres; + + if (var->bits_per_pixel == 16) + maxy /= 2; + + if (var->yres_virtual > maxy) + var->yres_virtual = maxy; + + var->xoffset = 0; + var->yoffset = 0; + + switch (var->bits_per_pixel) { + case 8: + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 16: /* RGB 565 */ + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + } + + return 0; +} + +static int hitfb_set_par(struct fb_info *info) +{ + unsigned short ldr3; + + switch (info->var.bits_per_pixel) { + case 8: + info->fix.line_length = info->var.xres; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + info->fix.ypanstep = 16; + break; + case 16: + info->fix.line_length = info->var.xres*2; + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.ypanstep = 8; + break; + } + + fb_writew(info->fix.line_length, HD64461_LCDCLOR); + ldr3 = fb_readw(HD64461_LDR3); + ldr3 &= ~15; + ldr3 |= (info->var.bits_per_pixel == 8) ? 4 : 8; + fb_writew(ldr3, HD64461_LDR3); + return 0; +} + static struct fb_ops hitfb_ops = { .owner = THIS_MODULE, + .fb_check_var = hitfb_check_var, + .fb_set_par = hitfb_set_par, .fb_setcolreg = hitfb_setcolreg, .fb_blank = hitfb_blank, + .fb_sync = hitfb_sync, .fb_pan_display = hitfb_pan_display, .fb_fillrect = hitfb_fillrect, .fb_copyarea = hitfb_copyarea, .fb_imageblit = cfb_imageblit, }; -int __init hitfb_init(void) +static int __init hitfb_probe(struct platform_device *dev) { unsigned short lcdclor, ldr3, ldvndr; - int size; if (fb_get_options("hitfb", NULL)) return -ENODEV; + hitfb_fix.mmio_start = CONFIG_HD64461_IOBASE+0x1000; + hitfb_fix.mmio_len = 0x1000; hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000; - hitfb_fix.smem_len = (MACH_HP690) ? 1024 * 1024 : 512 * 1024; + hitfb_fix.smem_len = 512 * 1024; lcdclor = fb_readw(HD64461_LCDCLOR); ldvndr = fb_readw(HD64461_LDVNDR); @@ -321,12 +390,12 @@ int __init hitfb_init(void) fb_info.var = hitfb_var; fb_info.fix = hitfb_fix; fb_info.pseudo_palette = pseudo_palette; - fb_info.flags = FBINFO_DEFAULT; + fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | + FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA; fb_info.screen_base = (void *)hitfb_fix.smem_start; - size = (fb_info.var.bits_per_pixel == 8) ? 256 : 16; - fb_alloc_cmap(&fb_info.cmap, size, 0); + fb_alloc_cmap(&fb_info.cmap, 256, 0); if (register_framebuffer(&fb_info) < 0) return -EINVAL; @@ -336,9 +405,75 @@ int __init hitfb_init(void) return 0; } +static int __devexit hitfb_remove(struct platform_device *dev) +{ + return unregister_framebuffer(&fb_info); +} + +#ifdef CONFIG_PM +static int hitfb_suspend(struct platform_device *dev, pm_message_t state) +{ + u16 v; + + hitfb_blank(1,0); + v = fb_readw(HD64461_STBCR); + v |= HD64461_STBCR_SLCKE_IST; + fb_writew(v, HD64461_STBCR); + + return 0; +} + +static int hitfb_resume(struct platform_device *dev) +{ + u16 v; + + v = fb_readw(HD64461_STBCR); + v &= ~HD64461_STBCR_SLCKE_OST; + msleep(100); + v = fb_readw(HD64461_STBCR); + v &= ~HD64461_STBCR_SLCKE_IST; + fb_writew(v, HD64461_STBCR); + hitfb_blank(0,0); + + return 0; +} +#endif + +static struct platform_driver hitfb_driver = { + .probe = hitfb_probe, + .remove = __devexit_p(hitfb_remove), +#ifdef CONFIG_PM + .suspend = hitfb_suspend, + .resume = hitfb_resume, +#endif + .driver = { + .name = "hitfb", + }, +}; + +static struct platform_device hitfb_device = { + .name = "hitfb", + .id = -1, +}; + +static int __init hitfb_init(void) +{ + int ret; + + ret = platform_driver_register(&hitfb_driver); + if (!ret) { + ret = platform_device_register(&hitfb_device); + if (ret) + platform_driver_unregister(&hitfb_driver); + } + return ret; +} + + static void __exit hitfb_exit(void) { - unregister_framebuffer(&fb_info); + platform_device_unregister(&hitfb_device); + platform_driver_unregister(&hitfb_driver); } module_init(hitfb_init); diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index 940ba2be55e..78dc59a1751 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c @@ -187,7 +187,7 @@ static short do_blank = 0; /* (Un)Blank the screen */ static unsigned int is_blanked = 0; /* Is the screen blanked? */ #ifdef CONFIG_SH_STORE_QUEUES -static struct sq_mapping *pvr2fb_map; +static unsigned long pvr2fb_map; #endif #ifdef CONFIG_SH_DMA @@ -213,15 +213,17 @@ static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp); static int pvr2_init_cable(void); static int pvr2_get_param(const struct pvr2_params *p, const char *s, int val, int size); +#ifdef CONFIG_SH_DMA static ssize_t pvr2fb_write(struct file *file, const char *buf, size_t count, loff_t *ppos); +#endif static struct fb_ops pvr2fb_ops = { - .owner = THIS_MODULE, - .fb_setcolreg = pvr2fb_setcolreg, - .fb_blank = pvr2fb_blank, - .fb_check_var = pvr2fb_check_var, - .fb_set_par = pvr2fb_set_par, + .owner = THIS_MODULE, + .fb_setcolreg = pvr2fb_setcolreg, + .fb_blank = pvr2fb_blank, + .fb_check_var = pvr2fb_check_var, + .fb_set_par = pvr2fb_set_par, #ifdef CONFIG_SH_DMA .fb_write = pvr2fb_write, #endif @@ -783,7 +785,7 @@ static int __init pvr2fb_common_init(void) goto out_err; } - fb_memset((unsigned long)fb_info->screen_base, 0, pvr2_fix.smem_len); + fb_memset(fb_info->screen_base, 0, pvr2_fix.smem_len); pvr2_fix.ypanstep = nopan ? 0 : 1; pvr2_fix.ywrapstep = nowrap ? 0 : 1; @@ -820,7 +822,7 @@ static int __init pvr2fb_common_init(void) modememused >> 10, (unsigned long)(fb_info->fix.smem_len >> 10)); printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n", fb_info->node, fb_info->var.xres, fb_info->var.yres, - fb_info->var.bits_per_pixel, + fb_info->var.bits_per_pixel, get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel), (char *)pvr2_get_param(cables, NULL, cable_type, 3), (char *)pvr2_get_param(outputs, NULL, video_output, 3)); @@ -829,10 +831,10 @@ static int __init pvr2fb_common_init(void) printk(KERN_NOTICE "fb%d: registering with SQ API\n", fb_info->node); pvr2fb_map = sq_remap(fb_info->fix.smem_start, fb_info->fix.smem_len, - fb_info->fix.id); + fb_info->fix.id, pgprot_val(PAGE_SHARED)); printk(KERN_NOTICE "fb%d: Mapped video memory to SQ addr 0x%lx\n", - fb_info->node, pvr2fb_map->sq_addr); + fb_info->node, pvr2fb_map); #endif return 0; |