/* * uart.c - UART Rx and Tx functions * * Copyright (C) 2008 Hugo Villeneuve * * Based on TI DaVinci Flash and Boot Utilities, original copyright follows: * Copyright 2008 Texas Instruments, Inc. * * 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, const uint8_t timeout) { uint32_t i, status = 0; uint32_t timerStatus = 1; for (i = 0; i < count; i++) { /* Enable timer one time */ timer0_start(SYSTEM_CLK_HZ * timeout); 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(SYSTEM_CLK_HZ * 5); 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, const uint8_t timeout) { 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, timeout) != 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, const uint8_t timeout) { 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, timeout) != 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) { return uart_get_cmd_timeout(boot_cmd, 5); } int uart_get_cmd_timeout(uint32_t *boot_cmd, uint8_t timeout) { if (uart_check_string(" CMD", true, timeout) != E_PASS) return E_FAIL; if (uart_recv_hex_uint32(boot_cmd, timeout) != 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, 5); if (error != E_PASS) return E_FAIL; /* Get the ACK header elements */ error = uart_recv_hex_uint32(&uart_ack_header->magic, 5); error |= uart_recv_hex_uint32(&recv_crc, 5); error |= uart_recv_hex_uint32(&uart_ack_header->size, 5); error |= uart_recv_hex_uint32(&uart_ack_header->entry_point, 5); error |= uart_check_string("0000", false, 5); 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, 5) != 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; }