Integrating Freescale drop of corrected OTP driver

Corrects the otp_write() method, and adds an otp_lock() method.

Patch was merged manually due to conflicting bases (patch was against original
OTP algorithm, we have the updated version already.)

Changes made to patch:

  * Made otp_smart_write_sequence(..) void rather than int as it has no returns.
  * Split comment in otp_smart_write_sequence(..) due to line length.
  * Split u32 declarations in otp_write(..), otp_lock(..) due to line length.
  * Changed printf in otp_write(..) to be more useful.
  * Whitespace changes to match existing code.

Original patch name: otp_driver_enhancement_2.patch

Change-Id: I16d0601c59d870d31d1610de0ab9f2fe11003e55
diff --git a/drivers/otp/c2k_otp.c b/drivers/otp/c2k_otp.c
index 74218a4..3642588 100644
--- a/drivers/otp/c2k_otp.c
+++ b/drivers/otp/c2k_otp.c
@@ -7,8 +7,8 @@
 #include <mach/clkcore.h>
 #include <clock.h>
 
-#define NP1	4
-#define NP2	16
+#define NP1	4       /* Number of initial programming pulses */
+#define NP2	12      /* Maximum number of additional programming pulses */
 
 extern u32 HAL_get_axi_clk(void);
 
@@ -88,7 +88,7 @@
 		return RETCODE_ERROR;
 
 	/* Setting up counters to program */
-	pgm2cpump_counter = axi_clk & 0x7FF ; 				/* 1 uSec */
+	pgm2cpump_counter = axi_clk & 0x7FF ;				/* 1 uSec */
 	cpump2web_counter = (axi_clk*3) & 0x7FF ;			/* 3 uSec */
 	web_counter = (axi_clk*5) & 0x7FF ;					/* 5 uSec */
 	web2cpump_counter = (axi_clk*2) & 0x7FF ;			/* 2 uSec */
@@ -119,18 +119,17 @@
 
 	for(i = 0 ; i < size ; i++) {
 
+		/* Skip bits that are 0 because 0 is the default value */
 		if (!prog_data[i]) {
-			/* Skip bits that are 0 because 0 is the default value.
-			 * */
 			continue;
 		}
 
 		for(k = 0 ; k < NP1-1 ; k++)
-			otp_smart_write_sequence(offset + i, prog_data[i]);
+			otp_smart_write_sequence(offset + i, 1);
 
 		for(k = 0 ; k < NP2+1 ; k++) {
 			ndelay(100);
-			otp_smart_write_sequence(offset + i, prog_data[i]);
+			otp_smart_write_sequence(offset + i, 1);
 
 			/* Verify Data */
 			read_data = readl(OTP_DATA_OUTPUT);
@@ -138,18 +137,19 @@
 			/* Adjust bit offset */
 			read_data = ((read_data >> ((offset+i) & 0x7)) & 0x1);
 
-			if(read_data == prog_data[i])
+			if(read_data)
 				break;
 		}
-		if(read_data != prog_data[i]) {
+		if(!read_data) {
 			printf("Warning : failed to write OTP value at bit %d (%d attempts) !\n",
 					offset + i, NP1 + NP2);
-			/* Not returrning Error here for debug */
+			return -1;
 		}
 	}
 
 	return 0;
 }
+EXPORT_SYMBOL(otp_write)
 
 /*
  * Reads from the OTP.
@@ -225,6 +225,99 @@
 }
 EXPORT_SYMBOL(otp_read);
 
+void otp_lock(void)
+{
+	u32 i;
+	u32 pgm2cpump_counter, cpump2web_counter, web_counter, web2cpump_counter;
+	u32 cpump2pgm_counter, dataout_counter;
+	u32 axi_clk = HAL_get_axi_clk();
+
+	/* Setting up counters to program */
+	pgm2cpump_counter = axi_clk & 0x7FF ;               /* 1 uSec */
+	cpump2web_counter = (axi_clk*3) & 0x7FF ;           /* 3 uSec */
+	web_counter = (axi_clk*5) & 0x7FF ;                 /* 5 uSec */
+	web2cpump_counter = (axi_clk*2) & 0x7FF ;           /* 2 uSec */
+	cpump2pgm_counter = axi_clk & 0x7FF ;               /* 1 uSec */
+	dataout_counter = ((axi_clk * 7 + 99) / 100) & 0x1FF ;  /* 70 nSec */
+
+	/* program the counters */
+	writel(pgm2cpump_counter, OTP_PGM2CPUMP_COUNTER);
+	writel(cpump2web_counter, OTP_CPUMP2WEB_COUNTER);
+	writel(web_counter, OTP_WEB_COUNTER);
+	writel(web2cpump_counter, OTP_WEB2CPUMP_COUNTER);
+	writel(cpump2pgm_counter, OTP_CPUMP2PGM_COUNTER);
+	writel(dataout_counter, OTP_DATA_OUT_COUNTER);
+
+	write_protect_unlock();
+	udelay(1);
+
+	/* rstb drive 0 */
+	writel(0x0, OTP_RSTB_INPUT);
+	ndelay(20);
+	/* rstb drive 1 to have pulse  */
+	writel(0x1, OTP_RSTB_INPUT);
+	udelay(1);
+
+	/* address input */
+	writel(0x8, OTP_ADDR_INPUT);
+	udelay(1);
+
+	/* CLE drive  "1" */
+	writel(0x1, OTP_CLE_INPUT);
+	/* Wait for at least 20nsec */
+	ndelay(20);
+
+	/* WEB drive  "0" */
+	writel(0x0, OTP_WEB_INPUT);
+	/* Wait for at least 20nsec */
+	ndelay(20);
+
+	/* WEB drive  "1" */
+	writel(0x1, OTP_WEB_INPUT);
+	/* Wait for at least 20nsec */
+	ndelay(20);
+
+	/* CLE drive  "0" */
+	writel(0x0, OTP_CLE_INPUT);
+
+	for( i = 0 ; i < 2 ; i++ )
+	{
+		/* PGMEN drive  "1" */
+		writel(0x1, OTP_PGMEN_INPUT);
+		udelay(100);
+
+		/* WEB drive  "0" */
+		writel(0x0, OTP_WEB_INPUT);
+		/* Wait for at least 20nsec */
+		udelay(100);
+
+		/* WEB drive  "1" */
+		writel(0x1, OTP_WEB_INPUT);
+		/* Wait for at least 20nsec */
+		udelay(100);
+	}
+
+	/* rstb drive 0 */
+	writel(0x0, OTP_RSTB_INPUT);
+	ndelay(20);
+	/* rstb drive 1 to have pulse  */
+	writel(0x1, OTP_RSTB_INPUT);
+	udelay(1);
+
+	/* read and check lock status register */
+	for (i = 0 ; i < 12 ; i++) {
+		if (readl(OTP_SECURE_LOCK_OUTPUT) & 1)
+			break;
+		udelay(100);
+	}
+
+	if (!(readl(OTP_SECURE_LOCK_OUTPUT) & 1))
+		printk("Timeout waiting for Security Lock Status Going high \n ");
+
+	return;
+}
+EXPORT_SYMBOL(otp_lock);
+
 static int c2k_otp_probe(struct device_d *pdev)
 {
 	printf("c2k_otp_probe.\n");
diff --git a/include/c2k_otp.h b/include/c2k_otp.h
index 40d75ff..6485f71 100644
--- a/include/c2k_otp.h
+++ b/include/c2k_otp.h
@@ -5,5 +5,6 @@
 
 int otp_read(u32 s_addr, u8 *read_data, int size) ;
 int otp_write(u32 offset, u8 *prog_data, int size);
+void otp_lock(void);
 
 #endif