Re: problem bring up initramfs and busybox

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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;

[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux