mirror of
https://review.coreboot.org/flashrom.git
synced 2025-04-26 22:52:34 +02:00
Add Altera USB-Blaster SPI programmer
Adds support for the Altera USB-Blaster programming dongle in Active Serial (AS) mode. Tested on both original product and a clone dongle. Corresponding to flashrom svn r1658. Signed-off-by: James Laird <jhl@mafipulation.org> Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com> Signed-off-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at> Acked-by: Kyösti Mälkki <kyosti.malkki@gmail.com> Acked-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
This commit is contained in:
parent
226037da3d
commit
c60de0e87f
30
Makefile
30
Makefile
@ -128,6 +128,11 @@ UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes
|
|||||||
else
|
else
|
||||||
override CONFIG_FT2232_SPI = no
|
override CONFIG_FT2232_SPI = no
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(CONFIG_USBBLASTER_SPI), yes)
|
||||||
|
UNSUPPORTED_FEATURES += CONFIG_USBBLASTER_SPI=yes
|
||||||
|
else
|
||||||
|
override CONFIG_USBBLASTER_SPI = no
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# FIXME: Should we check for Cygwin/MSVC as well?
|
# FIXME: Should we check for Cygwin/MSVC as well?
|
||||||
@ -240,6 +245,11 @@ UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes
|
|||||||
else
|
else
|
||||||
override CONFIG_FT2232_SPI = no
|
override CONFIG_FT2232_SPI = no
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(CONFIG_USBBLASTER_SPI), yes)
|
||||||
|
UNSUPPORTED_FEATURES += CONFIG_USBBLASTER_SPI=yes
|
||||||
|
else
|
||||||
|
override CONFIG_USBBLASTER_SPI = no
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(TARGET_OS), Linux)
|
ifneq ($(TARGET_OS), Linux)
|
||||||
@ -349,6 +359,9 @@ CONFIG_ATAHPT ?= no
|
|||||||
# Always enable FT2232 SPI dongles for now.
|
# Always enable FT2232 SPI dongles for now.
|
||||||
CONFIG_FT2232_SPI ?= yes
|
CONFIG_FT2232_SPI ?= yes
|
||||||
|
|
||||||
|
# Always enable Altera USB-Blaster dongles for now.
|
||||||
|
CONFIG_USBBLASTER_SPI ?= yes
|
||||||
|
|
||||||
# Always enable dummy tracing for now.
|
# Always enable dummy tracing for now.
|
||||||
CONFIG_DUMMY ?= yes
|
CONFIG_DUMMY ?= yes
|
||||||
|
|
||||||
@ -474,12 +487,23 @@ NEED_PCI := yes
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_FT2232_SPI), yes)
|
ifeq ($(CONFIG_FT2232_SPI), yes)
|
||||||
FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb")
|
|
||||||
# This is a totally ugly hack.
|
# This is a totally ugly hack.
|
||||||
FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "-D'CONFIG_FT2232_SPI=1'")
|
FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "-D'CONFIG_FT2232_SPI=1'")
|
||||||
|
NEED_FTDI := yes
|
||||||
|
PROGRAMMER_OBJS += ft2232_spi.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_USBBLASTER_SPI), yes)
|
||||||
|
# This is a totally ugly hack.
|
||||||
|
FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "-D'CONFIG_USBBLASTER_SPI=1'")
|
||||||
|
NEED_FTDI := yes
|
||||||
|
PROGRAMMER_OBJS += usbblaster_spi.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(NEED_FTDI), yes)
|
||||||
|
FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb")
|
||||||
FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FT232H := yes" .features && printf "%s" "-D'HAVE_FT232H=1'")
|
FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FT232H := yes" .features && printf "%s" "-D'HAVE_FT232H=1'")
|
||||||
FEATURE_LIBS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "$(FTDILIBS)")
|
FEATURE_LIBS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "$(FTDILIBS)")
|
||||||
PROGRAMMER_OBJS += ft2232_spi.o
|
|
||||||
# We can't set NEED_USB here because that would transform libftdi auto-enabling
|
# We can't set NEED_USB here because that would transform libftdi auto-enabling
|
||||||
# into a hard requirement for libusb, defeating the purpose of auto-enabling.
|
# into a hard requirement for libusb, defeating the purpose of auto-enabling.
|
||||||
endif
|
endif
|
||||||
@ -799,7 +823,7 @@ export LINUX_SPI_TEST
|
|||||||
|
|
||||||
features: compiler
|
features: compiler
|
||||||
@echo "FEATURES := yes" > .features.tmp
|
@echo "FEATURES := yes" > .features.tmp
|
||||||
ifeq ($(CONFIG_FT2232_SPI), yes)
|
ifeq ($(NEED_FTDI), yes)
|
||||||
@printf "Checking for FTDI support... "
|
@printf "Checking for FTDI support... "
|
||||||
@echo "$$FTDI_TEST" > .featuretest.c
|
@echo "$$FTDI_TEST" > .featuretest.c
|
||||||
@$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(FTDILIBS) $(LIBS) >/dev/null 2>&1 && \
|
@$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(FTDILIBS) $(LIBS) >/dev/null 2>&1 && \
|
||||||
|
4
README
4
README
@ -45,8 +45,8 @@ Build Instructions
|
|||||||
To build flashrom you need to install the following software:
|
To build flashrom you need to install the following software:
|
||||||
|
|
||||||
* pciutils+libpci (if you want support for mainboard or PCI device flashing)
|
* pciutils+libpci (if you want support for mainboard or PCI device flashing)
|
||||||
* libusb (if you want FT2232 or Dediprog support)
|
* libusb (if you want FT2232, Dediprog or USB-Blaster support)
|
||||||
* libftdi (if you want FT2232 support)
|
* libftdi (if you want FT2232 or USB-Blaster support)
|
||||||
|
|
||||||
Linux et al:
|
Linux et al:
|
||||||
|
|
||||||
|
@ -220,6 +220,8 @@ bitbanging adapter)
|
|||||||
.sp
|
.sp
|
||||||
.BR "* linux_spi" " (for SPI flash ROMs accessible via /dev/spidevX.Y on Linux)"
|
.BR "* linux_spi" " (for SPI flash ROMs accessible via /dev/spidevX.Y on Linux)"
|
||||||
.sp
|
.sp
|
||||||
|
.BR "* usbblaster_spi" " (for SPI flash ROMs attached to an Altera USB-Blaster compatible cable)"
|
||||||
|
.sp
|
||||||
Some programmers have optional or mandatory parameters which are described
|
Some programmers have optional or mandatory parameters which are described
|
||||||
in detail in the
|
in detail in the
|
||||||
.B PROGRAMMER SPECIFIC INFO
|
.B PROGRAMMER SPECIFIC INFO
|
||||||
@ -837,7 +839,7 @@ needs TCP access to the network or userspace access to a serial port.
|
|||||||
.B buspirate_spi
|
.B buspirate_spi
|
||||||
needs userspace access to a serial port.
|
needs userspace access to a serial port.
|
||||||
.sp
|
.sp
|
||||||
.BR dediprog " and " ft2232_spi
|
.BR dediprog ", " ft2232_spi " and " usbblaster_spi
|
||||||
need access to the USB device via libusb.
|
need access to the USB device via libusb.
|
||||||
.sp
|
.sp
|
||||||
.B dummy
|
.B dummy
|
||||||
@ -847,7 +849,7 @@ needs no access permissions at all.
|
|||||||
.BR gfxnvidia ", " drkaiser ", " satasii ", " satamv " and " atahpt
|
.BR gfxnvidia ", " drkaiser ", " satasii ", " satamv " and " atahpt
|
||||||
have to be run as superuser/root, and need additional raw access permission.
|
have to be run as superuser/root, and need additional raw access permission.
|
||||||
.sp
|
.sp
|
||||||
.BR serprog ", " buspirate_spi ", " dediprog " and " ft2232_spi
|
.BR serprog ", " buspirate_spi ", " dediprog ", " usbblaster_spi " and " ft2232_spi
|
||||||
can be run as normal user on most operating systems if appropriate device
|
can be run as normal user on most operating systems if appropriate device
|
||||||
permissions are set.
|
permissions are set.
|
||||||
.sp
|
.sp
|
||||||
|
12
flashrom.c
12
flashrom.c
@ -308,6 +308,18 @@ const struct programmer_entry programmer_table[] = {
|
|||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_USBBLASTER_SPI == 1
|
||||||
|
{
|
||||||
|
.name = "usbblaster_spi",
|
||||||
|
.type = USB,
|
||||||
|
.devs.dev = devs_usbblasterspi,
|
||||||
|
.init = usbblaster_spi_init,
|
||||||
|
.map_flash_region = fallback_map,
|
||||||
|
.unmap_flash_region = fallback_unmap,
|
||||||
|
.delay = internal_delay,
|
||||||
|
},
|
||||||
|
#endif
|
||||||
|
|
||||||
{0}, /* This entry corresponds to PROGRAMMER_INVALID. */
|
{0}, /* This entry corresponds to PROGRAMMER_INVALID. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
12
programmer.h
12
programmer.h
@ -86,6 +86,9 @@ enum programmer {
|
|||||||
#endif
|
#endif
|
||||||
#if CONFIG_LINUX_SPI == 1
|
#if CONFIG_LINUX_SPI == 1
|
||||||
PROGRAMMER_LINUX_SPI,
|
PROGRAMMER_LINUX_SPI,
|
||||||
|
#endif
|
||||||
|
#if CONFIG_USBBLASTER_SPI == 1
|
||||||
|
PROGRAMMER_USBBLASTER_SPI,
|
||||||
#endif
|
#endif
|
||||||
PROGRAMMER_INVALID /* This must always be the last entry. */
|
PROGRAMMER_INVALID /* This must always be the last entry. */
|
||||||
};
|
};
|
||||||
@ -431,6 +434,12 @@ int ft2232_spi_init(void);
|
|||||||
extern const struct dev_entry devs_ft2232spi[];
|
extern const struct dev_entry devs_ft2232spi[];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* usbblaster_spi.c */
|
||||||
|
#if CONFIG_USBBLASTER_SPI == 1
|
||||||
|
int usbblaster_spi_init(void);
|
||||||
|
extern const struct dev_entry devs_usbblasterspi[];
|
||||||
|
#endif
|
||||||
|
|
||||||
/* rayer_spi.c */
|
/* rayer_spi.c */
|
||||||
#if CONFIG_RAYER_SPI == 1
|
#if CONFIG_RAYER_SPI == 1
|
||||||
int rayer_spi_init(void);
|
int rayer_spi_init(void);
|
||||||
@ -509,6 +518,9 @@ enum spi_controller {
|
|||||||
#if CONFIG_SERPROG == 1
|
#if CONFIG_SERPROG == 1
|
||||||
SPI_CONTROLLER_SERPROG,
|
SPI_CONTROLLER_SERPROG,
|
||||||
#endif
|
#endif
|
||||||
|
#if CONFIG_USBBLASTER_SPI == 1
|
||||||
|
SPI_CONTROLLER_USBBLASTER,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_DATA_UNSPECIFIED 0
|
#define MAX_DATA_UNSPECIFIED 0
|
||||||
|
225
usbblaster_spi.c
Normal file
225
usbblaster_spi.c
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the flashrom project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 James Laird <jhl@mafipulation.org>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device should be connected as per "active serial" mode:
|
||||||
|
*
|
||||||
|
* +---------+------+-----------+
|
||||||
|
* | SPI | Pin | Altera |
|
||||||
|
* +---------+------+-----------+
|
||||||
|
* | SCLK | 1 | DCLK |
|
||||||
|
* | GND | 2,10 | GND |
|
||||||
|
* | VCC | 4 | VCC(TRGT) |
|
||||||
|
* | MISO | 7 | DATAOUT |
|
||||||
|
* | /CS | 8 | nCS |
|
||||||
|
* | MOSI | 9 | ASDI |
|
||||||
|
* +---------+------+-----------+
|
||||||
|
*
|
||||||
|
* See also the USB-Blaster Download Cable User Guide: http://www.altera.com/literature/ug/ug_usb_blstr.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if CONFIG_USBBLASTER_SPI == 1
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <ftdi.h>
|
||||||
|
#include "flash.h"
|
||||||
|
#include "programmer.h"
|
||||||
|
#include "spi.h"
|
||||||
|
|
||||||
|
/* Please keep sorted by vendor ID, then device ID. */
|
||||||
|
#define ALTERA_VID 0x09fb
|
||||||
|
#define ALTERA_USBBLASTER_PID 0x6001
|
||||||
|
|
||||||
|
const struct dev_entry devs_usbblasterspi[] = {
|
||||||
|
{ALTERA_VID, ALTERA_USBBLASTER_PID, OK, "Altera", "USB-Blaster"},
|
||||||
|
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct spi_programmer spi_programmer_usbblaster;
|
||||||
|
|
||||||
|
static struct ftdi_context ftdic;
|
||||||
|
|
||||||
|
// command bytes
|
||||||
|
#define BIT_BYTE (1<<7) // byte mode (rather than bitbang)
|
||||||
|
#define BIT_READ (1<<6) // read request
|
||||||
|
#define BIT_LED (1<<5)
|
||||||
|
#define BIT_CS (1<<3)
|
||||||
|
#define BIT_TMS (1<<1)
|
||||||
|
#define BIT_CLK (1<<0)
|
||||||
|
|
||||||
|
#define BUF_SIZE 64
|
||||||
|
|
||||||
|
/* The programmer shifts bits in the wrong order for SPI, so we use this method to reverse the bits when needed.
|
||||||
|
* http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits */
|
||||||
|
uint8_t reverse(uint8_t b)
|
||||||
|
{
|
||||||
|
return ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Returns 0 upon success, a negative number upon errors. */
|
||||||
|
int usbblaster_spi_init(void)
|
||||||
|
{
|
||||||
|
uint8_t buf[BUF_SIZE + 1];
|
||||||
|
|
||||||
|
if (ftdi_init(&ftdic) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ftdi_usb_open(&ftdic, ALTERA_VID, ALTERA_USBBLASTER_PID) < 0) {
|
||||||
|
msg_perr("Failed to open USB-Blaster: %s\n", ftdic.error_str);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftdi_usb_reset(&ftdic) < 0) {
|
||||||
|
msg_perr("USB-Blaster reset failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftdi_set_latency_timer(&ftdic, 2) < 0) {
|
||||||
|
msg_perr("USB-Blaster set latency timer failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftdi_write_data_set_chunksize(&ftdic, 4096) < 0 ||
|
||||||
|
ftdi_read_data_set_chunksize(&ftdic, BUF_SIZE) < 0) {
|
||||||
|
msg_perr("USB-Blaster set chunk size failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
buf[sizeof(buf)-1] = BIT_LED | BIT_CS;
|
||||||
|
if (ftdi_write_data(&ftdic, buf, sizeof(buf)) < 0) {
|
||||||
|
msg_perr("USB-Blaster reset write failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (ftdi_read_data(&ftdic, buf, sizeof(buf)) < 0) {
|
||||||
|
msg_perr("USB-Blaster reset read failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
register_spi_programmer(&spi_programmer_usbblaster);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int send_write(unsigned int writecnt, const unsigned char *writearr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8_t buf[BUF_SIZE];
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
while (writecnt) {
|
||||||
|
unsigned int n_write = min(writecnt, BUF_SIZE - 1);
|
||||||
|
msg_pspew("writing %d-byte packet\n", n_write);
|
||||||
|
|
||||||
|
buf[0] = BIT_BYTE | (uint8_t)n_write;
|
||||||
|
for (i = 0; i < n_write; i++) {
|
||||||
|
buf[i+1] = reverse(writearr[i]);
|
||||||
|
}
|
||||||
|
if (ftdi_write_data(&ftdic, buf, n_write + 1) < 0) {
|
||||||
|
msg_perr("USB-Blaster write failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
writearr += n_write;
|
||||||
|
writecnt -= n_write;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int send_read(unsigned int readcnt, unsigned char *readarr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned int n_read;
|
||||||
|
uint8_t buf[BUF_SIZE];
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
||||||
|
n_read = readcnt;
|
||||||
|
while (n_read) {
|
||||||
|
unsigned int payload_size = min(n_read, BUF_SIZE - 1);
|
||||||
|
msg_pspew("reading %d-byte packet\n", payload_size);
|
||||||
|
|
||||||
|
buf[0] = BIT_BYTE | BIT_READ | (uint8_t)payload_size;
|
||||||
|
if (ftdi_write_data(&ftdic, buf, payload_size + 1) < 0) {
|
||||||
|
msg_perr("USB-Blaster write failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
n_read -= payload_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
n_read = readcnt;
|
||||||
|
while (n_read) {
|
||||||
|
int ret = ftdi_read_data(&ftdic, readarr, n_read);
|
||||||
|
if (ret < 0) {
|
||||||
|
msg_perr("USB-Blaster read failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (i = 0; i < ret; i++) {
|
||||||
|
readarr[i] = reverse(readarr[i]);
|
||||||
|
}
|
||||||
|
n_read -= ret;
|
||||||
|
readarr += ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns 0 upon success, a negative number upon errors. */
|
||||||
|
static int usbblaster_spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
|
||||||
|
const unsigned char *writearr, unsigned char *readarr)
|
||||||
|
{
|
||||||
|
uint8_t cmd;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
cmd = BIT_LED; // asserts /CS
|
||||||
|
if (ftdi_write_data(&ftdic, &cmd, 1) < 0) {
|
||||||
|
msg_perr("USB-Blaster enable chip select failed\n");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret && writecnt)
|
||||||
|
ret = send_write(writecnt, writearr);
|
||||||
|
|
||||||
|
if (!ret && readcnt)
|
||||||
|
ret = send_read(readcnt, readarr);
|
||||||
|
|
||||||
|
cmd = BIT_CS;
|
||||||
|
if (ftdi_write_data(&ftdic, &cmd, 1) < 0) {
|
||||||
|
msg_perr("USB-Blaster disable chip select failed\n");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const struct spi_programmer spi_programmer_usbblaster = {
|
||||||
|
.type = SPI_CONTROLLER_USBBLASTER,
|
||||||
|
.max_data_read = 256,
|
||||||
|
.max_data_write = 256,
|
||||||
|
.command = usbblaster_spi_send_command,
|
||||||
|
.multicommand = default_spi_send_multicommand,
|
||||||
|
.read = default_spi_read,
|
||||||
|
.write_256 = default_spi_write_256,
|
||||||
|
.write_aai = default_spi_write_aai,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user