diff options
Diffstat (limited to 'rayer_spi.c')
-rw-r--r-- | rayer_spi.c | 302 |
1 files changed, 182 insertions, 120 deletions
diff --git a/rayer_spi.c b/rayer_spi.c index 8e869e66d..27caf2be1 100644 --- a/rayer_spi.c +++ b/rayer_spi.c @@ -22,14 +22,13 @@ * most OS parport drivers will perform many unnecessary accesses although * this driver just treats the parallel port as a GPIO set. */ -#if defined(__i386__) || defined(__x86_64__) #include <stdlib.h> #include <strings.h> #include <string.h> #include "flash.h" #include "programmer.h" -#include "hwaccess.h" +#include "hwaccess_x86_io.h" /* We have two sets of pins, out and in. The numbers for both sets are * independent and are bitshift values, not real pin numbers. @@ -48,10 +47,18 @@ struct rayer_pinout { uint8_t sck_bit; uint8_t mosi_bit; uint8_t miso_bit; - void (*preinit)(const void *); + void (*preinit)(void *); int (*shutdown)(void *); }; +struct rayer_spi_data { + uint16_t lpt_iobase; + /* Cached value of last byte sent. */ + uint8_t lpt_outbyte; + + const struct rayer_pinout *pinout; +}; + static const struct rayer_pinout rayer_spipgm = { .cs_bit = 5, .sck_bit = 6, @@ -59,8 +66,28 @@ static const struct rayer_pinout rayer_spipgm = { .miso_bit = 6, }; -static void dlc5_preinit(const void *); -static int dlc5_shutdown(void *); +static void dlc5_preinit(void *spi_data) +{ + struct rayer_spi_data *data = spi_data; + + msg_pdbg("dlc5_preinit\n"); + /* Assert pin 6 to receive MISO. */ + data->lpt_outbyte |= (1<<4); + OUTB(data->lpt_outbyte, data->lpt_iobase); +} + +static int dlc5_shutdown(void *spi_data) +{ + struct rayer_spi_data *data = spi_data; + + msg_pdbg("dlc5_shutdown\n"); + /* De-assert pin 6 to force MISO low. */ + data->lpt_outbyte &= ~(1<<4); + OUTB(data->lpt_outbyte, data->lpt_iobase); + + free(data); + return 0; +} static const struct rayer_pinout xilinx_dlc5 = { .cs_bit = 2, @@ -71,8 +98,26 @@ static const struct rayer_pinout xilinx_dlc5 = { .shutdown = dlc5_shutdown, }; -static void byteblaster_preinit(const void *); -static int byteblaster_shutdown(void *); +static void byteblaster_preinit(void *spi_data) +{ + struct rayer_spi_data *data = spi_data; + + msg_pdbg("byteblaster_preinit\n"); + /* Assert #EN signal. */ + OUTB(2, data->lpt_iobase + 2 ); +} + +static int byteblaster_shutdown(void *spi_data) +{ + struct rayer_spi_data *data = spi_data; + + msg_pdbg("byteblaster_shutdown\n"); + /* De-Assert #EN signal. */ + OUTB(0, data->lpt_iobase + 2 ); + + free(data); + return 0; +} static const struct rayer_pinout altera_byteblastermv = { .cs_bit = 1, @@ -83,8 +128,28 @@ static const struct rayer_pinout altera_byteblastermv = { .shutdown = byteblaster_shutdown, }; -static void stk200_preinit(const void *); -static int stk200_shutdown(void *); +static void stk200_preinit(void *spi_data) +{ + struct rayer_spi_data *data = spi_data; + + msg_pdbg("stk200_init\n"); + /* Assert #EN signals, set LED signal. */ + data->lpt_outbyte = (1 << 6) ; + OUTB(data->lpt_outbyte, data->lpt_iobase); +} + +static int stk200_shutdown(void *spi_data) +{ + struct rayer_spi_data *data = spi_data; + + msg_pdbg("stk200_shutdown\n"); + /* Assert #EN signals, clear LED signal. */ + data->lpt_outbyte = (1 << 2) | (1 << 3); + OUTB(data->lpt_outbyte, data->lpt_iobase); + + free(data); + return 0; +} static const struct rayer_pinout atmel_stk200 = { .cs_bit = 7, @@ -109,72 +174,99 @@ static const struct rayer_pinout spi_tt = { .miso_bit = 7, }; -static const struct rayer_programmer rayer_spi_types[] = { - {"rayer", NT, "RayeR SPIPGM", &rayer_spipgm}, - {"xilinx", NT, "Xilinx Parallel Cable III (DLC 5)", &xilinx_dlc5}, - {"byteblastermv", OK, "Altera ByteBlasterMV", &altera_byteblastermv}, - {"stk200", NT, "Atmel STK200/300 adapter", &atmel_stk200}, - {"wiggler", OK, "Wiggler LPT", &wiggler_lpt}, - {"spi_tt", NT, "SPI Tiny Tools (SPI_TT LPT)", &spi_tt}, - {0}, -}; - -static const struct rayer_pinout *pinout = NULL; - -static uint16_t lpt_iobase; - -/* Cached value of last byte sent. */ -static uint8_t lpt_outbyte; - -static void rayer_bitbang_set_cs(int val) +static void rayer_bitbang_set_cs(int val, void *spi_data) { - lpt_outbyte &= ~(1 << pinout->cs_bit); - lpt_outbyte |= (val << pinout->cs_bit); - OUTB(lpt_outbyte, lpt_iobase); + struct rayer_spi_data *data = spi_data; + + data->lpt_outbyte &= ~(1 << data->pinout->cs_bit); + data->lpt_outbyte |= (val << data->pinout->cs_bit); + OUTB(data->lpt_outbyte, data->lpt_iobase); } -static void rayer_bitbang_set_sck(int val) +static void rayer_bitbang_set_sck(int val, void *spi_data) { - lpt_outbyte &= ~(1 << pinout->sck_bit); - lpt_outbyte |= (val << pinout->sck_bit); - OUTB(lpt_outbyte, lpt_iobase); + struct rayer_spi_data *data = spi_data; + + data->lpt_outbyte &= ~(1 << data->pinout->sck_bit); + data->lpt_outbyte |= (val << data->pinout->sck_bit); + OUTB(data->lpt_outbyte, data->lpt_iobase); } -static void rayer_bitbang_set_mosi(int val) +static void rayer_bitbang_set_mosi(int val, void *spi_data) { - lpt_outbyte &= ~(1 << pinout->mosi_bit); - lpt_outbyte |= (val << pinout->mosi_bit); - OUTB(lpt_outbyte, lpt_iobase); + struct rayer_spi_data *data = spi_data; + + data->lpt_outbyte &= ~(1 << data->pinout->mosi_bit); + data->lpt_outbyte |= (val << data->pinout->mosi_bit); + OUTB(data->lpt_outbyte, data->lpt_iobase); } -static int rayer_bitbang_get_miso(void) +static int rayer_bitbang_get_miso(void *spi_data) { + struct rayer_spi_data *data = spi_data; uint8_t tmp; - tmp = INB(lpt_iobase + 1) ^ 0x80; // bit.7 inverted - tmp = (tmp >> pinout->miso_bit) & 0x1; + tmp = INB(data->lpt_iobase + 1) ^ 0x80; // bit.7 inverted + tmp = (tmp >> data->pinout->miso_bit) & 0x1; return tmp; } +static int rayer_shutdown(void *spi_data) +{ + free(spi_data); + return 0; +} + static const struct bitbang_spi_master bitbang_spi_master_rayer = { - .set_cs = rayer_bitbang_set_cs, - .set_sck = rayer_bitbang_set_sck, - .set_mosi = rayer_bitbang_set_mosi, - .get_miso = rayer_bitbang_get_miso, - .half_period = 0, + .set_cs = rayer_bitbang_set_cs, + .set_sck = rayer_bitbang_set_sck, + .set_mosi = rayer_bitbang_set_mosi, + .get_miso = rayer_bitbang_get_miso, + .half_period = 0, }; -int rayer_spi_init(void) +static const struct rayer_programmer *find_progtype(const char *prog_type) { + static const struct rayer_programmer rayer_spi_types[] = { + {"rayer", NT, "RayeR SPIPGM", &rayer_spipgm}, + {"xilinx", NT, "Xilinx Parallel Cable III (DLC 5)", &xilinx_dlc5}, + {"byteblastermv", OK, "Altera ByteBlasterMV", &altera_byteblastermv}, + {"stk200", NT, "Atmel STK200/300 adapter", &atmel_stk200}, + {"wiggler", OK, "Wiggler LPT", &wiggler_lpt}, + {"spi_tt", NT, "SPI Tiny Tools (SPI_TT LPT)", &spi_tt}, + {0}, + }; + if (!prog_type) + return &rayer_spi_types[0]; + const struct rayer_programmer *prog = rayer_spi_types; - char *arg = NULL; + for (; prog->type != NULL; prog++) { + if (strcasecmp(prog_type, prog->type) == 0) { + break; + } + } + + if (!prog->type) { + msg_perr("Error: Invalid device type specified.\n"); + return NULL; + } + + return prog; +} + +static int get_params(const struct programmer_cfg *cfg, uint16_t *lpt_iobase, + const struct rayer_programmer **prog) +{ + /* Pick a default value for the I/O base. */ + *lpt_iobase = 0x378; + /* no programmer type specified. */ + *prog = NULL; /* Non-default port requested? */ - arg = extract_programmer_param("iobase"); + char *arg = extract_programmer_param_str(cfg, "iobase"); if (arg) { char *endptr = NULL; - unsigned long tmp; - tmp = strtoul(arg, &endptr, 0); + unsigned long tmp = strtoul(arg, &endptr, 0); /* Port 0, port >0x10000, unaligned ports and garbage strings * are rejected. */ @@ -188,98 +280,68 @@ int rayer_spi_init(void) "given was invalid.\nIt must be a multiple of " "0x4 and lie between 0x100 and 0xfffc.\n"); free(arg); - return 1; + return -1; } else { - lpt_iobase = (uint16_t)tmp; + *lpt_iobase = (uint16_t)tmp; msg_pinfo("Non-default I/O base requested. This will " "not change the hardware settings.\n"); } - } else { - /* Pick a default value for the I/O base. */ - lpt_iobase = 0x378; + free(arg); } + + arg = extract_programmer_param_str(cfg, "type"); + *prog = find_progtype(arg); free(arg); + return *prog ? 0 : -1; +} + +static int rayer_spi_init(const struct programmer_cfg *cfg) +{ + const struct rayer_programmer *prog; + struct rayer_pinout *pinout = NULL; + uint16_t lpt_iobase; + + if (get_params(cfg, &lpt_iobase, &prog) < 0) + return 1; + msg_pdbg("Using address 0x%x as I/O base for parallel port access.\n", lpt_iobase); - arg = extract_programmer_param("type"); - if (arg) { - for (; prog->type != NULL; prog++) { - if (strcasecmp(arg, prog->type) == 0) { - break; - } - } - if (prog->type == NULL) { - msg_perr("Error: Invalid device type specified.\n"); - free(arg); - return 1; - } - free(arg); - } msg_pinfo("Using %s pinout.\n", prog->description); pinout = (struct rayer_pinout *)prog->dev_data; if (rget_io_perms()) return 1; + struct rayer_spi_data *data = calloc(1, sizeof(*data)); + if (!data) { + msg_perr("Unable to allocate space for SPI master data\n"); + return 1; + } + data->pinout = pinout; + data->lpt_iobase = lpt_iobase; /* Get the initial value before writing to any line. */ - lpt_outbyte = INB(lpt_iobase); + data->lpt_outbyte = INB(lpt_iobase); if (pinout->shutdown) - register_shutdown(pinout->shutdown, (void*)pinout); + register_shutdown(pinout->shutdown, data); + else + register_shutdown(rayer_shutdown, data); + if (pinout->preinit) - pinout->preinit(pinout); + pinout->preinit(data); - if (register_spi_bitbang_master(&bitbang_spi_master_rayer)) + if (register_spi_bitbang_master(&bitbang_spi_master_rayer, data)) return 1; return 0; } -static void byteblaster_preinit(const void *data){ - msg_pdbg("byteblaster_preinit\n"); - /* Assert #EN signal. */ - OUTB(2, lpt_iobase + 2 ); -} - -static int byteblaster_shutdown(void *data){ - msg_pdbg("byteblaster_shutdown\n"); - /* De-Assert #EN signal. */ - OUTB(0, lpt_iobase + 2 ); - return 0; -} - -static void stk200_preinit(const void *data) { - msg_pdbg("stk200_init\n"); - /* Assert #EN signals, set LED signal. */ - lpt_outbyte = (1 << 6) ; - OUTB(lpt_outbyte, lpt_iobase); -} - -static int stk200_shutdown(void *data) { - msg_pdbg("stk200_shutdown\n"); - /* Assert #EN signals, clear LED signal. */ - lpt_outbyte = (1 << 2) | (1 << 3); - OUTB(lpt_outbyte, lpt_iobase); - return 0; -} - -static void dlc5_preinit(const void *data) { - msg_pdbg("dlc5_preinit\n"); - /* Assert pin 6 to receive MISO. */ - lpt_outbyte |= (1<<4); - OUTB(lpt_outbyte, lpt_iobase); -} - -static int dlc5_shutdown(void *data) { - msg_pdbg("dlc5_shutdown\n"); - /* De-assert pin 6 to force MISO low. */ - lpt_outbyte &= ~(1<<4); - OUTB(lpt_outbyte, lpt_iobase); - return 0; -} - -#else -#error PCI port I/O access is not supported on this architecture yet. -#endif +const struct programmer_entry programmer_rayer_spi = { + .name = "rayer_spi", + .type = OTHER, + /* FIXME */ + .devs.note = "RayeR parallel port programmer\n", + .init = rayer_spi_init, +}; |