From be385b2b4882722af59eea256afd123c68ab66a9 Mon Sep 17 00:00:00 2001
From: Hannes Weisbach <hannes_weisbach@gmx.net>
Date: Mon, 6 May 2013 12:49:26 +0000
Subject: [PATCH] avr.c: Adds avr_tpi_program_enable

Generic function enabling external programming on TPI devices. This
function sets the required guard time (which is passed in as parameter),
checks the TPI identification register, writes SKEY command + SKEY, and
finally polls the NVMEN bit in TPISR.

avr.h: Add prototype definitions of avr_tpi_program_enable() and
avr_tpi_chip_erase().
avrftdi_tpi.c: Removes tpi_skey_cmd array, containing the SKEY command
and the SKEY bytes.
tpi.h: Adds tpi_skey_cmd array, containing the SKEY command and the SKEY
bytes, but in the reverse order of tpi_skey.

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1167 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 ChangeLog     |  6 ++++++
 avr.c         | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 avr.h         |  2 ++
 avrftdi_tpi.c |  2 --
 tpi.h         |  2 ++
 5 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 9d108810..015c01fd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -45,7 +45,13 @@
 	* avrftdi_tpi.c: Do all I/O in terms of pgm->cmd_tpi()-calls instead of
 	avrftdi_tpi_[read,write]_byte().
 	Remove unnecessary set_pin call to set MOSI high, speeds up I/O.
+	Removes SKEY array, moves it to tpi.h.
 	* avr.c: Adds avr_tpi_chip_erase() generic TPI chip erase function.
+	Adds avr_tpi_program_enable() - generic TPI external programming enable
+	function. Sets guard time, reads identification register, sends SKEY command
+	and key, checks NVMEN bit. The required guard time has to be passed as
+	parameter.
+	* tpi.h: Adds SKEY array including CMD_SKEY in "correct" order.
 
 2013-05-02  Hannes Weisbach <hannes_weisbach@gmx.net>
 
diff --git a/avr.c b/avr.c
index 07ab8e03..990ab5e2 100644
--- a/avr.c
+++ b/avr.c
@@ -103,6 +103,56 @@ int avr_tpi_chip_erase(PROGRAMMER * pgm, AVRPART * p)
 	}
 }
 
+/* TPI program enable sequence */
+int avr_tpi_program_enable(PROGRAMMER * pgm, AVRPART * p, unsigned char guard_time)
+{
+	int err, retry;
+	unsigned char cmd[2];
+	unsigned char response;
+
+	if(p->flags & AVRPART_HAS_TPI) {
+		/* set guard time */
+		cmd[0] = (TPI_CMD_SSTCS | TPI_REG_TPIPCR);
+		cmd[1] = guard_time;
+
+		err = pgm->cmd_tpi(pgm, cmd, sizeof(cmd), NULL, 0);
+    if(err)
+			return err;
+
+		/* read TPI ident reg */
+    cmd[0] = (TPI_CMD_SLDCS | TPI_REG_TPIIR);
+		err = pgm->cmd_tpi(pgm, cmd, 1, &response, sizeof(response));
+    if (err || response != TPI_IDENT_CODE) {
+      fprintf(stderr, "TPIIR not correct\n");
+      return -1;
+    }
+
+		/* send SKEY command + SKEY */
+		err = pgm->cmd_tpi(pgm, tpi_skey_cmd, sizeof(tpi_skey_cmd), NULL, 0);
+		if(err)
+			return err;
+
+		/* check if device is ready */
+		for(retry = 0; retry < 10; retry++)
+		{
+			cmd[0] =  (TPI_CMD_SLDCS | TPI_REG_TPISR);
+			err = pgm->cmd_tpi(pgm, cmd, 1, &response, sizeof(response));
+			if(err || !(response & TPI_REG_TPISR_NVMEN))
+				continue;
+
+			return 0;
+		}
+
+		fprintf(stderr, "Error enabling TPI external programming mode:");
+		fprintf(stderr, "Target does not reply\n");
+		return -1;
+
+	} else {
+		fprintf(stderr, "%s called for a part that has no TPI\n", __func__);
+		return -1;
+	}
+}
+
 /* TPI: setup NVMCMD register and pointer register (PR) for read/write/erase */
 static int avr_tpi_setup_rw(PROGRAMMER * pgm, AVRMEM * mem,
 			    unsigned long addr, unsigned char nvmcmd)
diff --git a/avr.h b/avr.h
index b70ce93c..cf9e690b 100644
--- a/avr.h
+++ b/avr.h
@@ -37,6 +37,8 @@ extern "C" {
 #endif
 
 int avr_tpi_poll_nvmbsy(PROGRAMMER *pgm);
+int avr_tpi_chip_erase(PROGRAMMER * pgm, AVRPART * p);
+int avr_tpi_program_enable(PROGRAMMER * pgm, AVRPART * p, unsigned char guard_time);
 int avr_read_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
 			  unsigned long addr, unsigned char * value);
 
diff --git a/avrftdi_tpi.c b/avrftdi_tpi.c
index cdcc8631..7b34e213 100644
--- a/avrftdi_tpi.c
+++ b/avrftdi_tpi.c
@@ -23,8 +23,6 @@
 
 static void avrftdi_tpi_disable(PROGRAMMER *);
 
-static const unsigned char tpi_skey_cmd[] = { TPI_CMD_SKEY, 0xff, 0x88, 0xd8, 0xcd, 0x45, 0xab, 0x89, 0x12 };
-
 static void
 avrftdi_debug_frame(uint16_t frame)
 {
diff --git a/tpi.h b/tpi.h
index f6b9fd3b..89d438d8 100644
--- a/tpi.h
+++ b/tpi.h
@@ -66,6 +66,8 @@ static const unsigned char tpi_skey[] = { 0x12, 0x89, 0xAB, 0x45, 0xCD, 0xD8, 0x
 #define TPI_NVMCMD_SECTION_ERASE	0x14
 #define TPI_NVMCMD_WORD_WRITE		0x1D
 
+static const unsigned char tpi_skey_cmd[] = { TPI_CMD_SKEY, 0xff, 0x88, 0xd8, 0xcd, 0x45, 0xab, 0x89, 0x12 };
+
 #ifdef __cplusplus
 }
 #endif