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
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