Finally, I figured out the problem. The main issue is in file irq.c, in which the register starting at CHNL_OFFSET() is not set correctly in big endian mode. With that problem, even though the serial port 8250 is generating interrupt, the interrupt controller blocks it. In big endian mode, the value written at line writel(i, REG(CHNL_OFFSET(i))); should be writel(i << 24, REG(CHNL_OFFSET(i))); I suspect this problem is applicable to AR7 running in big endian mode since my board is almost the same to AR7. I am attaching a patch for anyone's reference. Thanks to Florian, Kevin, Chris and Ralf for your advise. Best regards, Andrew On Thu, 26 Nov 2009 09:45 +0100, "Florian Fainelli" <florian@xxxxxxxxxxx> wrote: > Hi Andrew. > > Le jeudi 26 novembre 2009 01:24:13, myuboot@xxxxxxxxxxx a écrit : > > On Tue, 17 Nov 2009 20:03 -0500, "David VomLehn" <dvomlehn@xxxxxxxxx> > > > > wrote: > > > On Tue, Nov 17, 2009 at 06:58:35PM -0600, myuboot@xxxxxxxxxxx wrote: > > > > On Wed, 18 Nov 2009 01:39 +0100, "Florian Fainelli" > > > > > > > > <florian@xxxxxxxxxxx> wrote: > > > > > ------------------------------- > > > > > > > > Actually I already got this patch for the board in little endian mode, > > > > and it is still there for the big endian mode. And this is one of the > > > > place I have been wondering if that needs to be changed for big endian. > > > > > > It sounds like you've done a good job getting the bootloader and kernel > > > to work, so this may be a silly suggestion, but are you sure your root > > > filesystem and busybox are little-endian? It would be an easy mistake to > > > make... > > > > > > > thanks. Andrew > > > > > > David VL > > > > I have some clue on this issue now. It seems there is some problem with > > the serial console operating in interrupt mode. If the 8250 is in > > polling mode(set the IRQ for the 8250 serial port to 0), the output on > > the console is fine. But with 8250 in interrupt mode, 8250 serial driver > > does not receive any interrupt in serial8250_interrupt(). The same board > > works just fine when operating in little endian mode with interruption. > > I probably need to change something in IRQ initialization for big > > endian. I will post my solution when I can get it to work. In the > > meantime, any suggestion will be welcome. > > Do you need that patch to work in little-endian: > https://dev.openwrt.org/browser/trunk/target/linux/ar7/patches-2.6.30/500- > serial_kludge.patch ? If so, you are likely to need it in big-endian too > since > it works around a silicon issue. > -- > Best regards, Florian Fainelli > Email: florian@xxxxxxxxxxx > Web: http://openwrt.org > IRC: [florian] on irc.freenode.net > -------------------------------
--- irq.c 2009-09-21 19:24:30.000000000 -0500 +++ irq.c 2009-12-04 17:52:59.000000000 -0600 @@ -45,7 +45,8 @@ #define REG(addr) ((u32 *)(KSEG1ADDR(AR7_REGS_IRQ) + addr)) -#define CHNL_OFFSET(chnl) (CHNLS_OFFSET + (chnl * 4)) +#define CHNL_OFFSET(chnl) (CHNLS_OFFSET + (chnl * 4)) /* priority for interrupt chnl */ +#define LITTLE_TO_BIG_ENDIAN(i) (24-(i)/8*8 + ((i)%8)) /* convert the bit number from little to big endin within 32 bit*/ static void ar7_unmask_irq(unsigned int irq_nr); static void ar7_mask_irq(unsigned int irq_nr); @@ -78,35 +79,35 @@ static void ar7_unmask_irq(unsigned int irq) { - writel(1 << ((irq - ar7_irq_base) % 32), + writel(1<< LITTLE_TO_BIG_ENDIAN(irq - ar7_irq_base), REG(ESR_OFFSET(irq - ar7_irq_base))); } static void ar7_mask_irq(unsigned int irq) { - writel(1 << ((irq - ar7_irq_base) % 32), + writel(1<< LITTLE_TO_BIG_ENDIAN(irq - ar7_irq_base), REG(ECR_OFFSET(irq - ar7_irq_base))); } static void ar7_ack_irq(unsigned int irq) { - writel(1 << ((irq - ar7_irq_base) % 32), + writel(1<<LITTLE_TO_BIG_ENDIAN(irq - ar7_irq_base), REG(CR_OFFSET(irq - ar7_irq_base))); } static void ar7_unmask_sec_irq(unsigned int irq) { - writel(1 << (irq - ar7_irq_base - 40), REG(SEC_ESR_OFFSET)); + writel(1 << LITTLE_TO_BIG_ENDIAN(irq - ar7_irq_base - 40), REG(SEC_ESR_OFFSET)); } static void ar7_mask_sec_irq(unsigned int irq) { - writel(1 << (irq - ar7_irq_base - 40), REG(SEC_ECR_OFFSET)); + writel(1 << LITTLE_TO_BIG_ENDIAN(irq - ar7_irq_base - 40), REG(SEC_ECR_OFFSET)); } static void ar7_ack_sec_irq(unsigned int irq) { - writel(1 << (irq - ar7_irq_base - 40), REG(SEC_CR_OFFSET)); + writel(1 << LITTLE_TO_BIG_ENDIAN(irq - ar7_irq_base - 40), REG(SEC_CR_OFFSET)); } void __init arch_init_irq(void) @@ -123,16 +124,16 @@ * Disable interrupts and clear pending */ writel(0xffffffff, REG(ECR_OFFSET(0))); - writel(0xff, REG(ECR_OFFSET(32))); + writel(0xff000000, REG(ECR_OFFSET(32))); writel(0xffffffff, REG(SEC_ECR_OFFSET)); writel(0xffffffff, REG(CR_OFFSET(0))); - writel(0xff, REG(CR_OFFSET(32))); + writel(0xff000000, REG(CR_OFFSET(32))); writel(0xffffffff, REG(SEC_CR_OFFSET)); ar7_irq_base = base; for (i = 0; i < 40; i++) { - writel(i, REG(CHNL_OFFSET(i))); + writel(i<<24, REG(CHNL_OFFSET(i))); /* Primary IRQ's */ set_irq_chip_and_handler(base + i, &ar7_irq_type, handle_edge_irq); @@ -156,18 +157,18 @@ int i, irq; /* Primary IRQ's */ - irq = readl(REG(PIR_OFFSET)) & 0x3f; + irq = (readl(REG(PIR_OFFSET)) & 0x3f000000)>>24; if (irq) { do_IRQ(ar7_irq_base + irq); return; } /* Secondary IRQ's are cascaded through primary '0' */ - writel(1, REG(CR_OFFSET(irq))); + writel(0x01000000, REG(CR_OFFSET(irq))); status = readl(REG(SEC_SR_OFFSET)); for (i = 0; i < 32; i++) { if (status & 1) { - do_IRQ(ar7_irq_base + i + 40); + do_IRQ(ar7_irq_base + LITTLE_TO_BIG_ENDIAN(i) + 40); return; } status >>= 1;