diff --git a/Makefile b/Makefile
index 943d88d76f77..17cc8d53f139 100644
--- a/Makefile
+++ b/Makefile
@@ -153,12 +153,17 @@ UNSUPPORTED_FEATURES += CONFIG_PONY_SPI=yes
 else
 override CONFIG_PONY_SPI = no
 endif
-# Dediprog, USB-Blaster, PICkit2, CH341A and FT2232 are not supported under DOS (missing USB support).
+# Dediprog, Developerbox, USB-Blaster, PICkit2, CH341A and FT2232 are not supported under DOS (missing USB support).
 ifeq ($(CONFIG_DEDIPROG), yes)
 UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes
 else
 override CONFIG_DEDIPROG = no
 endif
+ifeq ($(CONFIG_DEVELOPERBOX), yes)
+UNSUPPORTED_FEATURES += CONFIG_DEVELOPERBOX=yes
+else
+override CONFIG_DEVELOPERBOX = no
+endif
 ifeq ($(CONFIG_FT2232_SPI), yes)
 UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes
 else
@@ -310,12 +315,17 @@ UNSUPPORTED_FEATURES += CONFIG_PONY_SPI=yes
 else
 override CONFIG_PONY_SPI = no
 endif
-# Dediprog, USB-Blaster, PICkit2, CH341A and FT2232 are not supported with libpayload (missing libusb support).
+# Dediprog, Developerbox, USB-Blaster, PICkit2, CH341A and FT2232 are not supported with libpayload (missing libusb support).
 ifeq ($(CONFIG_DEDIPROG), yes)
 UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes
 else
 override CONFIG_DEDIPROG = no
 endif
+ifeq ($(CONFIG_DEVELOPERBOX), yes)
+UNSUPPORTED_FEATURES += CONFIG_DEVELOPERBOX=yes
+else
+override CONFIG_DEVELOPERBOX = no
+endif
 ifeq ($(CONFIG_FT2232_SPI), yes)
 UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes
 else
@@ -626,6 +636,9 @@ CONFIG_BUSPIRATE_SPI ?= yes
 # Always enable Dediprog SF100 for now.
 CONFIG_DEDIPROG ?= yes
 
+# Always enable Developerbox emergency recovery for now.
+CONFIG_DEVELOPERBOX ?= yes
+
 # Always enable Marvell SATA controllers for now.
 CONFIG_SATAMV ?= yes
 
@@ -666,6 +679,7 @@ endif
 ifeq ($(CONFIG_ENABLE_LIBUSB1_PROGRAMMERS), no)
 override CONFIG_CH341A_SPI = no
 override CONFIG_DEDIPROG = no
+override CONFIG_DEVELOPERBOX = no
 endif
 ifeq ($(CONFIG_ENABLE_LIBPCI_PROGRAMMERS), no)
 override CONFIG_INTERNAL = no
@@ -902,6 +916,12 @@ PROGRAMMER_OBJS += dediprog.o
 NEED_LIBUSB1 += CONFIG_DEDIPROG
 endif
 
+ifeq ($(CONFIG_DEVELOPERBOX), yes)
+FEATURE_CFLAGS += -D'CONFIG_DEVELOPERBOX=1'
+PROGRAMMER_OBJS += developerbox_spi.o
+NEED_LIBUSB1 += CONFIG_DEVELOPERBOX
+endif
+
 ifeq ($(CONFIG_SATAMV), yes)
 FEATURE_CFLAGS += -D'CONFIG_SATAMV=1'
 PROGRAMMER_OBJS += satamv.o
diff --git a/developerbox_spi.c b/developerbox_spi.c
new file mode 100644
index 000000000000..5742ed093b1a
--- /dev/null
+++ b/developerbox_spi.c
@@ -0,0 +1,296 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2018 Linaro Limited
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.
+ */
+
+/* Bit bang driver for the 96Boards Developerbox (a.k.a. Synquacer E-series)
+ * on-board debug UART.  The Developerbox implements its debug UART using a
+ * CP2102N, a USB to UART bridge will also provides four GPIO pins. On
+ * Developerbox these can be hooked up to the onboard SPI NOR FLASH and used
+ * for emergency de-brick without any additional hardware programmer. Bit
+ * banging over USB is extremely slow compared to a proper SPI programmer so
+ * this is only practical as a de-brick tool.
+ *
+ * Schematic is available here:
+ * https://www.96boards.org/documentation/enterprise/developerbox/hardware-docs/
+ */
+
+#include "platform.h"
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include <libusb.h>
+#include "flash.h"
+#include "chipdrivers.h"
+#include "programmer.h"
+#include "spi.h"
+
+/* LIBUSB_CALL ensures the right calling conventions on libusb callbacks.
+ * However, the macro is not defined everywhere. m(
+ */
+#ifndef LIBUSB_CALL
+#define LIBUSB_CALL
+#endif
+
+/* To prepare a Developerbox for programming via the debug UART DSW4 must be
+ * changed from the default 00000000 to 10001000 (DSW4-1 and DSW4-5 should be
+ * turned on)
+ */
+
+/* Bit positions for each pin. */
+#define DEVELOPERBOX_SPI_SCK		0
+#define DEVELOPERBOX_SPI_CS		1
+#define DEVELOPERBOX_SPI_MISO		2
+#define DEVELOPERBOX_SPI_MOSI		3
+
+/* Config request types */
+#define REQTYPE_HOST_TO_DEVICE  0x40
+#define REQTYPE_DEVICE_TO_HOST  0xc0
+
+/* Config request codes */
+#define CP210X_VENDOR_SPECIFIC  0xFF
+
+/* CP210X_VENDOR_SPECIFIC */
+#define CP210X_WRITE_LATCH      0x37E1
+#define CP210X_READ_LATCH       0x00C2
+
+const struct dev_entry devs_developerbox[] = {
+	{0x10C4, 0xEA60, OK, "Silicon Labs", "CP2102N USB to UART Bridge Controller"},
+	{0},
+};
+
+struct libusb_context *usb_ctx;
+static libusb_device_handle *cp210x_handle;
+
+#define CP210X_FAST
+#ifdef CP210X_FAST
+static int cp210x_mosi;
+static int cp210x_sck;
+#endif
+
+static int cp210x_gpio_get()
+{
+	int res;
+	uint8_t gpio;
+
+	res = libusb_control_transfer (
+		cp210x_handle,          // libusb_device_handle *  dev_handle,
+                REQTYPE_DEVICE_TO_HOST, // uint8_t         bmRequestType,
+                CP210X_VENDOR_SPECIFIC, // uint8_t         bRequest,
+                CP210X_READ_LATCH,      // uint16_t        wValue,
+                0,                      // uint16_t        wIndex,
+                &gpio,                  // unsigned char * data,
+                1,                      // uint16_t        wLength,
+                0);                     // unsigned int    timeout
+
+	if (res < 0) {
+		msg_perr("Failed to read GPIO pins (%s)\n", libusb_error_name(res));
+		return 0;
+	}
+
+	return gpio;
+}
+
+static void cp210x_gpio_set(uint8_t val, uint8_t mask)
+{
+	int res;
+	uint16_t gpio;
+
+	gpio = ((val & 0xf) << 8) | (mask & 0xf);
+
+	/* Set relay state on the card */
+	res = libusb_control_transfer (
+                cp210x_handle,          // libusb_device_handle *  dev_handle,
+                REQTYPE_HOST_TO_DEVICE, // uint8_t         bmRequestType,
+                CP210X_VENDOR_SPECIFIC, // uint8_t         bRequest,
+                CP210X_WRITE_LATCH,     // uint16_t        wValue,
+                gpio,                   // uint16_t        wIndex,
+                NULL,                   // unsigned char * data,
+                0,                      // uint16_t        wLength,
+                0);                     // unsigned int    timeout
+
+	if (res < 0)
+		msg_perr("Failed to read GPIO pins (%s)\n", libusb_error_name(res));
+}
+
+static void cp210x_bitbang_set_cs(int val)
+{
+	msg_pspew(">><<: %s(%d)\n", __FUNCTION__, val);
+
+#ifdef CP210X_FAST
+	/* evict any cached state before updating chip select */
+	cp210x_gpio_set(cp210x_mosi << DEVELOPERBOX_SPI_MOSI |
+			    cp210x_sck << DEVELOPERBOX_SPI_SCK,
+			1 << DEVELOPERBOX_SPI_MOSI | 1 << DEVELOPERBOX_SPI_SCK);
+#endif
+
+	cp210x_gpio_set((!!val) << DEVELOPERBOX_SPI_CS, 1 << DEVELOPERBOX_SPI_CS);
+}
+
+static void cp210x_bitbang_set_sck(int val)
+{
+	msg_pspew(">><<: %s(%d)\n", __FUNCTION__, val);
+#ifndef CP210X_FAST
+	cp210x_gpio_set((!!val) << DEVELOPERBOX_SPI_SCK, 1 << DEVELOPERBOX_SPI_SCK);
+#else
+	/* evict any previous falling edge */
+	if (!cp210x_sck)
+		cp210x_gpio_set(cp210x_mosi << DEVELOPERBOX_SPI_MOSI,
+				1 << DEVELOPERBOX_SPI_MOSI | 1 << DEVELOPERBOX_SPI_SCK);
+
+	cp210x_sck = !!val;
+
+	/* send a rising edge */
+	if (cp210x_sck)
+		cp210x_gpio_set(cp210x_sck << DEVELOPERBOX_SPI_SCK,
+				1 << DEVELOPERBOX_SPI_SCK);
+#endif
+}
+
+static void cp210x_bitbang_set_mosi(int val)
+{
+	msg_pspew(">><<: %s(%d)\n", __FUNCTION__, val);
+#ifndef CP210X_FAST
+	cp210x_gpio_set((!!val) << DEVELOPERBOX_SPI_MOSI, 1 << DEVELOPERBOX_SPI_MOSI);
+#else
+	cp210x_mosi = !!val;
+#endif
+}
+
+static int cp210x_bitbang_get_miso(void)
+{
+	msg_pspew(">><<: %s\n", __FUNCTION__);
+	return !!(cp210x_gpio_get() & (1 << DEVELOPERBOX_SPI_MISO));
+}
+
+static const struct bitbang_spi_master bitbang_spi_master_cp210x = {
+	.type = BITBANG_SPI_MASTER_DEVELOPERBOX,
+	.set_cs = cp210x_bitbang_set_cs,
+	.set_sck = cp210x_bitbang_set_sck,
+	.set_mosi = cp210x_bitbang_set_mosi,
+	.get_miso = cp210x_bitbang_get_miso,
+	.half_period = 0,
+};
+
+/* Might be useful for other USB devices as well. static for now.
+ * num parameter allows user to specify one device of multiple installed */
+static struct libusb_device_handle *get_device_by_vid_pid_number(uint16_t vid, uint16_t pid, unsigned int num)
+{
+	struct libusb_device **list;
+	ssize_t count = libusb_get_device_list(usb_ctx, &list);
+	if (count < 0) {
+		msg_perr("Getting the USB device list failed (%s)!\n", libusb_error_name(count));
+		return NULL;
+	}
+
+	struct libusb_device_handle *handle = NULL;
+	ssize_t i = 0;
+	for (i = 0; i < count; i++) {
+		struct libusb_device *dev = list[i];
+		struct libusb_device_descriptor desc;
+		int err = libusb_get_device_descriptor(dev, &desc);
+		if (err != 0) {
+			msg_perr("Reading the USB device descriptor failed (%s)!\n", libusb_error_name(err));
+			libusb_free_device_list(list, 1);
+			return NULL;
+		}
+		if ((desc.idVendor == vid) && (desc.idProduct == pid)) {
+			msg_pdbg("Found USB device %04"PRIx16":%04"PRIx16" at address %d-%d.\n",
+				 desc.idVendor, desc.idProduct,
+				 libusb_get_bus_number(dev), libusb_get_device_address(dev));
+			if (num == 0) {
+				err = libusb_open(dev, &handle);
+				if (err != 0) {
+					msg_perr("Opening the USB device failed (%s)!\n",
+						 libusb_error_name(err));
+					libusb_free_device_list(list, 1);
+					return NULL;
+				}
+				break;
+			}
+			num--;
+		}
+	}
+	libusb_free_device_list(list, 1);
+
+	return handle;
+}
+
+static int developerbox_spi_shutdown(void *data)
+{
+	libusb_close(cp210x_handle);
+	libusb_exit(usb_ctx);
+
+	return 0;
+}
+
+int developerbox_spi_init()
+{
+	char *device;
+	long usedevice = 0;
+
+	device = extract_programmer_param("device");
+	if (device) {
+		char *dev_suffix;
+		errno = 0;
+		usedevice = strtol(device, &dev_suffix, 10);
+		if (errno != 0 || device == dev_suffix) {
+			msg_perr("Error: Could not convert 'device'.\n");
+			free(device);
+			return 1;
+		}
+		if (usedevice < 0 || usedevice > UINT_MAX) {
+			msg_perr("Error: Value for 'device' is out of range.\n");
+			free(device);
+			return 1;
+		}
+		if (strlen(dev_suffix) > 0) {
+			msg_perr("Error: Garbage following 'device' value.\n");
+			free(device);
+			return 1;
+		}
+		msg_pinfo("Using device %li.\n", usedevice);
+	}
+	free(device);
+
+	/* Here comes the USB stuff. */
+	libusb_init(&usb_ctx);
+	if (!usb_ctx) {
+		msg_perr("Could not initialize libusb!\n");
+		return 1;
+	}
+
+	const uint16_t vid = devs_developerbox[0].vendor_id;
+	const uint16_t pid = devs_developerbox[0].device_id;
+	cp210x_handle = get_device_by_vid_pid_number(vid, pid, (unsigned int) usedevice);
+	if (!cp210x_handle) {
+		msg_perr("Could not find a Developerbox programmer on USB.\n");
+		libusb_exit(usb_ctx);
+		return 1;
+	}
+
+	if (register_shutdown(developerbox_spi_shutdown, NULL))
+		return 1;
+
+	if (register_spi_bitbang_master(&bitbang_spi_master_cp210x)) {
+		/* This should never happen. */
+		msg_perr("Developerbox bitbang SPI master init failed!\n");
+		return 1;
+	}
+
+	return 0;
+}
diff --git a/flashrom.c b/flashrom.c
index f85dbb1f836c..6f8fc740d85b 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -255,6 +255,18 @@ const struct programmer_entry programmer_table[] = {
 	},
 #endif
 
+#if CONFIG_DEVELOPERBOX == 1
+	{
+		.name			= "developerbox",
+		.type			= USB,
+		.devs.dev		= devs_developerbox,
+		.init			= developerbox_spi_init,
+		.map_flash_region	= fallback_map,
+		.unmap_flash_region	= fallback_unmap,
+		.delay			= internal_delay,
+	},
+#endif
+
 #if CONFIG_RAYER_SPI == 1
 	{
 		.name			= "rayer_spi",
diff --git a/programmer.h b/programmer.h
index e49f2621ea1e..e0cf8ca759fe 100644
--- a/programmer.h
+++ b/programmer.h
@@ -73,6 +73,9 @@ enum programmer {
 #if CONFIG_DEDIPROG == 1
 	PROGRAMMER_DEDIPROG,
 #endif
+#if CONFIG_DEVELOPERBOX == 1
+	PROGRAMMER_DEVELOPERBOX,
+#endif
 #if CONFIG_RAYER_SPI == 1
 	PROGRAMMER_RAYER_SPI,
 #endif
@@ -169,6 +172,9 @@ enum bitbang_spi_master_type {
 #if CONFIG_OGP_SPI == 1
 	BITBANG_SPI_MASTER_OGP,
 #endif
+#if CONFIG_DEVELOPERBOX == 1
+	BITBANG_SPI_MASTER_DEVELOPERBOX,
+#endif
 };
 
 struct bitbang_spi_master {
@@ -542,6 +548,12 @@ int dediprog_init(void);
 extern const struct dev_entry devs_dediprog[];
 #endif
 
+/* developerbox_spi.c */
+#if CONFIG_DEVELOPERBOX == 1
+int developerbox_spi_init(void);
+extern const struct dev_entry devs_developerbox[];
+#endif
+
 /* ch341a_spi.c */
 #if CONFIG_CH341A_SPI == 1
 int ch341a_spi_init(void);
