Patchwork [4/7] add lpt_bitbang_spi based on rayer_spi

login
register
about
Submitter Maksim Kuleshov
Date 2013-03-31 15:06:23
Message ID <20130331190623.89cb0f48659deae11cc35926@mail.ru>
Download mbox | patch
Permalink /patch/3910/
State New
Headers show

Comments

Maksim Kuleshov - 2013-03-31 15:06:23
From 05f717c81da603472988e31c63a2c082fef6c491 Mon Sep 17 00:00:00 2001
From: Maksim Kuleshov <mmcx@mail.ru>

Date: Sun, 31 Mar 2013 17:41:12 +0400
Subject: [PATCH 4/7] add lpt_bitbang_spi based on rayer_spi
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

add lpt_bitbang_spi based on rayer_spi
    Integrated patchs:
        [flashrom] [PATCH (1-5)/5] rayer_spi: Create list of programmer types
            Wed Mar 6 23:48:43 CET 2013 Kyösti Mälkki
        [flashrom] [PATCH (0-3)/3] rayer_spi: Add support for Willem EPROM programmer SPI
            Sat Mar 16 23:42:50 CET 2013 Ondrej Zary

Signed-off-by: Maksim Kuleshov <mmcx@mail.ru>

---
 lpt_bitbang_spi.c |  406 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 lpt_bitbang_spi.h |    6 +
 2 files changed, 412 insertions(+)
 create mode 100644 lpt_bitbang_spi.c
 create mode 100644 lpt_bitbang_spi.h

-- 
1.7.10.4

Patch

diff --git a/lpt_bitbang_spi.c b/lpt_bitbang_spi.c

new file mode 100644
index 0000000..2350e2b

--- /dev/null

+++ b/lpt_bitbang_spi.c

@@ -0,0 +1,406 @@ 

+/*

+ * This file is part of the flashrom project.

+ *

+ * Copyright (C) 2009,2010 Carl-Daniel Hailfinger

+ * Copyright (C) 2013 Kyösti Mälkki

+ * Copyright (C) 2013 Ondrej Zary

+ * Copyright (C) 2013 Maksim Kuleshov

+ *

+ * 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.

+ *

+ * You should have received a copy of the GNU General Public License

+ * along with this program; if not, write to the Free Software

+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA

+ */

+

+#include <stdlib.h>

+#include <strings.h>

+#include <string.h>

+#include "lpt_bitbang_spi.h"

+

+#include "flash.h"

+#include "programmer.h"

+

+#include "lpt_io.h"

+

+typedef uint_fast16_t pins_mask_t;

+

+struct lpt_bitbang_spi_pin {

+	pins_mask_t set_mask;

+	pins_mask_t clear_mask;

+};

+

+struct lpt_bitbang_spi_programmer {

+	const char *type;

+	const enum test_state status;

+	const char *description;

+	const char *url;

+	struct lpt_bitbang_spi_pin spi_cs;

+	struct lpt_bitbang_spi_pin spi_sck;

+	struct lpt_bitbang_spi_pin spi_miso;

+	struct lpt_bitbang_spi_pin spi_mosi;

+	struct lpt_bitbang_spi_pin on_enable;

+	struct lpt_bitbang_spi_pin on_disable;

+	int (*preinit) (void *data);

+	int (*shutdown) (void *data);

+};

+

+enum {

+	LPT_OUT_PIN_1 = (1UL << (0 + 8)),

+	LPT_OUT_PIN_2 = (1UL << 0),

+	LPT_OUT_PIN_3 = (1UL << 1),

+	LPT_OUT_PIN_4 = (1UL << 2),

+	LPT_OUT_PIN_5 = (1UL << 3),

+	LPT_OUT_PIN_6 = (1UL << 4),

+	LPT_OUT_PIN_7 = (1UL << 5),

+	LPT_OUT_PIN_8 = (1UL << 6),

+	LPT_OUT_PIN_9 = (1UL << 7),

+	LPT_OUT_PIN_14 = (1UL << (1 + 8)),

+	LPT_OUT_PIN_15 = (1UL << 3),

+	LPT_OUT_PIN_16 = (1UL << (2 + 8)),

+	LPT_OUT_PIN_17 = (1UL << (3 + 8)),

+

+	LPT_IN_PIN_10 = (1UL << 6),

+	LPT_IN_PIN_11 = (1UL << 7),

+	LPT_IN_PIN_12 = (1UL << 5),

+	LPT_IN_PIN_13 = (1UL << 4),

+};

+

+static struct lpt_bitbang_spi_programmer prog_rayer_spipgm = {

+	.type = "rayer",

+	.status = NT,

+	.description = "SPIPGM hardware by \"RayeR\" Martin Rehak",

+	.url = "http://rayer.ic.cz/elektro/spipgm.htm",

+	.spi_cs = {LPT_OUT_PIN_7, 0},

+	.spi_sck = {LPT_OUT_PIN_8, 0},

+	.spi_mosi = {LPT_OUT_PIN_9, 0},

+	.spi_miso = {LPT_IN_PIN_10, 0},

+};

+

+static struct lpt_bitbang_spi_programmer prog_xilinx_dlc5 = {

+	.type = "xilinx",

+	.status = NT,

+	.description = "Xilinx Parallel Cable III (DLC 5)",

+	.url =

+	    "http://www.xilinx.com/support/documentation/user_guides/xtp029.pdf",

+	.spi_cs = {LPT_OUT_PIN_4, 0},

+	.spi_sck = {LPT_OUT_PIN_3, 0},

+	.spi_mosi = {LPT_OUT_PIN_2, 0},

+	.spi_miso = {LPT_IN_PIN_13, 0},

+	.on_enable = {LPT_OUT_PIN_6, LPT_OUT_PIN_5},

+	.on_disable = {LPT_OUT_PIN_6 | LPT_OUT_PIN_5, 0},

+};

+

+static struct lpt_bitbang_spi_programmer prog_altera_byteblastermv = {

+	.type = "byteblaster",

+	.status = NT,

+	.description = "Altera ByteBlasterMV",

+	.url = "ftp://ftp.altera.com/pub/lit_req/document/ds/dsbytemv.pdf",

+	.spi_cs = {LPT_OUT_PIN_3, 0},

+	.spi_sck = {LPT_OUT_PIN_2, 0},

+	.spi_mosi = {LPT_OUT_PIN_8, 0},

+	.spi_miso = {LPT_IN_PIN_11, 0},

+	.on_enable = {0, LPT_OUT_PIN_14},

+	.on_disable = {LPT_OUT_PIN_14, 0},

+};

+

+static struct lpt_bitbang_spi_programmer prog_atmel_stk200 = {

+	.type = "stk200",

+	.status = NT,

+	.description = "Atmel STK200/300 adapter",

+	.url = "http://real.kiev.ua/old/avreal/en/adapters.html#STK",

+	.spi_cs = {LPT_OUT_PIN_9, 0},

+	.spi_sck = {LPT_OUT_PIN_6, 0},

+	.spi_mosi = {LPT_OUT_PIN_7, 0},

+	.spi_miso = {LPT_IN_PIN_10, 0},

+	.on_enable = {0, LPT_OUT_PIN_4 | LPT_OUT_PIN_5},

+	.on_disable = {LPT_OUT_PIN_4 | LPT_OUT_PIN_5, 0},

+};

+

+static struct lpt_bitbang_spi_programmer prog_wiggler_lpt = {

+	.type = "wiggler",

+	.status = NT,

+	.description = "Wiggler LPT",

+	.url = "http://wiki.openwrt.org/doc/hardware/port.jtag.cable.buffered",

+	.spi_cs = {LPT_OUT_PIN_3, 0},

+	.spi_sck = {LPT_OUT_PIN_4, 0},

+	.spi_mosi = {LPT_OUT_PIN_5, 0},

+	.spi_miso = {LPT_IN_PIN_11, 0},

+};

+

+static struct lpt_bitbang_spi_programmer prog_willem_spi = {

+	.type = "willem",

+	.status = NT,

+	.description = "Willem EPROM Programmer SPI",

+	.spi_cs = {LPT_OUT_PIN_17, 0},

+	.spi_sck = {LPT_OUT_PIN_3, 0},

+	.spi_mosi = {0, LPT_OUT_PIN_2},

+	.spi_miso = {LPT_IN_PIN_11, 0},

+	.on_enable = {LPT_OUT_PIN_16 | LPT_OUT_PIN_14 | LPT_OUT_PIN_1, 0},

+	.on_disable = {LPT_OUT_PIN_1, LPT_OUT_PIN_16 | LPT_OUT_PIN_14},

+};

+

+static struct lpt_bitbang_spi_programmer *lpt_bitbang_spi_types[] = {

+	&prog_rayer_spipgm,

+	&prog_xilinx_dlc5,

+	&prog_altera_byteblastermv,

+	&prog_atmel_stk200,

+	&prog_wiggler_lpt,

+	&prog_willem_spi,

+	NULL

+};

+

+static struct lpt_bitbang_spi_programmer *programmer = NULL;

+static lpt_io_context_t lpt_io_context = NULL;

+static pins_mask_t lpt_pins_state_cached = 0;

+

+#define LOBYTE(value) ((value) & 0xff)

+#define HIBYTE(value) (((value)>>8) & 0xff)

+

+static void lpt_bitbang_out_pins(pins_mask_t lpt_pins_state)

+{

+	lpt_io_out_data(lpt_io_context, LOBYTE(lpt_pins_state));

+	lpt_io_out_control(lpt_io_context, HIBYTE(lpt_pins_state));

+	lpt_pins_state_cached = lpt_pins_state;

+}

+

+static void lpt_bitbang_change_pins(pins_mask_t set_mask,

+				    pins_mask_t clear_mask)

+{

+	pins_mask_t lpt_pins_state = lpt_pins_state_cached;

+	lpt_pins_state |= set_mask;

+	lpt_pins_state &= ~clear_mask;

+

+	if (LOBYTE(lpt_pins_state) != LOBYTE(lpt_pins_state_cached)) {

+		lpt_io_out_data(lpt_io_context, LOBYTE(lpt_pins_state));

+	}

+

+	if (HIBYTE(lpt_pins_state) != HIBYTE(lpt_pins_state_cached)) {

+		lpt_io_out_control(lpt_io_context, HIBYTE(lpt_pins_state));

+	}

+

+	lpt_pins_state_cached = lpt_pins_state;

+}

+

+static void lpt_bitbang_spi_set_pin(struct lpt_bitbang_spi_pin *pin, int val)

+{

+	if (val) {

+		lpt_bitbang_change_pins(pin->set_mask, pin->clear_mask);

+

+	} else {

+		lpt_bitbang_change_pins(pin->clear_mask, pin->set_mask);

+	}

+}

+

+static inline int lpt_bitbang_spi_get_pin(struct lpt_bitbang_spi_pin *pin)

+{

+	uint8_t tmp = lpt_io_in_status(lpt_io_context);

+	return ((tmp & pin->set_mask) | (~tmp & pin->clear_mask)) != 0;

+}

+

+static void lpt_bitbang_spi_set_cs(int val)

+{

+	lpt_bitbang_spi_set_pin(&programmer->spi_cs, val);

+}

+

+static void lpt_bitbang_spi_set_sck(int val)

+{

+	lpt_bitbang_spi_set_pin(&programmer->spi_sck, val);

+}

+

+static void lpt_bitbang_spi_set_mosi(int val)

+{

+	lpt_bitbang_spi_set_pin(&programmer->spi_mosi, val);

+}

+

+static int lpt_bitbang_spi_get_miso(void)

+{

+	return lpt_bitbang_spi_get_pin(&programmer->spi_miso);

+}

+

+static int lpt_bitbang_spi_generic_preinit(void *data)

+{

+	struct lpt_bitbang_spi_programmer *prog =

+	    (struct lpt_bitbang_spi_programmer *)data;

+	msg_pdbg("%s preinit\n", prog->type);

+	lpt_bitbang_spi_set_pin(&prog->on_enable, 1);

+	return 0;

+}

+

+static int lpt_bitbang_spi_generic_shutdown(void *data)

+{

+	struct lpt_bitbang_spi_programmer *prog =

+	    (struct lpt_bitbang_spi_programmer *)data;

+	msg_pdbg("%s shutdown\n", prog->type);

+	lpt_bitbang_spi_set_pin(&prog->spi_cs, 1);

+	lpt_bitbang_spi_set_pin(&prog->on_disable, 1);

+	return 0;

+}

+

+static const struct bitbang_spi_master lpt_bitbang_spi_master = {

+	.type = BITBANG_SPI_MASTER_RAYER,

+	.set_cs = lpt_bitbang_spi_set_cs,

+	.set_sck = lpt_bitbang_spi_set_sck,

+	.set_mosi = lpt_bitbang_spi_set_mosi,

+	.get_miso = lpt_bitbang_spi_get_miso,

+	.half_period = 0,

+};

+

+static int lpt_bitbang_spi_io_init(void *data)

+{

+	(void)data;

+	int io_selected = 0;

+

+	if (!io_selected) {

+		char *arg = extract_programmer_param("ppdev");

+

+		if (arg) {

+			int err;

+			msg_pdbg("Using ppdev=%s for parallel port access.\n",

+				 arg);

+			err =

+			    lpt_io_init(&lpt_io_context, "ppdev", (void *)arg);

+			free(arg);

+			io_selected = 1;

+

+			if (err) {

+				return err;

+			}

+		}

+	}

+

+	if (!io_selected) {

+		char *arg = extract_programmer_param("iobase");

+

+		if (arg) {

+			int err;

+			char *endptr = NULL;

+			unsigned long iobase = strtoul(arg, &endptr, 0);

+			free(arg);

+			io_selected = 2;

+

+			/* Port 0, port >0x10000, unaligned ports and garbage strings

+			 * are rejected.

+			 */

+			if ((iobase <= 0x100) || (iobase >= 0x10000)

+			    || (iobase & 0x3) || (*endptr != '\0')) {

+				/* Using ports below 0x100 is a really bad idea, and

+				 * should only be done if no port between 0x100 and

+				 * 0xfffc works due to routing issues.

+				 */

+				msg_perr

+				    ("Error: iobase= specified, but the I/O base "

+				     "given was invalid.\nIt must be a multiple of "

+				     "0x4 and lie between 0x100 and 0xfffc.\n");

+				return 1;

+

+			} else {

+				msg_pinfo

+				    ("Using address 0x%lx as I/O base for parallel port access.\n",

+				     iobase);

+				err =

+				    lpt_io_init(&lpt_io_context, "direct",

+						(void *)&iobase);

+

+				if (err) {

+					return err;

+				}

+			}

+		}

+	}

+

+	if (!io_selected) {

+		int err;

+		/* Pick a default value for the I/O base. */

+		unsigned long iobase = 0x378;

+		io_selected = 3;

+		msg_pdbg

+		    ("Using address 0x%lx as I/O base for parallel port access.\n",

+		     iobase);

+		err = lpt_io_init(&lpt_io_context, "direct", (void *)&iobase);

+

+		if (err) {

+			return err;

+		}

+	}

+

+	if (!io_selected) {

+		msg_perr("not awailable lpt_io method\n");

+		return 1;

+	}

+

+	/* Get the initial value before writing to any line. */

+	lpt_bitbang_out_pins(lpt_io_in_data(lpt_io_context));

+	return 0;

+}

+

+int lpt_bitbang_spi_init(void)

+{

+	struct lpt_bitbang_spi_programmer **prog = lpt_bitbang_spi_types;

+	char *arg = NULL;

+	programmer = *prog;

+	arg = extract_programmer_param("type");

+

+	if (arg) {

+		for (; *prog; ++prog) {

+			if (0 == strcasecmp(arg, (*prog)->type)) {

+				break;

+			}

+		}

+

+		free(arg);

+

+		if (!*prog) {

+			msg_perr("Error: Invalid device type specified.\n");

+			return 1;

+		}

+	}

+

+	msg_pinfo("programmer: %s\n", (*prog)->type);

+

+	if ((*prog)->description) {

+		msg_pinfo("decription: \"%s\"\n", (*prog)->description);

+	}

+

+	if ((*prog)->url) {

+		msg_pinfo("url: \"%s\"\n", (*prog)->url);

+	}

+

+	programmer = *prog;

+

+	if (lpt_bitbang_spi_io_init(NULL)) {

+		return 1;

+	}

+

+	if (programmer->shutdown) {

+		register_shutdown(programmer->shutdown, (void *)programmer);

+

+	} else {

+		register_shutdown(lpt_bitbang_spi_generic_shutdown,

+				  (void *)programmer);

+	}

+

+	if (programmer->preinit) {

+		if (programmer->preinit(programmer)) {

+			return 1;

+		}

+

+	} else {

+		if (lpt_bitbang_spi_generic_preinit(programmer)) {

+			return 1;

+		}

+	}

+

+	if (bitbang_spi_init(&lpt_bitbang_spi_master)) {

+		return 1;

+	}

+

+	return 0;

+}

diff --git a/lpt_bitbang_spi.h b/lpt_bitbang_spi.h

new file mode 100644
index 0000000..901628a

--- /dev/null

+++ b/lpt_bitbang_spi.h

@@ -0,0 +1,6 @@ 

+#ifndef lpt_bitbang_spi_h_included_

+#define lpt_bitbang_spi_h_included_

+

+int lpt_bitbang_spi_init(void);

+

+#endif