Skip to content

Commit

Permalink
[ARM] S3C64XX: Map timer memory and interrupts
Browse files Browse the repository at this point in the history
Add the physical to virtual memory mapping and the
necessary interrupt demuxing for the PWM timer blocks.

Signed-off-by: Ben Dooks <ben-linux@fluff.org>
  • Loading branch information
Ben Dooks committed Dec 15, 2008
1 parent e550ae7 commit f982dc5
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 9 deletions.
3 changes: 2 additions & 1 deletion arch/arm/plat-s3c/include/plat/regs-timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
* S3C2410 Timer configuration
*/


#ifndef __ASM_ARCH_REGS_TIMER_H
#define __ASM_ARCH_REGS_TIMER_H

Expand All @@ -21,6 +20,8 @@
#define S3C2410_TCFG1 S3C_TIMERREG(0x04)
#define S3C2410_TCON S3C_TIMERREG(0x08)

#define S3C64XX_TINT_CSTAT S3C_TIMERREG(0x44)

#define S3C2410_TCFG_PRESCALER0_MASK (255<<0)
#define S3C2410_TCFG_PRESCALER1_MASK (255<<8)
#define S3C2410_TCFG_PRESCALER1_SHIFT (8)
Expand Down
6 changes: 5 additions & 1 deletion arch/arm/plat-s3c64xx/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,16 @@ static struct map_desc s3c_iodesc[] __initdata = {
.pfn = __phys_to_pfn(S3C64XX_PA_VIC1),
.length = SZ_16K,
.type = MT_DEVICE,
}, {
.virtual = S3C_VA_TIMER,
.pfn = __phys_to_pfn(S3C_PA_TIMER),
.length = SZ_16K,
.type = MT_DEVICE,
},
};

/* read cpu identification code */


void __init s3c64xx_init_io(struct map_desc *mach_desc, int size)
{
unsigned long idcode;
Expand Down
20 changes: 14 additions & 6 deletions arch/arm/plat-s3c64xx/include/plat/irqs.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,12 @@
#define IRQ_ARM_DMA S3C64XX_IRQ_VIC0(20)
#define IRQ_ARM_DMAS S3C64XX_IRQ_VIC0(21)
#define IRQ_KEYPAD S3C64XX_IRQ_VIC0(22)
#define IRQ_TIMER0 S3C64XX_IRQ_VIC0(23)
#define IRQ_TIMER1 S3C64XX_IRQ_VIC0(24)
#define IRQ_TIMER2 S3C64XX_IRQ_VIC0(25)
#define IRQ_TIMER0_VIC S3C64XX_IRQ_VIC0(23)
#define IRQ_TIMER1_VIC S3C64XX_IRQ_VIC0(24)
#define IRQ_TIMER2_VIC S3C64XX_IRQ_VIC0(25)
#define IRQ_WDT S3C64XX_IRQ_VIC0(26)
#define IRQ_TIMER3 S3C64XX_IRQ_VIC0(27)
#define IRQ_TIMER4 S3C64XX_IRQ_VIC0(28)
#define IRQ_TIMER3_VIC S3C64XX_IRQ_VIC0(27)
#define IRQ_TIMER4_VIC S3C64XX_IRQ_VIC0(28)
#define IRQ_LCD_FIFO S3C64XX_IRQ_VIC0(29)
#define IRQ_LCD_VSYNC S3C64XX_IRQ_VIC0(30)
#define IRQ_LCD_SYSTEM S3C64XX_IRQ_VIC0(31)
Expand Down Expand Up @@ -136,11 +136,19 @@
#define IRQ_TC IRQ_PENDN
#define IRQ_ADC S3C64XX_IRQ_VIC1(31)

#define S3C64XX_TIMER_IRQ(x) S3C_IRQ(64 + (x))

#define IRQ_TIMER0 S3C64XX_TIMER_IRQ(0)
#define IRQ_TIMER1 S3C64XX_TIMER_IRQ(1)
#define IRQ_TIMER2 S3C64XX_TIMER_IRQ(2)
#define IRQ_TIMER3 S3C64XX_TIMER_IRQ(3)
#define IRQ_TIMER4 S3C64XX_TIMER_IRQ(4)

/* Since the IRQ_EINT(x) are a linear mapping on current s3c64xx series
* we just defined them as an IRQ_EINT(x) macro from S3C_IRQ_EINT_BASE
* which we place after the pair of VICs. */

#define S3C_IRQ_EINT_BASE S3C_IRQ(64)
#define S3C_IRQ_EINT_BASE S3C_IRQ(64+5)

#define S3C_EINT(x) ((x) + S3C_IRQ_EINT_BASE)

Expand Down
87 changes: 86 additions & 1 deletion arch/arm/plat-s3c64xx/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,106 @@

#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>

#include <asm/hardware/vic.h>
#include <asm/irq.h>

#include <mach/map.h>
#include <plat/regs-timer.h>
#include <plat/cpu.h>

/* Timer interrupt handling */

static void s3c_irq_demux_timer(unsigned int base_irq, unsigned int sub_irq)
{
generic_handle_irq(sub_irq);
}

static void s3c_irq_demux_timer0(unsigned int irq, struct irq_desc *desc)
{
s3c_irq_demux_timer(irq, IRQ_TIMER0);
}

static void s3c_irq_demux_timer1(unsigned int irq, struct irq_desc *desc)
{
s3c_irq_demux_timer(irq, IRQ_TIMER1);
}

static void s3c_irq_demux_timer2(unsigned int irq, struct irq_desc *desc)
{
s3c_irq_demux_timer(irq, IRQ_TIMER2);
}

static void s3c_irq_demux_timer3(unsigned int irq, struct irq_desc *desc)
{
s3c_irq_demux_timer(irq, IRQ_TIMER3);
}

static void s3c_irq_demux_timer4(unsigned int irq, struct irq_desc *desc)
{
s3c_irq_demux_timer(irq, IRQ_TIMER4);
}

/* We assume the IRQ_TIMER0..IRQ_TIMER4 range is continuous. */

static void s3c_irq_timer_mask(unsigned int irq)
{
u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);

reg &= 0x1f; /* mask out pending interrupts */
reg &= ~(1 << (irq - IRQ_TIMER0));
__raw_writel(reg, S3C64XX_TINT_CSTAT);
}

static void s3c_irq_timer_unmask(unsigned int irq)
{
u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);

reg &= 0x1f; /* mask out pending interrupts */
reg |= 1 << (irq - IRQ_TIMER0);
__raw_writel(reg, S3C64XX_TINT_CSTAT);
}

static void s3c_irq_timer_ack(unsigned int irq)
{
u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);

reg &= 0x1f;
reg |= (1 << 5) << (irq - IRQ_TIMER0);
__raw_writel(reg, S3C64XX_TINT_CSTAT);
}

static struct irq_chip s3c_irq_timer = {
.name = "s3c-timer",
.mask = s3c_irq_timer_mask,
.unmask = s3c_irq_timer_unmask,
.ack = s3c_irq_timer_ack,
};

void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
{
int irq;

printk(KERN_INFO "%s: initialising interrupts\n", __func__);

/* initialise the pair of VICs */
vic_init(S3C_VA_VIC0, S3C_VIC0_BASE, vic0_valid);
vic_init(S3C_VA_VIC1, S3C_VIC1_BASE, vic1_valid);

/* add the timer sub-irqs */

set_irq_chained_handler(IRQ_TIMER0_VIC, s3c_irq_demux_timer0);
set_irq_chained_handler(IRQ_TIMER1_VIC, s3c_irq_demux_timer1);
set_irq_chained_handler(IRQ_TIMER2_VIC, s3c_irq_demux_timer2);
set_irq_chained_handler(IRQ_TIMER3_VIC, s3c_irq_demux_timer3);
set_irq_chained_handler(IRQ_TIMER4_VIC, s3c_irq_demux_timer4);

for (irq = IRQ_TIMER0; irq <= IRQ_TIMER4; irq++) {
set_irq_chip(irq, &s3c_irq_timer);
set_irq_handler(irq, handle_level_irq);
set_irq_flags(irq, IRQF_VALID);
}
}


0 comments on commit f982dc5

Please sign in to comment.