| /* |
| * linux/arch/arm/mach-h720x/common.c |
| * |
| * Copyright (C) 2003 Thomas Gleixner <tglx@linutronix.de> |
| * 2003 Robert Schwebel <r.schwebel@pengutronix.de> |
| * 2004 Sascha Hauer <s.hauer@pengutronix.de> |
| * |
| * common stuff for Hynix h720x processors |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| */ |
| |
| #include <linux/sched.h> |
| #include <linux/mman.h> |
| #include <linux/init.h> |
| #include <linux/interrupt.h> |
| #include <linux/io.h> |
| |
| #include <asm/page.h> |
| #include <asm/pgtable.h> |
| #include <asm/dma.h> |
| #include <mach/hardware.h> |
| #include <asm/irq.h> |
| #include <asm/system_misc.h> |
| #include <asm/mach/irq.h> |
| #include <asm/mach/map.h> |
| #include <mach/irqs.h> |
| |
| #include <asm/mach/dma.h> |
| |
| #if 0 |
| #define IRQDBG(args...) printk(args) |
| #else |
| #define IRQDBG(args...) do {} while(0) |
| #endif |
| |
| void __init arch_dma_init(dma_t *dma) |
| { |
| } |
| |
| /* |
| * Return nsecs since last timer reload |
| * (timercount * (usecs perjiffie)) / (ticks per jiffie) |
| */ |
| u32 h720x_gettimeoffset(void) |
| { |
| return ((CPU_REG(TIMER_VIRT, TM0_COUNT) * tick_usec) / LATCH) * 1000; |
| } |
| |
| /* |
| * mask Global irq's |
| */ |
| static void mask_global_irq(struct irq_data *d) |
| { |
| CPU_REG (IRQC_VIRT, IRQC_IER) &= ~(1 << d->irq); |
| } |
| |
| /* |
| * unmask Global irq's |
| */ |
| static void unmask_global_irq(struct irq_data *d) |
| { |
| CPU_REG (IRQC_VIRT, IRQC_IER) |= (1 << d->irq); |
| } |
| |
| |
| /* |
| * ack GPIO irq's |
| * Ack only for edge triggered int's valid |
| */ |
| static void inline ack_gpio_irq(struct irq_data *d) |
| { |
| u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(d->irq)); |
| u32 bit = IRQ_TO_BIT(d->irq); |
| if ( (CPU_REG (reg_base, GPIO_EDGE) & bit)) |
| CPU_REG (reg_base, GPIO_CLR) = bit; |
| } |
| |
| /* |
| * mask GPIO irq's |
| */ |
| static void inline mask_gpio_irq(struct irq_data *d) |
| { |
| u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(d->irq)); |
| u32 bit = IRQ_TO_BIT(d->irq); |
| CPU_REG (reg_base, GPIO_MASK) &= ~bit; |
| } |
| |
| /* |
| * unmask GPIO irq's |
| */ |
| static void inline unmask_gpio_irq(struct irq_data *d) |
| { |
| u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(d->irq)); |
| u32 bit = IRQ_TO_BIT(d->irq); |
| CPU_REG (reg_base, GPIO_MASK) |= bit; |
| } |
| |
| static void |
| h720x_gpio_handler(unsigned int mask, unsigned int irq, |
| struct irq_desc *desc) |
| { |
| IRQDBG("%s irq: %d\n", __func__, irq); |
| while (mask) { |
| if (mask & 1) { |
| IRQDBG("handling irq %d\n", irq); |
| generic_handle_irq(irq); |
| } |
| irq++; |
| mask >>= 1; |
| } |
| } |
| |
| static void |
| h720x_gpioa_demux_handler(unsigned int irq_unused, struct irq_desc *desc) |
| { |
| unsigned int mask, irq; |
| |
| mask = CPU_REG(GPIO_A_VIRT,GPIO_STAT); |
| irq = IRQ_CHAINED_GPIOA(0); |
| IRQDBG("%s mask: 0x%08x irq: %d\n", __func__, mask,irq); |
| h720x_gpio_handler(mask, irq, desc); |
| } |
| |
| static void |
| h720x_gpiob_demux_handler(unsigned int irq_unused, struct irq_desc *desc) |
| { |
| unsigned int mask, irq; |
| mask = CPU_REG(GPIO_B_VIRT,GPIO_STAT); |
| irq = IRQ_CHAINED_GPIOB(0); |
| IRQDBG("%s mask: 0x%08x irq: %d\n", __func__, mask,irq); |
| h720x_gpio_handler(mask, irq, desc); |
| } |
| |
| static void |
| h720x_gpioc_demux_handler(unsigned int irq_unused, struct irq_desc *desc) |
| { |
| unsigned int mask, irq; |
| |
| mask = CPU_REG(GPIO_C_VIRT,GPIO_STAT); |
| irq = IRQ_CHAINED_GPIOC(0); |
| IRQDBG("%s mask: 0x%08x irq: %d\n", __func__, mask,irq); |
| h720x_gpio_handler(mask, irq, desc); |
| } |
| |
| static void |
| h720x_gpiod_demux_handler(unsigned int irq_unused, struct irq_desc *desc) |
| { |
| unsigned int mask, irq; |
| |
| mask = CPU_REG(GPIO_D_VIRT,GPIO_STAT); |
| irq = IRQ_CHAINED_GPIOD(0); |
| IRQDBG("%s mask: 0x%08x irq: %d\n", __func__, mask,irq); |
| h720x_gpio_handler(mask, irq, desc); |
| } |
| |
| #ifdef CONFIG_CPU_H7202 |
| static void |
| h720x_gpioe_demux_handler(unsigned int irq_unused, struct irq_desc *desc) |
| { |
| unsigned int mask, irq; |
| |
| mask = CPU_REG(GPIO_E_VIRT,GPIO_STAT); |
| irq = IRQ_CHAINED_GPIOE(0); |
| IRQDBG("%s mask: 0x%08x irq: %d\n", __func__, mask,irq); |
| h720x_gpio_handler(mask, irq, desc); |
| } |
| #endif |
| |
| static struct irq_chip h720x_global_chip = { |
| .irq_ack = mask_global_irq, |
| .irq_mask = mask_global_irq, |
| .irq_unmask = unmask_global_irq, |
| }; |
| |
| static struct irq_chip h720x_gpio_chip = { |
| .irq_ack = ack_gpio_irq, |
| .irq_mask = mask_gpio_irq, |
| .irq_unmask = unmask_gpio_irq, |
| }; |
| |
| /* |
| * Initialize IRQ's, mask all, enable multiplexed irq's |
| */ |
| void __init h720x_init_irq (void) |
| { |
| int irq; |
| |
| /* Mask global irq's */ |
| CPU_REG (IRQC_VIRT, IRQC_IER) = 0x0; |
| |
| /* Mask all multiplexed irq's */ |
| CPU_REG (GPIO_A_VIRT, GPIO_MASK) = 0x0; |
| CPU_REG (GPIO_B_VIRT, GPIO_MASK) = 0x0; |
| CPU_REG (GPIO_C_VIRT, GPIO_MASK) = 0x0; |
| CPU_REG (GPIO_D_VIRT, GPIO_MASK) = 0x0; |
| |
| /* Initialize global IRQ's, fast path */ |
| for (irq = 0; irq < NR_GLBL_IRQS; irq++) { |
| irq_set_chip_and_handler(irq, &h720x_global_chip, |
| handle_level_irq); |
| set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
| } |
| |
| /* Initialize multiplexed IRQ's, slow path */ |
| for (irq = IRQ_CHAINED_GPIOA(0) ; irq <= IRQ_CHAINED_GPIOD(31); irq++) { |
| irq_set_chip_and_handler(irq, &h720x_gpio_chip, |
| handle_edge_irq); |
| set_irq_flags(irq, IRQF_VALID ); |
| } |
| irq_set_chained_handler(IRQ_GPIOA, h720x_gpioa_demux_handler); |
| irq_set_chained_handler(IRQ_GPIOB, h720x_gpiob_demux_handler); |
| irq_set_chained_handler(IRQ_GPIOC, h720x_gpioc_demux_handler); |
| irq_set_chained_handler(IRQ_GPIOD, h720x_gpiod_demux_handler); |
| |
| #ifdef CONFIG_CPU_H7202 |
| for (irq = IRQ_CHAINED_GPIOE(0) ; irq <= IRQ_CHAINED_GPIOE(31); irq++) { |
| irq_set_chip_and_handler(irq, &h720x_gpio_chip, |
| handle_edge_irq); |
| set_irq_flags(irq, IRQF_VALID ); |
| } |
| irq_set_chained_handler(IRQ_GPIOE, h720x_gpioe_demux_handler); |
| #endif |
| |
| /* Enable multiplexed irq's */ |
| CPU_REG (IRQC_VIRT, IRQC_IER) = IRQ_ENA_MUX; |
| } |
| |
| static struct map_desc h720x_io_desc[] __initdata = { |
| { |
| .virtual = IO_VIRT, |
| .pfn = __phys_to_pfn(IO_PHYS), |
| .length = IO_SIZE, |
| .type = MT_DEVICE |
| }, |
| }; |
| |
| /* Initialize io tables */ |
| void __init h720x_map_io(void) |
| { |
| iotable_init(h720x_io_desc,ARRAY_SIZE(h720x_io_desc)); |
| } |
| |
| void h720x_restart(char mode, const char *cmd) |
| { |
| CPU_REG (PMU_BASE, PMU_STAT) |= PMU_WARMRESET; |
| } |
| |
| static void h720x__idle(void) |
| { |
| CPU_REG (PMU_BASE, PMU_MODE) = PMU_MODE_IDLE; |
| nop(); |
| nop(); |
| CPU_REG (PMU_BASE, PMU_MODE) = PMU_MODE_RUN; |
| nop(); |
| nop(); |
| } |
| |
| static int __init h720x_idle_init(void) |
| { |
| arm_pm_idle = h720x__idle; |
| return 0; |
| } |
| |
| arch_initcall(h720x_idle_init); |