diff options
Diffstat (limited to 'src/jtag/drivers/versaloon/versaloon.c')
-rw-r--r-- | src/jtag/drivers/versaloon/versaloon.c | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/src/jtag/drivers/versaloon/versaloon.c b/src/jtag/drivers/versaloon/versaloon.c new file mode 100644 index 00000000..dbb8e4fb --- /dev/null +++ b/src/jtag/drivers/versaloon/versaloon.c @@ -0,0 +1,398 @@ +/*************************************************************************** + * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * + * * + * 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. * + * * + * 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., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> + +#include "versaloon_include.h" +#include "versaloon.h" +#include "versaloon_internal.h" +#include "usbtoxxx/usbtoxxx.h" + +uint8_t *versaloon_buf = NULL; +uint8_t *versaloon_cmd_buf = NULL; +uint16_t versaloon_buf_size; + +struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER]; +uint16_t versaloon_pending_idx = 0; + +usb_dev_handle *versaloon_usb_device_handle = NULL; +static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT; + +RESULT versaloon_init(void); +RESULT versaloon_fini(void); +RESULT versaloon_get_target_voltage(uint16_t *voltage); +RESULT versaloon_set_target_voltage(uint16_t voltage); +RESULT versaloon_delay_ms(uint16_t ms); +RESULT versaloon_delay_us(uint16_t us); +struct versaloon_interface_t versaloon_interface = +{ + .init = versaloon_init, + .fini = versaloon_fini, + {// adaptors + {// target_voltage + .get = versaloon_get_target_voltage, + .set = versaloon_set_target_voltage, + }, + {// gpio + .init = usbtogpio_init, + .fini = usbtogpio_fini, + .config = usbtogpio_config, + .out = usbtogpio_out, + .in = usbtogpio_in, + }, + {// delay + .delayms = versaloon_delay_ms, + .delayus = versaloon_delay_us, + }, + {// swd + .init = usbtoswd_init, + .fini = usbtoswd_fini, + .config = usbtoswd_config, + .seqout = usbtoswd_seqout, + .seqin = usbtoswd_seqin, + .transact = usbtoswd_transact, + }, + {// jtag_raw + .init = usbtojtagraw_init, + .fini = usbtojtagraw_fini, + .config = usbtojtagraw_config, + .execute = usbtojtagraw_execute, + }, + .peripheral_commit = usbtoxxx_execute_command, + }, + {// usb_setting + .vid = VERSALOON_VID, + .pid = VERSALOON_PID, + .ep_out = VERSALOON_OUTP, + .ep_in = VERSALOON_INP, + .interface = VERSALOON_IFACE, + .serialstring = NULL, + .buf_size = 256, + } +}; + +// programmer_cmd +static uint32_t versaloon_pending_id = 0; +static versaloon_callback_t versaloon_callback = NULL; +static void *versaloon_extra_data = NULL; +static struct versaloon_want_pos_t *versaloon_want_pos = NULL; +void versaloon_set_pending_id(uint32_t id) +{ + versaloon_pending_id = id; +} +void versaloon_set_callback(versaloon_callback_t callback) +{ + versaloon_callback = callback; +} +void versaloon_set_extra_data(void * p) +{ + versaloon_extra_data = p; +} + +void versaloon_free_want_pos(void) +{ + uint16_t i; + struct versaloon_want_pos_t *tmp, *free_tmp; + + tmp = versaloon_want_pos; + while (tmp != NULL) + { + free_tmp = tmp; + tmp = tmp->next; + free(free_tmp); + } + versaloon_want_pos = NULL; + + for (i = 0; i < dimof(versaloon_pending); i++) + { + tmp = versaloon_pending[i].pos; + while (tmp != NULL) + { + free_tmp = tmp; + tmp = tmp->next; + free(free_tmp); + } + versaloon_pending[i].pos = NULL; + } +} + +RESULT versaloon_add_want_pos(uint16_t offset, uint16_t size, uint8_t *buff) +{ + struct versaloon_want_pos_t *new_pos = NULL; + + new_pos = (struct versaloon_want_pos_t *)malloc(sizeof(*new_pos)); + if (NULL == new_pos) + { + LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); + return ERRCODE_NOT_ENOUGH_MEMORY; + } + new_pos->offset = offset; + new_pos->size = size; + new_pos->buff = buff; + new_pos->next = NULL; + + if (NULL == versaloon_want_pos) + { + versaloon_want_pos = new_pos; + } + else + { + struct versaloon_want_pos_t *tmp = versaloon_want_pos; + + while (tmp->next != NULL) + { + tmp = tmp->next; + } + tmp->next = new_pos; + } + + return ERROR_OK; +} + +RESULT versaloon_add_pending(uint8_t type, uint8_t cmd, uint16_t actual_szie, + uint16_t want_pos, uint16_t want_size, uint8_t *buffer, uint8_t collect) +{ +#if PARAM_CHECK + if (versaloon_pending_idx >= VERSALOON_MAX_PENDING_NUMBER) + { + LOG_BUG(ERRMSG_INVALID_INDEX, versaloon_pending_idx, + "versaloon pending data"); + return ERROR_FAIL; + } +#endif + + versaloon_pending[versaloon_pending_idx].type = type; + versaloon_pending[versaloon_pending_idx].cmd = cmd; + versaloon_pending[versaloon_pending_idx].actual_data_size = actual_szie; + versaloon_pending[versaloon_pending_idx].want_data_pos = want_pos; + versaloon_pending[versaloon_pending_idx].want_data_size = want_size; + versaloon_pending[versaloon_pending_idx].data_buffer = buffer; + versaloon_pending[versaloon_pending_idx].collect = collect; + versaloon_pending[versaloon_pending_idx].id = versaloon_pending_id; + versaloon_pending_id = 0; + versaloon_pending[versaloon_pending_idx].extra_data = versaloon_extra_data; + versaloon_extra_data = NULL; + versaloon_pending[versaloon_pending_idx].callback = versaloon_callback; + versaloon_callback = NULL; + versaloon_pending[versaloon_pending_idx].pos = versaloon_want_pos; + versaloon_want_pos = NULL; + versaloon_pending_idx++; + + return ERROR_OK; +} + +RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen) +{ + int ret; + +#if PARAM_CHECK + if (NULL == versaloon_buf) + { + LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf)); + return ERRCODE_INVALID_BUFFER; + } + if ((0 == out_len) || (out_len > versaloon_interface.usb_setting.buf_size)) + { + LOG_BUG(ERRMSG_INVALID_PARAMETER, __FUNCTION__); + return ERRCODE_INVALID_PARAMETER; + } +#endif + + ret = usb_bulk_write(versaloon_usb_device_handle, + versaloon_interface.usb_setting.ep_out, (char *)versaloon_buf, + out_len, versaloon_usb_to); + if (ret != out_len) + { + LOG_ERROR(ERRMSG_FAILURE_OPERATION_ERRSTRING, "send usb data", + usb_strerror()); + return ERRCODE_FAILURE_OPERATION; + } + + if (inlen != NULL) + { + ret = usb_bulk_read(versaloon_usb_device_handle, + versaloon_interface.usb_setting.ep_in, (char *)versaloon_buf, + versaloon_interface.usb_setting.buf_size, versaloon_usb_to); + if (ret > 0) + { + *inlen = (uint16_t)ret; + return ERROR_OK; + } + else + { + LOG_ERROR(ERRMSG_FAILURE_OPERATION_ERRSTRING, "receive usb data", + usb_strerror()); + return ERROR_FAIL; + } + } + else + { + return ERROR_OK; + } +} + +#define VERSALOON_RETRY_CNT 10 +RESULT versaloon_init(void) +{ + uint16_t ret = 0; + uint8_t retry; + uint32_t timeout_tmp; + + // malloc temporary buffer + versaloon_buf = + (uint8_t *)malloc(versaloon_interface.usb_setting.buf_size); + if (NULL == versaloon_buf) + { + LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); + return ERRCODE_NOT_ENOUGH_MEMORY; + } + + // connect to versaloon + timeout_tmp = versaloon_usb_to; + // not output error message when connectting + // 100ms delay when connect + versaloon_usb_to = 100; + for (retry = 0; retry < VERSALOON_RETRY_CNT; retry++) + { + versaloon_buf[0] = VERSALOON_GET_INFO; + if ((ERROR_OK == versaloon_send_command(1, &ret)) && (ret >= 3)) + { + break; + } + } + versaloon_usb_to = timeout_tmp; + if (VERSALOON_RETRY_CNT == retry) + { + versaloon_fini(); + LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon"); + return ERRCODE_FAILURE_OPERATION; + } + + versaloon_buf[ret] = 0; + versaloon_buf_size = versaloon_buf[0] + (versaloon_buf[1] << 8); + versaloon_interface.usb_setting.buf_size = versaloon_buf_size; + LOG_INFO("%s", versaloon_buf + 2); + + // free temporary buffer + free(versaloon_buf); + versaloon_buf = NULL; + + versaloon_buf = + (uint8_t *)malloc(versaloon_interface.usb_setting.buf_size); + if (NULL == versaloon_buf) + { + versaloon_fini(); + LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); + return ERRCODE_NOT_ENOUGH_MEMORY; + } + versaloon_cmd_buf = + (uint8_t *)malloc(versaloon_interface.usb_setting.buf_size - 3); + if (NULL == versaloon_cmd_buf) + { + versaloon_fini(); + LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); + return ERRCODE_NOT_ENOUGH_MEMORY; + } + if (ERROR_OK != usbtoxxx_init()) + { + LOG_ERROR(ERRMSG_FAILURE_OPERATION, "initialize usbtoxxx"); + return ERROR_FAIL; + } + return versaloon_get_target_voltage(&ret); +} + +RESULT versaloon_fini(void) +{ + if (versaloon_usb_device_handle != NULL) + { + usbtoxxx_fini(); + versaloon_free_want_pos(); + + versaloon_usb_device_handle = NULL; + + if (versaloon_buf != NULL) + { + free(versaloon_buf); + versaloon_buf = NULL; + } + if (versaloon_cmd_buf != NULL) + { + free(versaloon_cmd_buf); + versaloon_cmd_buf = NULL; + } + } + + return ERROR_OK; +} + +RESULT versaloon_set_target_voltage(uint16_t voltage) +{ + usbtopwr_init(0); + usbtopwr_config(0); + usbtopwr_output(0, voltage); + usbtopwr_fini(0); + + return usbtoxxx_execute_command(); +} + +RESULT versaloon_get_target_voltage(uint16_t *voltage) +{ + uint16_t inlen; + +#if PARAM_CHECK + if (NULL == versaloon_buf) + { + LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf)); + return ERRCODE_INVALID_BUFFER; + } + if (NULL == voltage) + { + LOG_BUG(ERRMSG_INVALID_PARAMETER, __FUNCTION__); + return ERRCODE_INVALID_PARAMETER; + } +#endif + + versaloon_buf[0] = VERSALOON_GET_TVCC; + + if ((ERROR_OK != versaloon_send_command(1, &inlen)) || (inlen != 2)) + { + LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon"); + return ERRCODE_FAILURE_OPERATION; + } + else + { + *voltage = versaloon_buf[0] + (versaloon_buf[1] << 8); + return ERROR_OK; + } +} + +RESULT versaloon_delay_ms(uint16_t ms) +{ + return usbtodelay_delay(ms | 0x8000); +} + +RESULT versaloon_delay_us(uint16_t us) +{ + return usbtodelay_delay(us & 0x7FFF); +} + |