From 90d6100d88114cdea7d3e7d4d9b9e183e8e8c675 Mon Sep 17 00:00:00 2001
From: Joerg Wunsch <j@uriah.heep.sax.de>
Date: Thu, 26 Oct 2006 21:14:10 +0000
Subject: [PATCH] Add support for the AVR Dragon (JTAG and ISP mode).

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@675 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 ChangeLog        | 13 +++++++
 avrdude.1        | 15 +++++++-
 avrdude.conf.in  | 19 +++++++++-
 config_gram.y    | 14 ++++++++
 doc/avrdude.texi | 12 +++++++
 jtagmkII.c       | 91 +++++++++++++++++++++++++++++++++++++++++++---
 jtagmkII.h       |  1 +
 lexer.l          |  2 ++
 stk500v2.c       | 94 ++++++++++++++++++++++++++++++++++++++++++++++++
 stk500v2.h       |  1 +
 usbdevs.h        |  2 ++
 11 files changed, 258 insertions(+), 6 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 0cb1e4f1..00c5ec59 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2006-10-26 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add support for the AVR Dragon (JTAG and ISP mode).
+	* config_gram.y: (Ditto.)
+	* jtagmkII.c: (Ditto.)
+	* jtagmkII.h: (Ditto.)
+	* lexer.l: (Ditto.)
+	* stk500v2.c: (Ditto.)
+	* stk500v2.h: (Ditto.)
+	* usbdevs.h: (Ditto.)
+	* avrdude.1: Document the AVR Dragon support.
+	* doc/avrdude.texi: (Ditto.)
+
 2006-10-09 Joerg Wunsch <j@uriah.heep.sax.de>
 
 	Released AVRDUDE 5.2.
diff --git a/avrdude.1 b/avrdude.1
index 0b424356..3b1e969e 100644
--- a/avrdude.1
+++ b/avrdude.1
@@ -19,7 +19,7 @@
 .\"
 .\" $Id$
 .\"
-.Dd DATE October 9, 2006
+.Dd DATE October 26, 2006
 .Os
 .Dt AVRDUDE 1
 .Sh NAME
@@ -114,6 +114,19 @@ Atmel's JTAG ICE (both mkI and mkII) is supported as well to up- or download mem
 areas from/to an AVR target (no support for on-chip debugging).
 For the JTAG ICE mkII, both JTAG and ISP mode are supported.
 .Pp
+The AVR Dragon is supported in JTAG and ISP mode.
+(High-voltage programming is not yet supported.)
+When used in JTAG mode, the AVR Dragon behaves similar to a
+JTAG ICE mkII, so all device-specific comments for that device
+will apply as well.
+When used in ISP mode, the AVR Dragon behaves similar to an
+AVRISP mkII (or JTAG ICE mkII in ISP mode), so all device-specific
+comments will apply there.
+In particular, the Dragon starts out with a rather fast ISP clock
+frequency, so the
+.Fl B Ar bitclock
+option might be required to achieve a stable ISP communication.
+.Pp
 The USBasp ISP adapter is also supported, provided
 .Nm avrdude
 has been compiled with libusb support.
diff --git a/avrdude.conf.in b/avrdude.conf.in
index 6b1ff2c2..e5dba6c6 100644
--- a/avrdude.conf.in
+++ b/avrdude.conf.in
@@ -17,7 +17,8 @@
 #       desc     = <description> ;                  # quoted string
 #       type     = par | stk500 | stk500v2 | stk500pp | stk500hvsp | stk500generic |
 #                  avr910 | butterfly | usbasp |
-#                  jtagmki | jtagmkii | jtagmkii_isp; # programmer type
+#                  jtagmki | jtagmkii | jtagmkii_isp |
+#                  dragon_jtag | dragon_isp;        # programmer type
 #       baudrate = <num> ;                          # baudrate for avr910-programmer
 #       vcc      = <num1> [, <num2> ... ] ;         # pin number(s)
 #       reset    = <num> ;                          # pin number
@@ -441,6 +442,22 @@ programmer
   type  = jtagmkii_isp;
 ;
 
+# AVR Dragon in JTAG mode
+programmer
+  id    = "dragon_jtag";
+  desc  = "Atmel AVR Dragon in JTAG mode";
+  baudrate = 115200;
+  type  = dragon_jtag;
+;
+
+# AVR Dragon in ISP mode
+programmer
+  id    = "dragon_isp";
+  desc  = "Atmel AVR Dragon in ISP mode";
+  baudrate = 115200;
+  type  = dragon_isp;
+;
+
 programmer
   id    = "pavr";
   desc  = "Jason Kyle's pAVR Serial Programmer";
diff --git a/config_gram.y b/config_gram.y
index 10dc23f2..b8b8aa1b 100644
--- a/config_gram.y
+++ b/config_gram.y
@@ -88,6 +88,8 @@ static int parse_cmdbits(OPCODE * op);
 %token K_DEFAULT_SERIAL
 %token K_DESC
 %token K_DEVICECODE
+%token K_DRAGON_ISP
+%token K_DRAGON_JTAG
 %token K_STK500_DEVCODE
 %token K_AVR910_DEVCODE
 %token K_EEPROM
@@ -437,6 +439,18 @@ prog_parm :
     }
   } |
 
+  K_TYPE TKN_EQUAL K_DRAGON_ISP {
+    {
+      stk500v2_dragon_isp_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_DRAGON_JTAG {
+    {
+      jtagmkII_dragon_initpgm(current_prog);
+    }
+  } |
+
   K_DESC TKN_EQUAL TKN_STRING {
     strncpy(current_prog->desc, $3->value.string, PGM_DESCLEN);
     current_prog->desc[PGM_DESCLEN-1] = 0;
diff --git a/doc/avrdude.texi b/doc/avrdude.texi
index 9e3dafb8..f8ca982a 100644
--- a/doc/avrdude.texi
+++ b/doc/avrdude.texi
@@ -184,6 +184,18 @@ Only the memory programming functionality of the JTAG ICE is supported
 by AVRDUDE.
 For the JTAG ICE mkII, both JTAG and ISP mode are supported.
 
+The AVR Dragon is supported in JTAG and ISP mode.
+(High-voltage programming is not yet supported.)
+When used in JTAG mode, the AVR Dragon behaves similar to a
+JTAG ICE mkII, so all device-specific comments for that device
+will apply as well.
+When used in ISP mode, the AVR Dragon behaves similar to an
+AVRISP mkII (or JTAG ICE mkII in ISP mode), so all device-specific
+comments will apply there.
+In particular, the Dragon starts out with a rather fast ISP clock
+frequency, so the @code{-B @var{bitclock}}
+option might be required to achieve a stable ISP communication.
+
 The USBasp ISP adapter is also supported, provided AVRDUDE
 has been compiled with libusb support.
 It features a simple firwmare-only USB implementation, running on
diff --git a/jtagmkII.c b/jtagmkII.c
index cfb4e62a..f43a0a6a 100644
--- a/jtagmkII.c
+++ b/jtagmkII.c
@@ -26,6 +26,9 @@
 
 /*
  * avrdude interface for Atmel JTAG ICE mkII programmer
+ *
+ * The AVR Dragon also uses the same protocol, so it is handled here
+ * as well.
  */
 
 #include "ac_cfg.h"
@@ -573,7 +576,7 @@ int jtagmkII_getsync(PROGRAMMER * pgm, int mode) {
 #define MAXTRIES 33
   unsigned char buf[3], *resp, c = 0xff;
   int status;
-  unsigned int fwver;
+  unsigned int fwver, hwver;
 
   if (verbose >= 3)
     fprintf(stderr, "%s: jtagmkII_getsync()\n", progname);
@@ -601,6 +604,7 @@ int jtagmkII_getsync(PROGRAMMER * pgm, int mode) {
     if (status > 0) {
       if ((c = resp[0]) == RSP_SIGN_ON) {
 	fwver = ((unsigned)resp[8] << 8) | (unsigned)resp[7];
+	hwver = (unsigned)resp[9];
 	memcpy(serno, resp + 10, 6);
 	if (verbose >= 1 && status > 17) {
 	  fprintf(stderr, "JTAG ICE mkII sign-on message:\n");
@@ -651,15 +655,19 @@ int jtagmkII_getsync(PROGRAMMER * pgm, int mode) {
    * There's no official documentation from Atmel about what firmware
    * revision matches what device descriptor length.  The algorithm
    * below has been found empirically.
+   *
+   * The original JTAG ICE mkII has hardware version 0, the AVR Dragon
+   * has hardware version 2 (on the slave MCU) and doesn't need the
+   * firmware version checks (by now).
    */
 #define FWVER(maj, min) ((maj << 8) | (min))
-  if (fwver < FWVER(3, 16)) {
+  if (hwver == 0 && fwver < FWVER(3, 16)) {
     device_descriptor_length -= 2;
     fprintf(stderr,
 	    "%s: jtagmkII_getsync(): "
 	    "S_MCU firmware version might be too old to work correctly\n",
 	    progname);
-  } else if (fwver < FWVER(4, 0)) {
+  } else if (hwver == 0 && fwver < FWVER(4, 0)) {
     device_descriptor_length -= 2;
   }
   if (verbose >= 2 && mode != EMULATOR_MODE_SPI)
@@ -668,7 +676,7 @@ int jtagmkII_getsync(PROGRAMMER * pgm, int mode) {
 	    progname, device_descriptor_length);
   if (mode == EMULATOR_MODE_SPI) {
     device_descriptor_length = 0;
-    if (fwver < FWVER(4, 14)) {
+    if (hwver == 0 && fwver < FWVER(4, 14)) {
       fprintf(stderr,
 	      "%s: jtagmkII_getsync(): ISP functionality requires firmware "
 	      "version >= 4.14\n",
@@ -1167,6 +1175,51 @@ static int jtagmkII_open(PROGRAMMER * pgm, char * port)
 }
 
 
+static int jtagmkII_dragon_open(PROGRAMMER * pgm, char * port)
+{
+  long baud;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_dragon_open()\n", progname);
+
+  /*
+   * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
+   * attaching.  If the config file or command-line parameters specify
+   * a higher baud rate, we switch to it later on, after establishing
+   * the connection with the ICE.
+   */
+  baud = 19200;
+
+  /*
+   * If the port name starts with "usb", divert the serial routines
+   * to the USB ones.  The serial_open() function for USB overrides
+   * the meaning of the "baud" parameter to be the USB device ID to
+   * search for.
+   */
+  if (strncmp(port, "usb", 3) == 0) {
+#if defined(HAVE_LIBUSB)
+    serdev = &usb_serdev;
+    baud = USB_DEVICE_AVRDRAGON;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  pgm->fd = serial_open(port, baud);
+
+  /*
+   * drain any extraneous input
+   */
+  jtagmkII_drain(pgm, 0);
+
+  jtagmkII_getsync(pgm, EMULATOR_MODE_JTAG);
+
+  return 0;
+}
+
+
 void jtagmkII_close(PROGRAMMER * pgm)
 {
   int status;
@@ -1913,3 +1966,33 @@ void jtagmkII_initpgm(PROGRAMMER * pgm)
   pgm->set_sck_period = jtagmkII_set_sck_period;
   pgm->page_size      = 256;
 }
+
+
+void jtagmkII_dragon_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "DRAGON_JTAG");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = jtagmkII_initialize;
+  pgm->display        = jtagmkII_display;
+  pgm->enable         = jtagmkII_enable;
+  pgm->disable        = jtagmkII_disable;
+  pgm->program_enable = jtagmkII_program_enable_dummy;
+  pgm->chip_erase     = jtagmkII_chip_erase;
+  pgm->cmd            = jtagmkII_cmd;
+  pgm->open           = jtagmkII_dragon_open;
+  pgm->close          = jtagmkII_close;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = jtagmkII_paged_write;
+  pgm->paged_load     = jtagmkII_paged_load;
+  pgm->read_byte      = jtagmkII_read_byte;
+  pgm->write_byte     = jtagmkII_write_byte;
+  pgm->print_parms    = jtagmkII_print_parms;
+  pgm->set_sck_period = jtagmkII_set_sck_period;
+  pgm->page_size      = 256;
+}
diff --git a/jtagmkII.h b/jtagmkII.h
index 9a0ea2f7..39eea580 100644
--- a/jtagmkII.h
+++ b/jtagmkII.h
@@ -30,6 +30,7 @@ int  jtagmkII_getparm(PROGRAMMER * pgm, unsigned char parm,
 		      unsigned char * value);
 
 void jtagmkII_initpgm (PROGRAMMER * pgm);
+void jtagmkII_dragon_initpgm (PROGRAMMER * pgm);
 
 #endif
 
diff --git a/lexer.l b/lexer.l
index 32ccc928..04ba9ad4 100644
--- a/lexer.l
+++ b/lexer.l
@@ -135,6 +135,8 @@ default_parallel { yylval=NULL; return K_DEFAULT_PARALLEL; }
 default_programmer { yylval=NULL; return K_DEFAULT_PROGRAMMER; }
 default_serial   { yylval=NULL; return K_DEFAULT_SERIAL; }
 devicecode       { yylval=NULL; return K_DEVICECODE; }
+dragon_isp       { yylval=NULL; return K_DRAGON_ISP; }
+dragon_jtag      { yylval=NULL; return K_DRAGON_JTAG; }
 eecr             { yylval=NULL; return K_EECR; }
 eeprom           { yylval=NULL; return K_EEPROM; }
 enablepageprogramming { yylval=NULL; return K_ENABLEPAGEPROGRAMMING; }
diff --git a/stk500v2.c b/stk500v2.c
index 2087ae26..013504b1 100644
--- a/stk500v2.c
+++ b/stk500v2.c
@@ -2193,6 +2193,73 @@ static int stk500v2_jtagmkII_open(PROGRAMMER * pgm, char * port)
 }
 
 
+/*
+ * Wrapper functions for the AVR Dragon in ISP mode.  This mode
+ * uses the normal JTAG ICE mkII packet stream to communicate with the
+ * ICE, but then encapsulates AVRISP mkII commands using
+ * CMND_ISP_PACKET.
+ */
+
+/*
+ * Open an AVR Dragon in ISP mode.
+ */
+static int stk500v2_dragon_isp_open(PROGRAMMER * pgm, char * port)
+{
+  long baud;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: stk500v2_dragon_isp_open()\n", progname);
+
+  /*
+   * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
+   * attaching.  If the config file or command-line parameters specify
+   * a higher baud rate, we switch to it later on, after establishing
+   * the connection with the ICE.
+   */
+  baud = 19200;
+
+  /*
+   * If the port name starts with "usb", divert the serial routines
+   * to the USB ones.  The serial_open() function for USB overrides
+   * the meaning of the "baud" parameter to be the USB device ID to
+   * search for.
+   */
+  if (strncmp(port, "usb", 3) == 0) {
+#if defined(HAVE_LIBUSB)
+    serdev = &usb_serdev;
+    baud = USB_DEVICE_AVRDRAGON;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  pgm->fd = serial_open(port, baud);
+
+  /*
+   * drain any extraneous input
+   */
+  stk500v2_drain(pgm, 0);
+
+  if (jtagmkII_getsync(pgm, EMULATOR_MODE_SPI) != 0) {
+    fprintf(stderr, "%s: failed to sync with the JTAG ICE mkII in ISP mode\n",
+            progname);
+    pgm->close(pgm);		/* sign off correctly */
+    exit(1);
+  }
+
+  pgmtype = PGMTYPE_JTAGICE_MKII;
+
+  if (pgm->bitclock != 0.0) {
+    if (pgm->set_sck_period(pgm, pgm->bitclock) != 0)
+      return -1;
+  }
+
+  return 0;
+}
+
+
 void stk500v2_initpgm(PROGRAMMER * pgm)
 {
   strcpy(pgm->type, "STK500V2");
@@ -2315,3 +2382,30 @@ void stk500v2_jtagmkII_initpgm(PROGRAMMER * pgm)
   pgm->perform_osccal = stk500v2_perform_osccal;
   pgm->page_size      = 256;
 }
+
+void stk500v2_dragon_isp_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "DRAGON_ISP");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = stk500v2_initialize;
+  pgm->display        = stk500v2_display;
+  pgm->enable         = stk500v2_enable;
+  pgm->disable        = stk500v2_disable;
+  pgm->program_enable = stk500v2_program_enable;
+  pgm->chip_erase     = stk500v2_chip_erase;
+  pgm->cmd            = stk500v2_cmd;
+  pgm->open           = stk500v2_dragon_isp_open;
+  pgm->close          = jtagmkII_close;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = stk500v2_paged_write;
+  pgm->paged_load     = stk500v2_paged_load;
+  pgm->print_parms    = stk500v2_print_parms;
+  pgm->set_sck_period = stk500v2_set_sck_period_mk2;
+  pgm->page_size      = 256;
+}
diff --git a/stk500v2.h b/stk500v2.h
index 97cdf6a2..469a07bc 100644
--- a/stk500v2.h
+++ b/stk500v2.h
@@ -27,6 +27,7 @@ void stk500v2_initpgm (PROGRAMMER * pgm);
 void stk500hvsp_initpgm (PROGRAMMER * pgm);
 void stk500pp_initpgm (PROGRAMMER * pgm);
 void stk500v2_jtagmkII_initpgm(PROGRAMMER * pgm);
+void stk500v2_dragon_isp_initpgm(PROGRAMMER * pgm);
 
 #endif
 
diff --git a/usbdevs.h b/usbdevs.h
index 608f9d70..1b390ffb 100644
--- a/usbdevs.h
+++ b/usbdevs.h
@@ -29,6 +29,8 @@
 #define USB_VENDOR_ATMEL 1003
 #define USB_DEVICE_JTAGICEMKII 0x2103
 #define USB_DEVICE_AVRISPMKII  0x2104
+#define USB_DEVICE_AVRDRAGON   0x2107
+
 /*
  * Should we query the endpoint number and max transfer size from USB?
  * After all, the JTAG ICE mkII docs document these values.