[flashrom] [PATCH 4/7] add lpt_bitbang_spi based on rayer_spi
Maksim Kuleshov
mmcx at mail.ru
Sun Mar 31 17:06:23 CEST 2013
From 05f717c81da603472988e31c63a2c082fef6c491 Mon Sep 17 00:00:00 2001
From: Maksim Kuleshov <mmcx at 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 at 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
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
--
1.7.10.4
More information about the flashrom
mailing list