5c9688961e
New support as well as some buggy support fixed. Still no floating point support if ever that would be desired. Support (*): * Flags: '-', '+', ' ', '#', '0' * Width and precision: 'n', '.n', '*' and '.*' * Length modifiers: 'hh', 'h', 'j', 'l', 'll', 't', 'z' * Radix: 'c', 'd', 'i', 'n', 'o', 'p/P', 's', 'u', 'x/X' (*) Provision exists to switch lesser-used stuff on or off or when certain functionality isn't desired (bootloader?). The compulsory radixes are everything but 'o', 'n', 'p/P' and 'x/X' with length modifiers being optional. The default setup is 'l', 'z', 'c', 'd', 'p/P', 's', 'u', 'x/X'. * Move fdprintf() to its own file. It was in a strange place. * Make callers compatible and fix a couple snprintf() bugs while at it. Could smush it down in size but I'm gonna get over the binsize neurosis and just the let optimizer do its thing. Change-Id: Ibdc613a9b6775802c188b29b9dd46c568c94f7c3
283 lines
6.6 KiB
C
283 lines
6.6 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2009 by Bob Cousins
|
|
*
|
|
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/* Include Standard files */
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include "inttypes.h"
|
|
#include "string.h"
|
|
#include "cpu.h"
|
|
#include "system.h"
|
|
#include "kernel.h"
|
|
#include "thread.h"
|
|
#include "format.h"
|
|
|
|
#include "system-target.h"
|
|
#include "uart-s3c2440.h"
|
|
#include "serial.h"
|
|
|
|
#define MAX_PRINTF_BUF 1024
|
|
|
|
/****************************************************************************
|
|
* serial driver API
|
|
****************************************************************************/
|
|
void serial_setup (void)
|
|
{
|
|
uart_init();
|
|
uart_init_device(DEBUG_UART_PORT);
|
|
}
|
|
|
|
int tx_rdy(void)
|
|
{
|
|
if (uart_tx_ready (DEBUG_UART_PORT))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void tx_writec(unsigned char c)
|
|
{
|
|
uart_send_byte (DEBUG_UART_PORT, c);
|
|
}
|
|
|
|
|
|
static int uart_push(void *user_data, int ch)
|
|
{
|
|
(void)user_data;
|
|
|
|
uart_send_byte(DEBUG_UART_PORT, ch);
|
|
if (ch == '\n')
|
|
uart_send_byte(DEBUG_UART_PORT, '\r');
|
|
return 1;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* General purpose debug function
|
|
****************************************************************************/
|
|
void uart_printf (const char *format, ...)
|
|
{
|
|
static bool debug_uart_init = false;
|
|
va_list ap;
|
|
|
|
if (!debug_uart_init)
|
|
{
|
|
uart_init_device(DEBUG_UART_PORT);
|
|
debug_uart_init = true;
|
|
}
|
|
|
|
va_start(ap, format);
|
|
vuprintf(uart_push, NULL, format, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Device level functions specific to S3C2440
|
|
*****************************************************************************/
|
|
|
|
bool uart_init (void)
|
|
{
|
|
/* anything ? */
|
|
return true;
|
|
}
|
|
|
|
bool uart_init_device (unsigned dev)
|
|
{
|
|
/* set GPIOs, clock enable? etc */
|
|
|
|
switch (dev)
|
|
{
|
|
case 0:
|
|
{
|
|
S3C2440_GPIO_CONFIG (GPHCON, 2, GPIO_FUNCTION);
|
|
S3C2440_GPIO_CONFIG (GPHCON, 3, GPIO_FUNCTION);
|
|
S3C2440_GPIO_PULLUP (GPHUP, 2, GPIO_PULLUP_DISABLE);
|
|
S3C2440_GPIO_PULLUP (GPHUP, 3, GPIO_PULLUP_DISABLE);
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
S3C2440_GPIO_CONFIG (GPHCON, 4, GPIO_FUNCTION);
|
|
S3C2440_GPIO_CONFIG (GPHCON, 5, GPIO_FUNCTION);
|
|
S3C2440_GPIO_PULLUP (GPHUP, 4, GPIO_PULLUP_DISABLE);
|
|
S3C2440_GPIO_PULLUP (GPHUP, 5, GPIO_PULLUP_DISABLE);
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
S3C2440_GPIO_CONFIG (GPHCON, 6, GPIO_FUNCTION);
|
|
S3C2440_GPIO_CONFIG (GPHCON, 7, GPIO_FUNCTION);
|
|
S3C2440_GPIO_PULLUP (GPHUP, 6, GPIO_PULLUP_DISABLE);
|
|
S3C2440_GPIO_PULLUP (GPHUP, 7, GPIO_PULLUP_DISABLE);
|
|
break;
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
/* set a default configuration */
|
|
uart_config (dev, 115200, 8, UART_NO_PARITY, UART_1_STOP_BIT);
|
|
return true;
|
|
}
|
|
|
|
bool uart_config (unsigned dev, unsigned speed, unsigned num_bits,
|
|
unsigned parity, unsigned stop_bits)
|
|
{
|
|
switch (dev)
|
|
{
|
|
case 0:
|
|
ULCON0 = (parity << 3) + (stop_bits << 2) + (num_bits-5);
|
|
UCON0 = (1 << 2) + (1 << 0); /* enable TX, RX, use PCLK */
|
|
UBRDIV0 = PCLK / (speed*16);
|
|
break;
|
|
|
|
case 1:
|
|
ULCON1 = (parity << 3) + (stop_bits << 2) + (num_bits-5);
|
|
UCON1 = (1 << 2) + (1 << 0); /* enable TX, RX, use PCLK */
|
|
UBRDIV1 = PCLK / (speed*16);
|
|
break;
|
|
|
|
case 2:
|
|
ULCON2 = (parity << 3) + (stop_bits << 2) + (num_bits-5);
|
|
UCON2 = (1 << 2) + (1 << 0); /* enable TX, RX, use PCLK */
|
|
UBRDIV2 = PCLK / (speed*16);
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* transmit */
|
|
bool uart_tx_ready (unsigned dev)
|
|
{
|
|
/* test if transmit buffer empty */
|
|
switch (dev)
|
|
{
|
|
case 0:
|
|
if (UTRSTAT0 & 0x02)
|
|
return true;
|
|
else
|
|
return false;
|
|
break;
|
|
case 1:
|
|
if (UTRSTAT1 & 0x02)
|
|
return true;
|
|
else
|
|
return false;
|
|
break;
|
|
case 2:
|
|
if (UTRSTAT2 & 0x02)
|
|
return true;
|
|
else
|
|
return false;
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool uart_send_byte (unsigned dev, char ch)
|
|
{
|
|
/* wait for transmit buffer empty */
|
|
while (!uart_tx_ready(dev))
|
|
;
|
|
|
|
switch (dev)
|
|
{
|
|
case 0:
|
|
UTXH0 = ch;
|
|
break;
|
|
case 1:
|
|
UTXH1 = ch;
|
|
break;
|
|
case 2:
|
|
UTXH2 = ch;
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Receive */
|
|
|
|
bool uart_rx_ready (unsigned dev)
|
|
{
|
|
/* test receive buffer data ready */
|
|
switch (dev)
|
|
{
|
|
case 0:
|
|
if (UTRSTAT0 & 0x01)
|
|
return true;
|
|
else
|
|
return false;
|
|
break;
|
|
case 1:
|
|
if (UTRSTAT1 & 0x01)
|
|
return true;
|
|
else
|
|
return false;
|
|
break;
|
|
case 2:
|
|
if (UTRSTAT2 & 0x01)
|
|
return true;
|
|
else
|
|
return false;
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
char uart_read_byte (unsigned dev)
|
|
{
|
|
while (!uart_rx_ready(dev))
|
|
;
|
|
switch (dev)
|
|
{
|
|
case 0:
|
|
return URXH0;
|
|
break;
|
|
case 1:
|
|
return URXH1;
|
|
break;
|
|
case 2:
|
|
return URXH2;
|
|
break;
|
|
}
|
|
|
|
return '\0';
|
|
}
|
|
|
|
/****************************************************************************
|
|
* General
|
|
*****************************************************************************/
|
|
|
|
bool uart_send_buf (unsigned dev, char *buf, unsigned len)
|
|
{
|
|
unsigned index=0;
|
|
while (index<len)
|
|
{
|
|
uart_send_byte (dev, buf[index]);
|
|
index++;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|