123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- /*
- * 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
- */
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <unistd.h>
- #include "flash.h"
- #include "programmer.h"
- #include "spi.h"
- /* Change this to #define if you want to test without a serial implementation */
- #undef FAKE_COMMUNICATION
- struct buspirate_spispeeds {
- const char *name;
- const int speed;
- };
- #ifndef FAKE_COMMUNICATION
- static int buspirate_serialport_setup(char *dev)
- {
- /* 115200bps, 8 databits, no parity, 1 stopbit */
- sp_fd = sp_openserport(dev, 115200);
- return 0;
- }
- #else
- #define buspirate_serialport_setup(...) 0
- #define serialport_shutdown(...) 0
- #define serialport_write(...) 0
- #define serialport_read(...) 0
- #define sp_flush_incoming(...) 0
- #endif
- static int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt,
- unsigned int readcnt)
- {
- int i, ret = 0;
- msg_pspew("%s: write %i, read %i ", __func__, writecnt, readcnt);
- if (!writecnt && !readcnt) {
- msg_perr("Zero length command!\n");
- return 1;
- }
- msg_pspew("Sending");
- for (i = 0; i < writecnt; i++)
- msg_pspew(" 0x%02x", buf[i]);
- #ifdef FAKE_COMMUNICATION
- /* Placate the caller for now. */
- if (readcnt) {
- buf[0] = 0x01;
- memset(buf + 1, 0xff, readcnt - 1);
- }
- ret = 0;
- #else
- if (writecnt)
- ret = serialport_write(buf, writecnt);
- if (ret)
- return ret;
- if (readcnt)
- ret = serialport_read(buf, readcnt);
- if (ret)
- return ret;
- #endif
- msg_pspew(", receiving");
- for (i = 0; i < readcnt; i++)
- msg_pspew(" 0x%02x", buf[i]);
- msg_pspew("\n");
- return 0;
- }
- static int buspirate_spi_send_command(const struct flashctx *flash,
- unsigned int writecnt,
- unsigned int readcnt,
- const unsigned char *writearr,
- unsigned char *readarr);
- static const struct spi_programmer spi_programmer_buspirate = {
- .type = SPI_CONTROLLER_BUSPIRATE,
- .max_data_read = 12,
- .max_data_write = 12,
- .command = buspirate_spi_send_command,
- .multicommand = default_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- };
- static const struct buspirate_spispeeds spispeeds[] = {
- {"30k", 0x0},
- {"125k", 0x1},
- {"250k", 0x2},
- {"1M", 0x3},
- {"2M", 0x4},
- {"2.6M", 0x5},
- {"4M", 0x6},
- {"8M", 0x7},
- {NULL, 0x0},
- };
- static int buspirate_spi_shutdown(void *data)
- {
- unsigned char buf[5];
- int ret = 0;
- /* Exit raw SPI mode (enter raw bitbang mode) */
- buf[0] = 0x00;
- ret = buspirate_sendrecv(buf, 1, 5);
- if (ret)
- return ret;
- if (memcmp(buf, "BBIO", 4)) {
- msg_perr("Entering raw bitbang mode failed!\n");
- return 1;
- }
- msg_pdbg("Raw bitbang mode version %c\n", buf[4]);
- if (buf[4] != '1') {
- msg_perr("Can't handle raw bitbang mode version %c!\n",
- buf[4]);
- return 1;
- }
- /* Reset Bus Pirate (return to user terminal) */
- buf[0] = 0x0f;
- ret = buspirate_sendrecv(buf, 1, 0);
- if (ret)
- return ret;
- /* Shut down serial port communication */
- ret = serialport_shutdown(NULL);
- if (ret)
- return ret;
- msg_pdbg("Bus Pirate shutdown completed.\n");
- return 0;
- }
- int buspirate_spi_init(void)
- {
- unsigned char buf[512];
- char *dev = NULL;
- char *speed = NULL;
- int spispeed = 0x7;
- int ret = 0;
- int i;
- dev = extract_programmer_param("dev");
- if (!dev || !strlen(dev)) {
- msg_perr("No serial device given. Use flashrom -p "
- "buspirate_spi:dev=/dev/ttyUSB0\n");
- return 1;
- }
- speed = extract_programmer_param("spispeed");
- if (speed) {
- for (i = 0; spispeeds[i].name; i++)
- if (!strncasecmp(spispeeds[i].name, speed,
- strlen(spispeeds[i].name))) {
- spispeed = spispeeds[i].speed;
- break;
- }
- if (!spispeeds[i].name)
- msg_perr("Invalid SPI speed, using default.\n");
- }
- free(speed);
- /* This works because speeds numbering starts at 0 and is contiguous. */
- msg_pdbg("SPI speed is %sHz\n", spispeeds[spispeed].name);
- ret = buspirate_serialport_setup(dev);
- if (ret)
- return ret;
- free(dev);
- if (register_shutdown(buspirate_spi_shutdown, NULL))
- return 1;
- /* This is the brute force version, but it should work. */
- for (i = 0; i < 19; i++) {
- /* Enter raw bitbang mode */
- buf[0] = 0x00;
- /* Send the command, don't read the response. */
- ret = buspirate_sendrecv(buf, 1, 0);
- if (ret)
- return ret;
- /* Read any response and discard it. */
- sp_flush_incoming();
- }
- /* USB is slow. The Bus Pirate is even slower. Apparently the flush
- * action above is too fast or too early. Some stuff still remains in
- * the pipe after the flush above, and one additional flush is not
- * sufficient either. Use a 1.5 ms delay inside the loop to make
- * mostly sure that at least one USB frame had time to arrive.
- * Looping only 5 times is not sufficient and causes the
- * occasional failure.
- * Folding the delay into the loop above is not reliable either.
- */
- for (i = 0; i < 10; i++) {
- usleep(1500);
- /* Read any response and discard it. */
- sp_flush_incoming();
- }
- /* Enter raw bitbang mode */
- buf[0] = 0x00;
- ret = buspirate_sendrecv(buf, 1, 5);
- if (ret)
- return ret;
- if (memcmp(buf, "BBIO", 4)) {
- msg_perr("Entering raw bitbang mode failed!\n");
- msg_pdbg("Got %02x%02x%02x%02x%02x\n",
- buf[0], buf[1], buf[2], buf[3], buf[4]);
- return 1;
- }
- msg_pdbg("Raw bitbang mode version %c\n", buf[4]);
- if (buf[4] != '1') {
- msg_perr("Can't handle raw bitbang mode version %c!\n",
- buf[4]);
- return 1;
- }
- /* Enter raw SPI mode */
- buf[0] = 0x01;
- ret = buspirate_sendrecv(buf, 1, 4);
- if (ret)
- return ret;
- if (memcmp(buf, "SPI", 3)) {
- msg_perr("Entering raw SPI mode failed!\n");
- msg_pdbg("Got %02x%02x%02x%02x\n",
- buf[0], buf[1], buf[2], buf[3]);
- return 1;
- }
- msg_pdbg("Raw SPI mode version %c\n", buf[3]);
- if (buf[3] != '1') {
- msg_perr("Can't handle raw SPI mode version %c!\n",
- buf[3]);
- return 1;
- }
- /* Initial setup (SPI peripherals config): Enable power, CS high, AUX */
- buf[0] = 0x40 | 0xb;
- ret = buspirate_sendrecv(buf, 1, 1);
- if (ret)
- return 1;
- if (buf[0] != 0x01) {
- msg_perr("Protocol error while setting power/CS/AUX!\n");
- return 1;
- }
- /* Set SPI speed */
- buf[0] = 0x60 | spispeed;
- ret = buspirate_sendrecv(buf, 1, 1);
- if (ret)
- return 1;
- if (buf[0] != 0x01) {
- msg_perr("Protocol error while setting SPI speed!\n");
- return 1;
- }
-
- /* Set SPI config: output type, idle, clock edge, sample */
- buf[0] = 0x80 | 0xa;
- ret = buspirate_sendrecv(buf, 1, 1);
- if (ret)
- return 1;
- if (buf[0] != 0x01) {
- msg_perr("Protocol error while setting SPI config!\n");
- return 1;
- }
- /* De-assert CS# */
- buf[0] = 0x03;
- ret = buspirate_sendrecv(buf, 1, 1);
- if (ret)
- return 1;
- if (buf[0] != 0x01) {
- msg_perr("Protocol error while raising CS#!\n");
- return 1;
- }
- register_spi_programmer(&spi_programmer_buspirate);
- return 0;
- }
- static int buspirate_spi_send_command(const struct flashctx *flash,
- unsigned int writecnt,
- unsigned int readcnt,
- const unsigned char *writearr,
- unsigned char *readarr)
- {
- static unsigned char *buf = NULL;
- unsigned int i = 0;
- int ret = 0;
- if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
- return SPI_INVALID_LENGTH;
- /* 3 bytes extra for CS#, len, CS#. */
- buf = realloc(buf, writecnt + readcnt + 3);
- if (!buf) {
- msg_perr("Out of memory!\n");
- exit(1); // -1
- }
- /* Assert CS# */
- buf[i++] = 0x02;
- buf[i++] = 0x10 | (writecnt + readcnt - 1);
- memcpy(buf + i, writearr, writecnt);
- i += writecnt;
- memset(buf + i, 0, readcnt);
- i += readcnt;
- /* De-assert CS# */
- buf[i++] = 0x03;
- ret = buspirate_sendrecv(buf, i, i);
- if (ret) {
- msg_perr("Bus Pirate communication error!\n");
- return SPI_GENERIC_ERROR;
- }
- if (buf[0] != 0x01) {
- msg_perr("Protocol error while lowering CS#!\n");
- return SPI_GENERIC_ERROR;
- }
- if (buf[1] != 0x01) {
- msg_perr("Protocol error while reading/writing SPI!\n");
- return SPI_GENERIC_ERROR;
- }
- if (buf[i - 1] != 0x01) {
- msg_perr("Protocol error while raising CS#!\n");
- return SPI_GENERIC_ERROR;
- }
- /* Skip CS#, length, writearr. */
- memcpy(readarr, buf + 2 + writecnt, readcnt);
- return ret;
- }
|