p2020ds: add alternate boot bank support using the ngPIXIS FPGA

The Freescale P2020DS board uses a new type of PIXIS FPGA, called the ngPIXIS.
The ngPIXIS has one distinct new feature: the values of the on-board switches
can be selectively overridden with shadow registers.  This feature is used to
boot from a different NOR flash bank, instead of having a register dedicated
for this purpose.  Because the ngPIXIS is so different from the previous PIXIS,
a new file is introduced: ngpixis.c.

Also update the P2020DS checkboard() function to use the new macros defined
in the header file.

Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
diff --git a/board/freescale/common/Makefile b/board/freescale/common/Makefile
index 02a824d..620eb16 100644
--- a/board/freescale/common/Makefile
+++ b/board/freescale/common/Makefile
@@ -33,6 +33,7 @@
 COBJS-${CONFIG_FSL_VIA}		+= cds_via.o
 COBJS-${CONFIG_FSL_DIU_FB}	+= fsl_diu_fb.o fsl_logo_bmp.o
 COBJS-${CONFIG_FSL_PIXIS}	+= pixis.o
+COBJS-${CONFIG_FSL_NGPIXIS}	+= ngpixis.o
 COBJS-${CONFIG_PQ_MDS_PIB}	+= pq-mds-pib.o
 COBJS-${CONFIG_ID_EEPROM}	+= sys_eeprom.o
 COBJS-${CONFIG_FSL_SGMII_RISER}	+= sgmii_riser.o
diff --git a/board/freescale/common/ngpixis.c b/board/freescale/common/ngpixis.c
new file mode 100644
index 0000000..bb6794e
--- /dev/null
+++ b/board/freescale/common/ngpixis.c
@@ -0,0 +1,136 @@
+/**
+ * Copyright 2010 Freescale Semiconductor
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This file provides support for the ngPIXIS, a board-specific FPGA used on
+ * some Freescale reference boards.
+ *
+ * A "switch" is black rectangular block on the motherboard.  It contains
+ * eight "bits".  The ngPIXIS has a set of memory-mapped registers (SWx) that
+ * shadow the actual physical switches.  There is also another set of
+ * registers (ENx) that tell the ngPIXIS which bits of SWx should actually be
+ * used to override the values of the bits in the physical switches.
+ *
+ * The following macros need to be defined:
+ *
+ * PIXIS_BASE - The virtual address of the base of the PIXIS register map
+ *
+ * PIXIS_LBMAP_SWITCH - The switch number (i.e. the "x" in "SWx"). This value
+ *    is used in the PIXIS_SW() macro to determine which offset in
+ *    the PIXIS register map corresponds to the physical switch that controls
+ *    the boot bank.
+ *
+ * PIXIS_LBMAP_MASK - A bit mask the defines which bits in SWx to use.
+ *
+ * PIXIS_LBMAP_SHIFT - The shift value that corresponds to PIXIS_LBMAP_MASK.
+ *
+ * PIXIS_LBMAP_ALTBANK - The value to program into SWx to tell the ngPIXIS to
+ *    boot from the alternate bank.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <watchdog.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+
+#include "ngpixis.h"
+
+/*
+ * Reset the board. This ignores the ENx registers.
+ */
+void pixis_reset(void)
+{
+	out_8(&pixis->rst, 0);
+
+	while (1);
+}
+
+/*
+ * Reset the board.  Like pixis_reset(), but it honors the ENx registers.
+ */
+void pixis_bank_reset(void)
+{
+	out_8(&pixis->vctl, 0);
+	out_8(&pixis->vctl, 1);
+
+	while (1);
+}
+
+/**
+ * Set the boot bank to the power-on default bank
+ */
+void clear_altbank(void)
+{
+	/* Tell the ngPIXIS to use this the bits in the physical switch for the
+	 * boot bank value, instead of the SWx register.  We need to be careful
+	 * only to set the bits in SWx that correspond to the boot bank.
+	 */
+	clrbits_8(&PIXIS_EN(PIXIS_LBMAP_SWITCH), PIXIS_LBMAP_MASK);
+}
+
+/**
+ * Set the boot bank to the alternate bank
+ */
+void set_altbank(void)
+{
+	/* Program the alternate bank number into the SWx register.
+	 */
+	clrsetbits_8(&PIXIS_SW(PIXIS_LBMAP_SWITCH), PIXIS_LBMAP_MASK,
+		     PIXIS_LBMAP_ALTBANK);
+
+	/* Tell the ngPIXIS to use this the bits in the SWx register for the
+	 * boot bank value, instead of the physical switch.  We need to be
+	 * careful only to set the bits in SWx that correspond to the boot bank.
+	 */
+	setbits_8(&PIXIS_EN(PIXIS_LBMAP_SWITCH), PIXIS_LBMAP_MASK);
+}
+
+
+int pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	unsigned int i;
+	char *p_altbank = NULL;
+	char *unknown_param = NULL;
+
+	/* No args is a simple reset request.
+	 */
+	if (argc <= 1)
+		pixis_reset();
+
+	for (i = 1; i < argc; i++) {
+		if (strcmp(argv[i], "altbank") == 0) {
+			p_altbank = argv[i];
+			continue;
+		}
+
+		unknown_param = argv[i];
+	}
+
+	if (unknown_param) {
+		printf("Invalid option: %s\n", unknown_param);
+		return 1;
+	}
+
+	if (p_altbank)
+		set_altbank();
+	else
+		clear_altbank();
+
+	pixis_bank_reset();
+
+	/* Shouldn't be reached. */
+	return 0;
+}
+
+U_BOOT_CMD(
+	pixis_reset, CONFIG_SYS_MAXARGS, 1, pixis_reset_cmd,
+	"Reset the board using the FPGA sequencer",
+	"- hard reset to default bank\n"
+	"pixis_reset altbank - reset to alternate bank\n"
+	);
diff --git a/board/freescale/common/ngpixis.h b/board/freescale/common/ngpixis.h
new file mode 100644
index 0000000..284d044
--- /dev/null
+++ b/board/freescale/common/ngpixis.h
@@ -0,0 +1,57 @@
+/**
+ * Copyright 2010 Freescale Semiconductor
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This file provides support for the ngPIXIS, a board-specific FPGA used on
+ * some Freescale reference boards.
+ */
+
+/* ngPIXIS register set. Hopefully, this won't change too much over time.
+ * Feel free to add board-specific #ifdefs where necessary.
+ */
+typedef struct ngpixis {
+	u8 id;
+	u8 arch;
+	u8 scver;
+	u8 csr;
+	u8 rst;
+	u8 res1;
+	u8 aux;
+	u8 spd;
+	u8 brdcfg0;
+	u8 dma;
+	u8 addr;
+	u8 res2[2];
+	u8 data;
+	u8 led;
+	u8 res3;
+	u8 vctl;
+	u8 vstat;
+	u8 vcfgen0;
+	u8 res4;
+	u8 ocmcsr;
+	u8 ocmmsg;
+	u8 gmdbg;
+	u8 res5[2];
+	u8 sclk[3];
+	u8 dclk[3];
+	u8 watch;
+	struct {
+		u8 sw;
+		u8 en;
+	} s[8];
+} ngpixis_t  __attribute__ ((aligned(1)));
+
+/* Pointer to the PIXIS register set */
+#define pixis ((ngpixis_t *)PIXIS_BASE)
+
+/* The PIXIS SW register that corresponds to board switch X, where x >= 1 */
+#define PIXIS_SW(x)		(pixis->s[(x) - 1].sw)
+
+/* The PIXIS EN register that corresponds to board switch X, where x >= 1 */
+#define PIXIS_EN(x)		(pixis->s[(x) - 1].en)
diff --git a/board/freescale/p2020ds/p2020ds.c b/board/freescale/p2020ds/p2020ds.c
index 664135c..f0ff209 100644
--- a/board/freescale/p2020ds/p2020ds.c
+++ b/board/freescale/p2020ds/p2020ds.c
@@ -38,6 +38,7 @@
 #include <asm/mp.h>
 #include <netdev.h>
 
+#include "../common/ngpixis.h"
 #include "../common/sgmii_riser.h"
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -46,30 +47,24 @@
 
 int checkboard(void)
 {
-	u8 sw7;
-	u8 *pixis_base = (u8 *)PIXIS_BASE;
+	u8 sw;
 
 	puts("Board: P2020DS ");
 #ifdef CONFIG_PHYS_64BIT
 	puts("(36-bit addrmap) ");
 #endif
 
-	printf("Sys ID: 0x%02x, "
-		"Sys Ver: 0x%02x, FPGA Ver: 0x%02x, ",
-		in_8(pixis_base + PIXIS_ID), in_8(pixis_base + PIXIS_VER),
-		in_8(pixis_base + PIXIS_PVER));
+	printf("Sys ID: 0x%02x, Sys Ver: 0x%02x, FPGA Ver: 0x%02x, ",
+		in_8(&pixis->id), in_8(&pixis->arch), in_8(&pixis->scver));
 
-	sw7 = in_8(pixis_base + PIXIS_SW(7));
-	switch ((sw7 & PIXIS_SW7_LBMAP) >> 6) {
-		case 0:
-		case 1:
-			printf ("vBank: %d\n", ((sw7 & PIXIS_SW7_VBANK) >> 4));
-			break;
-		case 2:
-		case 3:
-			puts ("Promjet\n");
-			break;
-	}
+	sw = in_8(&PIXIS_SW(PIXIS_LBMAP_SWITCH));
+	sw = (sw & PIXIS_LBMAP_MASK) >> PIXIS_LBMAP_SHIFT;
+
+	if (sw < 0x8)
+		/* The lower two bits are the actual vbank number */
+		printf("vBank: %d\n", sw & 3);
+	else
+		puts("Promjet\n");
 
 	return 0;
 }
@@ -370,30 +365,22 @@
 	return gd->mem_clk;
 }
 
-unsigned long
-calculate_board_sys_clk(ulong dummy)
+unsigned long calculate_board_sys_clk(ulong dummy)
 {
 	ulong val;
-	u8 *pixis_base = (u8 *)PIXIS_BASE;
 
-	val = ics307_clk_freq(
-	    in_8(pixis_base + PIXIS_VSYSCLK0),
-	    in_8(pixis_base + PIXIS_VSYSCLK1),
-	    in_8(pixis_base + PIXIS_VSYSCLK2));
+	val = ics307_clk_freq(in_8(&pixis->sclk[0]), in_8(&pixis->sclk[1]),
+			      in_8(&pixis->sclk[2]));
 	debug("sysclk val = %lu\n", val);
 	return val;
 }
 
-unsigned long
-calculate_board_ddr_clk(ulong dummy)
+unsigned long calculate_board_ddr_clk(ulong dummy)
 {
 	ulong val;
-	u8 *pixis_base = (u8 *)PIXIS_BASE;
 
-	val = ics307_clk_freq(
-	    in_8(pixis_base + PIXIS_VDDRCLK0),
-	    in_8(pixis_base + PIXIS_VDDRCLK1),
-	    in_8(pixis_base + PIXIS_VDDRCLK2));
+	val = ics307_clk_freq(in_8(&pixis->dclk[0]), in_8(&pixis->dclk[1]),
+			      in_8(&pixis->dclk[2]));
 	debug("ddrclk val = %lu\n", val);
 	return val;
 }
@@ -402,9 +389,8 @@
 {
 	u8 i;
 	ulong val = 0;
-	u8 *pixis_base = (u8 *)PIXIS_BASE;
 
-	i = in_8(pixis_base + PIXIS_SPD);
+	i = in_8(&pixis->spd);
 	i &= 0x07;
 
 	switch (i) {
@@ -441,9 +427,8 @@
 {
 	u8 i;
 	ulong val = 0;
-	u8 *pixis_base = (u8 *)PIXIS_BASE;
 
-	i = in_8(pixis_base + PIXIS_SPD);
+	i = in_8(&pixis->spd);
 	i &= 0x38;
 	i >>= 3;