Fixed support for Winbond W39V040FA flash chip. The read support 
in revision 2744 is working.  But, the write support isn't working
because the block locking registers (BLRs) are not set accordingly.
This patch sets the BLRs to the right values prior to flashing so 
that flashrom can write to the chip.

Signed-off-by: Darmawan Mappatutu Salihun <darmawan.salihun@gmail.com>

Index: flashchips.c
===================================================================
--- flashchips.c	(revision 2744)
+++ flashchips.c	(working copy)
@@ -32,6 +32,7 @@
 #include "sst28sf040.h"
 #include "sst49lfxxxc.h"
 #include "w49f002u.h"
+#include "w39v040fa.h"
 #include "sst39sf020.h"
 #include "sst49lf040.h"
 #include "pm49fl004.h"
@@ -105,7 +106,7 @@
 	{"W49V002FA", 	WINBOND_ID, 	W_49V002FA,	256, 128,
 	 probe_jedec,	erase_chip_jedec, write_49f002},
 	{"W39V040FA", 	WINBOND_ID, 	W_39V040FA,	512, 64*1024,
-	 probe_jedec,	erase_chip_jedec, write_39sf020},
+	 probe_jedec,	erase_chip_jedec, write_39v040fa},
 	{"W39V040A", 	WINBOND_ID, 	W_39V040A,	512, 64*1024,
 	 probe_jedec,	erase_chip_jedec, write_39sf020},
 	{"W39V040B",    WINBOND_ID,     W_39V040B,      512, 64*1024,
Index: Makefile
===================================================================
--- Makefile	(revision 2744)
+++ Makefile	(working copy)
@@ -24,7 +24,7 @@
 	am29f040b.o mx29f002.o sst39sf020.o m29f400bt.o w49f002u.o \
 	82802ab.o msys_doc.o pm49fl004.o sst49lf040.o sst49lfxxxc.o \
 	sst_fwhub.o layout.o lbtable.o flashchips.o flashrom.o \
-	sharplhf00l04.o
+	sharplhf00l04.o w39v040fa.o
 
 all: pciutils dep $(PROGRAM)
 
Index: w39v040fa.c
===================================================================
--- w39v040fa.c	(revision 0)
+++ w39v040fa.c	(revision 0)
@@ -0,0 +1,111 @@
+/*
+ * w39v040fa.c: driver for Winbond W39V040FAx flash models.
+ *
+ *  	Copyright (C) 2007 Darmawan M Salihun <darmawan.salihun@gmail.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 program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 51 Franklin St, 5th floor, Boston, MA 02110, USA.
+ *
+ *
+ * Reference:
+ *	Winbond W39V040FA data sheet
+ *
+ */
+#include <sys/mman.h>
+#include <stdio.h>
+
+#include "flash.h"
+#include "jedec.h"
+#include "debug.h"
+
+enum {
+	BLOCKING_REGS_PHY_RANGE = 0x80000,
+     	BLOCKING_REGS_PHY_BASE = 0xFFB80000,
+};
+
+static volatile uint8_t* unprotect_39v040fa(void)
+{
+	uint8_t i, byte_val;
+	volatile uint8_t *block_regs_base;
+
+	block_regs_base = (volatile uint8_t*) mmap( 0, BLOCKING_REGS_PHY_RANGE, PROT_WRITE | PROT_READ, 
+			                            MAP_SHARED, fd_mem, (off_t)BLOCKING_REGS_PHY_BASE );
+	if (block_regs_base == NULL) {
+		perror("Error: Unable to map Winbond w39v040fa blocking registers!\n");
+		return NULL;
+	}
+
+	// 
+	// Unprotect the BIOS chip address range
+	//
+	for( i = 0; i < 8 ; i++ )
+	{
+		byte_val =  *(volatile uint8_t*)(block_regs_base + 2 + i*0x10000);
+		usleep(10);
+		byte_val &= 0xF8; // Enable full access to the chip
+		*(volatile uint8_t*)(block_regs_base + 2 + i*0x10000) = byte_val;
+		usleep(10);
+	}
+	
+	return block_regs_base;
+}
+
+static void protect_39v040fa(volatile uint8_t * reg_base)
+{
+	//
+ 	// Protect the BIOS chip address range
+	//
+	uint8_t i, byte_val;
+	volatile uint8_t *block_regs_base = reg_base;
+
+	for( i = 0; i < 8 ; i++ )
+	{
+		byte_val = *(volatile uint8_t*)(block_regs_base + 2 + i*0x10000);
+		usleep(10);
+		byte_val |= 1; // Prohibited to write in the block where set
+		*(volatile uint8_t*)(block_regs_base + 2 + i*0x10000) = byte_val;
+		usleep(10);
+	}
+	
+	munmap((void*) reg_base, BLOCKING_REGS_PHY_RANGE);
+}
+
+int write_39v040fa(struct flashchip *flash, uint8_t *buf)
+{
+ 	int i;
+	int total_size = flash->total_size * 1024;
+	int page_size = flash->page_size;
+	volatile uint8_t *bios = flash->virtual_memory;
+	volatile uint8_t * reg_base;
+					
+	reg_base = unprotect_39v040fa();
+	erase_chip_jedec(flash);
+
+	printf("Programming Page: ");
+		for (i = 0; i < total_size / page_size; i++) {
+			/* write to the sector */
+			printf("%04d at address: 0x%08x", i, i * page_size);
+			write_sector_jedec(bios, buf + i * page_size, bios + i * page_size, page_size);
+			printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
+			fflush(stdout);
+		}
+		printf("\n");
+
+	if(NULL != reg_base)
+	{
+	    protect_39v040fa(reg_base);
+    	}
+											
+	return (0);
+}
Index: w39v040fa.h
===================================================================
--- w39v040fa.h	(revision 0)
+++ w39v040fa.h	(revision 0)
@@ -0,0 +1,6 @@
+#ifndef __W39V040FA_H__
+#define __W39V040FA_H__ 1
+
+extern int write_39v040fa(struct flashchip *flash, uint8_t *buf);
+
+#endif				/* !__W39V040FA_H__ */
