mpc83xx: Store and display Arbiter Event Register values

Record the Arbiter Event Register values and optionally display them.

The Arbiter Event Register can record the type and effective address of
an arbiter error, even through an HRESET. This patch stores the values in
the global data structure.

Display of the Arbiter Event registers immediately after the RSR value
can be enabled with defines. The Arbiter values will only be displayed
if an arbiter event has occured since the last Power On Reset, and either
of the following defines exist:
 #define CONFIG_DISPLAY_AER_BRIEF - display only the arbiter address and
                                    and type register values
 #define CONFIG_DISPLAY_AER_FULL  - display and interpret the arbiter
                                    event register values

Address Only transactions are one of the trapped events that can register
as an arbiter event. They occur with some cache manipulation instructions
if the HID0_ABE (Address Broadcast Enable) is set and the memory region
has the MEMORY_COHERENCE WIMG bit set. Setting:
 #define CONFIG_MASK_AER_AO - prevents the arbiter from recording address
                              only events, so that it can still capture
                              other real problems.

Signed-off-by: Nick Spence <nick.spence@freescale.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
diff --git a/cpu/mpc83xx/cpu_init.c b/cpu/mpc83xx/cpu_init.c
index 4514dbb..ff01cf1 100644
--- a/cpu/mpc83xx/cpu_init.c
+++ b/cpu/mpc83xx/cpu_init.c
@@ -167,6 +167,10 @@
 	gd->reset_status = im->reset.rsr;
 	im->reset.rsr = ~(RSR_RES);
 
+	/* AER - Arbiter Event Register - store status */
+	gd->arbiter_event_attributes = im->arbiter.aeatr;
+	gd->arbiter_event_address = im->arbiter.aeadr;
+
 	/*
 	 * RMR - Reset Mode Register
 	 * contains checkstop reset enable (4.6.1.4)
@@ -303,6 +307,130 @@
 }
 
 /*
+ * Print out the bus arbiter event
+ */
+#if defined(CONFIG_DISPLAY_AER_FULL)
+static int print_83xx_arb_event(int force)
+{
+	static char* event[] = {
+		"Address Time Out",
+		"Data Time Out",
+		"Address Only Transfer Type",
+		"External Control Word Transfer Type",
+		"Reserved Transfer Type",
+		"Transfer Error",
+		"reserved",
+		"reserved"
+	};
+	static char* master[] = {
+		"e300 Core Data Transaction",
+		"reserved",
+		"e300 Core Instruction Fetch",
+		"reserved",
+		"TSEC1",
+		"TSEC2",
+		"USB MPH",
+		"USB DR",
+		"Encryption Core",
+		"I2C Boot Sequencer",
+		"JTAG",
+		"reserved",
+		"eSDHC",
+		"PCI1",
+		"PCI2",
+		"DMA",
+		"QUICC Engine 00",
+		"QUICC Engine 01",
+		"QUICC Engine 10",
+		"QUICC Engine 11",
+		"reserved",
+		"reserved",
+		"reserved",
+		"reserved",
+		"SATA1",
+		"SATA2",
+		"SATA3",
+		"SATA4",
+		"reserved",
+		"PCI Express 1",
+		"PCI Express 2",
+		"TDM-DMAC"
+	};
+	static char *transfer[] = {
+		"Address-only, Clean Block",
+		"Address-only, lwarx reservation set",
+		"Single-beat or Burst write",
+		"reserved",
+		"Address-only, Flush Block",
+		"reserved",
+		"Burst write",
+		"reserved",
+		"Address-only, sync",
+		"Address-only, tlbsync",
+		"Single-beat or Burst read",
+		"Single-beat or Burst read",
+		"Address-only, Kill Block",
+		"Address-only, icbi",
+		"Burst read",
+		"reserved",
+		"Address-only, eieio",
+		"reserved",
+		"Single-beat write",
+		"reserved",
+		"ecowx - Illegal single-beat write",
+		"reserved",
+		"reserved",
+		"reserved",
+		"Address-only, TLB Invalidate",
+		"reserved",
+		"Single-beat or Burst read",
+		"reserved",
+		"eciwx - Illegal single-beat read",
+		"reserved",
+		"Burst read",
+		"reserved"
+	};
+
+	int etype = (gd->arbiter_event_attributes & AEATR_EVENT)
+	            >> AEATR_EVENT_SHIFT;
+	int mstr_id = (gd->arbiter_event_attributes & AEATR_MSTR_ID)
+	              >> AEATR_MSTR_ID_SHIFT;
+	int tbst = (gd->arbiter_event_attributes & AEATR_TBST)
+	           >> AEATR_TBST_SHIFT;
+	int tsize = (gd->arbiter_event_attributes & AEATR_TSIZE)
+	            >> AEATR_TSIZE_SHIFT;
+	int ttype = (gd->arbiter_event_attributes & AEATR_TTYPE)
+	            >> AEATR_TTYPE_SHIFT;
+
+	if (!force && !gd->arbiter_event_address)
+		return 0;
+
+	puts("Arbiter Event Status:\n");
+	printf("       Event Address: 0x%08lX\n", gd->arbiter_event_address);
+	printf("       Event Type:    0x%1x  = %s\n", etype, event[etype]);
+	printf("       Master ID:     0x%02x = %s\n", mstr_id, master[mstr_id]);
+	printf("       Transfer Size: 0x%1x  = %d bytes\n", (tbst<<3) | tsize,
+				tbst ? (tsize ? tsize : 8) : 16 + 8 * tsize);
+	printf("       Transfer Type: 0x%02x = %s\n", ttype, transfer[ttype]);
+
+	return gd->arbiter_event_address;
+}
+
+#elif defined(CONFIG_DISPLAY_AER_BRIEF)
+
+static int print_83xx_arb_event(int force)
+{
+	if (!force && !gd->arbiter_event_address)
+		return 0;
+
+	printf("Arbiter Event Status: AEATR=0x%08lX, AEADR=0x%08lX\n",
+		gd->arbiter_event_attributes, gd->arbiter_event_address);
+
+	return gd->arbiter_event_address;
+}
+#endif /* CONFIG_DISPLAY_AER_xxxx */
+
+/*
  * Figure out the cause of the reset
  */
 int prt_83xx_rsr(void)
@@ -334,6 +462,12 @@
 			printf("%s%s", sep, bits[i].desc);
 			sep = ", ";
 		}
-	puts("\n\n");
+	puts("\n");
+
+#if defined(CONFIG_DISPLAY_AER_FULL) || defined(CONFIG_DISPLAY_AER_BRIEF)
+	print_83xx_arb_event(rsr & RSR_BMRS);
+#endif
+	puts("\n");
+
 	return 0;
 }
diff --git a/cpu/mpc83xx/start.S b/cpu/mpc83xx/start.S
index 75ad36c..e452bfb 100644
--- a/cpu/mpc83xx/start.S
+++ b/cpu/mpc83xx/start.S
@@ -483,6 +483,17 @@
 1:
 #endif /* CONFIG_WATCHDOG */
 
+#if defined(CONFIG_MASK_AER_AO)
+	/* Write the Arbiter Event Enable to mask Address Only traps. */
+	/* This prevents the dcbz instruction from being trapped when */
+	/* HID0_ABE Address Broadcast Enable is set and the MEMORY    */
+	/* COHERENCY bit is set in the WIMG bits, which is often      */
+	/* needed for PCI operation.                                  */
+	lwz	r4, 0x0808(r3)
+	rlwinm	r0, r4, 0, ~AER_AO
+	stw	r0, 0x0808(r3)
+#endif /* CONFIG_MASK_AER_AO */
+
 	/* Initialize the Hardware Implementation-dependent Registers */
 	/* HID0 also contains cache control			*/
 	/*------------------------------------------------------*/
diff --git a/include/asm-ppc/global_data.h b/include/asm-ppc/global_data.h
index c09b07d..a9366c3 100644
--- a/include/asm-ppc/global_data.h
+++ b/include/asm-ppc/global_data.h
@@ -122,6 +122,10 @@
 	phys_size_t	ram_size;	/* RAM size */
 	unsigned long	reloc_off;	/* Relocation Offset */
 	unsigned long	reset_status;	/* reset status register at boot	*/
+#if defined(CONFIG_MPC83XX)
+	unsigned long	arbiter_event_attributes;
+	unsigned long	arbiter_event_address;
+#endif
 	unsigned long	env_addr;	/* Address  of Environment struct	*/
 	unsigned long	env_valid;	/* Checksum of Environment valid?	*/
 	unsigned long	have_console;	/* serial_init() was called		*/