ubl/uart.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;
}