123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- /*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009,2010 Carl-Daniel Hailfinger
- *
- * 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
- */
- /* Driver for the SPIPGM hardware by "RayeR" Martin Rehak.
- * See http://rayer.ic.cz/elektro/spipgm.htm for schematics and instructions.
- */
- /* This driver uses non-portable direct I/O port accesses which won't work on
- * any non-x86 platform, and even on x86 there is a high chance there will be
- * collisions with any loaded parallel port drivers.
- * The big advantage of direct port I/O is OS independence and speed because
- * 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 <string.h>
- #include "flash.h"
- #include "programmer.h"
- enum rayer_type {
- TYPE_RAYER,
- TYPE_XILINX_DLC5,
- };
- /* We have two sets of pins, out and in. The numbers for both sets are
- * independent and are bitshift values, not real pin numbers.
- * Default settings are for the RayeR hardware.
- */
- /* Pins for master->slave direction */
- static int rayer_cs_bit = 5;
- static int rayer_sck_bit = 6;
- static int rayer_mosi_bit = 7;
- /* Pins for slave->master direction */
- static int rayer_miso_bit = 6;
- static uint16_t lpt_iobase;
- /* Cached value of last byte sent. */
- static uint8_t lpt_outbyte;
- static void rayer_bitbang_set_cs(int val)
- {
- lpt_outbyte &= ~(1 << rayer_cs_bit);
- lpt_outbyte |= (val << rayer_cs_bit);
- OUTB(lpt_outbyte, lpt_iobase);
- }
- static void rayer_bitbang_set_sck(int val)
- {
- lpt_outbyte &= ~(1 << rayer_sck_bit);
- lpt_outbyte |= (val << rayer_sck_bit);
- OUTB(lpt_outbyte, lpt_iobase);
- }
- static void rayer_bitbang_set_mosi(int val)
- {
- lpt_outbyte &= ~(1 << rayer_mosi_bit);
- lpt_outbyte |= (val << rayer_mosi_bit);
- OUTB(lpt_outbyte, lpt_iobase);
- }
- static int rayer_bitbang_get_miso(void)
- {
- uint8_t tmp;
- tmp = INB(lpt_iobase + 1);
- tmp = (tmp >> rayer_miso_bit) & 0x1;
- return tmp;
- }
- static const struct bitbang_spi_master bitbang_spi_master_rayer = {
- .type = 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,
- };
- int rayer_spi_init(void)
- {
- char *arg = NULL;
- enum rayer_type rayer_type = TYPE_RAYER;
- /* Non-default port requested? */
- arg = extract_programmer_param("iobase");
- if (arg) {
- char *endptr = NULL;
- unsigned long tmp;
- tmp = strtoul(arg, &endptr, 0);
- /* Port 0, port >0x10000, unaligned ports and garbage strings
- * are rejected.
- */
- if (!tmp || (tmp >= 0x10000) || (tmp & 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");
- free(arg);
- return 1;
- } else {
- 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);
-
- msg_pdbg("Using address 0x%x as I/O base for parallel port access.\n",
- lpt_iobase);
- arg = extract_programmer_param("type");
- if (arg) {
- if (!strcasecmp(arg, "rayer")) {
- rayer_type = TYPE_RAYER;
- } else if (!strcasecmp(arg, "xilinx")) {
- rayer_type = TYPE_XILINX_DLC5;
- } else {
- msg_perr("Error: Invalid device type specified.\n");
- free(arg);
- return 1;
- }
- }
- free(arg);
- switch (rayer_type) {
- case TYPE_RAYER:
- msg_pdbg("Using RayeR SPIPGM pinout.\n");
- /* Bits for master->slave direction */
- rayer_cs_bit = 5;
- rayer_sck_bit = 6;
- rayer_mosi_bit = 7;
- /* Bits for slave->master direction */
- rayer_miso_bit = 6;
- break;
- case TYPE_XILINX_DLC5:
- msg_pdbg("Using Xilinx Parallel Cable III (DLC 5) pinout.\n");
- /* Bits for master->slave direction */
- rayer_cs_bit = 2;
- rayer_sck_bit = 1;
- rayer_mosi_bit = 0;
- /* Bits for slave->master direction */
- rayer_miso_bit = 4;
- }
- get_io_perms();
- /* Get the initial value before writing to any line. */
- lpt_outbyte = INB(lpt_iobase);
- /* Zero halfperiod delay. */
- if (bitbang_spi_init(&bitbang_spi_master_rayer, 0))
- return 1;
- return 0;
- }
- #else
- #error PCI port I/O access is not supported on this architecture yet.
- #endif
|