551 lines
16 KiB
C
551 lines
16 KiB
C
/*
|
|
* 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.
|
|
*/
|
|
|
|
/* This file implements the UART console application operations. */
|
|
#define _GNU_SOURCE
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include "com_port.h"
|
|
#include "cmd.h"
|
|
#include "main.h"
|
|
#include "misc_util.h"
|
|
#include "opr.h"
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Global Variables
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
int port_handle = INVALID_HANDLE_VALUE;
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Constant definitions
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
#define MAX_PORT_NAME_SIZE 32
|
|
#define OPR_TIMEOUT 10L /* 10 seconds */
|
|
#define FLASH_ERASE_TIMEOUT 120L /* 120 seconds */
|
|
|
|
#define STS_MSG_MIN_SIZE 8
|
|
#define STS_MSG_APP_END 0x09
|
|
#define DUMMY_SIZE 2
|
|
|
|
#define MAX_SYNC_TRIALS 3
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Global variables
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
struct command_node cmd_buf[MAX_CMD_BUF_SIZE];
|
|
uint8_t resp_buf[MAX_RESP_BUF_SIZE];
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* Functions prototypes
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
static bool opr_send_cmds(struct command_node *cmd_buf, uint32_t cmd_num);
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function implementation
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function: opr_usage
|
|
*
|
|
* Parameters: none.
|
|
* Returns: none.
|
|
* Side effects:
|
|
* Description:
|
|
* Prints the console application operation menu.
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
void opr_usage(void)
|
|
{
|
|
printf("Operations:\n");
|
|
printf(" %s\t\t- Write To Memory/Flash\n", OPR_WRITE_MEM);
|
|
printf(" %s\t\t- Read From Memory/Flash\n", OPR_READ_MEM);
|
|
printf(" %s\t\t- Execute a non-return code\n", OPR_EXECUTE_EXIT);
|
|
printf(" %s\t\t- Execute a returnable code\n", OPR_EXECUTE_CONT);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function: opr_close_port
|
|
*
|
|
* Parameters: none
|
|
* Returns:
|
|
* Side effects:
|
|
* Description:
|
|
* This routine closes the opened COM port by the application
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
bool opr_close_port(void)
|
|
{
|
|
return com_port_close(port_handle);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function: opr_open_port
|
|
*
|
|
* Parameters: port_name - COM Port name.
|
|
* port_cfg - COM Port configuration structure.
|
|
* Returns: 1 if successful, 0 in the case of an error.
|
|
* Side effects:
|
|
* Description:
|
|
* Open a specified ComPort device.
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
bool opr_open_port(const char *port_name, struct comport_fields port_cfg)
|
|
{
|
|
char *full_port_name;
|
|
|
|
if (asprintf(&full_port_name, "/dev/%s", port_name) == -1)
|
|
return false;
|
|
|
|
if (port_handle > 0)
|
|
com_port_close(port_handle);
|
|
|
|
port_handle = com_port_open((const char *)full_port_name, port_cfg);
|
|
|
|
if (port_handle <= 0) {
|
|
display_color_msg(FAIL, "\nERROR: COM Port failed to open.\n");
|
|
DISPLAY_MSG(
|
|
("Please select the right serial port or check if "
|
|
"other serial\n"));
|
|
DISPLAY_MSG(("communication applications are opened.\n"));
|
|
return false;
|
|
}
|
|
|
|
display_color_msg(SUCCESS, "Port %s Opened\n", full_port_name);
|
|
|
|
return true;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function: opr_write_chunk
|
|
*
|
|
* Parameters:
|
|
* buffer - Input data buffer.
|
|
* addr - Memory address to write to.
|
|
* size - Data size to write.
|
|
* Returns: true if successful, false in the case of an error.
|
|
* Side effects:
|
|
* Description:
|
|
* Write data to RAM, starting from the given address (addr).
|
|
* Data size is limited to the max chunk size (256 bytes).
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
bool opr_write_chunk(uint8_t *buffer, uint32_t addr, uint32_t size)
|
|
{
|
|
struct command_node wr_cmd_buf;
|
|
|
|
if (size > MAX_RW_DATA_SIZE) {
|
|
display_color_msg(FAIL,
|
|
"ERROR: Block cannot exceed %d\n", MAX_RW_DATA_SIZE);
|
|
}
|
|
/* Initialize response size */
|
|
wr_cmd_buf.resp_size = 1;
|
|
cmd_create_write(addr, size, buffer,
|
|
wr_cmd_buf.cmd, &wr_cmd_buf.cmd_size);
|
|
return opr_send_cmds(&wr_cmd_buf, 1);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function: opr_read_chunk
|
|
*
|
|
* Parameters:
|
|
* buffer - Data read buffer.
|
|
* addr - Memory address to read from.
|
|
* size - Data size to read.
|
|
* Returns: true if successful, false in the case of an error.
|
|
* Side effects:
|
|
* Description:
|
|
* Read data from RAM, starting from the given address (addr).
|
|
* Data size is limited to the max chunk size (256 bytes).
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
bool opr_read_chunk(uint8_t *buffer, uint32_t addr, uint32_t size)
|
|
{
|
|
struct command_node rd_cmd_buf;
|
|
|
|
if (size > MAX_RW_DATA_SIZE) {
|
|
display_color_msg(FAIL,
|
|
"ERROR: Block cannot exceed %d\n", MAX_RW_DATA_SIZE);
|
|
return false;
|
|
}
|
|
|
|
cmd_create_read(addr, ((uint8_t)size - 1),
|
|
rd_cmd_buf.cmd, &rd_cmd_buf.cmd_size);
|
|
rd_cmd_buf.resp_size = size + 3;
|
|
if (opr_send_cmds(&rd_cmd_buf, 1)) {
|
|
if (resp_buf[0] == (uint8_t)(UFPP_READ_CMD)) {
|
|
memcpy(buffer, &resp_buf[1], size);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
/*----------------------------------------------------------------------------
|
|
* Function: opr_write_mem
|
|
*
|
|
* Parameters: input - Input (file-name/console), containing data to write.
|
|
* addr - Memory address to write to.
|
|
* size - Data size to write.
|
|
* Returns: none.
|
|
* Side effects:
|
|
* Description:
|
|
* Write data to memory, starting from a given address.
|
|
* Memory may be Flash (SPI), DRAM (DDR) or SRAM.
|
|
* The data is retrieved either from an input file or from a console.
|
|
* Data size is not limited.
|
|
* Data is sent in 256 bytes chunks (file mode) or 4 bytes chunks
|
|
* (console mode).
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
void opr_write_mem(uint8_t *buffer, uint32_t addr, uint32_t size)
|
|
{
|
|
uint32_t cur_addr = addr;
|
|
uint8_t data_buf[256];
|
|
uint32_t write_size, size_remain;
|
|
uint32_t cmd_idx = 1;
|
|
char seps[] = " ";
|
|
char *token = NULL;
|
|
char *stop_str;
|
|
uint32_t block_size = (console) ? sizeof(uint32_t) : MAX_RW_DATA_SIZE;
|
|
struct command_node wr_cmd_buf;
|
|
|
|
/* Initialize response size */
|
|
wr_cmd_buf.resp_size = 1;
|
|
|
|
DISPLAY_MSG(("Writing [%d] bytes in [%d] packets\n", size,
|
|
((size + (block_size - 1)) / block_size)));
|
|
|
|
/* Read first token from string */
|
|
if (console)
|
|
token = strtok(buffer, seps);
|
|
|
|
size_remain = size;
|
|
/* Main write loop */
|
|
while (true) {
|
|
if (console) {
|
|
/*
|
|
* Invert token to double-word and insert the value to
|
|
* data buffer
|
|
*/
|
|
(*(uint32_t *)data_buf) =
|
|
strtoul(token, &stop_str, BASE_HEXADECIMAL);
|
|
|
|
/* Prepare the next iteration */
|
|
token = strtok(NULL, seps);
|
|
}
|
|
write_size = (size_remain > block_size) ?
|
|
block_size : size_remain;
|
|
if (console) {
|
|
cmd_create_write(cur_addr, write_size, data_buf,
|
|
wr_cmd_buf.cmd, &wr_cmd_buf.cmd_size);
|
|
} else {
|
|
cmd_create_write(cur_addr, write_size, buffer,
|
|
wr_cmd_buf.cmd, &wr_cmd_buf.cmd_size);
|
|
buffer += write_size;
|
|
}
|
|
if (opr_send_cmds(&wr_cmd_buf, 1) != true)
|
|
break;
|
|
|
|
cmd_disp_write(resp_buf, write_size, cmd_idx,
|
|
((size + (block_size - 1)) / block_size));
|
|
cur_addr += write_size;
|
|
size_remain -= write_size;
|
|
cmd_idx++;
|
|
if (size_remain == 0)
|
|
break;
|
|
}
|
|
|
|
DISPLAY_MSG(("\n"));
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function: opr_read_mem
|
|
*
|
|
* Parameters: output - Output file name, containing data that was read.
|
|
* addr - Memory address to read from.
|
|
* size - Data size to read.
|
|
* Returns: none.
|
|
* Side effects:
|
|
* Description:
|
|
* Read data from memory, starting from a given address.
|
|
* Memory may be Flash (SPI), DRAM (DDR) or SRAM.
|
|
* The data is written into an output file, data size is limited
|
|
* as specified.
|
|
* Data is received in 256 bytes chunks.
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
void opr_read_mem(char *output, uint32_t addr, uint32_t size)
|
|
{
|
|
FILE *output_file_id = NULL;
|
|
uint32_t cur_addr;
|
|
uint32_t bytes_left;
|
|
uint32_t read_size;
|
|
uint32_t cmd_idx = 1;
|
|
struct command_node rd_cmd_buf;
|
|
|
|
if (!console) {
|
|
output_file_id = fopen(output, "w+b");
|
|
|
|
if (output_file_id == NULL) {
|
|
display_color_msg(FAIL,
|
|
"ERROR: could not open output file [%s]\n",
|
|
output);
|
|
return;
|
|
}
|
|
}
|
|
|
|
DISPLAY_MSG(("Reading [%d] bytes in [%d] packets\n", size,
|
|
((size + (MAX_RW_DATA_SIZE - 1)) / MAX_RW_DATA_SIZE)));
|
|
|
|
for (cur_addr = addr; cur_addr < (addr + size);
|
|
cur_addr += MAX_RW_DATA_SIZE) {
|
|
bytes_left = (uint32_t)(addr + size - cur_addr);
|
|
read_size = MIN(bytes_left, MAX_RW_DATA_SIZE);
|
|
|
|
cmd_create_read(cur_addr, ((uint8_t)read_size - 1),
|
|
rd_cmd_buf.cmd, &rd_cmd_buf.cmd_size);
|
|
rd_cmd_buf.resp_size = read_size + 3;
|
|
|
|
if (opr_send_cmds(&rd_cmd_buf, 1) != true)
|
|
break;
|
|
|
|
cmd_disp_read(resp_buf, read_size, cmd_idx,
|
|
((size + (MAX_RW_DATA_SIZE - 1)) / MAX_RW_DATA_SIZE));
|
|
|
|
if (console)
|
|
cmd_disp_data((resp_buf + 1), read_size);
|
|
else
|
|
fwrite((resp_buf + 1), 1, read_size, output_file_id);
|
|
|
|
cmd_idx++;
|
|
}
|
|
|
|
DISPLAY_MSG(("\n"));
|
|
if (!console)
|
|
fclose(output_file_id);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function: opr_execute_exit
|
|
*
|
|
* Parameters: addr - Start address to execute from.
|
|
* Returns: none.
|
|
* Side effects: ROM-Code is not in UART command mode anymore.
|
|
* Description:
|
|
* Execute code starting from a given address.
|
|
* Memory address may be in Flash (SPI), DRAM (DDR) or SRAM.
|
|
* No further communication with thr ROM-Code is expected at this point.
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
void opr_execute_exit(uint32_t addr)
|
|
{
|
|
uint32_t cmd_num;
|
|
|
|
cmd_build_exec_exit(addr, cmd_buf, &cmd_num);
|
|
if (opr_send_cmds(cmd_buf, cmd_num) != true)
|
|
return;
|
|
|
|
cmd_disp_exec_exit(resp_buf);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function: opr_execute_return
|
|
*
|
|
* Parameters: addr - Start address to execute from.
|
|
* Returns: true if successful, false in the case of an error.
|
|
* Side effects:
|
|
* Description:
|
|
* Execute code starting from the given address and then check the result.
|
|
* The executed code should return with the execution result.
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
bool opr_execute_return(uint32_t addr)
|
|
{
|
|
uint32_t cmd_num;
|
|
|
|
cmd_build_exec_ret(addr, cmd_buf, &cmd_num);
|
|
if (opr_send_cmds(cmd_buf, cmd_num) != true)
|
|
return false;
|
|
|
|
/*
|
|
* Check the response command code is UFPP_FCALL_RSLT_CMD and
|
|
* the return value from monitor is 0x03. (program finish and verify ok)
|
|
*/
|
|
if (resp_buf[1] != (uint8_t)(UFPP_FCALL_RSLT_CMD)
|
|
|| resp_buf[2] != 0x03)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function: opr_check_sync
|
|
*
|
|
* Parameters:
|
|
* baudrate - baud rate to check
|
|
*
|
|
* Returns:
|
|
* Side effects:
|
|
* Description:
|
|
* Checks whether the Host and the Core are synchoronized in the
|
|
* specified baud rate
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
enum sync_result opr_check_sync(uint32_t baudrate)
|
|
{
|
|
uint32_t cmd_num;
|
|
struct command_node *cur_cmd = cmd_buf;
|
|
uint32_t bytes_read = 0;
|
|
uint32_t i;
|
|
|
|
port_cfg.baudrate = baudrate;
|
|
if (!com_config_uart(port_handle, port_cfg))
|
|
return SR_ERROR;
|
|
|
|
cmd_build_sync(cmd_buf, &cmd_num);
|
|
|
|
if (!com_port_write_bin(port_handle, cur_cmd->cmd, cur_cmd->cmd_size))
|
|
return SR_ERROR;
|
|
|
|
/* Allow several SYNC trials */
|
|
for (i = 0; i < MAX_SYNC_TRIALS; i++) {
|
|
bytes_read = com_port_read_bin(port_handle, resp_buf, 1);
|
|
|
|
/* Quit if succeeded to read a response */
|
|
if (bytes_read == 1)
|
|
break;
|
|
/* Otherwise give the ROM-Code time to answer */
|
|
sleep(1);
|
|
}
|
|
|
|
if (bytes_read == 0)
|
|
/*
|
|
* Unable to read a response from ROM-Code in a reasonable
|
|
* time
|
|
*/
|
|
return SR_TIMEOUT;
|
|
|
|
if (resp_buf[0] != (uint8_t)(UFPP_D2H_SYNC_CMD))
|
|
/* ROM-Code response is not as expected */
|
|
return SR_WRONG_DATA;
|
|
|
|
/* Good response */
|
|
return SR_OK;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function: opr_scan_baudrate
|
|
*
|
|
* Parameters: none
|
|
* Returns:
|
|
* Side effects:
|
|
* Description:
|
|
* Scans the baud rate range by sending sync request to the core
|
|
* and prints the response
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
bool opr_scan_baudrate(void)
|
|
{
|
|
uint32_t baud = 0;
|
|
uint32_t step;
|
|
enum sync_result sr;
|
|
bool synched = false;
|
|
bool data_received = false;
|
|
|
|
/* Scan with HUGE STEPS */
|
|
/* BR_BIG_STEP is percents */
|
|
step = (BR_LOW_LIMIT * BR_BIG_STEP) / 100;
|
|
for (baud = BR_LOW_LIMIT; baud < BR_HIGH_LIMIT; baud += step) {
|
|
sr = opr_check_sync(baud);
|
|
step = (baud * BR_BIG_STEP) / 100;
|
|
if (sr == SR_OK) {
|
|
printf("SR_OK: Baud rate - %d, resp_buf - 0x%x\n",
|
|
baud, resp_buf[0]);
|
|
synched = true;
|
|
step = (baud * BR_SMALL_STEP) / 100;
|
|
} else if (sr == SR_WRONG_DATA) {
|
|
printf("SR_WRONG_DATA: Baud rate - %d, resp_buf - "
|
|
"0x%x\n", baud, resp_buf[0]);
|
|
data_received = true;
|
|
step = (baud * BR_MEDIUM_STEP) / 100;
|
|
} else if (sr == SR_TIMEOUT) {
|
|
printf("SR_TIMEOUT: Baud rate - %d, resp_buf - 0x%x\n",
|
|
baud, resp_buf[0]);
|
|
|
|
if (synched || data_received)
|
|
break;
|
|
} else if (sr == SR_ERROR) {
|
|
printf("SR_ERROR: Baud rate - %d, resp_buf - 0x%x\n",
|
|
baud, resp_buf[0]);
|
|
if (synched || data_received)
|
|
break;
|
|
} else
|
|
printf("Unknown error code: Baud rate - %d, resp_buf - "
|
|
"0x%x\n", baud, resp_buf[0]);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Function: opr_send_cmds
|
|
*
|
|
* Parameters: cmd_buf - Pointer to a Command Buffer.
|
|
* cmd_num - Number of commands to send.
|
|
* Returns: 1 if successful, 0 in the case of an error.
|
|
* Side effects:
|
|
* Description:
|
|
* Send a group of commands through COM port.
|
|
* A command is sent only after a valid response for the previous command
|
|
* was received.
|
|
*---------------------------------------------------------------------------
|
|
*/
|
|
static bool opr_send_cmds(struct command_node *cmd_buf, uint32_t cmd_num)
|
|
{
|
|
struct command_node *cur_cmd = cmd_buf;
|
|
uint32_t cmd;
|
|
uint32_t read;
|
|
time_t start;
|
|
double elapsed_time;
|
|
|
|
for (cmd = 0; cmd < cmd_num; cmd++, cur_cmd++) {
|
|
if (com_port_write_bin(port_handle, cur_cmd->cmd,
|
|
cur_cmd->cmd_size) == true) {
|
|
time(&start);
|
|
|
|
do {
|
|
read = com_port_wait_read(port_handle);
|
|
elapsed_time = difftime(time(NULL), start);
|
|
} while ((read < cur_cmd->resp_size) &&
|
|
(elapsed_time <= OPR_TIMEOUT));
|
|
com_port_read_bin(port_handle, resp_buf,
|
|
cur_cmd->resp_size);
|
|
|
|
if (elapsed_time > OPR_TIMEOUT)
|
|
display_color_msg(FAIL,
|
|
"ERROR: [%d] bytes received for read, "
|
|
"[%d] bytes are expected\n",
|
|
read, cur_cmd->resp_size);
|
|
} else {
|
|
display_color_msg(FAIL,
|
|
"ERROR: Failed to send Command number %d\n",
|
|
cmd);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|