Index: Makefile.am
===================================================================
--- Makefile.am	(revision 1395)
+++ Makefile.am	(working copy)
@@ -66,7 +66,7 @@
 libavrdude_a_CFLAGS   = @ENABLE_WARNINGS@
 libavrdude_la_CFLAGS  = $(libavrdude_a_CFLAGS)
 
-avrdude_LDADD  = $(top_builddir)/$(noinst_LIBRARIES) @LIBUSB_1_0@ @LIBHIDAPI@ @LIBUSB@ @LIBFTDI1@ @LIBFTDI@ @LIBHID@ @LIBELF@ @LIBPTHREAD@ -lm
+avrdude_LDADD  = $(top_builddir)/$(noinst_LIBRARIES) @LIBUSB_1_0@ @LIBHIDAPI@ @LIBUSB@ @LIBFTDI1@ @LIBFTDI@ @LIBHID@ @LIBELF@ @LIBPTHREAD@ @LIBPRUSSDRV@ -lm
 
 bin_PROGRAMS = avrdude
 
@@ -149,6 +149,8 @@
 	ppi.c \
 	ppi.h \
 	ppiwin.c \
+	pruss.c \
+	pruss.h \
 	safemode.c \
 	serbb.h \
 	serbb_posix.c \
Index: avrdude.conf.in
===================================================================
--- avrdude.conf.in	(revision 1395)
+++ avrdude.conf.in	(working copy)
@@ -630,6 +630,13 @@
 ;
 
 programmer
+  id    = "pruss";
+  desc  = "TI AM335x PRUSS";
+  type  = "pruss";
+  connection_type = serial;
+;
+
+programmer
   id    = "buspirate";
   desc  = "The Bus Pirate";
   type  = "buspirate";
Index: configure.ac
===================================================================
--- configure.ac	(revision 1395)
+++ configure.ac	(working copy)
@@ -113,6 +113,21 @@
 fi
 AC_SUBST(LIBUSB, $LIBUSB)
 
+AH_TEMPLATE([HAVE_LIBPRUSSDRV],
+            [Define if PRUSS support is enabled via libprussdrv])
+AC_CHECK_LIB([prussdrv], [prussdrv_init], [have_libprussdrv=yes])
+if test x$have_libprussdrv = xyes; then
+   case $target in
+       *)
+               LIBPRUSSDRV="/usr/lib/libprussdrv.a"
+               ;;
+   esac
+   AC_DEFINE([HAVE_LIBPRUSSDRV])
+   AC_CHECK_HEADERS([prussdrv.h])
+   AC_CHECK_HEADERS([pruss_intc_mapping.h])
+fi
+AC_SUBST(LIBPRUSSDRV, $LIBPRUSSDRV)
+
 AH_TEMPLATE([HAVE_LIBUSB_1_0],
             [Define if USB support is enabled via libusb 1.0])
 AC_CHECK_LIB([usb-1.0], [libusb_init], [have_libusb_1_0=yes])
@@ -570,3 +585,8 @@
    echo "DISABLED   linuxgpio"
 fi
 
+if test x$have_libprussdrv = xyes; then
+   echo "DO HAVE    libprussdrv"
+else
+   echo "DON'T HAVE libprussdrv"
+fi
Index: pgm_type.c
===================================================================
--- pgm_type.c	(revision 1395)
+++ pgm_type.c	(working copy)
@@ -43,6 +43,7 @@
 #include "par.h"
 #include "pickit2.h"
 #include "ppi.h"
+#include "pruss.h"
 #include "serbb.h"
 #include "stk500.h"
 #include "stk500generic.h"
@@ -82,6 +83,7 @@
         {"linuxgpio", linuxgpio_initpgm, linuxgpio_desc},
         {"par", par_initpgm, par_desc},
         {"pickit2", pickit2_initpgm, pickit2_desc},
+        {"pruss", pruss_initpgm, pruss_desc},
         {"serbb", serbb_initpgm, serbb_desc},
         {"stk500", stk500_initpgm, stk500_desc},
         {"stk500generic", stk500generic_initpgm, stk500generic_desc},
Index: pruss.c
===================================================================
--- pruss.c	(revision 0)
+++ pruss.c	(working copy)
@@ -0,0 +1,405 @@
+/*
+ * pruss - A Downloader/Uploader for AVR XMEGA device programmers
+ *
+ * Copyright (C) 2017 Enric Balletbo i Serra <enric.balletbo@collabora.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <unistd.h>
+#include <prussdrv.h>
+#include <pruss_intc_mapping.h>
+
+#include "avrdude.h"
+#include "libavrdude.h"
+#include "pruss.h"
+
+#define PATH_MAX	4096
+#define PRU_NUM		0
+
+/*
+ * Start address for uio_pdi-data-1.bin/uio_pdi-text-1.bin firmware
+ */
+#define START_ADDR 0x00000c20
+
+volatile unsigned int* shared_ram = NULL;
+
+/*
+ * Private data for this programmer.
+ */
+struct pdata
+{
+    char data[PATH_MAX]; // The data.bin file location
+    char text[PATH_MAX]; // The text.bin file location
+};
+
+#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
+
+/*
+ * Wait for interrupt from the PRU
+ */
+static inline void pruss_wait_event_from_pru(void)
+{
+  /* Wait for interrupt from PRU */
+  if (verbose >= 2)
+    fprintf(stderr, "%s: Waiting for interrupt from PRU\n", progname);
+
+  prussdrv_pru_wait_event(PRU_EVTOUT_0);
+  prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT);
+}
+
+/*
+ * Transmit an AVR device command and return the results; 'cmd' and
+ * 'res' must point to at least a 4 byte data buffer
+ */
+static int pruss_cmd(PROGRAMMER * pgm, const unsigned char *cmd,
+                      unsigned char *res)
+{
+  /* dummy function */
+  return 0;
+}
+
+/*
+ * Issue the 'chip erase' command to the AVR device
+ */
+static int pruss_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  if (verbose >= 2)
+    fprintf(stderr, "%s: Chip erase\n", progname);
+
+  shared_ram[0] = CMD_CHIP_ERASE;
+  pruss_wait_event_from_pru();
+
+  return 0;
+}
+
+/*
+ * Issue the 'program enable' command to the AVR device
+ */
+static int pruss_program_enable(PROGRAMMER * pgm, AVRPART * p)
+{
+  /* dummy function */
+  return 0;
+}
+
+/*
+ * Initialize the AVR device and prepare it to accept commands
+ */
+static int pruss_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+  return pgm->program_enable(pgm, p);
+}
+
+static void pruss_disable(PROGRAMMER * pgm)
+{
+  /* dummy function */
+  return;
+}
+
+static void pruss_enable(PROGRAMMER * pgm)
+{
+  /* dummy function */
+  return;
+}
+
+static void pruss_setup(PROGRAMMER * pgm)
+{
+   if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0)
+   {
+     fprintf(stderr,
+             "%s: pruss_setup(): Out of memory allocating private data\n",
+             progname);
+     exit(1);
+   }
+   memset(pgm->cookie, 0, sizeof(struct pdata));
+
+   strcpy(PDATA(pgm)->data, "/usr/share/avrdude/firmware/uio_pdi-data-1.bin");
+   strcpy(PDATA(pgm)->text, "/usr/share/avrdude/firmware/uio_pdi-text-1.bin");
+}
+
+static void pruss_teardown(PROGRAMMER * pgm)
+{
+    free(pgm->cookie);
+}
+
+static int pruss_open(PROGRAMMER * pgm, char * port)
+{
+  int ret;
+  void *map;
+  tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: Open programmer\n", progname);
+
+  ret = prussdrv_init();
+  if (ret) {
+    fprintf(stderr, "Error: PRU initialization failed!\n");
+    return ret;
+  }
+
+  ret = prussdrv_open(PRU_EVTOUT_0);
+  if (ret) {
+    fprintf(stderr, "Error: unable to open PRU device!\n");
+    return ret;
+  }
+
+  ret = prussdrv_pruintc_init(&pruss_intc_initdata);
+  if (ret) {
+    fprintf(stderr, "Error: PRU interrupts initialization failed!\n");
+    return ret;
+  }
+
+  /* Load and run the PRU program */
+  ret = prussdrv_load_datafile(PRU_NUM, PDATA(pgm)->data);
+  if (ret) {
+    fprintf(stderr, "Error: failed to load PRU program (%s)!\n", PDATA(pgm)->data);
+
+    return ret;
+  }
+
+  ret = prussdrv_exec_program_at(PRU_NUM, PDATA(pgm)->text, START_ADDR);
+  if (ret) {
+    fprintf(stderr, "Error: failed to run PRU program (%s)!\n", PDATA(pgm)->text);
+
+    return ret;
+  }
+
+  /* Get pointer to shared ram */
+  prussdrv_map_prumem(PRUSS0_SHARED_DATARAM, &map);
+  shared_ram = (unsigned int*)map;
+
+  return 0;
+}
+
+static void pruss_close(PROGRAMMER * pgm)
+{
+  if (verbose >= 2)
+    fprintf(stderr, "%s: Close programmer\n", progname);
+
+  /* Disable PRU and exit */
+  prussdrv_pru_disable(PRU_NUM);
+  prussdrv_exit ();
+
+  serial_close(&pgm->fd);
+  pgm->fd.ifd = -1;
+}
+
+static void pruss_display(PROGRAMMER * pgm, const char * p)
+{
+  /* dummy function */
+  return;
+}
+
+static int pruss_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			       unsigned long addr, unsigned char * value)
+{
+  if (verbose >= 2)
+    fprintf(stderr, "%s: pruss_read_byte(.., %s, 0x%lx, ...)\n",
+            progname, mem->desc, addr);
+
+  if (strcmp(mem->desc, "signature") == 0) {
+    shared_ram[1] = (unsigned int)addr;
+    shared_ram[0] = CMD_READ_SIGNATURE;
+  } else {
+    fprintf(stderr, "%s: Read byte from memory '%s' is not supported.",
+            progname, mem->desc);
+    return -1;
+  }
+
+  pruss_wait_event_from_pru();
+
+  *value = shared_ram[2];
+
+  return 0;
+}
+
+static int pruss_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+                                unsigned long addr, unsigned char value)
+{
+  fprintf(stderr, "%s: Write byte from memory '%s' is not supported.",
+          progname, mem->desc);
+
+  return -1;
+}
+
+static int pruss_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+                               unsigned int page_size,
+                               unsigned int addr, unsigned int n_bytes)
+{
+  int i;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: pruss_paged_load(.., %s, 0x%x, %d, %d...)\n",
+	    progname, mem->desc, addr, n_bytes, page_size);
+
+  memset(shared_ram, 0, 1024);
+
+  /* determine which command is to be used */
+  if (strcmp(mem->desc, "flash") == 0) {
+    shared_ram[1] = addr;
+    shared_ram[2] = n_bytes;
+    shared_ram[0] = CMD_READ_FLASH;
+  } else {
+    fprintf(stderr, "Error: Read from memory '%s' is not supported.", mem->desc);
+    return -1;
+  }
+
+  pruss_wait_event_from_pru();
+
+  if (verbose >= 2)
+    fprintf(stderr, "\n\nReading at '%s' memory at offset %x:\n",
+            mem->desc, addr);
+  for (i = 0; i < 256; i++) {
+        mem->buf[addr + i] = (uint8_t)shared_ram[i + 5];
+        if (verbose >= 2)
+	  fprintf(stderr, "0x%x ", shared_ram[i + 5]);
+  }
+  if (verbose >= 2)
+    fprintf(stderr, "\n\n");
+
+  return 0;
+}
+
+static int pruss_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+                               unsigned int page_size,
+                               unsigned int addr, unsigned int n_bytes)
+{
+  int i;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: pruss_paged_write(.., %s, 0x%x, %d, %d...)\n",
+            progname, mem->desc, addr, n_bytes, page_size);
+
+  /* clean shared_ram */
+  memset(shared_ram, 0, 1024);
+
+  /* copy data to shared ram */
+  if (verbose >= 2)
+    fprintf(stderr, "\n\nWritting at memory '%s' offset %x:\n",
+            mem->desc, addr);
+  for (i = 0; i < n_bytes; i++) {
+	shared_ram[i + 5] = *(mem->buf + addr + i);
+        if (verbose >= 2)
+	  fprintf(stderr, "0x%x ", *(mem->buf + addr + i));
+  }
+  if (verbose >= 2)
+    fprintf(stderr, "\n\n");
+
+  /* determine which command is to be used */
+  if (strcmp(mem->desc, "flash") == 0) {
+    shared_ram[1] = addr;
+    shared_ram[2] = page_size;
+    shared_ram[3] = n_bytes;
+    shared_ram[0] = CMD_PROGRAM_FLASH;
+  } else {
+    fprintf(stderr, "Error: Write to memory '%s' is not supported.", mem->desc);
+    return -1;
+  }
+
+  pruss_wait_event_from_pru();
+
+  return 0;
+}
+
+static int pruss_parseextparams(struct programmer_t * pgm, LISTID extparms)
+{
+    LNODEID ln;
+    const char *extended_param;
+    int rv = 0;
+
+    for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
+        extended_param = ldata(ln);
+
+        if (strncmp(extended_param, "data=", strlen("data=")) == 0) {
+            if (sscanf(extended_param, "data=%s", PDATA(pgm)->data) != 1) {
+                fprintf(stderr, "%s: pruss_parseextparms(): invalid '%s'\n",
+                        progname, extended_param);
+                rv = -1;
+                continue;
+            }
+
+            if (verbose >= 2) {
+                fprintf(stderr,
+			"%s: pruss_parseextparms(): fwpath set to %s\n",
+                        progname, PDATA(pgm)->data);
+            }
+
+            continue;
+        }
+
+        if (strncmp(extended_param, "text=", strlen("text=")) == 0) {
+            if (sscanf(extended_param, "text=%s", PDATA(pgm)->text) != 1) {
+                fprintf(stderr, "%s: pruss_parseextparms(): invalid '%s'\n",
+                        progname, extended_param);
+                rv = -1;
+                continue;
+            }
+
+            if (verbose >= 2) {
+                fprintf(stderr,
+			"%s: pruss_parseextparms(): fwpath set to %s\n",
+                        progname, PDATA(pgm)->text);
+            }
+
+            continue;
+        }
+
+        fprintf(stderr,
+                "%s: pruss_parseextparms(): invalid extended parameter '%s'\n",
+                progname, extended_param);
+        rv = -1;
+    }
+
+    return rv;
+}
+
+const char pruss_desc[] = "TI AM335x PRUSS Programmer";
+
+void pruss_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "PRUSS");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = pruss_initialize;
+  pgm->display        = pruss_display;
+  pgm->enable         = pruss_enable;
+  pgm->disable        = pruss_disable;
+  pgm->program_enable = pruss_program_enable;
+  pgm->chip_erase     = pruss_chip_erase;
+  pgm->cmd            = pruss_cmd;
+  pgm->open           = pruss_open;
+  pgm->close          = pruss_close;
+  pgm->read_byte      = pruss_read_byte;
+  pgm->write_byte     = pruss_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = pruss_paged_write;
+  pgm->paged_load     = pruss_paged_load;
+
+  pgm->parseextparams = pruss_parseextparams;
+
+  pgm->setup          = pruss_setup;
+  pgm->teardown       = pruss_teardown;
+}
Index: pruss.h
===================================================================
--- pruss.h	(revision 0)
+++ pruss.h	(working copy)
@@ -0,0 +1,41 @@
+/*
+ * pruss - A Downloader/Uploader for AVR XMEGA device programmers
+ *
+ * Copyright (C) 2017  Enric Balletbo i Serra <enric.balletbo@collabora.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef pruss_h
+#define pruss_h
+
+#define CMD_ENTER_PROGMODE	0x10
+#define CMD_LEAVE_PROGMODE	0x11
+#define CMD_READ_SIGNATURE	0x12
+#define CMD_CHIP_ERASE		0x13
+#define CMD_PROGRAM_FLASH	0x14
+#define CMD_READ_FLASH		0x15
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const char pruss_desc[];
+void pruss_initpgm (PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
