David Hendricks has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/30764
Change subject: Add freebsd_spi programmer ......................................................................
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
David Hendricks has posted comments on this change. ( https://review.coreboot.org/c/flashrom/+/30764 )
Change subject: Add freebsd_spi programmer ......................................................................
Patch Set 1: Code-Review-1
(1 comment)
Commit Message:
https://review.coreboot.org/c/flashrom/+/30764/comment/81c4faee_b85221bc PS1, Line 12: Greg V not a valid signed-off-by line
David Hendricks has abandoned this change. ( https://review.coreboot.org/c/flashrom/+/30764 )
Change subject: Add freebsd_spi programmer ......................................................................
Abandoned
Stale patch and invalid sign-off