53 #include <sys/ioctl.h>
54 #include <linux/spi/spidev.h>
64 #define SPI_DESELECT_DELAY 0
67 #define MAX_QUEUE_ENTRIES 64
75 #define SWD_WR_BITS (CMD_BITS + TURN_BITS + ACK_BITS + TURN_BITS + DATA_BITS + PARITY_BITS)
76 #define SWD_RD_BITS (CMD_BITS + TURN_BITS + ACK_BITS + DATA_BITS + PARITY_BITS + TURN_BITS)
77 #define SWD_OP_BITS (MAX(SWD_WR_BITS, SWD_RD_BITS))
78 #define SWD_OP_BYTES (DIV_ROUND_UP(SWD_OP_BITS, SPI_BITS))
80 #define AP_DELAY_CLOCKS 8
81 #define AP_DELAY_BYTES (DIV_ROUND_UP(AP_DELAY_CLOCKS, SPI_BITS))
83 #define END_IDLE_CLOCKS 8
84 #define END_IDLE_BYTES (DIV_ROUND_UP(END_IDLE_CLOCKS, SPI_BITS))
112 static void spi_exchange(
const uint8_t *tx_data, uint8_t *rx_data,
unsigned int len)
114 #ifdef LOG_SPI_EXCHANGE
123 if (!tx_data && !rx_data) {
124 LOG_DEBUG(
"exchange with no valid tx or rx pointers");
129 LOG_ERROR(
"exchange too large len=%u ", len);
135 for (
unsigned int i = 0; i < len; i++)
138 #ifdef LOG_SPI_EXCHANGE
141 for (
unsigned int i = 0; i < len; i++)
148 struct spi_ioc_transfer tr = {
154 .rx_buf = (
unsigned long)rx_data,
160 int ret = ioctl(
spi_fd, SPI_IOC_MESSAGE(1), &tr);
168 #ifdef LOG_SPI_EXCHANGE
171 for (
unsigned int i = 0; i < len; i++)
178 for (
unsigned int i = 0; i < len; i++)
179 rx_data[i] =
flip_u32(rx_data[i], 8);
185 uint32_t tmp_speed = speed;
187 int ret = ioctl(
spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &tmp_speed);
189 LOG_ERROR(
"Failed to set SPI %d speed", speed);
211 *jtag_speed = khz * 1000;
247 LOG_ERROR(
"Can't realloc queue when queue is in use");
251 unsigned int new_queue_buf_size =
282 LOG_ERROR(
"Couldn't allocate queue. Out of memory.");
314 ret = ioctl(
spi_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits);
316 LOG_ERROR(
"Failed to set SPI %" PRIu8
" bits per transfer", spi_bits);
320 LOG_INFO(
"Opened SPI device at %s in mode 0x%" PRIx32
" with %" PRIu8
" bits ",
372 for (
unsigned int queue_idx = 0; queue_idx <
queue_fill; queue_idx++) {
379 uint32_t data = read ?
387 "%s%s %s %s reg %X = %08" PRIx32,
388 check_ack ?
"" :
"ack ignored ",
393 read ?
"read" :
"write",
405 LOG_ERROR(
"SWD Read data parity mismatch");
520 LOG_ERROR(
"Sequence %d not supported", seq);
553 uint32_t new_queue_entries;
574 .handler = &spidev_handle_path_command,
576 .help =
"set the path to the spidev device",
577 .usage =
"path_to_spidev",
581 .handler = &spidev_handle_mode_command,
583 .help =
"set the mode of the spi port with optional bit flags (default=3)",
587 .name =
"queue_entries",
588 .handler = &spidev_handle_queue_entries_command,
590 .help =
"set the queue entry size (default=64)",
591 .usage =
"queue_entries",
600 .help =
"perform spidev management",
611 .
name =
"linuxspidev",
uint32_t flip_u32(uint32_t value, unsigned int num)
Inverts the ordering of bits inside a 32-bit word (e.g.
static uint32_t buf_get_u32(const uint8_t *_buffer, unsigned int first, unsigned int num)
Retrieves num bits from _buffer, starting at the first bit, returning the bits in a 32-bit word.
static void buf_set_u32(uint8_t *_buffer, unsigned int first, unsigned int num, uint32_t value)
Sets num bits in _buffer, starting at the first bit, using the bits in value.
#define CMD_ARGV
Use this macro to access the arguments for the command being handled, rather than accessing the varia...
#define ERROR_COMMAND_SYNTAX_ERROR
#define CMD_ARGC
Use this macro to access the number of arguments for the command being handled, rather than accessing...
#define COMMAND_PARSE_NUMBER(type, in, out)
parses the string in into out as a type, or prints a command error and passes the error code to the c...
#define COMMAND_REGISTRATION_DONE
Use this as the last entry in an array of command_registration records.
#define ERROR_JTAG_INIT_FAILED
static const struct command_registration spidev_subcommand_handlers[]
static void spidev_free_queue(void)
static void spidev_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk)
static void spidev_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk)
static int spidev_swd_init(void)
static int spidev_alloc_queue(unsigned int new_queue_entries)
static uint8_t * queue_tx_buf
static int spidev_swd_execute_queue(unsigned int end_idle_bytes)
const struct swd_driver spidev_swd
static uint8_t * queue_rx_buf
static void spidev_clear_queue(void)
static int spidev_quit(void)
COMMAND_HANDLER(spidev_handle_path_command)
static const char *const spidev_transports[]
struct adapter_driver linuxspidev_adapter_driver
static struct queue_info * queue_infos
static int spidev_khz(int khz, int *jtag_speed)
static unsigned int max_queue_entries
#define MAX_QUEUE_ENTRIES
static int spidev_init(void)
static uint32_t spi_speed
static int spidev_speed_div(int speed, int *khz)
#define SPI_DESELECT_DELAY
static uint8_t * tx_flip_buf
static unsigned int queue_buf_fill
static const struct command_registration spidev_command_handlers[]
static int spidev_swd_switch_seq(enum swd_special_seq seq)
static unsigned int queue_fill
static int spidev_speed(int speed)
static void spi_exchange(const uint8_t *tx_data, uint8_t *rx_data, unsigned int len)
static unsigned int queue_buf_size
static void spidev_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk)
static int spidev_swd_run_queue(void)
#define LOG_CUSTOM_LEVEL(level, expr ...)
#define LOG_OUTPUT(expr ...)
#define LOG_DEBUG_IO(expr ...)
#define LOG_ERROR(expr ...)
#define LOG_INFO(expr ...)
#define LOG_DEBUG(expr ...)
Represents a driver for a debugging interface.
const char *const name
The name of the interface driver.
const char * usage
a string listing the options and arguments, required or optional
int(* init)(void)
Initialize the debug link so it can perform SWD operations.
static const unsigned int swd_seq_dormant_to_swd_len
static const uint8_t swd_seq_dormant_to_jtag[]
Dormant-to-JTAG sequence.
static const uint8_t swd_seq_dormant_to_swd[]
Dormant-to-SWD sequence.
static const uint8_t swd_seq_jtag_to_dormant[]
JTAG-to-dormant sequence.
static bool swd_cmd_returns_ack(uint8_t cmd)
Test if we can rely on ACK returned by SWD command.
static int swd_ack_to_error_code(uint8_t ack)
Convert SWD ACK value returned from DP to OpenOCD error code.
static const unsigned int swd_seq_jtag_to_swd_len
static const unsigned int swd_seq_line_reset_len
static const unsigned int swd_seq_dormant_to_jtag_len
static const unsigned int swd_seq_swd_to_dormant_len
static const uint8_t swd_seq_line_reset[]
SWD Line reset.
static const uint8_t swd_seq_jtag_to_swd[]
JTAG-to-SWD sequence.
static const uint8_t swd_seq_swd_to_jtag[]
SWD-to-JTAG sequence.
static const unsigned int swd_seq_swd_to_jtag_len
static const unsigned int swd_seq_jtag_to_dormant_len
static const uint8_t swd_seq_swd_to_dormant[]
SWD-to-dormant sequence.
#define DIV_ROUND_UP(m, n)
Rounds m up to the nearest multiple of n using division.
static int parity_u32(uint32_t x)
Calculate the (even) parity of a 32-bit datum.
static unsigned int parity(unsigned int v)