David Hendricks has uploaded this change for review.

View Change

Add freebsd_spi programmer

Based on linux_spi, using FreeBSD's spigen(4) interface.

Change-Id: I4e1689416fbb309df94807f51635bc1f4b53e0c8
Signed-off-by: Greg V <greg@unrelenting.technology>
---
M Makefile
M flashrom.8.tmpl
M flashrom.c
A freebsd_spi.c
M programmer.h
5 files changed, 246 insertions(+), 0 deletions(-)

git pull ssh://review.coreboot.org:29418/flashrom refs/changes/64/30764/1
diff --git a/Makefile b/Makefile
index 1ff578c..7e709dc 100644
--- a/Makefile
+++ b/Makefile
@@ -379,6 +379,14 @@
endif
endif

+ifneq ($(TARGET_OS), FreeBSD)
+ifeq ($(CONFIG_FREEBSD_SPI), yes)
+UNSUPPORTED_FEATURES += CONFIG_FREEBSD_SPI=yes
+else
+override CONFIG_FREEBSD_SPI = no
+endif
+endif
+
###############################################################################
# General architecture-specific settings.
# Like above for the OS, below we verify user-supplied options depending on the target architecture.
@@ -647,6 +655,9 @@
CONFIG_LINUX_MTD ?= yes
CONFIG_LINUX_SPI ?= yes

+# Enable FreeBSD spigen interface by default. We disable them on non-FreeBSD targets.
+CONFIG_FREEBSD_SPI ?= yes
+
# Always enable ITE IT8212F PATA controllers for now.
CONFIG_IT8212 ?= yes

@@ -945,6 +956,11 @@
PROGRAMMER_OBJS += linux_spi.o
endif

+ifeq ($(CONFIG_FREEBSD_SPI), yes)
+FEATURE_CFLAGS += -D'CONFIG_FREEBSD_SPI=1'
+PROGRAMMER_OBJS += freebsd_spi.o
+endif
+
ifeq ($(CONFIG_MSTARDDC_SPI), yes)
# This is a totally ugly hack.
FEATURE_CFLAGS += $(call debug_shell,grep -q "LINUX_I2C_SUPPORT := yes" .features && printf "%s" "-D'CONFIG_MSTARDDC_SPI=1'")
diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl
index c557af7..092f070 100644
--- a/flashrom.8.tmpl
+++ b/flashrom.8.tmpl
@@ -319,6 +319,8 @@
.sp
.BR "* linux_spi" " (for SPI flash ROMs accessible via /dev/spidevX.Y on Linux)"
.sp
+.BR "* freebsd_spi" " (for SPI flash ROMs accessible via /dev/spigenX.Y on FreeBSD)"
+.sp
.BR "* usbblaster_spi" " (for SPI flash ROMs attached to an Altera USB-Blaster compatible cable)"
.sp
.BR "* nicintel_eeprom" " (for SPI EEPROMs on Intel Gigabit network cards)"
@@ -1065,6 +1067,25 @@
.sp
Please note that the linux_spi driver only works on Linux.
.SS
+.BR "freebsd_spi " programmer
+.IP
+You have to specify the SPI controller to use with the
+.sp
+.B " flashrom \-p freebsd_spi:dev=/dev/spigenX.Y"
+.sp
+syntax where
+.B /dev/spigenX.Y
+is the FreeBSD device node for your SPI controller.
+.sp
+In case the device supports it, you can set the SPI clock frequency with the optional
+.B spispeed
+parameter. The frequency is parsed as kilohertz.
+Example that sets the frequency to 8 MHz:
+.sp
+.B " flashrom \-p freebsd_spi:dev=/dev/spigenX.Y,spispeed=8000"
+.sp
+Please note that the freebsd_spi driver only works on FreeBSD.
+.SS
.BR "mstarddc_spi " programmer
.IP
The Display Data Channel (DDC) is an I2C bus present on VGA and DVI connectors, that allows exchanging
diff --git a/flashrom.c b/flashrom.c
index 59a7531..624bcfb 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -377,6 +377,18 @@
},
#endif

+#if CONFIG_FREEBSD_SPI == 1
+ {
+ .name = "freebsd_spi",
+ .type = OTHER,
+ .devs.note = "Device files /dev/spigen*.*\n",
+ .init = freebsd_spi_init,
+ .map_flash_region = fallback_map,
+ .unmap_flash_region = fallback_unmap,
+ .delay = internal_delay,
+ },
+#endif
+
#if CONFIG_USBBLASTER_SPI == 1
{
.name = "usbblaster_spi",
diff --git a/freebsd_spi.c b/freebsd_spi.c
new file mode 100644
index 0000000..215be20
--- /dev/null
+++ b/freebsd_spi.c
@@ -0,0 +1,186 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2011 Sven Schnelle <svens@stackframe.org>
+ * Copyright (C) 2018 Greg V <greg@unrelenting.technology>
+ *
+ * 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.
+ */
+
+#if CONFIG_FREEBSD_SPI == 1
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/ioccom.h>
+#include <sys/spigenio.h>
+#include "flash.h"
+#include "chipdrivers.h"
+#include "programmer.h"
+#include "spi.h"
+
+/* Tested on:
+ * Xunlong Orange Pi PC (Allwinner H3) */
+
+/* Same as in spi(8) */
+#define DEFAULT_BUFFER_SIZE 8192
+
+static int fd = -1;
+
+static int freebsd_spi_shutdown(void *data);
+static int freebsd_spi_send_command(struct flashctx *flash, unsigned int writecnt,
+ unsigned int readcnt,
+ const unsigned char *txbuf,
+ unsigned char *rxbuf);
+static int freebsd_spi_read(struct flashctx *flash, uint8_t *buf,
+ unsigned int start, unsigned int len);
+static int freebsd_spi_write_256(struct flashctx *flash, const uint8_t *buf,
+ unsigned int start, unsigned int len);
+
+static const struct spi_master spi_master_freebsd = {
+ .type = SPI_CONTROLLER_FREEBSD,
+ .features = SPI_MASTER_4BA,
+ .max_data_read = MAX_DATA_UNSPECIFIED, /* TODO? */
+ .max_data_write = MAX_DATA_UNSPECIFIED, /* TODO? */
+ .command = freebsd_spi_send_command,
+ .multicommand = default_spi_send_multicommand,
+ .read = freebsd_spi_read,
+ .write_256 = freebsd_spi_write_256,
+ .write_aai = default_spi_write_aai,
+};
+
+int freebsd_spi_init(void)
+{
+ char *p, *endp, *dev;
+ uint32_t speed_hz = 0;
+ /* FIXME: make the following configurable by CLI options. */
+ /* SPI mode 0 (beware this also includes: MSB first, CS active low and others */
+ const uint8_t mode = 0;
+
+ p = extract_programmer_param("spispeed");
+ if (p && strlen(p)) {
+ speed_hz = (uint32_t)strtoul(p, &endp, 10) * 1000;
+ if (p == endp) {
+ msg_perr("%s: invalid clock: %s kHz\n", __func__, p);
+ free(p);
+ return 1;
+ }
+ }
+ free(p);
+
+ dev = extract_programmer_param("dev");
+ if (!dev || !strlen(dev)) {
+ msg_perr("No SPI device given. Use flashrom -p "
+ "freebsd_spi:dev=/dev/spigenX.Y\n");
+ free(dev);
+ return 1;
+ }
+
+ msg_pdbg("Using device %s\n", dev);
+ if ((fd = open(dev, O_RDWR)) == -1) {
+ msg_perr("%s: failed to open %s: %s\n", __func__,
+ dev, strerror(errno));
+ free(dev);
+ return 1;
+ }
+ free(dev);
+
+ if (register_shutdown(freebsd_spi_shutdown, NULL))
+ return 1;
+ /* We rely on the shutdown function for cleanup from here on. */
+
+ if (speed_hz > 0) {
+ if (ioctl(fd, SPIGENIOC_SET_CLOCK_SPEED, &speed_hz) == -1) {
+ msg_perr("%s: failed to set speed to %d Hz: %s\n",
+ __func__, speed_hz, strerror(errno));
+ return 1;
+ }
+
+ msg_pdbg("Using %d kHz clock\n", speed_hz/1000);
+ }
+
+ if (ioctl(fd, SPIGENIOC_SET_SPI_MODE, &mode) == -1) {
+ msg_perr("%s: failed to set SPI mode to 0x%02x: %s\n",
+ __func__, mode, strerror(errno));
+ return 1;
+ }
+
+ register_spi_master(&spi_master_freebsd);
+ return 0;
+}
+
+static int freebsd_spi_shutdown(void *data)
+{
+ if (fd != -1) {
+ close(fd);
+ fd = -1;
+ }
+ return 0;
+}
+
+static int freebsd_spi_send_command(struct flashctx *flash, unsigned int writecnt,
+ unsigned int readcnt,
+ const unsigned char *txbuf,
+ unsigned char *rxbuf)
+{
+ if (fd == -1)
+ return -1;
+ /* The implementation currently does not support requests that
+ don't start with sending a command. */
+ if (writecnt == 0)
+ return SPI_INVALID_LENGTH;
+
+ /* FreeBSD uses a single buffer for rx and tx. Allocate a temporary one to avoid overwriting anything. */
+ size_t tmpcnt = readcnt + writecnt;
+ unsigned char *tmpbuf = alloca(tmpcnt);
+
+ bzero(tmpbuf, tmpcnt);
+ memcpy(tmpbuf, txbuf, writecnt);
+
+ /* Command/data separation is pretty useless, spi(8) only uses the command. */
+ struct spigen_transfer msg = {
+ .st_command = {
+ .iov_base = (void*)tmpbuf,
+ .iov_len = tmpcnt,
+ },
+ .st_data = {
+ .iov_base = NULL,
+ .iov_len = 0,
+ },
+ };
+
+ if (ioctl(fd, SPIGENIOC_TRANSFER, &msg) == -1) {
+ msg_cerr("%s: ioctl: %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ if (rxbuf)
+ memcpy(rxbuf, tmpbuf + writecnt, readcnt);
+
+ return 0;
+}
+
+static int freebsd_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
+{
+ return spi_read_chunked(flash, buf, start, len, DEFAULT_BUFFER_SIZE);
+}
+
+static int freebsd_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
+{
+ return spi_write_chunked(flash, buf, start, len, DEFAULT_BUFFER_SIZE);
+}
+
+#endif // CONFIG_FREEBSD_SPI == 1
diff --git a/programmer.h b/programmer.h
index 311992a..30687ed 100644
--- a/programmer.h
+++ b/programmer.h
@@ -103,6 +103,9 @@
#if CONFIG_LINUX_SPI == 1
PROGRAMMER_LINUX_SPI,
#endif
+#if CONFIG_FREEBSD_SPI == 1
+ PROGRAMMER_FREEBSD_SPI,
+#endif
#if CONFIG_USBBLASTER_SPI == 1
PROGRAMMER_USBBLASTER_SPI,
#endif
@@ -548,6 +551,11 @@
int linux_spi_init(void);
#endif

+/* freebsd_spi.c */
+#if CONFIG_FREEBSD_SPI == 1
+int freebsd_spi_init(void);
+#endif
+
/* dediprog.c */
#if CONFIG_DEDIPROG == 1
int dediprog_init(void);
@@ -623,6 +631,9 @@
#if CONFIG_LINUX_SPI == 1
SPI_CONTROLLER_LINUX,
#endif
+#if CONFIG_FREEBSD_SPI == 1
+ SPI_CONTROLLER_FREEBSD,
+#endif
#if CONFIG_SERPROG == 1
SPI_CONTROLLER_SERPROG,
#endif

To view, visit change 30764. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: I4e1689416fbb309df94807f51635bc1f4b53e0c8
Gerrit-Change-Number: 30764
Gerrit-PatchSet: 1
Gerrit-Owner: David Hendricks <david.hendricks@gmail.com>
Gerrit-MessageType: newchange