summaryrefslogtreecommitdiff
path: root/util/comm-servo-spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/comm-servo-spi.c')
-rw-r--r--util/comm-servo-spi.c358
1 files changed, 0 insertions, 358 deletions
diff --git a/util/comm-servo-spi.c b/util/comm-servo-spi.c
deleted file mode 100644
index ef6dc7880b..0000000000
--- a/util/comm-servo-spi.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/* Copyright 2018 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-/*
- * Transport using the Servo V2 SPI1 interface through the FT4232 MPSSE
- * hardware engine (driven by libftdi) in order to send host commands V3
- * directly to a MCU slave SPI controller.
- *
- * It allows to drive a MCU with the cros_ec host SPI interface directly from
- * a developer workstation or another test system.
- *
- * The USB serial number of the servo board can be passed in the 'name'
- * parameter, e.g. :
- * sudo ectool_servo --name=905537-00474 version
- */
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <libftdi1/ftdi.h>
-
-#include "comm-host.h"
-#include "cros_ec_dev.h"
-
-/* Servo V2 SPI1 interface identifiers */
-#define SERVO_V2_USB_VID 0x18d1
-#define SERVO_V2_USB_PID 0x5003
-#define SERVO_V2_USB_SPI1_INTERFACE INTERFACE_B
-
-/* SPI clock frequency in Hz */
-#define SPI_CLOCK_FREQ 1000000
-
-#define FTDI_LATENCY_1MS 2
-
-/* Timeout when waiting for the EC answer to our request */
-#define RESP_TIMEOUT 2 /* second */
-
-#ifdef DEBUG
-#define debug(format, arg...) printf(format, ##arg)
-#else
-#define debug(...)
-#endif
-
-/* Communication context */
-static struct ftdi_context ftdi;
-
-/* Size of a MPSSE command packet */
-#define MPSSE_CMD_SIZE 3
-
-enum mpsse_commands {
- ENABLE_ADAPTIVE_CLOCK = 0x96,
- DISABLE_ADAPTIVE_CLOCK = 0x97,
- TCK_X5 = 0x8A,
- TCK_D5 = 0x8B,
- TRISTATE_IO = 0x9E,
-};
-
-enum mpsse_pins {
- SCLK = 1,
- MOSI = 2,
- MISO = 4,
- CS_L = 8,
-};
-/* SCLK/MOSI/CS_L are outputs, MISO is an input */
-#define PINS_DIR (SCLK | MOSI | CS_L)
-
-/* SPI mode 0:
- * propagates data on the falling edge
- * and reads data on the rising edge of the clock.
- */
-#define SPI_CMD_TX (MPSSE_DO_WRITE | MPSSE_WRITE_NEG)
-#define SPI_CMD_RX (MPSSE_DO_READ)
-#define SPI_CMD_TXRX (MPSSE_DO_WRITE | MPSSE_DO_READ | MPSSE_WRITE_NEG)
-
-static int raw_read(uint8_t *buf, int size)
-{
- int rlen;
-
- while (size) {
- rlen = ftdi_read_data(&ftdi, buf, size);
- if (rlen < 0)
- break;
- buf += rlen;
- size -= rlen;
- }
- return !!size;
-}
-
-static int mpsse_set_pins(uint8_t levels)
-{
- uint8_t buf[MPSSE_CMD_SIZE] = {0};
-
- buf[0] = SET_BITS_LOW;
- buf[1] = levels;
- buf[2] = PINS_DIR;
-
- return ftdi_write_data(&ftdi, buf, sizeof(buf)) != sizeof(buf);
-}
-
-static int send_request(int cmd, int version,
- const uint8_t *outdata, size_t outsize)
-{
- uint8_t *txbuf;
- struct ec_host_request *request;
- size_t i;
- int ret = -EC_RES_ERROR;
- uint8_t csum = 0;
- size_t block_size = sizeof(struct ec_host_request) + outsize;
- size_t total_len = MPSSE_CMD_SIZE + block_size;
-
- txbuf = (uint8_t *)(calloc(1, total_len));
- if (!txbuf)
- return -ENOMEM;
-
- /* MPSSE block size is the full command minus 1 byte */
- txbuf[0] = SPI_CMD_TXRX;
- txbuf[1] = ((block_size - 1) & 0xFF);
- txbuf[2] = (((block_size - 1) >> 8) & 0xFF);
-
- /* Command header first */
- request = (struct ec_host_request *)(txbuf + MPSSE_CMD_SIZE);
- request->struct_version = EC_HOST_REQUEST_VERSION;
- request->checksum = 0;
- request->command = cmd;
- request->command_version = version;
- request->reserved = 0;
- request->data_len = outsize;
-
- /* copy the data to transmit after the command header */
- memcpy(txbuf + MPSSE_CMD_SIZE + sizeof(struct ec_host_request),
- outdata, outsize);
-
- /* Compute the checksum */
- for (i = MPSSE_CMD_SIZE; i < total_len; i++)
- csum += txbuf[i];
- request->checksum = -csum;
-
- if (ftdi_write_data(&ftdi, txbuf, total_len) != total_len)
- goto free_request;
-
- if (raw_read(txbuf, block_size) != 0)
- goto free_request;
-
- /* Make sure the EC was listening */
- ret = 0;
- for (i = 0; i < block_size; i++) {
- switch (txbuf[i]) {
- case EC_SPI_PAST_END:
- case EC_SPI_RX_BAD_DATA:
- case EC_SPI_NOT_READY:
- ret = txbuf[i];
- /* Fall-through */
- default:
- break;
- }
- if (ret)
- break;
- }
-
-free_request:
- free(txbuf);
- return ret;
-}
-
-static int spi_read(uint8_t *buf, size_t size)
-{
- uint8_t cmd[MPSSE_CMD_SIZE];
-
- cmd[0] = SPI_CMD_RX;
- cmd[1] = ((size - 1) & 0xFF);
- cmd[2] = (((size - 1) >> 8) & 0xFF);
-
- if (ftdi_write_data(&ftdi, cmd, sizeof(cmd)) != sizeof(cmd))
- return -EC_RES_ERROR;
-
- return raw_read(buf, size) != 0;
-}
-
-static int get_response(uint8_t *bodydest, size_t bodylen)
-{
- uint8_t sum = 0;
- size_t i;
- struct ec_host_response hdr;
- uint8_t status;
- time_t deadline = time(NULL) + RESP_TIMEOUT;
-
- /*
- * Read a byte at a time until we see the start of the frame.
- * This is slow, but often still faster than the EC.
- */
- while (time(NULL) < deadline) {
- if (spi_read(&status, sizeof(status)))
- goto read_error;
- if (status == EC_SPI_FRAME_START)
- break;
- }
- if (status != EC_SPI_FRAME_START) {
- fprintf(stderr, "timeout wait for response\n");
- return -EC_RES_ERROR;
- }
-
- /* Now read the response header */
- if (spi_read((uint8_t *)(&hdr), sizeof(hdr)))
- goto read_error;
-
- /* Check the header */
- if (hdr.struct_version != EC_HOST_RESPONSE_VERSION) {
- fprintf(stderr, "response version %d (should be %d)\n",
- hdr.struct_version,
- EC_HOST_RESPONSE_VERSION);
- return -EC_RES_ERROR;
- }
- if (hdr.data_len > bodylen) {
- fprintf(stderr, "response data_len %d is > %zd\n",
- hdr.data_len, bodylen);
- return -EC_RES_ERROR;
- }
-
- /* Read the data if needed */
- if (hdr.data_len && spi_read(bodydest, hdr.data_len))
- goto read_error;
-
- /* Verify the checksum */
- for (i = 0; i < sizeof(struct ec_host_response); i++)
- sum += ((uint8_t *)&hdr)[i];
- for (i = 0; i < hdr.data_len; i++)
- sum += bodydest[i];
- if (sum) {
- fprintf(stderr, "Checksum invalid\n");
- return -EC_RES_ERROR;
- }
-
- return hdr.result ? -EECRESULT - hdr.result : 0;
-
-read_error:
- fprintf(stderr, "Read failed: %s\n", ftdi_get_error_string(&ftdi));
- return -EC_RES_ERROR;
-}
-
-static int ec_command_servo_spi(int cmd, int version,
- const void *outdata, int outsize,
- void *indata, int insize)
-{
- int ret = -EC_RES_ERROR;
-
- /* Set the chip select low */
- if (mpsse_set_pins(0) != 0) {
- fprintf(stderr, "Start failed: %s\n",
- ftdi_get_error_string(&ftdi));
- return -EC_RES_ERROR;
- }
-
- if (send_request(cmd, version, (const uint8_t *)(outdata), outsize) ==
- 0)
- ret = get_response((uint8_t *)(indata), insize);
-
- if (mpsse_set_pins(CS_L) != 0) {
- fprintf(stderr, "Stop failed: %s\n",
- ftdi_get_error_string(&ftdi));
- return -EC_RES_ERROR;
- }
- /* SPI protocol gap ... */
- usleep(10);
-
- return ret;
-}
-
-static int mpsse_set_clock(uint32_t freq)
-{
- uint32_t system_clock = 0;
- uint16_t divisor = 0;
- uint8_t buf[MPSSE_CMD_SIZE] = {0};
-
- if (freq > 6000000) {
- buf[0] = TCK_X5;
- system_clock = 60000000;
- } else {
- buf[0] = TCK_D5;
- system_clock = 12000000;
- }
-
- if (ftdi_write_data(&ftdi, buf, 1) != 1)
- return -EC_RES_ERROR;
-
- divisor = (((system_clock / freq) / 2) - 1);
-
- buf[0] = TCK_DIVISOR;
- buf[1] = (divisor & 0xFF);
- buf[2] = ((divisor >> 8) & 0xFF);
-
- return ftdi_write_data(&ftdi, buf, MPSSE_CMD_SIZE) != MPSSE_CMD_SIZE;
-}
-
-static void servo_spi_close(void)
-{
- ftdi_set_bitmode(&ftdi, 0, BITMODE_RESET);
- ftdi_usb_close(&ftdi);
- ftdi_deinit(&ftdi);
-}
-
-int comm_init_servo_spi(const char *device_name)
-{
- int status;
- uint8_t buf[MPSSE_CMD_SIZE] = {0};
- /* if the user mentioned a device name, use it as serial string */
- const char *serial = strcmp(CROS_EC_DEV_NAME, device_name) ?
- device_name : NULL;
-
- if (ftdi_init(&ftdi))
- return -EC_RES_ERROR;
- ftdi_set_interface(&ftdi, SERVO_V2_USB_SPI1_INTERFACE);
-
- status = ftdi_usb_open_desc(&ftdi, SERVO_V2_USB_VID, SERVO_V2_USB_PID,
- NULL, serial);
- if (status) {
- debug("Can't find a Servo v2 USB device\n");
- return -EC_RES_ERROR;
- }
-
- status |= ftdi_usb_reset(&ftdi);
- status |= ftdi_set_latency_timer(&ftdi, FTDI_LATENCY_1MS);
- status |= ftdi_set_bitmode(&ftdi, 0, BITMODE_RESET);
- if (status)
- goto err_close;
-
- ftdi_set_bitmode(&ftdi, 0, BITMODE_MPSSE);
- if (mpsse_set_clock(SPI_CLOCK_FREQ))
- goto err_close;
-
- /* Disable FTDI internal loopback */
- buf[0] = LOOPBACK_END;
- if (ftdi_write_data(&ftdi, buf, 1) != 1)
- goto err_close;
- /* Ensure adaptive clock is disabled */
- buf[0] = DISABLE_ADAPTIVE_CLOCK;
- if (ftdi_write_data(&ftdi, buf, 1) != 1)
- goto err_close;
- /* Set the idle pin states */
- if (mpsse_set_pins(CS_L) != 0)
- goto err_close;
-
- ec_command_proto = ec_command_servo_spi;
- /* Set temporary size, will be updated later. */
- ec_max_outsize = EC_PROTO2_MAX_PARAM_SIZE - 8;
- ec_max_insize = EC_PROTO2_MAX_PARAM_SIZE;
-
- return 0;
-
-err_close:
- servo_spi_close();
- return -EC_RES_ERROR;
-}