diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/sh_eth.c | 5 | ||||
-rw-r--r-- | drivers/rtc/rtc-sh.c | 21 | ||||
-rw-r--r-- | drivers/serial/sh-sci.c | 90 | ||||
-rw-r--r-- | drivers/serial/sh-sci.h | 14 | ||||
-rw-r--r-- | drivers/sh/Makefile | 2 | ||||
-rw-r--r-- | drivers/sh/intc.c | 713 | ||||
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 8 |
7 files changed, 792 insertions, 61 deletions
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index b39d1cc1ef04..a24bb68887ab 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1205,11 +1205,12 @@ static int sh_eth_drv_probe(struct platform_device *pdev) devno = 0; ndev->dma = -1; - ndev->irq = platform_get_irq(pdev, 0); - if (ndev->irq < 0) { + ret = platform_get_irq(pdev, 0); + if (ret < 0) { ret = -ENODEV; goto out_release; } + ndev->irq = ret; SET_NETDEV_DEV(ndev, &pdev->dev); diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index fcead4c4cd1f..3f393c82e32c 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -568,7 +568,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) struct sh_rtc *rtc; struct resource *res; unsigned int tmp; - int ret = -ENOENT; + int ret; rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL); if (unlikely(!rtc)) @@ -577,26 +577,33 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) spin_lock_init(&rtc->lock); /* get periodic/carry/alarm irqs */ - rtc->periodic_irq = platform_get_irq(pdev, 0); - if (unlikely(rtc->periodic_irq < 0)) { + ret = platform_get_irq(pdev, 0); + if (unlikely(ret < 0)) { + ret = -ENOENT; dev_err(&pdev->dev, "No IRQ for period\n"); goto err_badres; } + rtc->periodic_irq = ret; - rtc->carry_irq = platform_get_irq(pdev, 1); - if (unlikely(rtc->carry_irq < 0)) { + ret = platform_get_irq(pdev, 1); + if (unlikely(ret < 0)) { + ret = -ENOENT; dev_err(&pdev->dev, "No IRQ for carry\n"); goto err_badres; } + rtc->carry_irq = ret; - rtc->alarm_irq = platform_get_irq(pdev, 2); - if (unlikely(rtc->alarm_irq < 0)) { + ret = platform_get_irq(pdev, 2); + if (unlikely(ret < 0)) { + ret = -ENOENT; dev_err(&pdev->dev, "No IRQ for alarm\n"); goto err_badres; } + rtc->alarm_irq = ret; res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (unlikely(res == NULL)) { + ret = -ENOENT; dev_err(&pdev->dev, "No IO resource\n"); goto err_badres; } diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 3df2aaec829f..3b9d2d83b590 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 - 2006 Paul Mundt + * Copyright (C) 2002 - 2008 Paul Mundt * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007). * * based off of the old drivers/char/sh-sci.c by: @@ -46,6 +46,7 @@ #include <linux/cpufreq.h> #include <linux/clk.h> #include <linux/ctype.h> +#include <linux/err.h> #ifdef CONFIG_SUPERH #include <asm/clock.h> @@ -78,7 +79,7 @@ struct sci_port { struct timer_list break_timer; int break_flag; -#ifdef CONFIG_SUPERH +#ifdef CONFIG_HAVE_CLK /* Port clock */ struct clk *clk; #endif @@ -831,7 +832,7 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) return IRQ_HANDLED; } -#ifdef CONFIG_CPU_FREQ +#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_HAVE_CLK) /* * Here we define a transistion notifier so that we can update all of our * ports' baud rate when the peripheral clock changes. @@ -860,7 +861,7 @@ static int sci_notifier(struct notifier_block *self, * Clean this up later.. */ clk = clk_get(NULL, "module_clk"); - port->uartclk = clk_get_rate(clk) * 16; + port->uartclk = clk_get_rate(clk); clk_put(clk); } @@ -873,7 +874,7 @@ static int sci_notifier(struct notifier_block *self, } static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 }; -#endif /* CONFIG_CPU_FREQ */ +#endif /* CONFIG_CPU_FREQ && CONFIG_HAVE_CLK */ static int sci_request_irq(struct sci_port *port) { @@ -1008,7 +1009,7 @@ static int sci_startup(struct uart_port *port) if (s->enable) s->enable(port); -#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) +#ifdef CONFIG_HAVE_CLK s->clk = clk_get(NULL, "module_clk"); #endif @@ -1030,7 +1031,7 @@ static void sci_shutdown(struct uart_port *port) if (s->disable) s->disable(port); -#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) +#ifdef CONFIG_HAVE_CLK clk_put(s->clk); s->clk = NULL; #endif @@ -1041,24 +1042,11 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, { struct sci_port *s = &sci_ports[port->line]; unsigned int status, baud, smr_val; - int t; + int t = -1; 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) - t = SCBRR_VALUE(baud, clk_get_rate(s->clk)); -#else - t = SCBRR_VALUE(baud); -#endif - break; - } - } + if (likely(baud)) + t = SCBRR_VALUE(baud, port->uartclk); do { status = sci_in(port, SCxSR); @@ -1113,7 +1101,7 @@ static const char *sci_type(struct uart_port *port) case PORT_IRDA: return "irda"; } - return 0; + return NULL; } static void sci_release_port(struct uart_port *port) @@ -1145,12 +1133,16 @@ static void sci_config_port(struct uart_port *port, int flags) break; } -#if defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) - if (port->mapbase == 0) + if (port->flags & UPF_IOREMAP && !port->membase) { +#if defined(CONFIG_SUPERH64) port->mapbase = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF"); - - port->membase = (void __iomem *)port->mapbase; + port->membase = (void __iomem *)port->mapbase; +#else + port->membase = ioremap_nocache(port->mapbase, 0x40); #endif + + printk(KERN_ERR "sci: can't remap port#%d\n", port->line); + } } static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) @@ -1207,17 +1199,17 @@ static void __init sci_init_ports(void) 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 +#elif defined(CONFIG_HAVE_CLK) /* * XXX: We should use a proper SCI/SCIF clock */ { struct clk *clk = clk_get(NULL, "module_clk"); - sci_ports[i].port.uartclk = clk_get_rate(clk) * 16; + sci_ports[i].port.uartclk = clk_get_rate(clk); clk_put(clk); } +#else +#error "Need a valid uartclk" #endif sci_ports[i].break_timer.data = (unsigned long)&sci_ports[i]; @@ -1285,7 +1277,7 @@ static int __init serial_console_setup(struct console *co, char *options) port->type = serial_console_port->type; -#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64) +#ifdef CONFIG_HAVE_CLK if (!serial_console_port->clk) serial_console_port->clk = clk_get(NULL, "module_clk"); #endif @@ -1436,7 +1428,7 @@ static struct uart_driver sci_uart_driver = { static int __devinit sci_probe(struct platform_device *dev) { struct plat_sci_port *p = dev->dev.platform_data; - int i; + int i, ret = -EINVAL; for (i = 0; p && p->flags != 0; p++, i++) { struct sci_port *sciport = &sci_ports[i]; @@ -1453,12 +1445,22 @@ static int __devinit sci_probe(struct platform_device *dev) sciport->port.mapbase = p->mapbase; - /* - * 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 (p->mapbase && !p->membase) { + if (p->flags & UPF_IOREMAP) { + p->membase = ioremap_nocache(p->mapbase, 0x40); + if (IS_ERR(p->membase)) { + ret = PTR_ERR(p->membase); + goto err_unreg; + } + } else { + /* + * For the simple (and majority of) cases + * where we don't need to do any remapping, + * just cast the cookie directly. + */ + p->membase = (void __iomem *)p->mapbase; + } + } sciport->port.membase = p->membase; @@ -1479,7 +1481,7 @@ static int __devinit sci_probe(struct platform_device *dev) kgdb_putchar = kgdb_sci_putchar; #endif -#ifdef CONFIG_CPU_FREQ +#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_HAVE_CLK) cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER); dev_info(&dev->dev, "CPU frequency notifier registered\n"); #endif @@ -1489,6 +1491,12 @@ static int __devinit sci_probe(struct platform_device *dev) #endif return 0; + +err_unreg: + for (i = i - 1; i >= 0; i--) + uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port); + + return ret; } static int __devexit sci_remove(struct platform_device *dev) diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index 8a0749e34ca3..511c10d42187 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -320,18 +320,16 @@ #define SCI_EVENT_WRITE_WAKEUP 0 #define SCI_IN(size, offset) \ - unsigned int addr = port->mapbase + (offset); \ if ((size) == 8) { \ - return ctrl_inb(addr); \ + return ioread8(port->membase + (offset)); \ } else { \ - return ctrl_inw(addr); \ + return ioread16(port->membase + (offset)); \ } #define SCI_OUT(size, offset, value) \ - unsigned int addr = port->mapbase + (offset); \ if ((size) == 8) { \ - ctrl_outb(value, addr); \ + iowrite8(value, port->membase + (offset)); \ } else if ((size) == 16) { \ - ctrl_outw(value, addr); \ + iowrite16(value, port->membase + (offset)); \ } #define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\ @@ -793,9 +791,7 @@ static inline int sci_rxd_in(struct uart_port *port) #elif defined(CONFIG_CPU_SUBTYPE_SH7723) #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(16*bps)-1) #elif defined(__H8300H__) || defined(__H8300S__) -#define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1) -#elif defined(CONFIG_SUPERH64) -#define SCBRR_VALUE(bps) ((current_cpu_data.module_clock+16*bps)/(32*bps)-1) +#define SCBRR_VALUE(bps, clk) (((clk*1000/32)/bps)-1) #else /* Generic SH */ #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1) #endif diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile index a96f4a8cfeb8..6a025cefe6dc 100644 --- a/drivers/sh/Makefile +++ b/drivers/sh/Makefile @@ -1,6 +1,6 @@ # # Makefile for the SuperH specific drivers. # - obj-$(CONFIG_SUPERHYWAY) += superhyway/ obj-$(CONFIG_MAPLE) += maple/ +obj-y += intc.o diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c new file mode 100644 index 000000000000..58d24c5a76ce --- /dev/null +++ b/drivers/sh/intc.c @@ -0,0 +1,713 @@ +/* + * Shared interrupt handling code for IPR and INTC2 types of IRQs. + * + * Copyright (C) 2007, 2008 Magnus Damm + * + * Based on intc2.c and ipr.c + * + * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi + * Copyright (C) 2000 Kazumoto Kojima + * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) + * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp> + * Copyright (C) 2005, 2006 Paul Mundt + * + * 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/init.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/bootmem.h> +#include <linux/sh_intc.h> + +#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ + ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \ + ((addr_e) << 16) | ((addr_d << 24))) + +#define _INTC_SHIFT(h) (h & 0x1f) +#define _INTC_WIDTH(h) ((h >> 5) & 0xf) +#define _INTC_FN(h) ((h >> 9) & 0xf) +#define _INTC_MODE(h) ((h >> 13) & 0x7) +#define _INTC_ADDR_E(h) ((h >> 16) & 0xff) +#define _INTC_ADDR_D(h) ((h >> 24) & 0xff) + +struct intc_handle_int { + unsigned int irq; + unsigned long handle; +}; + +struct intc_desc_int { + unsigned long *reg; +#ifdef CONFIG_SMP + unsigned long *smp; +#endif + unsigned int nr_reg; + struct intc_handle_int *prio; + unsigned int nr_prio; + struct intc_handle_int *sense; + unsigned int nr_sense; + struct irq_chip chip; +}; + +#ifdef CONFIG_SMP +#define IS_SMP(x) x.smp +#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c)) +#define SMP_NR(d, x) ((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1) +#else +#define IS_SMP(x) 0 +#define INTC_REG(d, x, c) (d->reg[(x)]) +#define SMP_NR(d, x) 1 +#endif + +static unsigned int intc_prio_level[NR_IRQS]; /* for now */ +#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) +static unsigned long ack_handle[NR_IRQS]; +#endif + +static inline struct intc_desc_int *get_intc_desc(unsigned int irq) +{ + struct irq_chip *chip = get_irq_chip(irq); + return (void *)((char *)chip - offsetof(struct intc_desc_int, chip)); +} + +static inline unsigned int set_field(unsigned int value, + unsigned int field_value, + unsigned int handle) +{ + unsigned int width = _INTC_WIDTH(handle); + unsigned int shift = _INTC_SHIFT(handle); + + value &= ~(((1 << width) - 1) << shift); + value |= field_value << shift; + return value; +} + +static void write_8(unsigned long addr, unsigned long h, unsigned long data) +{ + __raw_writeb(set_field(0, data, h), addr); +} + +static void write_16(unsigned long addr, unsigned long h, unsigned long data) +{ + __raw_writew(set_field(0, data, h), addr); +} + +static void write_32(unsigned long addr, unsigned long h, unsigned long data) +{ + __raw_writel(set_field(0, data, h), addr); +} + +static void modify_8(unsigned long addr, unsigned long h, unsigned long data) +{ + unsigned long flags; + local_irq_save(flags); + __raw_writeb(set_field(__raw_readb(addr), data, h), addr); + local_irq_restore(flags); +} + +static void modify_16(unsigned long addr, unsigned long h, unsigned long data) +{ + unsigned long flags; + local_irq_save(flags); + __raw_writew(set_field(__raw_readw(addr), data, h), addr); + local_irq_restore(flags); +} + +static void modify_32(unsigned long addr, unsigned long h, unsigned long data) +{ + unsigned long flags; + local_irq_save(flags); + __raw_writel(set_field(__raw_readl(addr), data, h), addr); + local_irq_restore(flags); +} + +enum { REG_FN_ERR = 0, REG_FN_WRITE_BASE = 1, REG_FN_MODIFY_BASE = 5 }; + +static void (*intc_reg_fns[])(unsigned long addr, + unsigned long h, + unsigned long data) = { + [REG_FN_WRITE_BASE + 0] = write_8, + [REG_FN_WRITE_BASE + 1] = write_16, + [REG_FN_WRITE_BASE + 3] = write_32, + [REG_FN_MODIFY_BASE + 0] = modify_8, + [REG_FN_MODIFY_BASE + 1] = modify_16, + [REG_FN_MODIFY_BASE + 3] = modify_32, +}; + +enum { MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */ + MODE_MASK_REG, /* Bit(s) set -> interrupt disabled */ + MODE_DUAL_REG, /* Two registers, set bit to enable / disable */ + MODE_PRIO_REG, /* Priority value written to enable interrupt */ + MODE_PCLR_REG, /* Above plus all bits set to disable interrupt */ +}; + +static void intc_mode_field(unsigned long addr, + unsigned long handle, + void (*fn)(unsigned long, + unsigned long, + unsigned long), + unsigned int irq) +{ + fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1)); +} + +static void intc_mode_zero(unsigned long addr, + unsigned long handle, + void (*fn)(unsigned long, + unsigned long, + unsigned long), + unsigned int irq) +{ + fn(addr, handle, 0); +} + +static void intc_mode_prio(unsigned long addr, + unsigned long handle, + void (*fn)(unsigned long, + unsigned long, + unsigned long), + unsigned int irq) +{ + fn(addr, handle, intc_prio_level[irq]); +} + +static void (*intc_enable_fns[])(unsigned long addr, + unsigned long handle, + void (*fn)(unsigned long, + unsigned long, + unsigned long), + unsigned int irq) = { + [MODE_ENABLE_REG] = intc_mode_field, + [MODE_MASK_REG] = intc_mode_zero, + [MODE_DUAL_REG] = intc_mode_field, + [MODE_PRIO_REG] = intc_mode_prio, + [MODE_PCLR_REG] = intc_mode_prio, +}; + +static void (*intc_disable_fns[])(unsigned long addr, + unsigned long handle, + void (*fn)(unsigned long, + unsigned long, + unsigned long), + unsigned int irq) = { + [MODE_ENABLE_REG] = intc_mode_zero, + [MODE_MASK_REG] = intc_mode_field, + [MODE_DUAL_REG] = intc_mode_field, + [MODE_PRIO_REG] = intc_mode_zero, + [MODE_PCLR_REG] = intc_mode_field, +}; + +static inline void _intc_enable(unsigned int irq, unsigned long handle) +{ + struct intc_desc_int *d = get_intc_desc(irq); + unsigned long addr; + unsigned int cpu; + + for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) { + addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu); + intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\ + [_INTC_FN(handle)], irq); + } +} + +static void intc_enable(unsigned int irq) +{ + _intc_enable(irq, (unsigned long)get_irq_chip_data(irq)); +} + +static void intc_disable(unsigned int irq) +{ + struct intc_desc_int *d = get_intc_desc(irq); + unsigned long handle = (unsigned long) get_irq_chip_data(irq); + unsigned long addr; + unsigned int cpu; + + for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { + addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu); + intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\ + [_INTC_FN(handle)], irq); + } +} + +#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) +static void intc_mask_ack(unsigned int irq) +{ + struct intc_desc_int *d = get_intc_desc(irq); + unsigned long handle = ack_handle[irq]; + unsigned long addr; + + intc_disable(irq); + + /* read register and write zero only to the assocaited bit */ + + if (handle) { + addr = INTC_REG(d, _INTC_ADDR_D(handle), 0); + switch (_INTC_FN(handle)) { + case REG_FN_MODIFY_BASE + 0: /* 8bit */ + __raw_readb(addr); + __raw_writeb(0xff ^ set_field(0, 1, handle), addr); + break; + case REG_FN_MODIFY_BASE + 1: /* 16bit */ + __raw_readw(addr); + __raw_writew(0xffff ^ set_field(0, 1, handle), addr); + break; + case REG_FN_MODIFY_BASE + 3: /* 32bit */ + __raw_readl(addr); + __raw_writel(0xffffffff ^ set_field(0, 1, handle), addr); + break; + default: + BUG(); + break; + } + } +} +#endif + +static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp, + unsigned int nr_hp, + unsigned int irq) +{ + int i; + + /* this doesn't scale well, but... + * + * this function should only be used for cerain uncommon + * operations such as intc_set_priority() and intc_set_sense() + * and in those rare cases performance doesn't matter that much. + * keeping the memory footprint low is more important. + * + * one rather simple way to speed this up and still keep the + * memory footprint down is to make sure the array is sorted + * and then perform a bisect to lookup the irq. + */ + + for (i = 0; i < nr_hp; i++) { + if ((hp + i)->irq != irq) + continue; + + return hp + i; + } + + return NULL; +} + +int intc_set_priority(unsigned int irq, unsigned int prio) +{ + struct intc_desc_int *d = get_intc_desc(irq); + struct intc_handle_int *ihp; + + if (!intc_prio_level[irq] || prio <= 1) + return -EINVAL; + + ihp = intc_find_irq(d->prio, d->nr_prio, irq); + if (ihp) { + if (prio >= (1 << _INTC_WIDTH(ihp->handle))) + return -EINVAL; + + intc_prio_level[irq] = prio; + + /* + * only set secondary masking method directly + * primary masking method is using intc_prio_level[irq] + * priority level will be set during next enable() + */ + + if (_INTC_FN(ihp->handle) != REG_FN_ERR) + _intc_enable(irq, ihp->handle); + } + return 0; +} + +#define VALID(x) (x | 0x80) + +static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = { + [IRQ_TYPE_EDGE_FALLING] = VALID(0), + [IRQ_TYPE_EDGE_RISING] = VALID(1), + [IRQ_TYPE_LEVEL_LOW] = VALID(2), + /* SH7706, SH7707 and SH7709 do not support high level triggered */ +#if !defined(CONFIG_CPU_SUBTYPE_SH7706) && \ + !defined(CONFIG_CPU_SUBTYPE_SH7707) && \ + !defined(CONFIG_CPU_SUBTYPE_SH7709) + [IRQ_TYPE_LEVEL_HIGH] = VALID(3), +#endif +}; + +static int intc_set_sense(unsigned int irq, unsigned int type) +{ + struct intc_desc_int *d = get_intc_desc(irq); + unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK]; + struct intc_handle_int *ihp; + unsigned long addr; + + if (!value) + return -EINVAL; + + ihp = intc_find_irq(d->sense, d->nr_sense, irq); + if (ihp) { + addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0); + intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value); + } + return 0; +} + +static unsigned int __init intc_get_reg(struct intc_desc_int *d, + unsigned long address) +{ + unsigned int k; + + for (k = 0; k < d->nr_reg; k++) { + if (d->reg[k] == address) + return k; + } + + BUG(); + return 0; +} + +static intc_enum __init intc_grp_id(struct intc_desc *desc, + intc_enum enum_id) +{ + struct intc_group *g = desc->groups; + unsigned int i, j; + + for (i = 0; g && enum_id && i < desc->nr_groups; i++) { + g = desc->groups + i; + + for (j = 0; g->enum_ids[j]; j++) { + if (g->enum_ids[j] != enum_id) + continue; + + return g->enum_id; + } + } + + return 0; +} + +static unsigned int __init intc_mask_data(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id, int do_grps) +{ + struct intc_mask_reg *mr = desc->mask_regs; + unsigned int i, j, fn, mode; + unsigned long reg_e, reg_d; + + for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) { + mr = desc->mask_regs + i; + + for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) { + if (mr->enum_ids[j] != enum_id) + continue; + + if (mr->set_reg && mr->clr_reg) { + fn = REG_FN_WRITE_BASE; + mode = MODE_DUAL_REG; + reg_e = mr->clr_reg; + reg_d = mr->set_reg; + } else { + fn = REG_FN_MODIFY_BASE; + if (mr->set_reg) { + mode = MODE_ENABLE_REG; + reg_e = mr->set_reg; + reg_d = mr->set_reg; + } else { + mode = MODE_MASK_REG; + reg_e = mr->clr_reg; + reg_d = mr->clr_reg; + } + } + + fn += (mr->reg_width >> 3) - 1; + return _INTC_MK(fn, mode, + intc_get_reg(d, reg_e), + intc_get_reg(d, reg_d), + 1, + (mr->reg_width - 1) - j); + } + } + + if (do_grps) + return intc_mask_data(desc, d, intc_grp_id(desc, enum_id), 0); + + return 0; +} + +static unsigned int __init intc_prio_data(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id, int do_grps) +{ + struct intc_prio_reg *pr = desc->prio_regs; + unsigned int i, j, fn, mode, bit; + unsigned long reg_e, reg_d; + + for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) { + pr = desc->prio_regs + i; + + for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) { + if (pr->enum_ids[j] != enum_id) + continue; + + if (pr->set_reg && pr->clr_reg) { + fn = REG_FN_WRITE_BASE; + mode = MODE_PCLR_REG; + reg_e = pr->set_reg; + reg_d = pr->clr_reg; + } else { + fn = REG_FN_MODIFY_BASE; + mode = MODE_PRIO_REG; + if (!pr->set_reg) + BUG(); + reg_e = pr->set_reg; + reg_d = pr->set_reg; + } + + fn += (pr->reg_width >> 3) - 1; + + BUG_ON((j + 1) * pr->field_width > pr->reg_width); + + bit = pr->reg_width - ((j + 1) * pr->field_width); + + return _INTC_MK(fn, mode, + intc_get_reg(d, reg_e), + intc_get_reg(d, reg_d), + pr->field_width, bit); + } + } + + if (do_grps) + return intc_prio_data(desc, d, intc_grp_id(desc, enum_id), 0); + + return 0; +} + +#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) +static unsigned int __init intc_ack_data(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id) +{ + struct intc_mask_reg *mr = desc->ack_regs; + unsigned int i, j, fn, mode; + unsigned long reg_e, reg_d; + + for (i = 0; mr && enum_id && i < desc->nr_ack_regs; i++) { + mr = desc->ack_regs + i; + + for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) { + if (mr->enum_ids[j] != enum_id) + continue; + + fn = REG_FN_MODIFY_BASE; + mode = MODE_ENABLE_REG; + reg_e = mr->set_reg; + reg_d = mr->set_reg; + + fn += (mr->reg_width >> 3) - 1; + return _INTC_MK(fn, mode, + intc_get_reg(d, reg_e), + intc_get_reg(d, reg_d), + 1, + (mr->reg_width - 1) - j); + } + } + + return 0; +} +#endif + +static unsigned int __init intc_sense_data(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id) +{ + struct intc_sense_reg *sr = desc->sense_regs; + unsigned int i, j, fn, bit; + + for (i = 0; sr && enum_id && i < desc->nr_sense_regs; i++) { + sr = desc->sense_regs + i; + + for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) { + if (sr->enum_ids[j] != enum_id) + continue; + + fn = REG_FN_MODIFY_BASE; + fn += (sr->reg_width >> 3) - 1; + + BUG_ON((j + 1) * sr->field_width > sr->reg_width); + + bit = sr->reg_width - ((j + 1) * sr->field_width); + + return _INTC_MK(fn, 0, intc_get_reg(d, sr->reg), + 0, sr->field_width, bit); + } + } + + return 0; +} + +static void __init intc_register_irq(struct intc_desc *desc, + struct intc_desc_int *d, + intc_enum enum_id, + unsigned int irq) +{ + struct intc_handle_int *hp; + unsigned int data[2], primary; + + /* Prefer single interrupt source bitmap over other combinations: + * 1. bitmap, single interrupt source + * 2. priority, single interrupt source + * 3. bitmap, multiple interrupt sources (groups) + * 4. priority, multiple interrupt sources (groups) + */ + + data[0] = intc_mask_data(desc, d, enum_id, 0); + data[1] = intc_prio_data(desc, d, enum_id, 0); + + primary = 0; + if (!data[0] && data[1]) + primary = 1; + + data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1); + data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1); + + if (!data[primary]) + primary ^= 1; + + BUG_ON(!data[primary]); /* must have primary masking method */ + + disable_irq_nosync(irq); + set_irq_chip_and_handler_name(irq, &d->chip, + handle_level_irq, "level"); + set_irq_chip_data(irq, (void *)data[primary]); + + /* set priority level + * - this needs to be at least 2 for 5-bit priorities on 7780 + */ + intc_prio_level[irq] = 2; + + /* enable secondary masking method if present */ + if (data[!primary]) + _intc_enable(irq, data[!primary]); + + /* add irq to d->prio list if priority is available */ + if (data[1]) { + hp = d->prio + d->nr_prio; + hp->irq = irq; + hp->handle = data[1]; + + if (primary) { + /* + * only secondary priority should access registers, so + * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority() + */ + + hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0); + hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0); + } + d->nr_prio++; + } + + /* add irq to d->sense list if sense is available */ + data[0] = intc_sense_data(desc, d, enum_id); + if (data[0]) { + (d->sense + d->nr_sense)->irq = irq; + (d->sense + d->nr_sense)->handle = data[0]; + d->nr_sense++; + } + + /* irq should be disabled by default */ + d->chip.mask(irq); + +#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) + if (desc->ack_regs) + ack_handle[irq] = intc_ack_data(desc, d, enum_id); +#endif +} + +static unsigned int __init save_reg(struct intc_desc_int *d, + unsigned int cnt, + unsigned long value, + unsigned int smp) +{ + if (value) { + d->reg[cnt] = value; +#ifdef CONFIG_SMP + d->smp[cnt] = smp; +#endif + return 1; + } + + return 0; +} + + +void __init register_intc_controller(struct intc_desc *desc) +{ + unsigned int i, k, smp; + struct intc_desc_int *d; + + d = alloc_bootmem(sizeof(*d)); + + d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0; + d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0; + d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0; + +#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) + d->nr_reg += desc->ack_regs ? desc->nr_ack_regs : 0; +#endif + d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg)); +#ifdef CONFIG_SMP + d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp)); +#endif + k = 0; + + if (desc->mask_regs) { + for (i = 0; i < desc->nr_mask_regs; i++) { + smp = IS_SMP(desc->mask_regs[i]); + k += save_reg(d, k, desc->mask_regs[i].set_reg, smp); + k += save_reg(d, k, desc->mask_regs[i].clr_reg, smp); + } + } + + if (desc->prio_regs) { + d->prio = alloc_bootmem(desc->nr_vectors * sizeof(*d->prio)); + + for (i = 0; i < desc->nr_prio_regs; i++) { + smp = IS_SMP(desc->prio_regs[i]); + k += save_reg(d, k, desc->prio_regs[i].set_reg, smp); + k += save_reg(d, k, desc->prio_regs[i].clr_reg, smp); + } + } + + if (desc->sense_regs) { + d->sense = alloc_bootmem(desc->nr_vectors * sizeof(*d->sense)); + + for (i = 0; i < desc->nr_sense_regs; i++) { + k += save_reg(d, k, desc->sense_regs[i].reg, 0); + } + } + + d->chip.name = desc->name; + d->chip.mask = intc_disable; + d->chip.unmask = intc_enable; + d->chip.mask_ack = intc_disable; + d->chip.set_type = intc_set_sense; + +#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) + if (desc->ack_regs) { + for (i = 0; i < desc->nr_ack_regs; i++) + k += save_reg(d, k, desc->ack_regs[i].set_reg, 0); + + d->chip.mask_ack = intc_mask_ack; + } +#endif + + BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */ + + for (i = 0; i < desc->nr_vectors; i++) { + struct intc_vect *vect = desc->vectors + i; + + intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect)); + } +} diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 4c32c06579a0..b7468bacce80 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -16,7 +16,7 @@ #include <linux/clk.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> -#include <asm/sh_mobile_lcdc.h> +#include <video/sh_mobile_lcdc.h> #define PALETTE_NR 16 @@ -34,7 +34,9 @@ struct sh_mobile_lcdc_chan { struct sh_mobile_lcdc_priv { void __iomem *base; +#ifdef CONFIG_HAVE_CLK struct clk *clk; +#endif unsigned long lddckr; struct sh_mobile_lcdc_chan ch[2]; }; @@ -422,6 +424,7 @@ static int sh_mobile_lcdc_setup_clocks(struct device *dev, int clock_source, priv->lddckr = icksel << 16; +#ifdef CONFIG_HAVE_CLK if (str) { priv->clk = clk_get(dev, str); if (IS_ERR(priv->clk)) { @@ -431,6 +434,7 @@ static int sh_mobile_lcdc_setup_clocks(struct device *dev, int clock_source, clk_enable(priv->clk); } +#endif return 0; } @@ -688,10 +692,12 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev) fb_dealloc_cmap(&info->cmap); } +#ifdef CONFIG_HAVE_CLK if (priv->clk) { clk_disable(priv->clk); clk_put(priv->clk); } +#endif if (priv->base) iounmap(priv->base); |