mirror of
https://review.coreboot.org/flashrom.git
synced 2025-04-27 23:22:37 +02:00
Add initial J-Link SPI programmer
Tested with SEGGER J-Link EDU, Flasher ARM and flash chip W25Q16.V. Change-Id: Ie03a054a75457ec9e1cab36ea124bb53b10e8d7e Signed-off-by: Marc Schink <flashrom-dev@marcschink.de> Reviewed-on: https://review.coreboot.org/c/28087 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Nico Huber <nico.h@gmx.de>
This commit is contained in:
parent
9cecc7e25d
commit
3578ec6a3d
57
Makefile
57
Makefile
@ -656,6 +656,9 @@ CONFIG_CH341A_SPI ?= yes
|
|||||||
# Digilent Development board JTAG
|
# Digilent Development board JTAG
|
||||||
CONFIG_DIGILENT_SPI ?= yes
|
CONFIG_DIGILENT_SPI ?= yes
|
||||||
|
|
||||||
|
# Disable J-Link for now.
|
||||||
|
CONFIG_JLINK_SPI ?= no
|
||||||
|
|
||||||
# Disable wiki printing by default. It is only useful if you have wiki access.
|
# Disable wiki printing by default. It is only useful if you have wiki access.
|
||||||
CONFIG_PRINT_WIKI ?= no
|
CONFIG_PRINT_WIKI ?= no
|
||||||
|
|
||||||
@ -964,6 +967,12 @@ PROGRAMMER_OBJS += digilent_spi.o
|
|||||||
NEED_LIBUSB1 += CONFIG_DIGILENT_SPI
|
NEED_LIBUSB1 += CONFIG_DIGILENT_SPI
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_JLINK_SPI), yes)
|
||||||
|
NEED_LIBJAYLINK += CONFIG_JLINK_SPI
|
||||||
|
FEATURE_CFLAGS += -D'CONFIG_JLINK_SPI=1'
|
||||||
|
PROGRAMMER_OBJS += jlink_spi.o
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq ($(NEED_SERIAL), )
|
ifneq ($(NEED_SERIAL), )
|
||||||
LIB_OBJS += serial.o custom_baud.o
|
LIB_OBJS += serial.o custom_baud.o
|
||||||
endif
|
endif
|
||||||
@ -1038,6 +1047,12 @@ endif
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(NEED_LIBJAYLINK), )
|
||||||
|
CHECK_LIBJAYLINK = yes
|
||||||
|
JAYLINKLIBS += $(call debug_shell,[ -n "$(PKG_CONFIG_LIBDIR)" ] && export PKG_CONFIG_LIBDIR="$(PKG_CONFIG_LIBDIR)"; $(PKG_CONFIG) --libs libjaylink)
|
||||||
|
override CPPFLAGS += $(call debug_shell,[ -n "$(PKG_CONFIG_LIBDIR)" ] && export PKG_CONFIG_LIBDIR="$(PKG_CONFIG_LIBDIR)"; $(PKG_CONFIG) --cflags-only-I libjaylink)
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_PRINT_WIKI), yes)
|
ifeq ($(CONFIG_PRINT_WIKI), yes)
|
||||||
FEATURE_CFLAGS += -D'CONFIG_PRINT_WIKI=1'
|
FEATURE_CFLAGS += -D'CONFIG_PRINT_WIKI=1'
|
||||||
CLI_OBJS += print_wiki.o
|
CLI_OBJS += print_wiki.o
|
||||||
@ -1060,7 +1075,7 @@ ifeq ($(ARCH), x86)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
$(PROGRAM)$(EXEC_SUFFIX): $(OBJS)
|
$(PROGRAM)$(EXEC_SUFFIX): $(OBJS)
|
||||||
$(CC) $(LDFLAGS) -o $(PROGRAM)$(EXEC_SUFFIX) $(OBJS) $(LIBS) $(PCILIBS) $(FEATURE_LIBS) $(USBLIBS) $(USB1LIBS)
|
$(CC) $(LDFLAGS) -o $(PROGRAM)$(EXEC_SUFFIX) $(OBJS) $(LIBS) $(PCILIBS) $(FEATURE_LIBS) $(USBLIBS) $(USB1LIBS) $(JAYLINKLIBS)
|
||||||
|
|
||||||
libflashrom.a: $(LIBFLASHROM_OBJS)
|
libflashrom.a: $(LIBFLASHROM_OBJS)
|
||||||
$(AR) rcs $@ $^
|
$(AR) rcs $@ $^
|
||||||
@ -1194,6 +1209,24 @@ int main(int argc, char **argv)
|
|||||||
endef
|
endef
|
||||||
export LIBUSB1_TEST
|
export LIBUSB1_TEST
|
||||||
|
|
||||||
|
define LIBJAYLINK_TEST
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <libjaylink/libjaylink.h>
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct jaylink_context *ctx;
|
||||||
|
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
jaylink_init(&ctx);
|
||||||
|
jaylink_exit(ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
endef
|
||||||
|
export LIBJAYLINK_TEST
|
||||||
|
|
||||||
hwlibs: compiler
|
hwlibs: compiler
|
||||||
@printf "" > .libdeps
|
@printf "" > .libdeps
|
||||||
ifeq ($(CHECK_LIBPCI), yes)
|
ifeq ($(CHECK_LIBPCI), yes)
|
||||||
@ -1272,6 +1305,28 @@ ifeq ($(CHECK_LIBUSB1), yes)
|
|||||||
rm -f .test.c .test.o .test$(EXEC_SUFFIX); exit 1; }; } 2>>$(BUILD_DETAILS_FILE); echo $? >&3 ; } | tee -a $(BUILD_DETAILS_FILE) >&4; } 3>&1;} | { read rc ; exit ${rc}; } } 4>&1
|
rm -f .test.c .test.o .test$(EXEC_SUFFIX); exit 1; }; } 2>>$(BUILD_DETAILS_FILE); echo $? >&3 ; } | tee -a $(BUILD_DETAILS_FILE) >&4; } 3>&1;} | { read rc ; exit ${rc}; } } 4>&1
|
||||||
@rm -f .test.c .test.o .test$(EXEC_SUFFIX)
|
@rm -f .test.c .test.o .test$(EXEC_SUFFIX)
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(CHECK_LIBJAYLINK), yes)
|
||||||
|
@printf "Checking for libjaylink headers... " | tee -a $(BUILD_DETAILS_FILE)
|
||||||
|
@echo "$$LIBJAYLINK_TEST" > .test.c
|
||||||
|
@printf "\nexec: %s\n" "$(CC) -c $(CPPFLAGS) $(CFLAGS) .test.c -o .test.o" >>$(BUILD_DETAILS_FILE)
|
||||||
|
@{ { { { { $(CC) -c $(CPPFLAGS) $(CFLAGS) .test.c -o .test.o >&2 && \
|
||||||
|
echo "found." || { echo "not found."; echo; \
|
||||||
|
echo "The following feature requires libjaylink: $(NEED_LIBJAYLINK)."; \
|
||||||
|
echo "Please install libjaylink headers or disable the feature"; \
|
||||||
|
echo "mentioned above by specifying make CONFIG_JLINK_SPI=no"; \
|
||||||
|
echo "See README for more information."; echo; \
|
||||||
|
rm -f .test.c .test.o; exit 1; }; } 2>>$(BUILD_DETAILS_FILE); echo $? >&3 ; } | tee -a $(BUILD_DETAILS_FILE) >&4; } 3>&1;} | { read rc ; exit ${rc}; } } 4>&1
|
||||||
|
@printf "Checking if libjaylink is usable... " | tee -a $(BUILD_DETAILS_FILE)
|
||||||
|
@printf "\nexec: %s\n" "$(CC) $(LDFLAGS) .test.o -o .test$(EXEC_SUFFIX) $(LIBS) $(JAYLINKLIBS)" >>$(BUILD_DETAILS_FILE)
|
||||||
|
@{ { { { { $(CC) $(LDFLAGS) .test.o -o .test$(EXEC_SUFFIX) $(LIBS) $(JAYLINKLIBS) >&2 && \
|
||||||
|
echo "yes." || { echo "no."; \
|
||||||
|
echo "The following feature requires libjaylink: $(NEED_LIBJAYLINK)."; \
|
||||||
|
echo "Please install libjaylink or disable the feature"; \
|
||||||
|
echo "mentioned above by specifying make CONFIG_JLINK_SPI=no"; \
|
||||||
|
echo "See README for more information."; echo; \
|
||||||
|
rm -f .test.c .test.o .test$(EXEC_SUFFIX); exit 1; }; } 2>>$(BUILD_DETAILS_FILE); echo $? >&3 ; } | tee -a $(BUILD_DETAILS_FILE) >&4; } 3>&1;} | { read rc ; exit ${rc}; } } 4>&1
|
||||||
|
@rm -f .test.c .test.o .test$(EXEC_SUFFIX)
|
||||||
|
endif
|
||||||
|
|
||||||
.features: features
|
.features: features
|
||||||
|
|
||||||
|
1
README
1
README
@ -50,6 +50,7 @@ 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, Dediprog or USB-Blaster support)
|
* libusb (if you want FT2232, Dediprog or USB-Blaster support)
|
||||||
* libftdi (if you want FT2232 or USB-Blaster support)
|
* libftdi (if you want FT2232 or USB-Blaster support)
|
||||||
|
* libjaylink (if you want support for SEGGER J-Link and compatible devices)
|
||||||
|
|
||||||
Linux et al:
|
Linux et al:
|
||||||
|
|
||||||
|
@ -331,6 +331,8 @@ bitbanging adapter)
|
|||||||
.sp
|
.sp
|
||||||
.BR "* digilent_spi" " (for SPI flash ROMs attached to iCEblink40 development boards)"
|
.BR "* digilent_spi" " (for SPI flash ROMs attached to iCEblink40 development boards)"
|
||||||
.sp
|
.sp
|
||||||
|
.BR "* jlink_spi" " (for SPI flash ROMs attached to SEGGER J-Link and compatible devices)"
|
||||||
|
.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 INFORMATION
|
.B PROGRAMMER-SPECIFIC INFORMATION
|
||||||
@ -1131,6 +1133,60 @@ can be
|
|||||||
(in Hz). The default is a frequency of 4 MHz.
|
(in Hz). The default is a frequency of 4 MHz.
|
||||||
.sp
|
.sp
|
||||||
.SS
|
.SS
|
||||||
|
.BR "jlink_spi " programmer
|
||||||
|
.IP
|
||||||
|
This module supports SEGGER J-Link and compatible devices.
|
||||||
|
|
||||||
|
The \fBMOSI\fP signal of the flash chip must be attached to \fBTDI\fP pin of
|
||||||
|
the programmer, \fBMISO\fP to \fBTDO\fP and \fBSCK\fP to \fBTCK\fP.
|
||||||
|
The chip select (\fBCS\fP) signal of the flash chip can be attached to
|
||||||
|
different pins of the programmer which can be selected with the
|
||||||
|
.sp
|
||||||
|
.B " flashrom \-p jlink_spi:cs=pin"
|
||||||
|
.sp
|
||||||
|
syntax where \fBpin\fP can be either \fBTRST\fP or \fBRESET\fP.
|
||||||
|
The default pin for chip select is \fBRESET\fP.
|
||||||
|
Note that, when using \fBRESET\fP, it is normal that the indicator LED blinks
|
||||||
|
orange or red.
|
||||||
|
.br
|
||||||
|
Additionally, the \fBVTref\fP pin of the programmer must be attached to the
|
||||||
|
logic level of the flash chip.
|
||||||
|
The programmer measures the voltage on this pin and generates the reference
|
||||||
|
voltage for its input comparators and adapts its output voltages to it.
|
||||||
|
.sp
|
||||||
|
Pinout for devices with 20-pin JTAG connector:
|
||||||
|
.sp
|
||||||
|
+-------+
|
||||||
|
| 1 2 | 1: VTref 2:
|
||||||
|
| 3 4 | 3: TRST 4: GND
|
||||||
|
| 5 6 | 5: TDI 6: GND
|
||||||
|
+-+ 7 8 | 7: 8: GND
|
||||||
|
| 9 10 | 9: TCK 10: GND
|
||||||
|
| 11 12 | 11: 12: GND
|
||||||
|
+-+ 13 14 | 13: TDO 14:
|
||||||
|
| 15 16 | 15: RESET 16:
|
||||||
|
| 17 18 | 17: 18:
|
||||||
|
| 19 20 | 19: PWR_5V 20:
|
||||||
|
+-------+
|
||||||
|
.sp
|
||||||
|
If there is more than one compatible device connected, you can select which one
|
||||||
|
should be used by specifying its serial number with the
|
||||||
|
.sp
|
||||||
|
.B " flashrom \-p jlink_spi:serial=number"
|
||||||
|
.sp
|
||||||
|
syntax where
|
||||||
|
.B number
|
||||||
|
is the serial number of the device (which can be found for example in the
|
||||||
|
output of lsusb -v).
|
||||||
|
.sp
|
||||||
|
The SPI speed can be selected by using the
|
||||||
|
.sp
|
||||||
|
.B " flashrom \-p jlink_spi:spispeed=frequency"
|
||||||
|
.sp
|
||||||
|
syntax where \fBfrequency\fP is the SPI clock frequency in kHz.
|
||||||
|
The maximum speed depends on the device in use.
|
||||||
|
.SS
|
||||||
|
|
||||||
.SH EXAMPLES
|
.SH EXAMPLES
|
||||||
To back up and update your BIOS, run
|
To back up and update your BIOS, run
|
||||||
.sp
|
.sp
|
||||||
|
12
flashrom.c
12
flashrom.c
@ -437,6 +437,18 @@ const struct programmer_entry programmer_table[] = {
|
|||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_JLINK_SPI == 1
|
||||||
|
{
|
||||||
|
.name = "jlink_spi",
|
||||||
|
.type = OTHER,
|
||||||
|
.init = jlink_spi_init,
|
||||||
|
.devs.note = "SEGGER J-Link and compatible devices\n",
|
||||||
|
.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. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
456
jlink_spi.c
Normal file
456
jlink_spi.c
Normal file
@ -0,0 +1,456 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the flashrom project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Marc Schink <flashrom-dev@marcschink.de>
|
||||||
|
*
|
||||||
|
* 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver for the J-Link hardware by SEGGER.
|
||||||
|
* See https://www.segger.com/ for more info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libjaylink/libjaylink.h>
|
||||||
|
|
||||||
|
#include "flash.h"
|
||||||
|
#include "programmer.h"
|
||||||
|
#include "spi.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum number of bytes that can be transferred at once via the JTAG
|
||||||
|
* interface, see jaylink_jtag_io().
|
||||||
|
*/
|
||||||
|
#define JTAG_MAX_TRANSFER_SIZE (UINT16_MAX / 8)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default base frequency in Hz. Used when the base frequency can not be
|
||||||
|
* retrieved from the device.
|
||||||
|
*/
|
||||||
|
#define DEFAULT_FREQ 16000000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default frequency divider. Used when the frequency divider can not be
|
||||||
|
* retrieved from the device.
|
||||||
|
*/
|
||||||
|
#define DEFAULT_FREQ_DIV 4
|
||||||
|
|
||||||
|
/* Minimum target voltage required for operation in mV. */
|
||||||
|
#define MIN_TARGET_VOLTAGE 1200
|
||||||
|
|
||||||
|
static struct jaylink_context *jaylink_ctx;
|
||||||
|
static struct jaylink_device_handle *jaylink_devh;
|
||||||
|
static bool reset_cs;
|
||||||
|
|
||||||
|
static bool assert_cs(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (reset_cs) {
|
||||||
|
ret = jaylink_clear_reset(jaylink_devh);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_clear_reset() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = jaylink_jtag_clear_trst(jaylink_devh);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_jtag_clear_trst() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool deassert_cs(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (reset_cs) {
|
||||||
|
ret = jaylink_set_reset(jaylink_devh);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_set_reset() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = jaylink_jtag_set_trst(jaylink_devh);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_jtag_set_trst() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jlink_spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
|
||||||
|
const unsigned char *writearr, unsigned char *readarr)
|
||||||
|
{
|
||||||
|
uint32_t length;
|
||||||
|
uint8_t *buffer;
|
||||||
|
|
||||||
|
length = writecnt + readcnt;
|
||||||
|
|
||||||
|
if (length > JTAG_MAX_TRANSFER_SIZE)
|
||||||
|
return SPI_INVALID_LENGTH;
|
||||||
|
|
||||||
|
buffer = malloc(length);
|
||||||
|
|
||||||
|
if (!buffer) {
|
||||||
|
msg_perr("Memory allocation failed.\n");
|
||||||
|
return SPI_GENERIC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reverse all bytes because the device transfers data LSB first. */
|
||||||
|
reverse_bytes(buffer, writearr, writecnt);
|
||||||
|
|
||||||
|
memset(buffer + writecnt, 0x00, readcnt);
|
||||||
|
|
||||||
|
if (!assert_cs()) {
|
||||||
|
free(buffer);
|
||||||
|
return SPI_PROGRAMMER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = jaylink_jtag_io(jaylink_devh, buffer, buffer, buffer, length * 8, JAYLINK_JTAG_VERSION_2);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_jag_io() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
free(buffer);
|
||||||
|
return SPI_PROGRAMMER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!deassert_cs()) {
|
||||||
|
free(buffer);
|
||||||
|
return SPI_PROGRAMMER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reverse all bytes because the device transfers data LSB first. */
|
||||||
|
reverse_bytes(readarr, buffer + writecnt, readcnt);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct spi_master spi_master_jlink_spi = {
|
||||||
|
.type = SPI_CONTROLLER_JLINK_SPI,
|
||||||
|
/* Maximum data read size in one go (excluding opcode+address). */
|
||||||
|
.max_data_read = JTAG_MAX_TRANSFER_SIZE - 5,
|
||||||
|
/* Maximum data write size in one go (excluding opcode+address). */
|
||||||
|
.max_data_write = JTAG_MAX_TRANSFER_SIZE - 5,
|
||||||
|
.command = jlink_spi_send_command,
|
||||||
|
.multicommand = default_spi_send_multicommand,
|
||||||
|
.read = default_spi_read,
|
||||||
|
.write_256 = default_spi_write_256,
|
||||||
|
.write_aai = default_spi_write_aai,
|
||||||
|
.features = SPI_MASTER_4BA,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int jlink_spi_shutdown(void *data)
|
||||||
|
{
|
||||||
|
if (jaylink_devh)
|
||||||
|
jaylink_close(jaylink_devh);
|
||||||
|
|
||||||
|
jaylink_exit(jaylink_ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int jlink_spi_init(void)
|
||||||
|
{
|
||||||
|
char *arg;
|
||||||
|
unsigned long speed = 0;
|
||||||
|
|
||||||
|
register_shutdown(jlink_spi_shutdown, NULL);
|
||||||
|
|
||||||
|
arg = extract_programmer_param("spispeed");
|
||||||
|
|
||||||
|
if (arg) {
|
||||||
|
char *endptr;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
speed = strtoul(arg, &endptr, 10);
|
||||||
|
|
||||||
|
if (*endptr != '\0' || errno != 0) {
|
||||||
|
msg_perr("Invalid SPI speed specified: %s.\n", arg);
|
||||||
|
free(arg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (speed < 1) {
|
||||||
|
msg_perr("SPI speed must be at least 1 kHz.\n");
|
||||||
|
free(arg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(arg);
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
bool use_serial_number;
|
||||||
|
uint32_t serial_number;
|
||||||
|
|
||||||
|
arg = extract_programmer_param("serial");
|
||||||
|
|
||||||
|
if (arg) {
|
||||||
|
if (!strlen(arg)) {
|
||||||
|
msg_perr("Emptpy serial number specified.\n");
|
||||||
|
free(arg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = jaylink_parse_serial_number(arg, &serial_number);
|
||||||
|
|
||||||
|
if (ret == JAYLINK_ERR) {
|
||||||
|
msg_perr("Invalid serial number specified: %s.\n", arg);
|
||||||
|
free(arg);
|
||||||
|
return 1;
|
||||||
|
} if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_parse_serial_number() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
free(arg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
use_serial_number = true;
|
||||||
|
} else {
|
||||||
|
use_serial_number = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(arg);
|
||||||
|
|
||||||
|
reset_cs = true;
|
||||||
|
arg = extract_programmer_param("cs");
|
||||||
|
|
||||||
|
if (arg) {
|
||||||
|
if (!strcasecmp(arg, "reset")) {
|
||||||
|
reset_cs = true;
|
||||||
|
} else if (!strcasecmp(arg, "trst")) {
|
||||||
|
reset_cs = false;
|
||||||
|
} else {
|
||||||
|
msg_perr("Invalid chip select pin specified: '%s'.\n", arg);
|
||||||
|
free(arg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(arg);
|
||||||
|
|
||||||
|
if (reset_cs)
|
||||||
|
msg_pdbg("Using RESET as chip select signal.\n");
|
||||||
|
else
|
||||||
|
msg_pdbg("Using TRST as chip select signal.\n");
|
||||||
|
|
||||||
|
ret = jaylink_init(&jaylink_ctx);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_init() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = jaylink_discovery_scan(jaylink_ctx, 0);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_discover_scan() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct jaylink_device **devs;
|
||||||
|
|
||||||
|
ret = jaylink_get_devices(jaylink_ctx, &devs, NULL);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_get_devices() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!use_serial_number)
|
||||||
|
msg_pdbg("No device selected, using first device.\n");
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
struct jaylink_device *dev;
|
||||||
|
bool device_found = false;
|
||||||
|
|
||||||
|
for (i = 0; devs[i]; i++) {
|
||||||
|
if (use_serial_number) {
|
||||||
|
uint32_t tmp;
|
||||||
|
|
||||||
|
ret = jaylink_device_get_serial_number(devs[i], &tmp);
|
||||||
|
|
||||||
|
if (ret == JAYLINK_ERR_NOT_AVAILABLE) {
|
||||||
|
continue;
|
||||||
|
} else if (ret != JAYLINK_OK) {
|
||||||
|
msg_pwarn("jaylink_device_get_serial_number() failed: %s.\n",
|
||||||
|
jaylink_strerror(ret));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serial_number != tmp)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = jaylink_open(devs[i], &jaylink_devh);
|
||||||
|
|
||||||
|
if (ret == JAYLINK_OK) {
|
||||||
|
dev = devs[i];
|
||||||
|
device_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
jaylink_devh = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jaylink_free_devices(devs, true);
|
||||||
|
|
||||||
|
if (!device_found) {
|
||||||
|
msg_perr("No J-Link device found.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length;
|
||||||
|
char *firmware_version;
|
||||||
|
|
||||||
|
ret = jaylink_get_firmware_version(jaylink_devh, &firmware_version,
|
||||||
|
&length);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_get_firmware_version() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return 1;
|
||||||
|
} else if (length > 0) {
|
||||||
|
msg_pdbg("Firmware: %s\n", firmware_version);
|
||||||
|
free(firmware_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = jaylink_device_get_serial_number(dev, &serial_number);
|
||||||
|
|
||||||
|
if (ret == JAYLINK_OK) {
|
||||||
|
msg_pdbg("S/N: %" PRIu32 "\n", serial_number);
|
||||||
|
} else if (ret == JAYLINK_ERR_NOT_AVAILABLE) {
|
||||||
|
msg_pdbg("S/N: N/A\n");
|
||||||
|
} else {
|
||||||
|
msg_perr("jaylink_device_get_serial_number() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t caps[JAYLINK_DEV_EXT_CAPS_SIZE];
|
||||||
|
|
||||||
|
memset(caps, 0, sizeof(caps));
|
||||||
|
ret = jaylink_get_caps(jaylink_devh, caps);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_get_caps() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_EXT_CAPS)) {
|
||||||
|
ret = jaylink_get_extended_caps(jaylink_devh, caps);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_get_available_interfaces() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ifaces;
|
||||||
|
|
||||||
|
ret = jaylink_get_available_interfaces(jaylink_devh, &ifaces);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_get_available_interfaces() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ifaces & (1 << JAYLINK_TIF_JTAG))) {
|
||||||
|
msg_perr("Device does not support JTAG interface.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = jaylink_select_interface(jaylink_devh, JAYLINK_TIF_JTAG, NULL);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_select_interface() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct jaylink_hardware_status hwstat;
|
||||||
|
|
||||||
|
ret = jaylink_get_hardware_status(jaylink_devh, &hwstat);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_get_hardware_status() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_pdbg("VTarget: %u.%03u V\n", hwstat.target_voltage / 1000,
|
||||||
|
hwstat.target_voltage % 1000);
|
||||||
|
|
||||||
|
if (hwstat.target_voltage < MIN_TARGET_VOLTAGE) {
|
||||||
|
msg_perr("Target voltage is below %u.%03u V. You need to attach VTref to the I/O voltage of "
|
||||||
|
"the chip.\n", MIN_TARGET_VOLTAGE / 1000, MIN_TARGET_VOLTAGE % 1000);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct jaylink_speed device_speeds;
|
||||||
|
|
||||||
|
device_speeds.freq = DEFAULT_FREQ;
|
||||||
|
device_speeds.div = DEFAULT_FREQ_DIV;
|
||||||
|
|
||||||
|
if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_SPEEDS)) {
|
||||||
|
ret = jaylink_get_speeds(jaylink_devh, &device_speeds);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_get_speeds() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
device_speeds.freq /= 1000;
|
||||||
|
|
||||||
|
msg_pdbg("Maximum SPI speed: %" PRIu32 " kHz\n", device_speeds.freq / device_speeds.div);
|
||||||
|
|
||||||
|
if (!speed) {
|
||||||
|
speed = device_speeds.freq / device_speeds.div;
|
||||||
|
msg_pdbg("SPI speed not specified, using %lu kHz.\n", speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (speed > (device_speeds.freq / device_speeds.div)) {
|
||||||
|
msg_perr("Specified SPI speed of %lu kHz is too high. Maximum is %" PRIu32 " kHz.\n", speed,
|
||||||
|
device_speeds.freq / device_speeds.div);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = jaylink_set_speed(jaylink_devh, speed);
|
||||||
|
|
||||||
|
if (ret != JAYLINK_OK) {
|
||||||
|
msg_perr("jaylink_set_speed() failed: %s.\n", jaylink_strerror(ret));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_pdbg("SPI speed: %lu kHz\n", speed);
|
||||||
|
|
||||||
|
/* Ensure that the CS signal is not active initially. */
|
||||||
|
if (!deassert_cs())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
register_spi_master(&spi_master_jlink_spi);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
11
programmer.h
11
programmer.h
@ -117,6 +117,9 @@ enum programmer {
|
|||||||
#endif
|
#endif
|
||||||
#if CONFIG_DIGILENT_SPI == 1
|
#if CONFIG_DIGILENT_SPI == 1
|
||||||
PROGRAMMER_DIGILENT_SPI,
|
PROGRAMMER_DIGILENT_SPI,
|
||||||
|
#endif
|
||||||
|
#if CONFIG_JLINK_SPI == 1
|
||||||
|
PROGRAMMER_JLINK_SPI,
|
||||||
#endif
|
#endif
|
||||||
PROGRAMMER_INVALID /* This must always be the last entry. */
|
PROGRAMMER_INVALID /* This must always be the last entry. */
|
||||||
};
|
};
|
||||||
@ -573,6 +576,11 @@ int digilent_spi_init(void);
|
|||||||
extern const struct dev_entry devs_digilent_spi[];
|
extern const struct dev_entry devs_digilent_spi[];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* jlink_spi.c */
|
||||||
|
#if CONFIG_JLINK_SPI == 1
|
||||||
|
int jlink_spi_init(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* flashrom.c */
|
/* flashrom.c */
|
||||||
struct decode_sizes {
|
struct decode_sizes {
|
||||||
uint32_t parallel;
|
uint32_t parallel;
|
||||||
@ -641,6 +649,9 @@ enum spi_controller {
|
|||||||
#if CONFIG_DIGILENT_SPI == 1
|
#if CONFIG_DIGILENT_SPI == 1
|
||||||
SPI_CONTROLLER_DIGILENT_SPI,
|
SPI_CONTROLLER_DIGILENT_SPI,
|
||||||
#endif
|
#endif
|
||||||
|
#if CONFIG_JLINK_SPI == 1
|
||||||
|
SPI_CONTROLLER_JLINK_SPI,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_DATA_UNSPECIFIED 0
|
#define MAX_DATA_UNSPECIFIED 0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user