263 lines
5.6 KiB
C
263 lines
5.6 KiB
C
/*
|
|
* uart.c - UART Rx and Tx functions
|
|
*
|
|
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
|
|
*
|
|
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
|
|
* Copyright 2008 Texas Instruments, Inc. <www.ti.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "common.h"
|
|
#include "davinci.h"
|
|
#include "uart.h"
|
|
#include "util.h"
|
|
#include "crc.h"
|
|
|
|
/* Symbol from linker script */
|
|
extern uint32_t __DDR_FREE; /* Start of free DDR memory region. */
|
|
|
|
/* Receive data from UART */
|
|
static int
|
|
uart_recv_bytes(size_t count, uint8_t *dest)
|
|
{
|
|
uint32_t i, status = 0;
|
|
uint32_t timerStatus = 1;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
/* Enable timer one time */
|
|
timer0_start();
|
|
do {
|
|
status = (UART0->LSR)&(0x01);
|
|
timerStatus = timer0_status();
|
|
} while (!status && timerStatus);
|
|
|
|
if (timerStatus == 0) {
|
|
host_msg("UART_TIMEOUT");
|
|
return E_TIMEOUT;
|
|
}
|
|
|
|
/* Receive byte */
|
|
dest[i] = (UART0->RBR) & 0xFF;
|
|
|
|
/* Check status for errors */
|
|
if ((UART0->LSR & 0x1C) != 0) {
|
|
host_msg("UART_RXERR");
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
return E_PASS;
|
|
}
|
|
|
|
/* Send bytes with optional null terminating character. */
|
|
static void
|
|
uart_send_bytes(char *string)
|
|
{
|
|
uint32_t status = 0;
|
|
int32_t i, count;
|
|
uint32_t timerStatus = 1;
|
|
|
|
count = strlen(string);
|
|
|
|
for (i = 0; i < count; i++) {
|
|
/* Enable Timer one time */
|
|
timer0_start();
|
|
do {
|
|
status = (UART0->LSR)&(0x20);
|
|
timerStatus = timer0_status();
|
|
} while (!status && timerStatus);
|
|
|
|
if (timerStatus == 0)
|
|
return; /* E_TIMEOUT */
|
|
|
|
/* Send byte */
|
|
(UART0->THR) = string[i];
|
|
}
|
|
}
|
|
|
|
/* Check if the given string is received via UART */
|
|
static int
|
|
uart_check_string(char *string, int include_null)
|
|
{
|
|
int i, count;
|
|
|
|
count = strlen(string);
|
|
if (include_null != false)
|
|
count++;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
uint8_t recv;
|
|
|
|
/* Get one byte */
|
|
if (uart_recv_bytes(1, &recv) != E_PASS)
|
|
return E_FAIL;
|
|
|
|
if (recv != string[i])
|
|
return E_FAIL;
|
|
}
|
|
return E_PASS;
|
|
}
|
|
|
|
/* Receive a uint32 value in HEX form (8 bytes) */
|
|
static int
|
|
uart_recv_hex_uint32(uint32_t *data)
|
|
{
|
|
int k;
|
|
uint8_t recv[8];
|
|
uint32_t temp;
|
|
int shift;
|
|
const int num_ascii_char = 8;
|
|
|
|
/* Get 8 bytes from UART */
|
|
if (uart_recv_bytes(num_ascii_char, recv) != E_PASS)
|
|
return E_FAIL;
|
|
|
|
*data = 0;
|
|
|
|
/* Converting ascii to Hex */
|
|
for (k = 0, shift = 28; k < num_ascii_char; k++, shift -= 4) {
|
|
temp = recv[k] - 48;
|
|
|
|
if (temp > 22) /* Lower case a,b,c,d,e,f */
|
|
temp -= 39;
|
|
else if (temp > 9) /* Upper case A,B,C,D,E,F */
|
|
temp -= 7;
|
|
|
|
*data |= temp << shift;
|
|
}
|
|
return E_PASS;
|
|
}
|
|
|
|
/* Send line feed (\n) to UART. */
|
|
void
|
|
uart_send_lf(void)
|
|
{
|
|
uart_send_bytes("\r\n");
|
|
}
|
|
|
|
/* Send a string to UART, without line feed. */
|
|
void
|
|
uart_send_str(char *string)
|
|
{
|
|
uart_send_bytes(string);
|
|
}
|
|
|
|
/* Send a string to UART, with line feed. */
|
|
void
|
|
uart_send_str_lf(char *string)
|
|
{
|
|
uart_send_bytes(string);
|
|
uart_send_lf();
|
|
}
|
|
|
|
void
|
|
uart_send_hexnum(uint32_t value, int digits)
|
|
{
|
|
char seq[9];
|
|
uint32_t i, shift;
|
|
uint8_t temp;
|
|
|
|
for (i = 0; i < digits; i++) {
|
|
shift = ((digits - 1) - i) * 4;
|
|
temp = (value >> shift) & 0x0F;
|
|
if (temp > 9)
|
|
temp += 7;
|
|
seq[i] = temp + 48;
|
|
}
|
|
seq[digits] = 0;
|
|
|
|
uart_send_str("0x");
|
|
uart_send_bytes(seq);
|
|
}
|
|
|
|
int
|
|
uart_get_cmd(uint32_t *boot_cmd)
|
|
{
|
|
if (uart_check_string(" CMD", true) != E_PASS)
|
|
return E_FAIL;
|
|
|
|
if (uart_recv_hex_uint32(boot_cmd) != E_PASS)
|
|
return E_FAIL;
|
|
|
|
return E_PASS;
|
|
}
|
|
|
|
uint32_t
|
|
uart_get_prog(struct uart_ack_header_t *uart_ack_header)
|
|
{
|
|
uint32_t error;
|
|
uint32_t recv_crc, computed_crc;
|
|
uint8_t *ddr_free = (uint8_t *) &__DDR_FREE;
|
|
|
|
uart_ack_header->recv_buffer = ddr_free;
|
|
|
|
/* Send ACK command */
|
|
error = uart_check_string(" ACK", true);
|
|
if (error != E_PASS)
|
|
return E_FAIL;
|
|
|
|
/* Get the ACK header elements */
|
|
error = uart_recv_hex_uint32(&uart_ack_header->magic);
|
|
error |= uart_recv_hex_uint32(&recv_crc);
|
|
error |= uart_recv_hex_uint32(&uart_ack_header->size);
|
|
error |= uart_recv_hex_uint32(&uart_ack_header->entry_point);
|
|
error |= uart_check_string("0000", false);
|
|
if (error != E_PASS)
|
|
return E_FAIL;
|
|
|
|
uart_send_str("Magic = ");
|
|
uart_send_hexnum(uart_ack_header->magic, 8);
|
|
uart_send_str(", CRC = ");
|
|
uart_send_hexnum(recv_crc, 8);
|
|
uart_send_str(", Entry = ");
|
|
uart_send_hexnum(uart_ack_header->entry_point, 8);
|
|
uart_send_str(", Size = ");
|
|
uart_send_hexnum(uart_ack_header->size, 8);
|
|
uart_send_lf();
|
|
|
|
/* Verify that the file size is appropriate */
|
|
if ((uart_ack_header->size == 0) ||
|
|
(uart_ack_header->size > MAX_IMAGE_SIZE)) {
|
|
host_msg("BADCNT");
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* Send BEGIN command */
|
|
host_msg("BEGIN");
|
|
|
|
/* Receive the data over UART */
|
|
if (uart_recv_bytes(uart_ack_header->size,
|
|
uart_ack_header->recv_buffer)
|
|
!= E_PASS) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* Return first DONE when all data arrives */
|
|
host_msg("DONE");
|
|
|
|
computed_crc = crc32_dv_compute(uart_ack_header->recv_buffer,
|
|
uart_ack_header->size);
|
|
if (computed_crc != recv_crc) {
|
|
host_msg("BADCRC");
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* Return DONE when all data is validated */
|
|
host_msg("DONE");
|
|
|
|
return E_PASS;
|
|
}
|