QCA provided 32M support for board956x.

This is raw version QCA patched for board956x to support 32M.
Keep it untouchd in the CL.

Change-Id: I0097c3683133f8f438ad2d8fdbd8ab2f1c458011
diff --git a/board/atheros/common/ath_flash.c b/board/atheros/common/ath_flash.c
index ee4bf1d..e89c89b 100755
--- a/board/atheros/common/ath_flash.c
+++ b/board/atheros/common/ath_flash.c
@@ -25,6 +25,10 @@
 #	define	ath_spi_flash_print_info	flash_print_info
 #endif
 
+#if ENABLE_EXT_ADDR_SUPPORT
+/* for legacy flash only support 16M */
+#define LEGACY_SPI_ADDR_BOUNDARY 0x1000000
+#endif
 /*
  * globals
  */
@@ -40,6 +44,11 @@
 #endif
 static void ath_spi_sector_erase(uint32_t addr);
 
+#if ENABLE_EXT_ADDR_SUPPORT
+static void ath_spi_wrear(uint32_t data);
+static uchar ath_spi_rdear(void);
+#endif
+
 static void
 ath_spi_read_id(void)
 {
@@ -141,11 +150,10 @@
 }
 
 int
-write_buff(flash_info_t *info, uchar *src, ulong dst, ulong len)
+ath_write_buff(flash_info_t *info, uchar *src, ulong dst, ulong len)
 {
 	uint32_t val;
 
-	dst = dst - CFG_FLASH_BASE;
 	printf("write len: %lu dst: 0x%x src: %p\n", len, dst, src);
 
 	for (; len; len--, dst++, src++) {
@@ -174,14 +182,13 @@
 }
 #else
 int
-write_buff(flash_info_t *info, uchar *source, ulong addr, ulong len)
+ath_write_buff(flash_info_t *info, uchar *source, ulong addr, ulong len)
 {
 	int total = 0, len_this_lp, bytes_this_page;
 	ulong dst;
 	uchar *src;
 
 	printf("write addr: %x\n", addr);
-	addr = addr - CFG_FLASH_BASE;
 
 	while (total < len) {
 		src = source + total;
@@ -201,6 +208,75 @@
 }
 #endif
 
+int
+write_buff(flash_info_t *info, uchar *source, ulong addr, ulong len)
+{
+	return(ath_write_buff(info, source, addr - CFG_FLASH_BASE, len));
+}
+
+#if ENABLE_EXT_ADDR_SUPPORT
+int
+read_buff_ext(flash_info_t *info, uchar *buf, ulong offset, ulong len)
+{
+	ulong    i = 0;
+	uint32_t curr_addr = offset;
+	uint32_t ori_ear = (uint32_t)ath_spi_rdear();
+	uint32_t new_ear;
+
+	while (i < len) {
+		new_ear = curr_addr >> 24;
+		ath_spi_wrear(new_ear);
+		ath_spi_write_enable();
+		ath_spi_bit_banger(ATH_SPI_CMD_READ);
+		ath_spi_send_addr(curr_addr);
+		do {
+			ath_spi_delay_8();
+			*(buf + i++) = (uchar) (ath_reg_rd(ATH_SPI_RD_STATUS));
+			/* Update the extended adress update if it's a multiple of 16M */
+			if (!((++ curr_addr) & (LEGACY_SPI_ADDR_BOUNDARY - 1))) {
+				break;
+			}
+		} while (i < len);
+		ath_spi_go();
+	}
+	if (new_ear != ori_ear) {
+		ath_spi_wrear(ori_ear);
+	}
+	ath_spi_done();
+	return 0;
+}
+
+int
+write_buff_ext(flash_info_t *info, uchar *source, ulong offset, ulong len)
+{
+	int      status;
+	uint32_t ori_ear = (uint32_t)ath_spi_rdear();
+	uint32_t new_ear = 0;
+	uint32_t curr_addr = offset;
+	uint32_t bytes_this_16M, total = 0;
+
+	while (len) {
+		new_ear = curr_addr >> 24;
+		ath_spi_wrear(new_ear);
+		bytes_this_16M = LEGACY_SPI_ADDR_BOUNDARY - curr_addr % LEGACY_SPI_ADDR_BOUNDARY;
+		bytes_this_16M = (bytes_this_16M < len) ? bytes_this_16M : len;
+		if((status = ath_write_buff(info, source + total, curr_addr, bytes_this_16M)) != ERR_OK) {
+			printf("failed to write 0x%x bytes to 0x%x\n", bytes_this_16M, curr_addr);
+			break;
+		}
+		curr_addr += bytes_this_16M;
+		total += bytes_this_16M;
+		len -= bytes_this_16M;
+	}
+	if (new_ear != ori_ear) {
+		ath_spi_wrear(ori_ear);
+	}
+	ath_spi_done();
+
+	return(status);
+}
+#endif /* #if ENABLE_EXT_ADDR_SUPPORT */
+
 static void
 ath_spi_write_enable()
 {
@@ -219,10 +295,40 @@
 		ath_reg_wr_nf(ATH_SPI_WRITE, ATH_SPI_CS_DIS);
 		ath_spi_bit_banger(ATH_SPI_CMD_RD_STATUS);
 		ath_spi_delay_8();
+		// Back ported bug fix, always write CE_LOW, CS_DIS before poll.
+		ath_spi_go();
 		rd = (ath_reg_rd(ATH_SPI_RD_STATUS) & 1);
 	} while (rd);
 }
 
+#if ENABLE_EXT_ADDR_SUPPORT
+static void
+ath_spi_wrear(uint32_t data)
+{
+	ath_spi_write_enable();
+	ath_spi_bit_banger(ATH_SPI_CMD_WREAR);
+	ath_spi_bit_banger((uchar)data);
+	ath_spi_go();
+
+	ath_spi_poll();
+}
+
+static uchar
+ath_spi_rdear(void)
+{
+	uchar data;
+
+	ath_spi_write_enable();
+	ath_spi_bit_banger(ATH_SPI_CMD_RDEAR);
+	ath_spi_delay_8();
+	ath_spi_go();
+	data = (uchar)(ath_reg_rd(ATH_SPI_RD_STATUS));
+	ath_spi_poll();
+	return(data);
+}
+
+#endif /* #if ENABLE_EXT_ADDR_SUPPORT */
+
 #if !defined(ATH_SST_FLASH)
 static void
 ath_spi_write_page(uint32_t addr, uint8_t *data, int len)
@@ -250,12 +356,24 @@
 static void
 ath_spi_sector_erase(uint32_t addr)
 {
+#if ENABLE_EXT_ADDR_SUPPORT
+	uint32_t ori_ear = (uint32_t)ath_spi_rdear();
+	uint32_t new_ear = addr >> 24;
+
+	if(new_ear != ori_ear)
+		ath_spi_wrear(new_ear);
+#endif
 	ath_spi_write_enable();
 	ath_spi_bit_banger(ATH_SPI_CMD_SECTOR_ERASE);
 	ath_spi_send_addr(addr);
 	ath_spi_go();
 	display(0x7d);
 	ath_spi_poll();
+#if ENABLE_EXT_ADDR_SUPPORT
+	/* recover extended address register */
+	if(new_ear != ori_ear)
+		ath_spi_wrear(ori_ear);
+#endif
 }
 
 #ifdef ATH_DUAL_FLASH
diff --git a/common/cmd_flash.c b/common/cmd_flash.c
index ecc10b5..6a5263c 100755
--- a/common/cmd_flash.c
+++ b/common/cmd_flash.c
@@ -307,6 +307,106 @@
 }
 #endif /* #ifndef COMPRESSED_UBOOT */
 
+#if ENABLE_EXT_ADDR_SUPPORT
+int do_flread_ext (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	flash_info_t *info;
+	ulong buf, offset, len;
+	int   bank = 1;
+
+	if (argc < 4) {
+		printf ("Usage:\n%s\n%s\n", cmdtp->usage, cmdtp->help);
+		return 1;
+	}
+	buf = simple_strtoul(argv[1], NULL, 16);
+	offset = simple_strtoul(argv[2], NULL, 16);
+	len = simple_strtoul(argv[3], NULL, 16);
+	if (argc > 4) {
+		bank = simple_strtoul(argv[4], NULL, 16);
+		if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
+			printf ("Only FLASH Banks # 1 ... # %d supported\n",
+			CFG_MAX_FLASH_BANKS);
+			return 1;
+		}
+	}
+	info = &flash_info[bank - 1];
+
+	if ((offset + len) > info->size){
+		printf ("Bad parameters, 'offset' + 'len' should < 0x%x\n", info->size);
+		return 1;
+	}
+	return(read_buff_ext(info, (uchar *)buf, offset, len));
+}
+
+int do_flwrite_ext (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+    flash_info_t *info;
+    ulong source, offset, len;
+	int   bank = 1;
+
+    if (argc < 4) {
+        printf ("Usage:\n%s\n%s\n", cmdtp->usage, cmdtp->help);
+		return 1;
+	}
+	source = simple_strtoul(argv[1], NULL, 16);
+	offset = simple_strtoul(argv[2], NULL, 16);
+	len = simple_strtoul(argv[3], NULL, 16);
+	if (argc > 4) {
+		bank = simple_strtoul(argv[4], NULL, 16);
+		if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
+			printf ("Only FLASH Banks # 1 ... # %d supported\n",
+			CFG_MAX_FLASH_BANKS);
+			return 1;
+		}
+	}
+
+	info = &flash_info[bank - 1];
+	if ((offset + len) > info->size){
+		printf ("Bad parameters, 'offset' + 'len' should < 0x%x\n", info->size);
+	    return 1;
+	}
+
+	return(write_buff_ext(info, (uchar *)source, offset, len));
+}
+
+int do_flerase_ext (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	flash_info_t *info;
+	ulong offset, len;
+	int sect_first, sect_last, sect_size;
+	int   bank = 1;
+
+    if (argc < 3) {
+	     printf ("Usage:\n%s\n%s\n", cmdtp->usage, cmdtp->help);
+	     return 1;
+	}
+	offset = simple_strtoul(argv[1], NULL, 16);
+	len = simple_strtoul(argv[2], NULL, 16);
+
+	if (argc > 4) {
+		bank = simple_strtoul(argv[4], NULL, 16);
+		if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
+			printf ("Only FLASH Banks # 1 ... # %d supported\n",
+			CFG_MAX_FLASH_BANKS);
+			return 1;
+		}
+	}
+
+	info = &flash_info[bank - 1];
+	if ((offset + len) > info->size){
+		printf ("Bad parameters, 'offset' + 'len' should < 0x%x\n", info->size);
+		return 1;
+	}
+	sect_size = info->size / info->sector_count;
+	sect_first = offset / sect_size;
+	sect_last = (offset + len - 1) / sect_size;
+	printf("flash size:0x%x offset:0x%x len:0x%x sect_size:0x%x first:0x%x last:0x%x\n",
+			info->size, offset, len, sect_size, sect_first, sect_last);
+
+	return(flash_erase(info, sect_first, sect_last));
+}
+#endif /* #if ENABLE_EXT_ADDR_SUPPORT */
+
 int do_flerase (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
 	flash_info_t *info;
@@ -744,7 +844,31 @@
 	"erase all\n    - erase all FLASH banks\n"
 );
 
+#if ENABLE_EXT_ADDR_SUPPORT
+U_BOOT_CMD(
+	read_ext,   5,   1,  do_flread_ext,
+	"read_ext   - read SPI NOR FLASH memory(0-32M space)\n",
+	"read_ext dst offset(offset of the flash) len [N]\n"
+	"    - read 'len' bytes from FLASH bank #N addr 'start' to memory addr 'dst'\n"
+	"    - 'N' is optional, default the first bank\n"
+    );
 
+U_BOOT_CMD(
+	erase_ext,   4,   1,  do_flerase_ext,
+	"erase_ext   - erase SPI NOR FLASH memory(0-32M space)\n",
+	"erase_ext start(offset of the flash) len [N]\n"
+	"    - erase FLASH bank #N from addr 'start' to the end of sect addr 'start'+'len'-1\n"
+	"    - 'N' is optional, default the first bank\n"
+	);
+
+U_BOOT_CMD(
+	write_ext,   5,   1,  do_flwrite_ext,
+	"write_ext   - write SPI NOR FLASH memory(0-32M space)\n",
+	"write_ext src dst(offset of the flash) len [N]\n"
+	"    - copy 'len' bytes from memory addr 'src' to FLASH bank #N addr 'start'\n"
+	"    - 'N' is optional, default the first bank\n"
+	);
+#endif /* #if ENABLE_EXT_ADDR_SUPPORT */
 
 #undef	TMP_ERASE
 #undef	TMP_PROT_ON
diff --git a/include/956x.h b/include/956x.h
index 5788cb2..161fb40 100755
--- a/include/956x.h
+++ b/include/956x.h
@@ -3511,6 +3511,8 @@
 #define ATH_SPI_CS_DIS      0x70000
 #define ATH_SPI_CE_LOW      0x60000
 #define ATH_SPI_CE_HIGH     0x60100
+#define ATH_SPI_CD_LOW      0x70000
+#define ATH_SPI_CD_HIGH     0x70100
 
 #define ATH_SPI_SECTOR_SIZE (1024*64)
 #define ATH_SPI_PAGE_SIZE   256
@@ -3533,6 +3535,15 @@
 #define ATH_SPI_CMD_SECTOR_ERASE    0xd8
 #define ATH_SPI_CMD_CHIP_ERASE      0xc7
 #define ATH_SPI_CMD_RDID        0x9f
+/* commands for 32MB and above */
+#define ATH_SPI_CMD_WREAR       0xC5
+#define ATH_SPI_CMD_RDEAR       0xC8
+#define ATH_SPI_CMD_READ        0x03
+#define ATH_SPI_CMD_EN4B        0xB7
+#define ATH_SPI_CMD_EX4B        0xE9
+#define ATH_SPI_CMD_WRDIS       0x04
+#define ATH_SPI_CMD_RD_STATUS_2 0x35
+#define ATH_SPI_CMD_RD_STATUS_3 0x15
 
 #if defined(CFG_ATH_EMULATION)
 
diff --git a/include/configs/board956x.h b/include/configs/board956x.h
index 3e0e58e..a8ce12d 100755
--- a/include/configs/board956x.h
+++ b/include/configs/board956x.h
@@ -38,7 +38,10 @@
  * FLASH and environment organization
  */
 #define CFG_MAX_FLASH_BANKS	1	/* max number of memory banks */
-#if (FLASH_SIZE == 16)
+#if (FLASH_SIZE == 32)
+#define CFG_MAX_FLASH_SECT  512 /* max number of sectors on one chip */
+#define ATH_MTDPARTS_MIB0   "64k(mib0)"
+#elif (FLASH_SIZE == 16)
 #define CFG_MAX_FLASH_SECT	256	/* max number of sectors on one chip */
 #define ATH_MTDPARTS_MIB0	"64k(mib0)"
 #elif (FLASH_SIZE == 8)
@@ -50,7 +53,9 @@
 #endif
 
 #define CFG_FLASH_SECTOR_SIZE	(64*1024)
-#if (FLASH_SIZE == 16)
+#if (FLASH_SIZE == 32)
+#define CFG_FLASH_SIZE      0x02000000  /* Total flash size */
+#elif (FLASH_SIZE == 16)
 #define CFG_FLASH_SIZE		0x01000000	/* Total flash size */
 #elif (FLASH_SIZE == 8)
 #define CFG_FLASH_SIZE		0x00800000	/* max number of sectors on one chip */
@@ -190,7 +195,14 @@
 		 */
 #		define MTDPARTS_DEFAULT	"mtdparts=ath-nor0:32k(u-boot1),32k(u-boot2),3008k(rootfs),896k(uImage),64k(mib0),64k(ART)"
 #	else
-#if (FLASH_SIZE == 16) /*FLASH SIZE */
+#if (FLASH_SIZE == 32) /*FLASH SIZE */
+#   define ATH_F_FILE       fs_name(${bc}-jffs2)
+#   define ATH_F_LEN        $filesize
+#   define ATH_F_ADDR       0x9f050000
+#   define ATH_K_FILE       vmlinux${bc}.lzma.uImage
+#   define ATH_K_ADDR       0x9fe80000
+#   define MTDPARTS_DEFAULT     "mtdparts=ath-nor0:256k(u-boot),64k(u-boot-env),14528k(rootfs),1408k(uImage),64k(mib0),64k(ART),16m(test)"
+#elif (FLASH_SIZE == 16) /*FLASH SIZE */
 #	define ATH_F_FILE		fs_name(${bc}-jffs2)
 #	define ATH_F_LEN		0xE30000
 #	define ATH_F_ADDR		0x9f050000
diff --git a/include/flash.h b/include/flash.h
index d9955e0..4978f7d 100755
--- a/include/flash.h
+++ b/include/flash.h
@@ -89,6 +89,10 @@
 extern int flash_write (char *, ulong, ulong);
 extern flash_info_t *addr2info (ulong);
 extern int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt);
+#if ENABLE_EXT_ADDR_SUPPORT
+extern int write_buff_ext (flash_info_t *info, uchar *src, ulong offset, ulong cnt);
+extern int read_buff_ext (flash_info_t *info, uchar *buf, ulong offset, ulong cnt);
+#endif
 
 /* board/?/flash.c */
 #if defined(CFG_FLASH_PROTECTION)