Line 46... |
Line 46... |
#include "vapi.h"
|
#include "vapi.h"
|
#include "sched.h"
|
#include "sched.h"
|
#include "channel.h"
|
#include "channel.h"
|
#include "debug.h"
|
#include "debug.h"
|
|
|
|
DEFAULT_DEBUG_CHANNEL(uart);
|
|
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
|
|
/* Number of clock cycles (one clock cycle is one call to the uart_clock())
|
/* Number of clock cycles (one clock cycle is one call to the uart_clock())
|
before a single character is transmitted or received. */
|
before a single character is transmitted or received. */
|
static unsigned long char_clks(int dll, int dlh, int lcr)
|
static unsigned long char_clks(int dll, int dlh, int lcr)
|
Line 77... |
Line 79... |
/* Set a specific UART register with value. */
|
/* Set a specific UART register with value. */
|
void uart_write_byte(oraddr_t addr, uint32_t value, void *dat)
|
void uart_write_byte(oraddr_t addr, uint32_t value, void *dat)
|
{
|
{
|
struct dev_16450 *uart = dat;
|
struct dev_16450 *uart = dat;
|
|
|
debug(4, "uart_write_byte(%"PRIxADDR",%02"PRIx32")\n", addr, value);
|
TRACE("uart_write_byte(%"PRIxADDR",%02"PRIx32")\n", addr, value);
|
|
|
if (uart->regs.lcr & UART_LCR_DLAB) {
|
if (uart->regs.lcr & UART_LCR_DLAB) {
|
switch (addr % UART_ADDR_SPACE) {
|
switch (addr % UART_ADDR_SPACE) {
|
case UART_DLL:
|
case UART_DLL:
|
uart->regs.dll = value;
|
uart->regs.dll = value;
|
uart->char_clks = char_clks(uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
|
uart->char_clks = char_clks(uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
|
|
TRACE("\tSetting char_clks to %li (%02x, %02x, %02x)\n", uart->char_clks,
|
|
uart->regs.dll, uart->regs.dlh, uart->regs.lcr);
|
return;
|
return;
|
case UART_DLH:
|
case UART_DLH:
|
uart->regs.dlh = value;
|
uart->regs.dlh = value;
|
return;
|
return;
|
}
|
}
|
Line 138... |
Line 142... |
break;
|
break;
|
case UART_SCR:
|
case UART_SCR:
|
uart->regs.scr = value;
|
uart->regs.scr = value;
|
break;
|
break;
|
default:
|
default:
|
debug(1, "write out of range (addr %x)\n", addr);
|
TRACE("write out of range (addr %x)\n", addr);
|
}
|
}
|
}
|
}
|
|
|
/* Read a specific UART register. */
|
/* Read a specific UART register. */
|
uint32_t uart_read_byte(oraddr_t addr, void *dat)
|
uint32_t uart_read_byte(oraddr_t addr, void *dat)
|
{
|
{
|
struct dev_16450 *uart = dat;
|
struct dev_16450 *uart = dat;
|
uint8_t value = 0;
|
uint8_t value = 0;
|
|
|
debug(4, "uart_read_byte(%"PRIxADDR")", addr);
|
TRACE("uart_read_byte(%"PRIxADDR")", addr);
|
|
|
if (uart->regs.lcr & UART_LCR_DLAB) {
|
if (uart->regs.lcr & UART_LCR_DLAB) {
|
switch (addr % UART_ADDR_SPACE) {
|
switch (addr % UART_ADDR_SPACE) {
|
case UART_DLL:
|
case UART_DLL:
|
value = uart->regs.dll;
|
value = uart->regs.dll;
|
debug(4, "= %"PRIx8"\n", value);
|
TRACE("= %"PRIx8"\n", value);
|
return value;
|
return value;
|
case UART_DLH:
|
case UART_DLH:
|
value = uart->regs.dlh;
|
value = uart->regs.dlh;
|
debug(4, "= %"PRIx8"\n", value);
|
TRACE("= %"PRIx8"\n", value);
|
return value;
|
return value;
|
}
|
}
|
}
|
}
|
|
|
switch (addr % UART_ADDR_SPACE) {
|
switch (addr % UART_ADDR_SPACE) {
|
case UART_RXBUF:
|
case UART_RXBUF:
|
{ /* Print out FIFO for debugging */
|
{ /* Print out FIFO for debugging */
|
int i;
|
int i;
|
debug(4, "(%i/%i,%i,%i:", uart->istat.rxbuf_full, uart->fifo_len,
|
TRACE("(%i/%i, %i, %i:", uart->istat.rxbuf_full, uart->fifo_len,
|
uart->istat.rxbuf_head, uart->istat.rxbuf_tail);
|
uart->istat.rxbuf_head, uart->istat.rxbuf_tail);
|
for (i = 0; i < uart->istat.rxbuf_full; i++)
|
for (i = 0; i < uart->istat.rxbuf_full; i++)
|
debug(4, "%02x ", uart->regs.rxbuf[(uart->istat.rxbuf_tail + i) % uart->fifo_len]);
|
TRACE("%02x ", uart->regs.rxbuf[(uart->istat.rxbuf_tail + i) % uart->fifo_len]);
|
debug(4, ")");
|
TRACE(")");
|
}
|
}
|
if (uart->istat.rxbuf_full) {
|
if (uart->istat.rxbuf_full) {
|
value = uart->regs.rxbuf[uart->istat.rxbuf_tail];
|
value = uart->regs.rxbuf[uart->istat.rxbuf_tail];
|
uart->istat.rxbuf_tail = (uart->istat.rxbuf_tail + 1) % uart->fifo_len;
|
uart->istat.rxbuf_tail = (uart->istat.rxbuf_tail + 1) % uart->fifo_len;
|
uart->istat.rxbuf_full--;
|
uart->istat.rxbuf_full--;
|
Line 214... |
Line 218... |
break;
|
break;
|
case UART_SCR:
|
case UART_SCR:
|
value = uart->regs.scr;
|
value = uart->regs.scr;
|
break;
|
break;
|
default:
|
default:
|
debug(1, "read out of range (addr %"PRIxADDR")\n", addr);
|
TRACE("read out of range (addr %"PRIxADDR")\n", addr);
|
}
|
}
|
debug(4, " = %"PRIx8"\n", value);
|
TRACE(" = %"PRIx8"\n", value);
|
return value;
|
return value;
|
}
|
}
|
|
|
/* Function that handles incoming VAPI data. */
|
/* Function that handles incoming VAPI data. */
|
void uart_vapi_read (unsigned long id, unsigned long data, void *dat)
|
void uart_vapi_read (unsigned long id, unsigned long data, void *dat)
|
{
|
{
|
struct dev_16450 *uart = dat;
|
struct dev_16450 *uart = dat;
|
debug(4, "UART: id %08lx, data %08lx\n", id, data);
|
TRACE("UART: id %08lx, data %08lx\n", id, data);
|
uart->vapi_buf[uart->vapi_buf_head_ptr] = data;
|
uart->vapi_buf[uart->vapi_buf_head_ptr] = data;
|
uart->vapi_buf_head_ptr = (uart->vapi_buf_head_ptr + 1) % UART_VAPI_BUF_LEN;
|
uart->vapi_buf_head_ptr = (uart->vapi_buf_head_ptr + 1) % UART_VAPI_BUF_LEN;
|
if (uart->vapi_buf_tail_ptr == uart->vapi_buf_head_ptr) {
|
if (uart->vapi_buf_tail_ptr == uart->vapi_buf_head_ptr) {
|
fprintf (stderr, "FATAL: uart VAPI buffer to small.\n");
|
fprintf (stderr, "FATAL: uart VAPI buffer to small.\n");
|
exit (1);
|
exit (1);
|
Line 236... |
Line 240... |
}
|
}
|
|
|
static void send_char (struct dev_16450 *uart, int bits_send)
|
static void send_char (struct dev_16450 *uart, int bits_send)
|
{
|
{
|
PRINTF ("%c", (char)uart->iregs.txser);
|
PRINTF ("%c", (char)uart->iregs.txser);
|
debug(4, "TX \'%c\' via UART at %"PRIxADDR"...\n", (char)uart->iregs.txser,
|
TRACE("TX \'%c\' via UART at %"PRIxADDR"...\n", (char)uart->iregs.txser,
|
uart->baseaddr);
|
uart->baseaddr);
|
if (uart->regs.mcr & UART_MCR_LOOP)
|
if (uart->regs.mcr & UART_MCR_LOOP)
|
uart->iregs.loopback = uart->iregs.txser;
|
uart->iregs.loopback = uart->iregs.txser;
|
else {
|
else {
|
/* Send to either VAPI or to file */
|
/* Send to either VAPI or to file */
|
Line 295... |
Line 299... |
|
|
fe = ((packet >> (nbits++)) & 1) ^ 1;
|
fe = ((packet >> (nbits++)) & 1) ^ 1;
|
if (uart->vapi.lcr & UART_LCR_STOP)
|
if (uart->vapi.lcr & UART_LCR_STOP)
|
fe |= ((packet >> (nbits++)) & 1) ^ 1;
|
fe |= ((packet >> (nbits++)) & 1) ^ 1;
|
|
|
debug (4, "lcr vapi %02x, uart %02x\n", uart->vapi.lcr, uart->regs.lcr);
|
TRACE ("lcr vapi %02x, uart %02x\n", uart->vapi.lcr, uart->regs.lcr);
|
data |= (uart->vapi.lcr << 8) | (pe << 16) | (fe << 17) | (uart->vapi.lcr << 8);
|
data |= (uart->vapi.lcr << 8) | (pe << 16) | (fe << 17) | (uart->vapi.lcr << 8);
|
PRINTF ("vapi_send (%08lx, %08x)\n", uart->vapi_id, data);
|
PRINTF ("vapi_send (%08lx, %08x)\n", uart->vapi_id, data);
|
debug (4, "vapi_send (%08lx, %08x)\n", uart->vapi_id, data);
|
TRACE ("vapi_send (%08lx, %08x)\n", uart->vapi_id, data);
|
vapi_send (uart->vapi_id, data);
|
vapi_send (uart->vapi_id, data);
|
} else {
|
} else {
|
char buffer[1] = { uart->iregs.txser & 0xFF };
|
char buffer[1] = { uart->iregs.txser & 0xFF };
|
channel_write(uart->channel, buffer, 1);
|
channel_write(uart->channel, buffer, 1);
|
}
|
}
|
Line 316... |
Line 320... |
void uart_add_char (struct dev_16450 *uart, int ch)
|
void uart_add_char (struct dev_16450 *uart, int ch)
|
{
|
{
|
if (uart->istat.rxbuf_full + 1 > uart->fifo_len)
|
if (uart->istat.rxbuf_full + 1 > uart->fifo_len)
|
uart->regs.lsr |= UART_LSR_OVRRUN | UART_LSR_RXERR;
|
uart->regs.lsr |= UART_LSR_OVRRUN | UART_LSR_RXERR;
|
else {
|
else {
|
debug(4, "add %02x\n", ch);
|
TRACE("add %02x\n", ch);
|
uart->regs.rxbuf[uart->istat.rxbuf_head] = ch;
|
uart->regs.rxbuf[uart->istat.rxbuf_head] = ch;
|
uart->istat.rxbuf_head = (uart->istat.rxbuf_head + 1) % uart->fifo_len;
|
uart->istat.rxbuf_head = (uart->istat.rxbuf_head + 1) % uart->fifo_len;
|
uart->istat.rxbuf_full++;
|
uart->istat.rxbuf_full++;
|
}
|
}
|
uart->regs.lsr |= UART_LSR_RDRDY;
|
uart->regs.lsr |= UART_LSR_RDRDY;
|
Line 335... |
Line 339... |
int retval;
|
int retval;
|
|
|
/* Schedule for later */
|
/* Schedule for later */
|
SCHED_ADD (uart_clock16, dat, UART_CLOCK_DIVIDER);
|
SCHED_ADD (uart_clock16, dat, UART_CLOCK_DIVIDER);
|
|
|
|
TRACE("Running uart clock:\n");
|
|
|
/* If VAPI is not selected, UART communicates with two file streams;
|
/* If VAPI is not selected, UART communicates with two file streams;
|
if VAPI is selected, we use VAPI streams. */
|
if VAPI is selected, we use VAPI streams. */
|
/* if txfs is corrupted, skip this uart. */
|
/* if txfs is corrupted, skip this uart. */
|
if (!uart->vapi_id && !channel_ok(uart->channel)) return;
|
if (!uart->vapi_id && !channel_ok(uart->channel)) return;
|
|
|
|
TRACE("\tChannel stream or VAPI checks out ok\n");
|
|
|
if (uart->vapi.next_break_cnt >= 0)
|
if (uart->vapi.next_break_cnt >= 0)
|
if (--uart->vapi.next_break_cnt < 0) {
|
if (--uart->vapi.next_break_cnt < 0) {
|
if (!(uart->vapi.cur_break = uart->vapi.next_break))
|
if (!(uart->vapi.cur_break = uart->vapi.next_break))
|
uart->istat.break_set = 0;
|
uart->istat.break_set = 0;
|
}
|
}
|
|
|
/***************** Transmit *****************/
|
/***************** Transmit *****************/
|
|
TRACE("\tuart->istat.txser_full = %i\n", uart->istat.txser_full);
|
|
TRACE("\tuart->istat.txbuf_full = %i\n", uart->istat.txser_full);
|
|
TRACE("\tuart->char_clks = %li\n", uart->char_clks);
|
if (!uart->istat.txser_full) {
|
if (!uart->istat.txser_full) {
|
// uart->regs.lsr |= UART_LSR_TXBUFE;
|
// uart->regs.lsr |= UART_LSR_TXBUFE;
|
if (uart->istat.txbuf_full) {
|
if (uart->istat.txbuf_full) {
|
uart->iregs.txser = uart->regs.txbuf[uart->istat.txbuf_tail];
|
uart->iregs.txser = uart->regs.txbuf[uart->istat.txbuf_tail];
|
uart->istat.txbuf_tail = (uart->istat.txbuf_tail + 1) % uart->fifo_len;
|
uart->istat.txbuf_tail = (uart->istat.txbuf_tail + 1) % uart->fifo_len;
|
Line 416... |
Line 427... |
} else {
|
} else {
|
if (uart->istat.rxser_full) {
|
if (uart->istat.rxser_full) {
|
if (uart->char_clks <= uart->istat.rxser_clks++) {
|
if (uart->char_clks <= uart->istat.rxser_clks++) {
|
/* Set unused character bits to zero and allow lsr register in fifo */
|
/* Set unused character bits to zero and allow lsr register in fifo */
|
uart->iregs.rxser &= ((1 << ((uart->regs.lcr & 3) + 5)) - 1) | 0xff00;
|
uart->iregs.rxser &= ((1 << ((uart->regs.lcr & 3) + 5)) - 1) | 0xff00;
|
debug(4, "Receiving 0x%02lx'%c' via UART (at %"PRIxADDR"...\n",
|
TRACE("\tReceiving 0x%02lx'%c' via UART (at %"PRIxADDR"...\n",
|
uart->iregs.rxser, (char)uart->iregs.rxser, uart->baseaddr);
|
uart->iregs.rxser, (char)uart->iregs.rxser, uart->baseaddr);
|
PRINTF ("%c", (char)uart->iregs.rxser);
|
PRINTF ("%c", (char)uart->iregs.rxser);
|
uart->istat.rxser_full = 0;
|
uart->istat.rxser_full = 0;
|
uart->istat.rxser_clks = 0;
|
uart->istat.rxser_clks = 0;
|
uart_add_char (uart, uart->iregs.rxser);
|
uart_add_char (uart, uart->iregs.rxser);
|
Line 454... |
Line 465... |
/* do not handle commands while receiving */
|
/* do not handle commands while receiving */
|
if (uart->istat.rxser_full) return;
|
if (uart->istat.rxser_full) return;
|
while (!received) {
|
while (!received) {
|
if (uart->vapi_buf_head_ptr != uart->vapi_buf_tail_ptr) {
|
if (uart->vapi_buf_head_ptr != uart->vapi_buf_tail_ptr) {
|
unsigned long data = uart->vapi_buf[uart->vapi_buf_tail_ptr];
|
unsigned long data = uart->vapi_buf[uart->vapi_buf_tail_ptr];
|
debug(4, "Handling: %08lx (%i,%i)\n", data, uart->vapi_buf_head_ptr,
|
TRACE("\tHandling: %08lx (%i,%i)\n", data, uart->vapi_buf_head_ptr,
|
uart->vapi_buf_tail_ptr);
|
uart->vapi_buf_tail_ptr);
|
uart->vapi_buf_tail_ptr = (uart->vapi_buf_tail_ptr + 1) % UART_VAPI_BUF_LEN;
|
uart->vapi_buf_tail_ptr = (uart->vapi_buf_tail_ptr + 1) % UART_VAPI_BUF_LEN;
|
switch (data >> 24) {
|
switch (data >> 24) {
|
case 0x00:
|
case 0x00:
|
uart->vapi.lcr = (data >> 8) & 0xff;
|
uart->vapi.lcr = (data >> 8) & 0xff;
|
Line 466... |
Line 477... |
uart->iregs.rxser = data & 0xff;
|
uart->iregs.rxser = data & 0xff;
|
uart->vapi.char_clks = char_clks (uart->vapi.dll, uart->vapi.dlh, uart->vapi.lcr);
|
uart->vapi.char_clks = char_clks (uart->vapi.dll, uart->vapi.dlh, uart->vapi.lcr);
|
if ((uart->vapi.lcr & ~UART_LCR_SBC) != (uart->regs.lcr & ~UART_LCR_SBC)
|
if ((uart->vapi.lcr & ~UART_LCR_SBC) != (uart->regs.lcr & ~UART_LCR_SBC)
|
|| uart->vapi.char_clks != uart->char_clks
|
|| uart->vapi.char_clks != uart->char_clks
|
|| uart->vapi.skew < -MAX_SKEW || uart->vapi.skew > MAX_SKEW) {
|
|| uart->vapi.skew < -MAX_SKEW || uart->vapi.skew > MAX_SKEW) {
|
debug (3, "WARNING: unmatched VAPI (%02x) and uart (%02x) modes.\n",
|
WARN("WARNING: unmatched VAPI (%02x) and uart (%02x) modes.\n",
|
uart->vapi.lcr & ~UART_LCR_SBC, uart->regs.lcr & ~UART_LCR_SBC);
|
uart->vapi.lcr & ~UART_LCR_SBC, uart->regs.lcr & ~UART_LCR_SBC);
|
/* Set error bits */
|
/* Set error bits */
|
uart->iregs.rxser |= (UART_LSR_FRAME | UART_LSR_RXERR) << 8;
|
uart->iregs.rxser |= (UART_LSR_FRAME | UART_LSR_RXERR) << 8;
|
if (uart->regs.lcr & UART_LCR_PARITY) uart->iregs.rxser |= UART_LSR_PARITY << 8;
|
if (uart->regs.lcr & UART_LCR_PARITY) uart->iregs.rxser |= UART_LSR_PARITY << 8;
|
}
|
}
|
Line 490... |
Line 501... |
case 0x04:
|
case 0x04:
|
uart->vapi.next_break_cnt = data & 0xffff;
|
uart->vapi.next_break_cnt = data & 0xffff;
|
uart->vapi.next_break = (data >> 16) & 1;
|
uart->vapi.next_break = (data >> 16) & 1;
|
break;
|
break;
|
default:
|
default:
|
debug (0, "WARNING: Invalid vapi command %02lx\n", data >> 24);
|
WARN ("WARNING: Invalid vapi command %02lx\n", data >> 24);
|
break;
|
break;
|
}
|
}
|
} else break;
|
} else break;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
/***************** Loopback *****************/
|
/***************** Loopback *****************/
|
if (uart->regs.mcr & UART_MCR_LOOP) {
|
if (uart->regs.mcr & UART_MCR_LOOP) {
|
debug(5, "uart_clock: Loopback\n");
|
TRACE("uart_clock: Loopback\n");
|
if ((uart->regs.mcr & UART_MCR_AUX2) !=
|
if ((uart->regs.mcr & UART_MCR_AUX2) !=
|
((uart->regs.msr & UART_MSR_DCD) >> 4))
|
((uart->regs.msr & UART_MSR_DCD) >> 4))
|
uart->regs.msr |= UART_MSR_DDCD;
|
uart->regs.msr |= UART_MSR_DDCD;
|
if ((uart->regs.mcr & UART_MCR_AUX1) <
|
if ((uart->regs.mcr & UART_MCR_AUX1) <
|
((uart->regs.msr & UART_MSR_RI) >> 4))
|
((uart->regs.msr & UART_MSR_RI) >> 4))
|
Line 554... |
Line 565... |
uart->regs.msr & (UART_MSR_DCTS | UART_MSR_DDSR
|
uart->regs.msr & (UART_MSR_DCTS | UART_MSR_DDSR
|
| UART_MSR_TERI | UART_MSR_DDCD)) {
|
| UART_MSR_TERI | UART_MSR_DDCD)) {
|
uart->regs.iir = UART_IIR_MSI;
|
uart->regs.iir = UART_IIR_MSI;
|
}
|
}
|
if (!(uart->regs.iir & UART_IIR_NO_INT)) {
|
if (!(uart->regs.iir & UART_IIR_NO_INT)) {
|
debug (4, "uart->regs.iir = %i\t", uart->regs.iir);
|
TRACE("\tuart->regs.iir = %i\t", uart->regs.iir);
|
report_interrupt(uart->irq);
|
report_interrupt(uart->irq);
|
}
|
}
|
}
|
}
|
|
|
/* Reset. It initializes all registers of all UART devices to zero values,
|
/* Reset. It initializes all registers of all UART devices to zero values,
|
Line 572... |
Line 583... |
if(uart->channel)
|
if(uart->channel)
|
channel_close(uart->channel);
|
channel_close(uart->channel);
|
else
|
else
|
uart->channel = channel_init(uart->channel_str);
|
uart->channel = channel_init(uart->channel_str);
|
if(channel_open(uart->channel) < 0) {
|
if(channel_open(uart->channel) < 0) {
|
debug (0, "WARNING: UART has problems with channel \"%s\".\n", uart->channel_str);
|
WARN ("WARNING: UART has problems with channel \"%s\".\n", uart->channel_str);
|
} else if (config.sim.verbose)
|
} else if (config.sim.verbose)
|
PRINTF("UART at 0x%"PRIxADDR" uses ", uart->baseaddr);
|
PRINTF("UART at 0x%"PRIxADDR" uses ", uart->baseaddr);
|
} else {
|
} else {
|
debug (0, "WARNING: UART at %"PRIxADDR" has no vapi nor channel specified\n", uart->baseaddr);
|
WARN ("WARNING: UART at %"PRIxADDR" has no vapi nor channel specified\n", uart->baseaddr);
|
}
|
}
|
|
|
if (uart->uart16550)
|
if (uart->uart16550)
|
uart->fifo_len = 16;
|
uart->fifo_len = 16;
|
else
|
else
|