diff options
Diffstat (limited to 'arch/arm/plat-s3c24xx/irq.c')
-rw-r--r-- | arch/arm/plat-s3c24xx/irq.c | 52 |
1 files changed, 51 insertions, 1 deletions
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c index 963f7a4f26f2..a5040b163c18 100644 --- a/arch/arm/plat-s3c24xx/irq.c +++ b/arch/arm/plat-s3c24xx/irq.c @@ -253,6 +253,9 @@ s3c_irqext_type(unsigned int irq, unsigned int type) void __iomem *gpcon_reg; unsigned long gpcon_offset, extint_offset; unsigned long newvalue = 0, value; +#if defined(CONFIG_CPU_S3C2443) + unsigned int t; +#endif if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3)) { @@ -322,6 +325,49 @@ s3c_irqext_type(unsigned int irq, unsigned int type) } value = __raw_readl(extint_reg); + + /* According to Samsung's document 'S3C2443 guide to extra gpio' + * several registers (including EXTINT0-2) must use a precompiled + * function for read access. We don't have the original code but + * we have seen the following behavior in U-Boot: + * EXTINT0: + * 1. Read values are given in big endian (at nibble level): + * a read value of 0x00001234 is really 0x43210000. + * 2. The read value does not return the LSB: + * after writing 0xffffffff value read is 0x7fffffff. + * EXTINT1/2: + * 1. Read values are given in big endian (at nibble level) + * and bits at nibble level suffer a 1 bit rotation to the left: + * after writing 0x12488822 value read is 0x44111842 + */ +#if defined(CONFIG_CPU_S3C2443) + t = (value & 0x0000000f) << 28; + t |= (value & 0x000000f0) << 20; + t |= (value & 0x00000f00) << 12; + t |= (value & 0x0000f000) << 4; + t |= (value & 0x000f0000) >> 4; + t |= (value & 0x00f00000) >> 12; + t |= (value & 0x0f000000) >> 20; + t |= (value & 0xf0000000) >> 28; + value = t; + + if (S3C24XX_EXTINT1 == extint_reg || + S3C24XX_EXTINT2 == extint_reg) { + /* Swap bits in nibbles */ + unsigned char old_n, new_n; + int i; + + t = 0; + for (i=0; i < 8; i++) { + old_n = (value & (0xf << (4*i))) >> (4*i); + new_n = ((old_n & 0xe) >> 1); + if (old_n & 0x1) + new_n |= 0x8; + t |= new_n << (4*i); + } + value = t; + } +#endif /* CONFIG_CPU_S3C2443 */ value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); __raw_writel(value, extint_reg); @@ -729,7 +775,6 @@ void __init s3c24xx_init_irq(void) } /* setup the cascade irq handlers */ - set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7); set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8); @@ -786,5 +831,10 @@ void __init s3c24xx_init_irq(void) set_irq_flags(irqno, IRQF_VALID); } + /* Register CF/ATA interrupt */ + set_irq_chip(IRQ_S3C2443_CFCON, &s3c_irq_level_chip); + set_irq_handler(IRQ_S3C2443_CFCON, handle_level_irq); + set_irq_flags(IRQ_S3C2443_CFCON, IRQF_VALID); + irqdbf("s3c2410: registered interrupt handlers\n"); } |