mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-11-16 12:34:45 +00:00
Compare commits
124 Commits
18b2ce8e81
...
5.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05461aa475 | ||
|
|
cab00c7035 | ||
|
|
c5b794227b | ||
|
|
b9de5b3bd6 | ||
|
|
fc7584d719 | ||
|
|
8d54187a19 | ||
|
|
5d73509a34 | ||
|
|
be5d2bc03d | ||
|
|
fc89cc7680 | ||
|
|
fc21b923ba | ||
|
|
f7a204e3d7 | ||
|
|
f71c620f7e | ||
|
|
9942ff80c4 | ||
|
|
779847a5ef | ||
|
|
d9c0dd3c32 | ||
|
|
ff3f3490df | ||
|
|
18bbfc729e | ||
|
|
5382f617ff | ||
|
|
780b468845 | ||
|
|
1c378f1a98 | ||
|
|
68a3658d44 | ||
|
|
1640657022 | ||
|
|
4f130929b8 | ||
|
|
e27dc9d6ac | ||
|
|
f03147f172 | ||
|
|
fc06357840 | ||
|
|
1ca98b274b | ||
|
|
2cf37001fc | ||
|
|
c3fc52ec06 | ||
|
|
512e0b59af | ||
|
|
62c428f241 | ||
|
|
eb909371c7 | ||
|
|
166a80c3d8 | ||
|
|
265c2e620b | ||
|
|
bc9c0e00cc | ||
|
|
402dafa495 | ||
|
|
a9ce44bf8f | ||
|
|
975ecc1702 | ||
|
|
f43beb03c2 | ||
|
|
c54b13b072 | ||
|
|
f77b692e5c | ||
|
|
7d3712fb26 | ||
|
|
73b77be719 | ||
|
|
d5649e25f3 | ||
|
|
c8a1060988 | ||
|
|
99698fb5a2 | ||
|
|
cfef84a007 | ||
|
|
e9712e7890 | ||
|
|
ff94ddcd84 | ||
|
|
e5a1b15848 | ||
|
|
4925ab4f52 | ||
|
|
8d4382ba34 | ||
|
|
50a835393a | ||
|
|
06427c8df4 | ||
|
|
d697769d46 | ||
|
|
bc806d41a5 | ||
|
|
a274b6fdcb | ||
|
|
ec2660548e | ||
|
|
ce2b276803 | ||
|
|
14e74e4312 | ||
|
|
c86d513664 | ||
|
|
08f807e64a | ||
|
|
3a66586c9e | ||
|
|
645dbc5fcc | ||
|
|
2f323700b9 | ||
|
|
2497a46a76 | ||
|
|
3074eb0f37 | ||
|
|
291267113b | ||
|
|
8cfaa0eb76 | ||
|
|
b0eb952427 | ||
|
|
1161e1fb92 | ||
|
|
d9d96f0608 | ||
|
|
cb8379dc09 | ||
|
|
81e4a15b18 | ||
|
|
0ed294b6cc | ||
|
|
c13205f691 | ||
|
|
23cc5a6090 | ||
|
|
e180f281ab | ||
|
|
c41e7bae9c | ||
|
|
e1062fae3c | ||
|
|
7db032cf02 | ||
|
|
78b45cc561 | ||
|
|
da7cb87b4d | ||
|
|
0ab993b04a | ||
|
|
84fb340ac4 | ||
|
|
8004ffb649 | ||
|
|
14fcf38891 | ||
|
|
1223f5e402 | ||
|
|
a97a4732f7 | ||
|
|
980cdb82a7 | ||
|
|
f4d00aa538 | ||
|
|
d1bab986ca | ||
|
|
3824960f24 | ||
|
|
2f56b7375a | ||
|
|
388bd8054c | ||
|
|
6d9843e189 | ||
|
|
ef1ac8afff | ||
|
|
cc2a237129 | ||
|
|
5861e42567 | ||
|
|
5ae7ec9477 | ||
|
|
0d44334ca1 | ||
|
|
2a8f755107 | ||
|
|
21ed8d11c5 | ||
|
|
dedc3e1d49 | ||
|
|
1dbdf94e67 | ||
|
|
0af682cf5d | ||
|
|
f84c4a5b81 | ||
|
|
7021c01464 | ||
|
|
e71e271ce1 | ||
|
|
3d7da43562 | ||
|
|
40f23ceae6 | ||
|
|
fdbe9b7599 | ||
|
|
18549295be | ||
|
|
b11745148d | ||
|
|
61ccb9c05d | ||
|
|
7661402bc2 | ||
|
|
5284e812e2 | ||
|
|
e95c00a79e | ||
|
|
95036a4591 | ||
|
|
534f9dbe13 | ||
|
|
4a2ac5ef8d | ||
|
|
5eb0773159 | ||
|
|
849d741832 | ||
|
|
a1f9265c03 |
@@ -16,6 +16,7 @@
|
||||
#include <bsp/irq.h>
|
||||
#include <bsp/fatal.h>
|
||||
#include <rtems/console.h>
|
||||
#include <rtems/seterr.h>
|
||||
|
||||
#include <rtems/termiostypes.h>
|
||||
|
||||
@@ -23,230 +24,12 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#define UART_RX_DMA_BUF_SIZE 32l
|
||||
|
||||
typedef struct {
|
||||
rtems_termios_device_context base;
|
||||
Usart *regs;
|
||||
rtems_vector_number irq;
|
||||
uint32_t id;
|
||||
bool console;
|
||||
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
|
||||
bool transmitting;
|
||||
#endif
|
||||
} atsam_usart_context;
|
||||
|
||||
static atsam_usart_context atsam_usart_instances[] = {
|
||||
{
|
||||
.regs = USART0,
|
||||
.irq = USART0_IRQn,
|
||||
.id = ID_USART0
|
||||
}
|
||||
#ifdef USART1
|
||||
, {
|
||||
.regs = USART1,
|
||||
.irq = USART1_IRQn,
|
||||
.id = ID_USART1
|
||||
}
|
||||
#endif
|
||||
#ifdef USART2
|
||||
, {
|
||||
.regs = USART2,
|
||||
.irq = USART2_IRQn,
|
||||
.id = ID_USART2
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
|
||||
static void atsam_usart_interrupt(void *arg)
|
||||
{
|
||||
rtems_termios_tty *tty = arg;
|
||||
atsam_usart_context *ctx = rtems_termios_get_device_context(tty);
|
||||
Usart *regs = ctx->regs;
|
||||
uint32_t csr = regs->US_CSR;
|
||||
|
||||
while ((csr & US_CSR_RXRDY) != 0) {
|
||||
char c = (char) regs->US_RHR;
|
||||
|
||||
rtems_termios_enqueue_raw_characters(tty, &c, 1);
|
||||
|
||||
csr = regs->US_CSR;
|
||||
}
|
||||
|
||||
if (ctx->transmitting && (csr & US_CSR_TXEMPTY) != 0) {
|
||||
rtems_termios_dequeue_characters(tty, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool atsam_usart_set_attributes(
|
||||
rtems_termios_device_context *base,
|
||||
const struct termios *term
|
||||
)
|
||||
{
|
||||
atsam_usart_context *ctx = (atsam_usart_context *) base;
|
||||
Usart *regs = ctx->regs;
|
||||
rtems_termios_baud_t baud;
|
||||
uint32_t mr;
|
||||
|
||||
baud = rtems_termios_baud_to_number(term->c_ospeed);
|
||||
regs->US_BRGR = (BOARD_MCK / baud) / 16;
|
||||
|
||||
if ((term->c_cflag & CREAD) != 0) {
|
||||
regs->US_CR = US_CR_RXEN | US_CR_TXEN;
|
||||
} else {
|
||||
regs->US_CR = US_CR_TXEN;
|
||||
}
|
||||
|
||||
mr = US_MR_USART_MODE_NORMAL | US_MR_USCLKS_MCK;
|
||||
|
||||
switch (term->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
mr |= US_MR_CHRL_5_BIT;
|
||||
break;
|
||||
case CS6:
|
||||
mr |= US_MR_CHRL_6_BIT;
|
||||
break;
|
||||
case CS7:
|
||||
mr |= US_MR_CHRL_7_BIT;
|
||||
break;
|
||||
default:
|
||||
mr |= US_MR_CHRL_8_BIT;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((term->c_cflag & PARENB) != 0) {
|
||||
if ((term->c_cflag & PARODD) != 0) {
|
||||
mr |= US_MR_PAR_ODD;
|
||||
} else {
|
||||
mr |= US_MR_PAR_EVEN;
|
||||
}
|
||||
} else {
|
||||
mr |= US_MR_PAR_NO;
|
||||
}
|
||||
|
||||
if ((term->c_cflag & CSTOPB) != 0) {
|
||||
mr |= US_MR_NBSTOP_2_BIT;
|
||||
} else {
|
||||
mr |= US_MR_NBSTOP_1_BIT;
|
||||
}
|
||||
|
||||
regs->US_MR = mr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool atsam_usart_first_open(
|
||||
rtems_termios_tty *tty,
|
||||
rtems_termios_device_context *base,
|
||||
struct termios *term,
|
||||
rtems_libio_open_close_args_t *args
|
||||
)
|
||||
{
|
||||
atsam_usart_context *ctx = (atsam_usart_context *) base;
|
||||
Usart *regs = ctx->regs;
|
||||
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
|
||||
rtems_status_code sc;
|
||||
#endif
|
||||
|
||||
regs->US_CR = US_CR_RSTRX | US_CR_RSTTX | US_CR_RSTSTA;
|
||||
regs->US_IDR = 0xffffffff;
|
||||
|
||||
PMC_EnablePeripheral(ctx->id);
|
||||
|
||||
rtems_termios_set_initial_baud(tty, ATSAM_CONSOLE_BAUD);
|
||||
atsam_usart_set_attributes(base, term);
|
||||
|
||||
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
|
||||
regs->US_IER = US_IDR_RXRDY;
|
||||
sc = rtems_interrupt_handler_install(
|
||||
ctx->irq,
|
||||
"USART",
|
||||
RTEMS_INTERRUPT_SHARED,
|
||||
atsam_usart_interrupt,
|
||||
tty
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void atsam_usart_last_close(
|
||||
rtems_termios_tty *tty,
|
||||
rtems_termios_device_context *base,
|
||||
rtems_libio_open_close_args_t *args
|
||||
)
|
||||
{
|
||||
atsam_usart_context *ctx = (atsam_usart_context *) base;
|
||||
|
||||
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
|
||||
rtems_interrupt_handler_remove(ctx->irq, atsam_usart_interrupt, tty);
|
||||
#endif
|
||||
|
||||
if (!ctx->console) {
|
||||
PMC_DisablePeripheral(ctx->id);
|
||||
}
|
||||
}
|
||||
|
||||
static void atsam_usart_write(
|
||||
rtems_termios_device_context *base,
|
||||
const char *buf,
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
atsam_usart_context *ctx = (atsam_usart_context *) base;
|
||||
Usart *regs = ctx->regs;
|
||||
|
||||
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
|
||||
if (len > 0) {
|
||||
ctx->transmitting = true;
|
||||
regs->US_THR = buf[0];
|
||||
regs->US_IER = US_IDR_TXEMPTY;
|
||||
} else {
|
||||
ctx->transmitting = false;
|
||||
regs->US_IDR = US_IDR_TXEMPTY;
|
||||
}
|
||||
#else
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
while ((regs->US_CSR & US_CSR_TXEMPTY) == 0) {
|
||||
/* Wait */
|
||||
}
|
||||
|
||||
regs->US_THR = buf[i];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef ATSAM_CONSOLE_USE_INTERRUPTS
|
||||
static int atsam_usart_read(rtems_termios_device_context *base)
|
||||
{
|
||||
atsam_usart_context *ctx = (atsam_usart_context *) base;
|
||||
Usart *regs = ctx->regs;
|
||||
|
||||
if ((regs->US_CSR & US_CSR_RXRDY) != 0) {
|
||||
return (char) regs->US_RHR;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static const rtems_termios_device_handler atsam_usart_handler = {
|
||||
.first_open = atsam_usart_first_open,
|
||||
.last_close = atsam_usart_last_close,
|
||||
.write = atsam_usart_write,
|
||||
.set_attributes = atsam_usart_set_attributes,
|
||||
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
|
||||
.mode = TERMIOS_IRQ_DRIVEN
|
||||
#else
|
||||
.poll_read = atsam_usart_read,
|
||||
.mode = TERMIOS_POLLED
|
||||
#endif
|
||||
};
|
||||
char buf[UART_RX_DMA_BUF_SIZE];
|
||||
LinkedListDescriporView3 desc;
|
||||
} atsam_uart_rx_dma;
|
||||
|
||||
typedef struct {
|
||||
rtems_termios_device_context base;
|
||||
@@ -254,43 +37,79 @@ typedef struct {
|
||||
rtems_vector_number irq;
|
||||
uint32_t id;
|
||||
bool console;
|
||||
bool is_usart;
|
||||
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
|
||||
bool transmitting;
|
||||
bool rx_dma_enabled;
|
||||
uint32_t rx_dma_channel;
|
||||
atsam_uart_rx_dma *rx_dma;
|
||||
char *volatile*rx_dma_da;
|
||||
char *rx_next_read_pos;
|
||||
#endif
|
||||
} atsam_uart_context;
|
||||
|
||||
static atsam_uart_context atsam_usart_instances[] = {
|
||||
{
|
||||
.regs = (Uart *)USART0,
|
||||
.irq = USART0_IRQn,
|
||||
.id = ID_USART0,
|
||||
.is_usart = true,
|
||||
}
|
||||
#ifdef USART1
|
||||
, {
|
||||
.regs = (Uart *)USART1,
|
||||
.irq = USART1_IRQn,
|
||||
.id = ID_USART1,
|
||||
.is_usart = true,
|
||||
}
|
||||
#endif
|
||||
#ifdef USART2
|
||||
, {
|
||||
.regs = (Uart *)USART2,
|
||||
.irq = USART2_IRQn,
|
||||
.id = ID_USART2,
|
||||
.is_usart = true,
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
static atsam_uart_context atsam_uart_instances[] = {
|
||||
{
|
||||
.regs = UART0,
|
||||
.irq = UART0_IRQn,
|
||||
.id = ID_UART0
|
||||
.id = ID_UART0,
|
||||
.is_usart = false,
|
||||
}
|
||||
#ifdef UART1
|
||||
, {
|
||||
.regs = UART1,
|
||||
.irq = UART1_IRQn,
|
||||
.id = ID_UART1
|
||||
.id = ID_UART1,
|
||||
.is_usart = false,
|
||||
}
|
||||
#endif
|
||||
#ifdef UART2
|
||||
, {
|
||||
.regs = UART2,
|
||||
.irq = UART2_IRQn,
|
||||
.id = ID_UART2
|
||||
.id = ID_UART2,
|
||||
.is_usart = false,
|
||||
}
|
||||
#endif
|
||||
#ifdef UART3
|
||||
, {
|
||||
.regs = UART3,
|
||||
.irq = UART3_IRQn,
|
||||
.id = ID_UART3
|
||||
.id = ID_UART3,
|
||||
.is_usart = false,
|
||||
}
|
||||
#endif
|
||||
#ifdef UART4
|
||||
, {
|
||||
.regs = UART4,
|
||||
.irq = UART4_IRQn,
|
||||
.id = ID_UART4
|
||||
.id = ID_UART4,
|
||||
.is_usart = false,
|
||||
}
|
||||
#endif
|
||||
};
|
||||
@@ -303,16 +122,32 @@ static void atsam_uart_interrupt(void *arg)
|
||||
Uart *regs = ctx->regs;
|
||||
uint32_t sr = regs->UART_SR;
|
||||
|
||||
while ((sr & UART_SR_RXRDY) != 0) {
|
||||
char c = (char) regs->UART_RHR;
|
||||
if (!ctx->rx_dma_enabled) {
|
||||
while ((sr & UART_SR_RXRDY) != 0) {
|
||||
char c = (char) regs->UART_RHR;
|
||||
|
||||
rtems_termios_enqueue_raw_characters(tty, &c, 1);
|
||||
rtems_termios_enqueue_raw_characters(tty, &c, 1);
|
||||
|
||||
sr = regs->UART_SR;
|
||||
sr = regs->UART_SR;
|
||||
}
|
||||
} else {
|
||||
while (*ctx->rx_dma_da != ctx->rx_next_read_pos) {
|
||||
char c;
|
||||
|
||||
c = *ctx->rx_next_read_pos;
|
||||
|
||||
++ctx->rx_next_read_pos;
|
||||
if (ctx->rx_next_read_pos >= &ctx->rx_dma->buf[UART_RX_DMA_BUF_SIZE]) {
|
||||
ctx->rx_next_read_pos = &ctx->rx_dma->buf[0];
|
||||
}
|
||||
|
||||
rtems_termios_enqueue_raw_characters(tty, &c, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->transmitting && (sr & UART_SR_TXEMPTY) != 0) {
|
||||
while (ctx->transmitting && (sr & UART_SR_TXRDY) != 0) {
|
||||
rtems_termios_dequeue_characters(tty, 1);
|
||||
sr = regs->UART_SR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -336,10 +171,31 @@ static bool atsam_uart_set_attributes(
|
||||
regs->UART_CR = UART_CR_TXEN;
|
||||
}
|
||||
|
||||
mr = UART_MR_FILTER_DISABLED | UART_MR_BRSRCCK_PERIPH_CLK;
|
||||
if (ctx->is_usart) {
|
||||
mr = US_MR_USART_MODE_NORMAL | US_MR_USCLKS_MCK;
|
||||
} else {
|
||||
mr = UART_MR_FILTER_DISABLED | UART_MR_BRSRCCK_PERIPH_CLK;
|
||||
}
|
||||
|
||||
if ((term->c_cflag & CSIZE) != CS8) {
|
||||
return false;
|
||||
if (ctx->is_usart) {
|
||||
switch (term->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
mr |= US_MR_CHRL_5_BIT;
|
||||
break;
|
||||
case CS6:
|
||||
mr |= US_MR_CHRL_6_BIT;
|
||||
break;
|
||||
case CS7:
|
||||
mr |= US_MR_CHRL_7_BIT;
|
||||
break;
|
||||
default:
|
||||
mr |= US_MR_CHRL_8_BIT;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if ((term->c_cflag & CSIZE) != CS8) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((term->c_cflag & PARENB) != 0) {
|
||||
@@ -352,8 +208,16 @@ static bool atsam_uart_set_attributes(
|
||||
mr |= UART_MR_PAR_NO;
|
||||
}
|
||||
|
||||
if ((term->c_cflag & CSTOPB) != 0) {
|
||||
return false;
|
||||
if (ctx->is_usart) {
|
||||
if ((term->c_cflag & CSTOPB) != 0) {
|
||||
mr |= US_MR_NBSTOP_2_BIT;
|
||||
} else {
|
||||
mr |= US_MR_NBSTOP_1_BIT;
|
||||
}
|
||||
} else {
|
||||
if ((term->c_cflag & CSTOPB) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
regs->UART_MR = mr;
|
||||
@@ -361,6 +225,118 @@ static bool atsam_uart_set_attributes(
|
||||
return true;
|
||||
}
|
||||
|
||||
static void atsam_uart_disable_rx_dma(atsam_uart_context *ctx)
|
||||
{
|
||||
if (ctx->rx_dma) {
|
||||
rtems_cache_coherent_free(ctx->rx_dma);
|
||||
ctx->rx_dma = NULL;
|
||||
}
|
||||
|
||||
if (ctx->rx_dma_channel != XDMAD_ALLOC_FAILED) {
|
||||
XDMAD_FreeChannel(&XDMAD_Instance, ctx->rx_dma_channel);
|
||||
}
|
||||
|
||||
ctx->rx_dma_enabled = false;
|
||||
}
|
||||
|
||||
static rtems_status_code atsam_uart_enable_rx_dma(atsam_uart_context *ctx)
|
||||
{
|
||||
eXdmadRC rc;
|
||||
int channel_id;
|
||||
|
||||
if (ctx->rx_dma_enabled) {
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure everything is in a clean default state so that the cleanup works
|
||||
* in an error case.
|
||||
*/
|
||||
ctx->rx_dma = NULL;
|
||||
ctx->rx_dma_channel = XDMAD_ALLOC_FAILED;
|
||||
|
||||
ctx->rx_dma = rtems_cache_coherent_allocate(sizeof(*ctx->rx_dma), 0, 0);
|
||||
if (ctx->rx_dma == NULL) {
|
||||
atsam_uart_disable_rx_dma(ctx);
|
||||
return RTEMS_NO_MEMORY;
|
||||
}
|
||||
|
||||
ctx->rx_next_read_pos = &ctx->rx_dma->buf[0];
|
||||
|
||||
ctx->rx_dma_channel = XDMAD_AllocateChannel(
|
||||
&XDMAD_Instance,
|
||||
XDMAD_TRANSFER_MEMORY,
|
||||
ctx->id
|
||||
);
|
||||
|
||||
if (ctx->rx_dma_channel == XDMAD_ALLOC_FAILED) {
|
||||
atsam_uart_disable_rx_dma(ctx);
|
||||
return RTEMS_IO_ERROR;
|
||||
}
|
||||
|
||||
rc = XDMAD_PrepareChannel(&XDMAD_Instance, ctx->rx_dma_channel);
|
||||
if (rc != XDMAD_OK) {
|
||||
atsam_uart_disable_rx_dma(ctx);
|
||||
return RTEMS_IO_ERROR;
|
||||
}
|
||||
|
||||
channel_id = ctx->rx_dma_channel & 0xff;
|
||||
ctx->rx_dma_da =
|
||||
(char *volatile*) &XDMAD_Instance.pXdmacs->XDMAC_CHID[channel_id].XDMAC_CDA;
|
||||
|
||||
ctx->rx_dma->desc.mbr_nda = (uint32_t)&ctx->rx_dma->desc;
|
||||
ctx->rx_dma->desc.mbr_ubc =
|
||||
1 |
|
||||
XDMA_UBC_NVIEW_NDV3 |
|
||||
XDMA_UBC_NDE_FETCH_EN |
|
||||
XDMA_UBC_NDEN_UPDATED |
|
||||
XDMA_UBC_NSEN_UPDATED;
|
||||
ctx->rx_dma->desc.mbr_sa = (uint32_t) &ctx->regs->UART_RHR;
|
||||
ctx->rx_dma->desc.mbr_da = (uint32_t) &ctx->rx_dma->buf[0];
|
||||
ctx->rx_dma->desc.mbr_cfg =
|
||||
XDMAC_CC_TYPE_PER_TRAN |
|
||||
XDMAC_CC_MBSIZE_SINGLE |
|
||||
XDMAC_CC_DSYNC_PER2MEM |
|
||||
XDMAC_CC_SWREQ_HWR_CONNECTED |
|
||||
XDMAC_CC_MEMSET_NORMAL_MODE |
|
||||
XDMAC_CC_CSIZE_CHK_1 |
|
||||
XDMAC_CC_DWIDTH_BYTE |
|
||||
XDMAC_CC_SIF_AHB_IF1 |
|
||||
XDMAC_CC_DIF_AHB_IF1 |
|
||||
XDMAC_CC_SAM_FIXED_AM |
|
||||
XDMAC_CC_DAM_UBS_AM |
|
||||
XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(ctx->id, XDMAD_TRANSFER_RX));
|
||||
ctx->rx_dma->desc.mbr_bc = UART_RX_DMA_BUF_SIZE - 1;
|
||||
ctx->rx_dma->desc.mbr_ds = 0;
|
||||
ctx->rx_dma->desc.mbr_sus = 0;
|
||||
ctx->rx_dma->desc.mbr_dus = 0;
|
||||
|
||||
rc = XDMAD_ConfigureTransfer(
|
||||
&XDMAD_Instance,
|
||||
ctx->rx_dma_channel,
|
||||
NULL,
|
||||
XDMAC_CNDC_NDE_DSCR_FETCH_EN |
|
||||
XDMAC_CNDC_NDVIEW_NDV3 |
|
||||
XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED |
|
||||
XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED,
|
||||
(uint32_t)&ctx->rx_dma->desc,
|
||||
0);
|
||||
if (rc != XDMAD_OK) {
|
||||
atsam_uart_disable_rx_dma(ctx);
|
||||
return RTEMS_IO_ERROR;
|
||||
}
|
||||
|
||||
rc = XDMAD_StartTransfer(&XDMAD_Instance, ctx->rx_dma_channel);
|
||||
if (rc != XDMAD_OK) {
|
||||
atsam_uart_disable_rx_dma(ctx);
|
||||
return RTEMS_IO_ERROR;
|
||||
}
|
||||
|
||||
ctx->rx_dma_enabled = true;
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static bool atsam_uart_first_open(
|
||||
rtems_termios_tty *tty,
|
||||
rtems_termios_device_context *base,
|
||||
@@ -386,7 +362,7 @@ static bool atsam_uart_first_open(
|
||||
regs->UART_IER = UART_IDR_RXRDY;
|
||||
sc = rtems_interrupt_handler_install(
|
||||
ctx->irq,
|
||||
"UART",
|
||||
ctx->is_usart ? "USART" : "UART",
|
||||
RTEMS_INTERRUPT_SHARED,
|
||||
atsam_uart_interrupt,
|
||||
tty
|
||||
@@ -411,6 +387,10 @@ static void atsam_uart_last_close(
|
||||
rtems_interrupt_handler_remove(ctx->irq, atsam_uart_interrupt, tty);
|
||||
#endif
|
||||
|
||||
if (ctx->rx_dma_enabled) {
|
||||
atsam_uart_disable_rx_dma(ctx);
|
||||
}
|
||||
|
||||
if (!ctx->console) {
|
||||
PMC_DisablePeripheral(ctx->id);
|
||||
}
|
||||
@@ -429,16 +409,16 @@ static void atsam_uart_write(
|
||||
if (len > 0) {
|
||||
ctx->transmitting = true;
|
||||
regs->UART_THR = buf[0];
|
||||
regs->UART_IER = UART_IDR_TXEMPTY;
|
||||
regs->UART_IER = UART_IDR_TXRDY;
|
||||
} else {
|
||||
ctx->transmitting = false;
|
||||
regs->UART_IDR = UART_IDR_TXEMPTY;
|
||||
regs->UART_IDR = UART_IDR_TXRDY;
|
||||
}
|
||||
#else
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
while ((regs->UART_SR & UART_SR_TXEMPTY) == 0) {
|
||||
while ((regs->UART_SR & UART_SR_TXRDY) == 0) {
|
||||
/* Wait */
|
||||
}
|
||||
|
||||
@@ -461,13 +441,41 @@ static int atsam_uart_read(rtems_termios_device_context *base)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
|
||||
static int atsam_uart_ioctl(
|
||||
rtems_termios_device_context *base,
|
||||
ioctl_command_t request,
|
||||
void *buffer
|
||||
)
|
||||
{
|
||||
atsam_uart_context *ctx = (atsam_uart_context *) base;
|
||||
rtems_status_code sc;
|
||||
|
||||
switch (request) {
|
||||
case ATSAM_UART_ENABLE_RX_DMA:
|
||||
sc = atsam_uart_enable_rx_dma(ctx);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
rtems_set_errno_and_return_minus_one(EIO);
|
||||
} else {
|
||||
ctx->rx_dma_enabled = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rtems_set_errno_and_return_minus_one(EINVAL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const rtems_termios_device_handler atsam_uart_handler = {
|
||||
.first_open = atsam_uart_first_open,
|
||||
.last_close = atsam_uart_last_close,
|
||||
.write = atsam_uart_write,
|
||||
.set_attributes = atsam_uart_set_attributes,
|
||||
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
|
||||
.mode = TERMIOS_IRQ_DRIVEN
|
||||
.mode = TERMIOS_IRQ_DRIVEN,
|
||||
.ioctl = atsam_uart_ioctl,
|
||||
#else
|
||||
.poll_read = atsam_uart_read,
|
||||
.mode = TERMIOS_POLLED
|
||||
@@ -490,7 +498,7 @@ rtems_status_code console_initialize(
|
||||
usart[sizeof(usart) - 2] = (char) ('0' + i);
|
||||
rtems_termios_device_install(
|
||||
&usart[0],
|
||||
&atsam_usart_handler,
|
||||
&atsam_uart_handler,
|
||||
NULL,
|
||||
&atsam_usart_instances[i].base
|
||||
);
|
||||
|
||||
@@ -132,9 +132,66 @@ static uint32_t XDMAD_AllocateXdmacChannel(sXdmad *pXdmad,
|
||||
return XDMAD_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the internal xdmad state. Returns true if further processing in the
|
||||
* callback is recommended.
|
||||
*
|
||||
* In an earlier version of the API this has been done by the interrupt handler
|
||||
* directly. But in some cases the application might want to process some of the
|
||||
* other interrupts too. Therefore the user callback should now decide itself
|
||||
* whether this is necessary or not.
|
||||
*/
|
||||
bool XDMAD_UpdateStatusFromCallback(sXdmad *pXdmad,
|
||||
uint32_t Channel,
|
||||
uint32_t status)
|
||||
{
|
||||
Xdmac *pXdmac;
|
||||
uint32_t xdmaGlobalChStatus;
|
||||
bool bExec;
|
||||
|
||||
bExec = false;
|
||||
pXdmac = pXdmad->pXdmacs;
|
||||
xdmaGlobalChStatus = XDMAC_GetGlobalChStatus(pXdmac);
|
||||
|
||||
if ((xdmaGlobalChStatus & (XDMAC_GS_ST0 << Channel)) == 0) {
|
||||
uint32_t xdmaChannelIntMask;
|
||||
sXdmadChannel *pCh;
|
||||
|
||||
pCh = &pXdmad->XdmaChannels[Channel];
|
||||
|
||||
xdmaChannelIntMask = XDMAC_GetChannelItMask(pXdmac, Channel);
|
||||
status &= xdmaChannelIntMask;
|
||||
|
||||
if (status & XDMAC_CIS_BIS) {
|
||||
if ((xdmaChannelIntMask & XDMAC_CIM_LIM) == 0) {
|
||||
pCh->state = XDMAD_STATE_DONE;
|
||||
bExec = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (status & XDMAC_CIS_LIS) {
|
||||
pCh->state = XDMAD_STATE_DONE;
|
||||
bExec = true;
|
||||
}
|
||||
|
||||
if (status & XDMAC_CIS_DIS) {
|
||||
pCh->state = XDMAD_STATE_DONE;
|
||||
bExec = true;
|
||||
}
|
||||
} else {
|
||||
/* Block end interrupt for LLI dma mode */
|
||||
if (XDMAC_GetChannelIsr(pXdmac, Channel) & XDMAC_CIS_BIS) {
|
||||
bExec = true;
|
||||
}
|
||||
}
|
||||
|
||||
return bExec;
|
||||
}
|
||||
|
||||
void XDMAD_DoNothingCallback(uint32_t Channel, void *pArg, uint32_t status)
|
||||
{
|
||||
/* Do nothing */
|
||||
/* Do nothing except status update */
|
||||
XDMAD_UpdateStatusFromCallback((sXdmad *)pArg, Channel, status);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -157,6 +214,7 @@ static void XDMAD_SysInitialize(void)
|
||||
|
||||
for (j = 0; j < pXdmad->numChannels; j ++) {
|
||||
pXdmad->XdmaChannels[j].fCallback = XDMAD_DoNothingCallback;
|
||||
pXdmad->XdmaChannels[j].pArg = (void *)pXdmad;
|
||||
}
|
||||
|
||||
sc = rtems_interrupt_handler_install(
|
||||
|
||||
@@ -33,72 +33,65 @@
|
||||
static void
|
||||
atsam_i2c_disable_interrupts(Twihs *regs)
|
||||
{
|
||||
regs->TWIHS_IDR = 0xFFFFFFFF;
|
||||
TWI_DisableIt(regs, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static void
|
||||
atsam_i2c_set_transfer_status(transfer_desc *trans_desc, transfer_state state)
|
||||
/*
|
||||
* Return true if the message is done right after this. That is the case if all
|
||||
* bytes are received but no stop is requested.
|
||||
*/
|
||||
static bool
|
||||
atsam_i2c_continue_read(Twihs *regs, atsam_i2c_bus *bus)
|
||||
{
|
||||
trans_desc->trans_state = state;
|
||||
}
|
||||
bool done = false;
|
||||
|
||||
static void
|
||||
atsam_i2c_continue_read(Twihs *regs, transfer_desc *trans_desc)
|
||||
{
|
||||
trans_desc->data[trans_desc->already_transferred] = TWI_ReadByte(regs);
|
||||
trans_desc->already_transferred++;
|
||||
*bus->current_msg_byte = TWI_ReadByte(regs);
|
||||
++bus->current_msg_byte;
|
||||
--bus->current_msg_todo;
|
||||
|
||||
/* check for transfer finish */
|
||||
if (trans_desc->already_transferred == trans_desc->data_size) {
|
||||
if (trans_desc->stop_request){
|
||||
if (bus->current_msg_todo == 0) {
|
||||
if (bus->stop_request){
|
||||
TWI_DisableIt(regs, TWIHS_IDR_RXRDY);
|
||||
TWI_EnableIt(regs, TWIHS_IER_TXCOMP);
|
||||
atsam_i2c_set_transfer_status(trans_desc, TX_RX_STOP_SENT);
|
||||
} else {
|
||||
atsam_i2c_set_transfer_status(trans_desc, RX_CONT_MESSAGE_NEEDED);
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
/* Last byte? */
|
||||
else if ((trans_desc->already_transferred == (trans_desc->data_size - 1))
|
||||
&& (trans_desc->stop_request)){
|
||||
else if (bus->current_msg_todo == 1 && bus->stop_request) {
|
||||
TWI_Stop(regs);
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the message is done right after this. That is the case if all
|
||||
* bytes are sent but no stop is requested.
|
||||
*/
|
||||
static bool
|
||||
atsam_i2c_is_state(transfer_desc *trans_desc, transfer_state state)
|
||||
atsam_i2c_continue_write(Twihs *regs, atsam_i2c_bus *bus)
|
||||
{
|
||||
return (trans_desc->trans_state == state);
|
||||
}
|
||||
bool done = false;
|
||||
|
||||
static void
|
||||
atsam_i2c_continue_write(Twihs *regs, transfer_desc *trans_desc)
|
||||
{
|
||||
/* Transfer finished ? */
|
||||
if (trans_desc->already_transferred == trans_desc->data_size) {
|
||||
if (bus->current_msg_todo == 0) {
|
||||
TWI_DisableIt(regs, TWIHS_IDR_TXRDY);
|
||||
if (trans_desc->stop_request){
|
||||
if (bus->stop_request){
|
||||
TWI_EnableIt(regs, TWIHS_IER_TXCOMP);
|
||||
TWI_SendSTOPCondition(regs);
|
||||
atsam_i2c_set_transfer_status(trans_desc, TX_RX_STOP_SENT);
|
||||
} else {
|
||||
atsam_i2c_set_transfer_status(trans_desc, TX_CONT_MESSAGE_NEEDED);
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
/* Bytes remaining */
|
||||
else {
|
||||
TWI_WriteByte(regs,
|
||||
trans_desc->data[trans_desc->already_transferred]);
|
||||
trans_desc->already_transferred++;
|
||||
TWI_WriteByte(regs, *bus->current_msg_byte);
|
||||
++bus->current_msg_byte;
|
||||
--bus->current_msg_todo;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
atsam_i2c_finish_write_transfer(Twihs *regs, transfer_desc *trans_desc)
|
||||
{
|
||||
TWI_ReadByte(regs);
|
||||
TWI_DisableIt(regs, TWIHS_IDR_TXCOMP);
|
||||
trans_desc->status = 0;
|
||||
return done;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -115,19 +108,6 @@ atsam_i2c_next_packet(atsam_i2c_bus *bus)
|
||||
bus->current_msg_byte = msg->buf;
|
||||
}
|
||||
|
||||
static void
|
||||
atsam_i2c_set_td(atsam_i2c_bus *bus, uint32_t already_transferred,
|
||||
bool stop_needed)
|
||||
{
|
||||
transfer_desc *trans_desc = &bus->trans_desc;
|
||||
|
||||
trans_desc->status = ASYNC_STATUS_PENDING;
|
||||
trans_desc->data = bus->current_msg_byte;
|
||||
trans_desc->data_size = bus->current_msg_todo;
|
||||
trans_desc->already_transferred = already_transferred;
|
||||
trans_desc->stop_request = stop_needed;
|
||||
}
|
||||
|
||||
static bool
|
||||
atsam_i2c_set_address_size(const i2c_msg *msg)
|
||||
{
|
||||
@@ -186,6 +166,8 @@ atsam_i2c_setup_write_transfer(atsam_i2c_bus *bus, Twihs *regs, bool ctrl,
|
||||
{
|
||||
atsam_i2c_set_address_regs(regs, slave_addr, ctrl, false);
|
||||
TWI_WriteByte(regs, *bus->current_msg_byte);
|
||||
++bus->current_msg_byte;
|
||||
--bus->current_msg_todo;
|
||||
TWI_EnableIt(regs, TWIHS_IER_TXRDY);
|
||||
}
|
||||
|
||||
@@ -197,8 +179,8 @@ atsam_i2c_setup_transfer(atsam_i2c_bus *bus, Twihs *regs)
|
||||
uint32_t msg_todo = bus->msg_todo;
|
||||
uint16_t slave_addr;
|
||||
bool ten_bit_addr = false;
|
||||
uint32_t already_transferred;
|
||||
bool stop_needed = true;
|
||||
bool read;
|
||||
|
||||
ten_bit_addr = atsam_i2c_set_address_size(msgs);
|
||||
|
||||
@@ -206,22 +188,17 @@ atsam_i2c_setup_transfer(atsam_i2c_bus *bus, Twihs *regs)
|
||||
stop_needed = false;
|
||||
}
|
||||
|
||||
bus->read = (msgs->flags & I2C_M_RD) != 0;
|
||||
read = (msgs->flags & I2C_M_RD) != 0;
|
||||
slave_addr = msgs->addr;
|
||||
already_transferred = (bus->read == true) ? 0 : 1;
|
||||
atsam_i2c_set_td(bus, already_transferred, stop_needed);
|
||||
bus->stop_request = stop_needed;
|
||||
|
||||
transfer_desc *trans_desc = &bus->trans_desc;
|
||||
|
||||
if (bus->read){
|
||||
if (read){
|
||||
if (bus->current_msg_todo == 1){
|
||||
send_stop = true;
|
||||
}
|
||||
atsam_i2c_set_transfer_status(trans_desc, RX_SEND_DATA);
|
||||
atsam_i2c_setup_read_transfer(regs, ten_bit_addr,
|
||||
slave_addr, send_stop);
|
||||
} else {
|
||||
atsam_i2c_set_transfer_status(trans_desc, TX_SEND_DATA);
|
||||
atsam_i2c_setup_write_transfer(bus, regs, ten_bit_addr,
|
||||
slave_addr);
|
||||
}
|
||||
@@ -233,40 +210,28 @@ atsam_i2c_interrupt(void *arg)
|
||||
atsam_i2c_bus *bus = arg;
|
||||
uint32_t irqstatus;
|
||||
bool done = false;
|
||||
transfer_desc *trans_desc;
|
||||
|
||||
Twihs *regs = bus->regs;
|
||||
|
||||
/* read interrupts */
|
||||
irqstatus = regs->TWIHS_SR;
|
||||
irqstatus = TWI_GetMaskedStatus(regs);
|
||||
|
||||
if((irqstatus & (TWIHS_SR_ARBLST | TWIHS_SR_NACK)) != 0) {
|
||||
if((irqstatus & ATSAMV_I2C_IRQ_ERROR) != 0) {
|
||||
done = true;
|
||||
}
|
||||
|
||||
trans_desc = &bus->trans_desc;
|
||||
|
||||
if (((irqstatus & TWIHS_SR_RXRDY) != 0) &&
|
||||
(atsam_i2c_is_state(trans_desc, RX_SEND_DATA))){
|
||||
/* carry on read transfer */
|
||||
atsam_i2c_continue_read(regs, trans_desc);
|
||||
} else if (((irqstatus & TWIHS_SR_TXCOMP) != 0) &&
|
||||
(atsam_i2c_is_state(trans_desc, TX_RX_STOP_SENT))){
|
||||
atsam_i2c_finish_write_transfer(regs, trans_desc);
|
||||
} else if ((irqstatus & TWIHS_SR_RXRDY) != 0) {
|
||||
done = atsam_i2c_continue_read(regs, bus);
|
||||
} else if ((irqstatus & TWIHS_SR_TXCOMP) != 0) {
|
||||
TWI_DisableIt(regs, TWIHS_IDR_TXCOMP);
|
||||
done = true;
|
||||
} else if (((irqstatus & TWIHS_SR_TXRDY) != 0) &&
|
||||
(atsam_i2c_is_state(trans_desc, TX_SEND_DATA))){
|
||||
atsam_i2c_continue_write(regs, trans_desc);
|
||||
if (trans_desc->trans_state == TX_CONT_MESSAGE_NEEDED){
|
||||
done = true;
|
||||
}
|
||||
} else if ((irqstatus & TWIHS_SR_TXRDY) != 0) {
|
||||
done = atsam_i2c_continue_write(regs, bus);
|
||||
}
|
||||
|
||||
if(done){
|
||||
uint32_t err = irqstatus & ATSAMV_I2C_IRQ_ERROR;
|
||||
bus->err = irqstatus & ATSAMV_I2C_IRQ_ERROR;
|
||||
|
||||
atsam_i2c_next_packet(bus);
|
||||
if (bus->msg_todo == 0 || err != 0) {
|
||||
if (bus->msg_todo == 0 || bus->err != 0) {
|
||||
atsam_i2c_disable_interrupts(regs);
|
||||
rtems_binary_semaphore_post(&bus->sem);
|
||||
} else {
|
||||
@@ -291,27 +256,38 @@ atsam_i2c_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t msg_count)
|
||||
if ((msgs[i].flags & I2C_M_RECV_LEN) != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (msgs[i].len == 0) {
|
||||
/* Hardware doesn't support zero length messages */
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
bus->msgs = &msgs[0];
|
||||
bus->msg_todo = msg_count;
|
||||
bus->current_msg_todo = msgs[0].len;
|
||||
bus->current_msg_byte = msgs[0].buf;
|
||||
bus->err = 0;
|
||||
|
||||
regs = bus->regs;
|
||||
|
||||
atsam_i2c_setup_transfer(bus, regs);
|
||||
/* Start with a clean start. Enable error interrupts. */
|
||||
TWI_ConfigureMaster(bus->regs, bus->output_clock, BOARD_MCK);
|
||||
TWI_EnableIt(regs, ATSAMV_I2C_IRQ_ERROR);
|
||||
|
||||
regs->TWIHS_IER = ATSAMV_I2C_IRQ_ERROR;
|
||||
atsam_i2c_setup_transfer(bus, regs);
|
||||
|
||||
eno = rtems_binary_semaphore_wait_timed_ticks(
|
||||
&bus->sem,
|
||||
bus->base.timeout
|
||||
);
|
||||
if (eno != 0) {
|
||||
if (eno != 0 || bus->err != 0) {
|
||||
TWI_ConfigureMaster(bus->regs, bus->output_clock, BOARD_MCK);
|
||||
rtems_binary_semaphore_try_wait(&bus->sem);
|
||||
return -ETIMEDOUT;
|
||||
if (bus->err != 0) {
|
||||
return -EIO;
|
||||
} else {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include <bspopts.h>
|
||||
#include <bsp/default-initial-extension.h>
|
||||
#include <sys/ioccom.h>
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
@@ -109,6 +110,18 @@ void atsam_rtc_get_time(rtems_time_of_day *tod);
|
||||
|
||||
void bsp_restart( const void *const addr );
|
||||
|
||||
/*
|
||||
* This ioctl enables the receive DMA for an UART. The DMA can be usefull if you
|
||||
* loose characters in high interrupt load situations.
|
||||
*
|
||||
* Disabling the DMA again is only possible by closing all file descriptors of
|
||||
* that UART.
|
||||
*
|
||||
* Note that every UART needs one DMA channel and the system has only a limited
|
||||
* amount of DMAs. So only use it if you need it.
|
||||
*/
|
||||
#define ATSAM_UART_ENABLE_RX_DMA _IO('d', 0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -28,35 +28,23 @@ extern "C" {
|
||||
|
||||
#define TWI_AMOUNT_PINS 2
|
||||
|
||||
typedef enum {
|
||||
TX_SEND_DATA,
|
||||
TX_SEND_STOP,
|
||||
TX_CONT_MESSAGE_NEEDED,
|
||||
RX_SEND_DATA,
|
||||
RX_SEND_STOP,
|
||||
RX_CONT_MESSAGE_NEEDED,
|
||||
TX_RX_STOP_SENT
|
||||
}transfer_state;
|
||||
|
||||
typedef struct {
|
||||
uint8_t status;
|
||||
uint8_t *data;
|
||||
bool stop_request;
|
||||
uint32_t data_size;
|
||||
uint32_t already_transferred;
|
||||
transfer_state trans_state;
|
||||
} transfer_desc;
|
||||
|
||||
typedef struct {
|
||||
i2c_bus base;
|
||||
i2c_msg *msgs;
|
||||
Twihs *regs;
|
||||
transfer_desc trans_desc;
|
||||
|
||||
/* First message and number of messages that have to be processed. */
|
||||
i2c_msg *msgs;
|
||||
uint32_t msg_todo;
|
||||
|
||||
/* Information about the current transfer. */
|
||||
bool stop_request;
|
||||
uint32_t current_msg_todo;
|
||||
uint8_t *current_msg_byte;
|
||||
|
||||
/* Error information that can be returned to the task */
|
||||
uint32_t err;
|
||||
|
||||
uint32_t output_clock;
|
||||
bool read;
|
||||
rtems_binary_semaphore sem;
|
||||
rtems_vector_number irq;
|
||||
} atsam_i2c_bus;
|
||||
|
||||
@@ -24,44 +24,85 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* @brief The SC16IS752 device context.
|
||||
*
|
||||
* All members are private to the device driver.
|
||||
*/
|
||||
typedef struct {
|
||||
sc16is752_spi_context base;
|
||||
Pin irq_pin;
|
||||
rtems_interrupt_server_entry irqs_entry; /* Internal. Don't touch. */
|
||||
rtems_interrupt_server_action irqs_action; /* Internal. Don't touch. */
|
||||
rtems_interrupt_server_entry irqs_entry;
|
||||
rtems_interrupt_server_action irqs_action;
|
||||
uint32_t irqs_index;
|
||||
} atsam_sc16is752_spi_context;
|
||||
|
||||
/**
|
||||
* @brief The SC16IS752 device configuration.
|
||||
*
|
||||
* @see atsam_sc16is752_spi_create().
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief The device file path for the new device.
|
||||
*/
|
||||
const char *device_path;
|
||||
|
||||
/**
|
||||
* @brief The SC16IS752 mode.
|
||||
*/
|
||||
sc16is752_mode mode;
|
||||
|
||||
/**
|
||||
* @brief The input frequency in Hertz of the SC16IS752 chip. See XTAL1 and
|
||||
* XTAL2 pins.
|
||||
*/
|
||||
uint32_t input_frequency;
|
||||
|
||||
/**
|
||||
* @brief The SPI bus device path.
|
||||
*/
|
||||
const char *spi_path;
|
||||
|
||||
/**
|
||||
* @brief The SPI chip select (starts with 0, the SPI driver uses
|
||||
* SPI_ChipSelect(1 << spi_chip_select)).
|
||||
*/
|
||||
uint8_t spi_chip_select;
|
||||
|
||||
/**
|
||||
* @brief The SPI bus speed in Hertz.
|
||||
*/
|
||||
uint32_t spi_speed_hz;
|
||||
|
||||
/**
|
||||
* @brief The interrupt pin, e.g. { PIO_PD28, PIOD, ID_PIOD, PIO_INPUT,
|
||||
* PIO_IT_LOW_LEVEL }.
|
||||
*/
|
||||
const Pin irq_pin;
|
||||
|
||||
/**
|
||||
* @brief The index to identify the interrupt server used for interrupt
|
||||
* processing.
|
||||
*/
|
||||
uint32_t server_index;
|
||||
} atsam_sc16is752_spi_config;
|
||||
|
||||
/**
|
||||
* @brief Creates an SPI connected SC16IS752 device.
|
||||
*
|
||||
* This devices uses the interrupt server, see
|
||||
* rtems_interrupt_server_initialize().
|
||||
* This devices uses the interrupt server, see rtems_interrupt_server_create().
|
||||
*
|
||||
* The device claims the interrupt of the PIO block.
|
||||
*
|
||||
* @param[in] ctx The device context. May have an arbitrary content.
|
||||
* @param[in] device_path The device file path for the new device.
|
||||
* @param[in] mode The SC16IS752 mode.
|
||||
* @param[in] input_frequency The input frequency in Hertz of the SC16IS752
|
||||
* chip. See XTAL1 and XTAL2 pins.
|
||||
* @param[in] spi_path The SPI bus device path.
|
||||
* @param[in] spi_chip_select The SPI chip select (starts with 0, the SPI
|
||||
* driver uses SPI_ChipSelect(1 << spi_chip_select)).
|
||||
* @param[in] spi_speed_hz The SPI bus speed in Hertz.
|
||||
* @param[in] irq_pin The interrupt pin, e.g. { PIO_PD28, PIOD, ID_PIOD,
|
||||
* PIO_INPUT, PIO_IT_LOW_LEVEL }.
|
||||
* @param[out] ctx is the device context. It may have an arbitrary content.
|
||||
* @param config is the device configuration.
|
||||
*
|
||||
* @return See sc16is752_spi_create().
|
||||
*/
|
||||
int atsam_sc16is752_spi_create(
|
||||
atsam_sc16is752_spi_context *ctx,
|
||||
const char *device_path,
|
||||
sc16is752_mode mode,
|
||||
uint32_t input_frequency,
|
||||
const char *spi_path,
|
||||
uint8_t spi_chip_select,
|
||||
uint32_t spi_speed_hz,
|
||||
const Pin *irq_pin
|
||||
atsam_sc16is752_spi_context *ctx,
|
||||
const atsam_sc16is752_spi_config *config
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -241,6 +241,10 @@ extern eXdmadRC XDMAD_StartTransfer(sXdmad *pXdmad, uint32_t dwChannel);
|
||||
|
||||
extern void XDMAD_DoNothingCallback(uint32_t Channel, void *pArg, uint32_t status);
|
||||
|
||||
extern bool XDMAD_UpdateStatusFromCallback(sXdmad *pXdmad,
|
||||
uint32_t Channel,
|
||||
uint32_t status);
|
||||
|
||||
extern eXdmadRC XDMAD_SetCallback(sXdmad *pXdmad,
|
||||
uint32_t dwChannel,
|
||||
XdmadTransferCallback fCallback,
|
||||
|
||||
@@ -41,7 +41,7 @@ static bool atsam_sc16is752_install_interrupt(sc16is752_context *base)
|
||||
rtems_status_code sc;
|
||||
uint8_t rv;
|
||||
|
||||
sc = rtems_interrupt_server_entry_initialize(RTEMS_INTERRUPT_SERVER_DEFAULT,
|
||||
sc = rtems_interrupt_server_entry_initialize(ctx->irqs_index,
|
||||
&ctx->irqs_entry);
|
||||
rtems_interrupt_server_action_prepend(&ctx->irqs_entry,
|
||||
&ctx->irqs_action, atsam_sc16i752_irqs_handler, ctx);
|
||||
@@ -64,24 +64,19 @@ static void atsam_sc16is752_remove_interrupt(sc16is752_context *base)
|
||||
}
|
||||
|
||||
int atsam_sc16is752_spi_create(
|
||||
atsam_sc16is752_spi_context *ctx,
|
||||
const char *device_path,
|
||||
sc16is752_mode mode,
|
||||
uint32_t input_frequency,
|
||||
const char *spi_path,
|
||||
uint8_t spi_chip_select,
|
||||
uint32_t spi_speed_hz,
|
||||
const Pin *irq_pin
|
||||
atsam_sc16is752_spi_context *ctx,
|
||||
const atsam_sc16is752_spi_config *config
|
||||
)
|
||||
{
|
||||
ctx->base.base.mode = mode;
|
||||
ctx->base.base.input_frequency = input_frequency;
|
||||
ctx->base.base.mode = config->mode;
|
||||
ctx->base.base.input_frequency = config->input_frequency;
|
||||
ctx->base.base.install_irq = atsam_sc16is752_install_interrupt;
|
||||
ctx->base.base.remove_irq = atsam_sc16is752_remove_interrupt;
|
||||
ctx->base.spi_path = spi_path;
|
||||
ctx->base.cs = spi_chip_select;
|
||||
ctx->base.speed_hz = spi_speed_hz;
|
||||
ctx->irq_pin = *irq_pin;
|
||||
ctx->base.spi_path = config->spi_path;
|
||||
ctx->base.cs = config->spi_chip_select;
|
||||
ctx->base.speed_hz = config->spi_speed_hz;
|
||||
ctx->irq_pin = config->irq_pin;
|
||||
ctx->irqs_index = config->server_index;
|
||||
|
||||
return sc16is752_spi_create(&ctx->base, device_path);
|
||||
return sc16is752_spi_create(&ctx->base, config->device_path);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@ include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/lpc-timer.h
|
||||
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/start.h
|
||||
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/zynq-uart-regs.h
|
||||
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/zynq-uart.h
|
||||
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/cadence-spi-regs.h
|
||||
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/cadence-spi.h
|
||||
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/xilinx-axi-spi-regs.h
|
||||
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/xilinx-axi-spi.h
|
||||
|
||||
include_libcpudir = $(includedir)/libcpu
|
||||
include_libcpu_HEADERS =
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <bsp/fdt.h>
|
||||
#include <bsp/irq-generic.h>
|
||||
#include <bsp/linker-symbols.h>
|
||||
#include <libcpu/arm-cp15.h>
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
@@ -58,6 +59,60 @@ uint32_t bsp_fdt_map_intr(const uint32_t *intr, size_t icells)
|
||||
return intr[1] + MAGIC_IRQ_OFFSET;
|
||||
}
|
||||
|
||||
static bool imx_is_imx6(const void *fdt)
|
||||
{
|
||||
/*
|
||||
* At the moment: Check for some compatible strings that should be there
|
||||
* somewhere in every fdt.
|
||||
*
|
||||
* FIXME: It would be nice if some CPU-ID could be used instead. But I didn't
|
||||
* find one.
|
||||
*/
|
||||
int node;
|
||||
|
||||
node = fdt_node_offset_by_compatible(fdt, -1, "fsl,imx6ul");
|
||||
if (node >= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
node = fdt_node_offset_by_compatible(fdt, -1, "fsl,imx6ull");
|
||||
if (node >= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define SYSCNT_CNTCR (0x0)
|
||||
#define SYSCNT_CNTCR_ENABLE (1 << 0)
|
||||
#define SYSCNT_CNTCR_HDBG (1 << 1)
|
||||
#define SYSCNT_CNTCR_FCREQ(n) (1 << (8 + (n)))
|
||||
#define SYSCNT_CNTFID(n) (0x20 + 4 * (n))
|
||||
|
||||
static uint32_t imx_syscnt_enable_and_return_frequency(const void *fdt)
|
||||
{
|
||||
uint32_t freq;
|
||||
volatile void *syscnt_base;
|
||||
|
||||
/* That's not in the usual FDTs. Sorry for falling back to a magic value. */
|
||||
if (imx_is_imx6(fdt)) {
|
||||
syscnt_base = (void *)0x021dc000;
|
||||
} else {
|
||||
syscnt_base = (void *)0x306c0000;
|
||||
}
|
||||
|
||||
freq = *(uint32_t *)(syscnt_base + SYSCNT_CNTFID(0));
|
||||
|
||||
arm_cp15_set_counter_frequency(freq);
|
||||
|
||||
*(uint32_t *)(syscnt_base + SYSCNT_CNTCR) =
|
||||
SYSCNT_CNTCR_ENABLE |
|
||||
SYSCNT_CNTCR_HDBG |
|
||||
SYSCNT_CNTCR_FCREQ(0);
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
void arm_generic_timer_get_config(
|
||||
uint32_t *frequency,
|
||||
uint32_t *irq
|
||||
@@ -75,7 +130,11 @@ void arm_generic_timer_get_config(
|
||||
if (val != NULL && len >= 4) {
|
||||
*frequency = fdt32_to_cpu(val[0]);
|
||||
} else {
|
||||
bsp_fatal(IMX_FATAL_GENERIC_TIMER_FREQUENCY);
|
||||
/*
|
||||
* Normally clock-frequency would be provided by the boot loader. If it
|
||||
* didn't add one, we have to initialize the system counter ourself.
|
||||
*/
|
||||
*frequency = imx_syscnt_enable_and_return_frequency(fdt);
|
||||
}
|
||||
|
||||
/* FIXME: Figure out how Linux gets a proper IRQ number */
|
||||
|
||||
@@ -123,6 +123,35 @@ arm_a9mpcore_start_enable_smp_in_auxiliary_control(void)
|
||||
actlr |= ARM_CORTEX_A9_ACTL_SMP | ARM_CORTEX_A9_ACTL_FW;
|
||||
arm_cp15_set_auxiliary_control(actlr);
|
||||
}
|
||||
|
||||
BSP_START_TEXT_SECTION static inline void
|
||||
arm_a9mpcore_start_errata_794072_handler(void)
|
||||
{
|
||||
uint32_t diag;
|
||||
|
||||
/*
|
||||
* Workaround for Errata 794072: A short loop including a DMB instruction
|
||||
* might cause a denial of service on another which executes a CP15 broadcast
|
||||
* operation.
|
||||
*/
|
||||
diag = arm_cp15_get_diagnostic_control();
|
||||
diag |= 1U << 4;
|
||||
arm_cp15_set_diagnostic_control(diag);
|
||||
}
|
||||
|
||||
BSP_START_TEXT_SECTION static inline void
|
||||
arm_a9mpcore_start_errata_845369_handler(void)
|
||||
{
|
||||
uint32_t diag;
|
||||
|
||||
/*
|
||||
* Workaround for Errata 845369: Under Very Rare Timing Circumstances
|
||||
* Transition into Streaming Mode Might Create Data Corruption.
|
||||
*/
|
||||
diag = arm_cp15_get_diagnostic_control();
|
||||
diag |= 1U << 22;
|
||||
arm_cp15_set_diagnostic_control(diag);
|
||||
}
|
||||
#endif
|
||||
|
||||
BSP_START_TEXT_SECTION static inline void arm_a9mpcore_start_hook_0(void)
|
||||
@@ -138,6 +167,8 @@ BSP_START_TEXT_SECTION static inline void arm_a9mpcore_start_hook_0(void)
|
||||
}
|
||||
|
||||
#ifdef RTEMS_SMP
|
||||
arm_a9mpcore_start_errata_794072_handler();
|
||||
arm_a9mpcore_start_errata_845369_handler();
|
||||
arm_a9mpcore_start_enable_smp_in_auxiliary_control();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -73,6 +73,10 @@ typedef struct {
|
||||
.begin = (uint32_t) bsp_section_bss_begin, \
|
||||
.end = (uint32_t) bsp_section_bss_end, \
|
||||
.flags = ARMV7_MMU_DATA_READ_WRITE_CACHED \
|
||||
}, { \
|
||||
.begin = (uint32_t) bsp_section_rtemsstack_begin, \
|
||||
.end = (uint32_t) bsp_section_rtemsstack_end, \
|
||||
.flags = ARMV7_MMU_DATA_READ_WRITE_CACHED \
|
||||
}, { \
|
||||
.begin = (uint32_t) bsp_section_work_begin, \
|
||||
.end = (uint32_t) bsp_section_work_end, \
|
||||
@@ -95,7 +99,7 @@ typedef struct {
|
||||
.flags = ARMV7_MMU_DATA_READ_WRITE_CACHED \
|
||||
}
|
||||
|
||||
#define ARMV7_CP15_START_WORKSPACE_ENTRY_INDEX 8
|
||||
#define ARMV7_CP15_START_WORKSPACE_ENTRY_INDEX 9
|
||||
|
||||
BSP_START_DATA_SECTION extern const arm_cp15_start_section_config
|
||||
arm_cp15_start_mmu_config_table[];
|
||||
@@ -119,7 +123,7 @@ arm_cp15_start_set_translation_table_entries(
|
||||
|
||||
pt = &ttb[ARM_MMU_TRANSLATION_TABLE_ENTRY_COUNT];
|
||||
i = ARM_MMU_SMALL_PAGE_GET_INDEX(config->begin);
|
||||
iend = ARM_MMU_SMALL_PAGE_GET_INDEX(ARM_MMU_SECT_MVA_ALIGN_UP(config->end));
|
||||
iend = ARM_MMU_SMALL_PAGE_GET_INDEX(ARM_MMU_SMALL_PAGE_MVA_ALIGN_UP(config->end));
|
||||
index_mask = (1U << (32 - ARM_MMU_SMALL_PAGE_BASE_SHIFT)) - 1U;
|
||||
flags = ARM_MMU_SECT_FLAGS_TO_SMALL_PAGE(config->flags);
|
||||
|
||||
|
||||
84
bsps/arm/include/bsp/cadence-spi-regs.h
Normal file
84
bsps/arm/include/bsp/cadence-spi-regs.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_REGS_H
|
||||
#define LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_REGS_H
|
||||
|
||||
#include <bsp/utility.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t config;
|
||||
#define CADENCE_SPI_CONFIG_MODEFAIL_EN BSP_BIT32(17)
|
||||
#define CADENCE_SPI_CONFIG_MANSTRT BSP_BIT32(16)
|
||||
#define CADENCE_SPI_CONFIG_MANSTRT_EN BSP_BIT32(15)
|
||||
#define CADENCE_SPI_CONFIG_MANUAL_CS BSP_BIT32(14)
|
||||
#define CADENCE_SPI_CONFIG_CS(val) BSP_FLD32(val, 10, 13)
|
||||
#define CADENCE_SPI_CONFIG_CS_GET(reg) BSP_FLD32GET(reg, 10, 13)
|
||||
#define CADENCE_SPI_CONFIG_CS_SET(reg, val) BSP_FLD32SET(reg, val, 10, 13)
|
||||
#define CADENCE_SPI_CONFIG_PERI_SEL BSP_BIT32(9)
|
||||
#define CADENCE_SPI_CONFIG_REF_CLK BSP_BIT32(8)
|
||||
#define CADENCE_SPI_CONFIG_BAUD_DIV(val) BSP_FLD32(val, 3, 5)
|
||||
#define CADENCE_SPI_CONFIG_BAUD_DIV_GET(reg) BSP_FLD32GET(reg, 3, 5)
|
||||
#define CADENCE_SPI_CONFIG_BAUD_DIV_SET(reg, val) BSP_FLD32SET(reg, val, 3, 5)
|
||||
#define CADENCE_SPI_CONFIG_CLK_PH BSP_BIT32(2)
|
||||
#define CADENCE_SPI_CONFIG_CLK_POL BSP_BIT32(1)
|
||||
#define CADENCE_SPI_CONFIG_MSTREN BSP_BIT32(0)
|
||||
uint32_t irqstatus;
|
||||
uint32_t irqenable;
|
||||
uint32_t irqdisable;
|
||||
uint32_t irqmask;
|
||||
#define CADENCE_SPI_IXR_TXUF BSP_BIT32(6)
|
||||
#define CADENCE_SPI_IXR_RXFULL BSP_BIT32(5)
|
||||
#define CADENCE_SPI_IXR_RXNEMPTY BSP_BIT32(4)
|
||||
#define CADENCE_SPI_IXR_TXFULL BSP_BIT32(3)
|
||||
#define CADENCE_SPI_IXR_TXOW BSP_BIT32(2)
|
||||
#define CADENCE_SPI_IXR_MODF BSP_BIT32(1)
|
||||
#define CADENCE_SPI_IXR_RXOVR BSP_BIT32(0)
|
||||
uint32_t spienable;
|
||||
#define CADENCE_SPI_EN BSP_BIT32(0)
|
||||
uint32_t delay;
|
||||
#define CADENCE_SPI_DELAY_DNSS(val) BSP_FLD32(val, 24, 31)
|
||||
#define CADENCE_SPI_DELAY_DNSS_GET(reg) BSP_FLD32GET(reg, 24, 31)
|
||||
#define CADENCE_SPI_DELAY_DNSS_SET(reg, val) BSP_FLD32SET(reg, val, 24, 31)
|
||||
#define CADENCE_SPI_DELAY_DBTWN(val) BSP_FLD32(val, 16, 23)
|
||||
#define CADENCE_SPI_DELAY_DBTWN_GET(reg) BSP_FLD32GET(reg, 16, 23)
|
||||
#define CADENCE_SPI_DELAY_DBTWN_SET(reg, val) BSP_FLD32SET(reg, val, 16, 23)
|
||||
#define CADENCE_SPI_DELAY_DAFTER(val) BSP_FLD32(val, 8, 15)
|
||||
#define CADENCE_SPI_DELAY_DAFTER_GET(reg) BSP_FLD32GET(reg, 8, 15)
|
||||
#define CADENCE_SPI_DELAY_DAFTER_SET(reg, val) BSP_FLD32SET(reg, val, 8, 15)
|
||||
#define CADENCE_SPI_DELAY_DINT(val) BSP_FLD32(val, 0, 7)
|
||||
#define CADENCE_SPI_DELAY_DINT_GET(reg) BSP_FLD32GET(reg, 0, 7)
|
||||
#define CADENCE_SPI_DELAY_DINT_SET(reg, val) BSP_FLD32SET(reg, val, 0, 7)
|
||||
uint32_t txdata;
|
||||
uint32_t rxdata;
|
||||
uint32_t slave_idle_count;
|
||||
uint32_t txthreshold;
|
||||
uint32_t rxthreshold;
|
||||
uint32_t moduleid;
|
||||
} cadence_spi;
|
||||
|
||||
#endif /* LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_REGS_H */
|
||||
63
bsps/arm/include/bsp/cadence-spi.h
Normal file
63
bsps/arm/include/bsp/cadence-spi.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_H
|
||||
#define LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_H
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* Register the cadence-spi device with rtems
|
||||
*
|
||||
* @param bus_path path of the new device (e.g. /dev/spi0)
|
||||
* @register_base Address of the first (i.e. config) register
|
||||
* @input_clock Configured frequency of the input clock
|
||||
*
|
||||
* @return RTEMS_SUCCESSFUL on success, negative number on failure
|
||||
*
|
||||
* Note: The spi frequencies the cadence spi device can achieve
|
||||
* are the @p input_clock divided by a power of 2 between
|
||||
* 4 and 256.
|
||||
* The driver tries to find a divider which yields a spi
|
||||
* frequency equal to or lower than the desired bus frequency.
|
||||
*/
|
||||
int spi_bus_register_cadence(
|
||||
const char *bus_path,
|
||||
uintptr_t register_base,
|
||||
uint32_t input_clock,
|
||||
rtems_vector_number irq
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_H */
|
||||
@@ -90,6 +90,10 @@ LINKER_SYMBOL(bsp_section_bss_begin)
|
||||
LINKER_SYMBOL(bsp_section_bss_end)
|
||||
LINKER_SYMBOL(bsp_section_bss_size)
|
||||
|
||||
LINKER_SYMBOL(bsp_section_rtemsstack_begin)
|
||||
LINKER_SYMBOL(bsp_section_rtemsstack_end)
|
||||
LINKER_SYMBOL(bsp_section_rtemsstack_size)
|
||||
|
||||
LINKER_SYMBOL(bsp_section_work_begin)
|
||||
LINKER_SYMBOL(bsp_section_work_end)
|
||||
LINKER_SYMBOL(bsp_section_work_size)
|
||||
|
||||
88
bsps/arm/include/bsp/xilinx-axi-spi-regs.h
Normal file
88
bsps/arm/include/bsp/xilinx-axi-spi-regs.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LIBBSP_ARM_XILINX_AXI_SPI_REGS_H
|
||||
#define LIBBSP_ARM_XILINX_AXI_SPI_REGS_H
|
||||
|
||||
#include <bsp/utility.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t reserved1[7];
|
||||
uint32_t globalirq;
|
||||
#define XILINX_AXI_SPI_GLOBAL_IRQ_ENABLE BSP_BIT32(31)
|
||||
uint32_t irqstatus;
|
||||
uint32_t reserved2;
|
||||
uint32_t irqenable;
|
||||
#define XILINX_AXI_SPI_IRQ_CMD_ERR BSP_BIT32(13)
|
||||
#define XILINX_AXI_SPI_IRQ_LOOP_ERR BSP_BIT32(12)
|
||||
#define XILINX_AXI_SPI_IRQ_MSB_ERR BSP_BIT32(11)
|
||||
#define XILINX_AXI_SPI_IRQ_SLV_ERR BSP_BIT32(10)
|
||||
#define XILINX_AXI_SPI_IRQ_CPOL_CPHA_ERR BSP_BIT32(9)
|
||||
#define XILINX_AXI_SPI_IRQ_RXNEMPTY BSP_BIT32(8)
|
||||
#define XILINX_AXI_SPI_IRQ_CS_MODE BSP_BIT32(7)
|
||||
#define XILINX_AXI_SPI_IRQ_TXHALF BSP_BIT32(6)
|
||||
#define XILINX_AXI_SPI_IRQ_RXOVR BSP_BIT32(5)
|
||||
#define XILINX_AXI_SPI_IRQ_RXFULL BSP_BIT32(4)
|
||||
#define XILINX_AXI_SPI_IRQ_TXUF BSP_BIT32(3)
|
||||
#define XILINX_AXI_SPI_IRQ_TXEMPTY BSP_BIT32(2)
|
||||
#define XILINX_AXI_SPI_IRQ_SLV_MODF BSP_BIT32(1)
|
||||
#define XILINX_AXI_SPI_IRQ_MODF BSP_BIT32(0)
|
||||
uint32_t reserved3[5];
|
||||
uint32_t reset;
|
||||
#define XILINX_AXI_SPI_RESET 0x0000000a
|
||||
uint32_t reserved4[7];
|
||||
uint32_t control;
|
||||
#define XILINX_AXI_SPI_CONTROL_LSBFIRST BSP_BIT32(9)
|
||||
#define XILINX_AXI_SPI_CONTROL_MST_TRANS_INHIBIT BSP_BIT32(8)
|
||||
#define XILINX_AXI_SPI_CONTROL_MANUAL_CS BSP_BIT32(7)
|
||||
#define XILINX_AXI_SPI_CONTROL_RX_FIFO_RESET BSP_BIT32(6)
|
||||
#define XILINX_AXI_SPI_CONTROL_TX_FIFO_RESET BSP_BIT32(5)
|
||||
#define XILINX_AXI_SPI_CONTROL_CPHA BSP_BIT32(4)
|
||||
#define XILINX_AXI_SPI_CONTROL_CPOL BSP_BIT32(3)
|
||||
#define XILINX_AXI_SPI_CONTROL_MSTREN BSP_BIT32(2)
|
||||
#define XILINX_AXI_SPI_CONTROL_SPIEN BSP_BIT32(1)
|
||||
#define XILINX_AXI_SPI_CONTROL_LOOP BSP_BIT32(0)
|
||||
uint32_t status;
|
||||
#define XILINX_AXI_SPI_STATUS_CMD_ERR BSP_BIT32(10)
|
||||
#define XILINX_AXI_SPI_STATUS_LOOP_ERR BSP_BIT32(9)
|
||||
#define XILINX_AXI_SPI_STATUS_MSB_ERR BSP_BIT32(8)
|
||||
#define XILINX_AXI_SPI_STATUS_SLV_ERR BSP_BIT32(7)
|
||||
#define XILINX_AXI_SPI_STATUS_CPOL_CPHA_ERR BSP_BIT32(6)
|
||||
#define XILINX_AXI_SPI_STATUS_SLV_MODE BSP_BIT32(5)
|
||||
#define XILINX_AXI_SPI_STATUS_MODF BSP_BIT32(4)
|
||||
#define XILINX_AXI_SPI_STATUS_TXFULL BSP_BIT32(3)
|
||||
#define XILINX_AXI_SPI_STATUS_TXEMPTY BSP_BIT32(2)
|
||||
#define XILINX_AXI_SPI_STATUS_RXFULL BSP_BIT32(1)
|
||||
#define XILINX_AXI_SPI_STATUS_RXEMPTY BSP_BIT32(0)
|
||||
uint32_t txdata;
|
||||
uint32_t rxdata;
|
||||
uint32_t cs;
|
||||
uint32_t tx_fifo_len;
|
||||
uint32_t rx_fifo_len;
|
||||
} xilinx_axi_spi;
|
||||
|
||||
#endif /* LIBBSP_ARM_XILINX_AXI_SPI_REGS_H */
|
||||
67
bsps/arm/include/bsp/xilinx-axi-spi.h
Normal file
67
bsps/arm/include/bsp/xilinx-axi-spi.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LIBBSP_ARM_XILINX_AXI_SPI_H
|
||||
#define LIBBSP_ARM_XILINX_AXI_SPI_H
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* Register Xilinx AXI SPI device
|
||||
*
|
||||
* Note:
|
||||
* The Xilinx Quad SPI device is very versatile and
|
||||
* supports many options. This driver assumes the
|
||||
* following setup:
|
||||
* - Standard SPI mode and AXI Lite interface
|
||||
* - FIFO available (driver might also work without FIFOs)
|
||||
*
|
||||
* @param bus_path path for the new device node (e.g. "/dev/spi0")
|
||||
* @param register_base base address of the device
|
||||
* @param fifo_size Configured fifo size. Either 0, 16 or 256
|
||||
* @param num_cs Number of configured CS lines (0-32)
|
||||
*
|
||||
* @return 0 on success. Negative number otherwise.
|
||||
*
|
||||
*/
|
||||
int spi_bus_register_xilinx_axi(
|
||||
const char *bus_path,
|
||||
uintptr_t register_base,
|
||||
uint32_t fifo_size,
|
||||
uint32_t num_cs,
|
||||
rtems_vector_number irq
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* LIBBSP_ARM_XILINX_AXI_SPI_H */
|
||||
@@ -71,6 +71,13 @@ void zynq_uart_write_polled(
|
||||
*/
|
||||
void zynq_uart_reset_tx_flush(zynq_uart_context *ctx);
|
||||
|
||||
int zynq_cal_baud_rate(
|
||||
uint32_t baudrate,
|
||||
uint32_t* brgr,
|
||||
uint32_t* bauddiv,
|
||||
uint32_t modereg
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -40,7 +40,7 @@ uint32_t zynq_uart_input_clock(void)
|
||||
return ZYNQ_CLOCK_UART;
|
||||
}
|
||||
|
||||
static int zynq_cal_baud_rate(uint32_t baudrate,
|
||||
int zynq_cal_baud_rate(uint32_t baudrate,
|
||||
uint32_t* brgr,
|
||||
uint32_t* bauddiv,
|
||||
uint32_t modereg)
|
||||
@@ -122,6 +122,8 @@ void zynq_uart_initialize(rtems_termios_device_context *base)
|
||||
uint32_t brgr = 0x3e;
|
||||
uint32_t bauddiv = 0x6;
|
||||
|
||||
zynq_uart_reset_tx_flush(ctx);
|
||||
|
||||
zynq_cal_baud_rate(ZYNQ_UART_DEFAULT_BAUD, &brgr, &bauddiv, regs->mode);
|
||||
|
||||
regs->control &= ~(ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN);
|
||||
|
||||
@@ -142,25 +142,82 @@ static bool zynq_uart_set_attributes(
|
||||
const struct termios *term
|
||||
)
|
||||
{
|
||||
#if 0
|
||||
volatile zynq_uart *regs = zynq_uart_get_regs(minor);
|
||||
zynq_uart_context *ctx = (zynq_uart_context *) context;
|
||||
volatile zynq_uart *regs = ctx->regs;
|
||||
int32_t baud;
|
||||
uint32_t brgr = 0;
|
||||
uint32_t bauddiv = 0;
|
||||
uint32_t mode = 0;
|
||||
int rc;
|
||||
|
||||
rc = zynq_cal_baud_rate(115200, &brgr, &bauddiv, regs->mode);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
/*
|
||||
* Determine the baud rate
|
||||
*/
|
||||
baud = rtems_termios_baud_to_number(term->c_ospeed);
|
||||
|
||||
if (baud > 0) {
|
||||
rc = zynq_cal_baud_rate(baud, &brgr, &bauddiv, regs->mode);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure the mode register
|
||||
*/
|
||||
mode |= ZYNQ_UART_MODE_CHMODE(ZYNQ_UART_MODE_CHMODE_NORMAL);
|
||||
|
||||
/*
|
||||
* Parity
|
||||
*/
|
||||
mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_NONE);
|
||||
if (term->c_cflag & PARENB) {
|
||||
if (!(term->c_cflag & PARODD)) {
|
||||
mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_ODD);
|
||||
} else {
|
||||
mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_EVEN);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Character Size
|
||||
*/
|
||||
switch (term->c_cflag & CSIZE)
|
||||
{
|
||||
case CS5:
|
||||
return false;
|
||||
case CS6:
|
||||
mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_6);
|
||||
break;
|
||||
case CS7:
|
||||
mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_7);
|
||||
break;
|
||||
case CS8:
|
||||
default:
|
||||
mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_8);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop Bits
|
||||
*/
|
||||
if (term->c_cflag & CSTOPB) {
|
||||
/* 2 stop bits */
|
||||
mode |= ZYNQ_UART_MODE_NBSTOP(ZYNQ_UART_MODE_NBSTOP_STOP_2);
|
||||
} else {
|
||||
/* 1 stop bit */
|
||||
mode |= ZYNQ_UART_MODE_NBSTOP(ZYNQ_UART_MODE_NBSTOP_STOP_1);
|
||||
}
|
||||
|
||||
regs->control &= ~(ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN);
|
||||
regs->baud_rate_gen = ZYNQ_UART_BAUD_RATE_GEN_CD(brgr);
|
||||
regs->baud_rate_div = ZYNQ_UART_BAUD_RATE_DIV_BDIV(bauddiv);
|
||||
regs->mode = mode;
|
||||
/* Ignore baud rate of B0. There are no modem control lines to de-assert */
|
||||
if (baud > 0) {
|
||||
regs->baud_rate_gen = ZYNQ_UART_BAUD_RATE_GEN_CD(brgr);
|
||||
regs->baud_rate_div = ZYNQ_UART_BAUD_RATE_DIV_BDIV(bauddiv);
|
||||
}
|
||||
regs->control |= ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN;
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
const rtems_termios_device_handler zynq_uart_handler = {
|
||||
|
||||
444
bsps/arm/shared/spi/cadence-spi.c
Normal file
444
bsps/arm/shared/spi/cadence-spi.c
Normal file
@@ -0,0 +1,444 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include <bsp.h>
|
||||
|
||||
#include <rtems/irq-extension.h>
|
||||
#include <sys/param.h> /* MAX() */
|
||||
|
||||
#include <dev/spi/spi.h>
|
||||
#include <bsp/cadence-spi.h>
|
||||
#include <bsp/cadence-spi-regs.h>
|
||||
|
||||
#define CADENCE_SPI_FIFO_SIZE 128
|
||||
#define CADENCE_SPI_MAX_CHIPSELECTS 3
|
||||
#define CADENCE_SPI_CS_NONE 0xF
|
||||
|
||||
typedef struct cadence_spi_bus cadence_spi_bus;
|
||||
|
||||
struct cadence_spi_bus {
|
||||
spi_bus base;
|
||||
volatile cadence_spi *regs;
|
||||
uint32_t clk_in;
|
||||
uint16_t clk_per_usecs;
|
||||
uint32_t msg_todo;
|
||||
const spi_ioc_transfer *msg;
|
||||
uint32_t todo;
|
||||
uint32_t in_transfer;
|
||||
uint8_t *rx_buf;
|
||||
const uint8_t *tx_buf;
|
||||
rtems_id task_id;
|
||||
rtems_vector_number irq;
|
||||
};
|
||||
|
||||
|
||||
static void cadence_spi_disable_interrupts(volatile cadence_spi *regs)
|
||||
{
|
||||
regs->irqdisable = 0xffff;
|
||||
}
|
||||
|
||||
static void cadence_spi_clear_irq_status(volatile cadence_spi *regs)
|
||||
{
|
||||
regs->irqstatus = regs->irqstatus;
|
||||
}
|
||||
|
||||
static bool cadence_spi_rx_fifo_not_empty(volatile cadence_spi *regs)
|
||||
{
|
||||
return (regs->irqstatus & CADENCE_SPI_IXR_RXNEMPTY) != 0;
|
||||
}
|
||||
|
||||
static void cadence_spi_reset(cadence_spi_bus *bus)
|
||||
{
|
||||
volatile cadence_spi *regs = bus->regs;
|
||||
uint32_t val;
|
||||
|
||||
cadence_spi_disable_interrupts(regs);
|
||||
|
||||
regs->spienable = 0;
|
||||
|
||||
val = regs->config;
|
||||
val &= ~(CADENCE_SPI_CONFIG_MODEFAIL_EN
|
||||
| CADENCE_SPI_CONFIG_MANSTRT_EN
|
||||
| CADENCE_SPI_CONFIG_MANUAL_CS
|
||||
| CADENCE_SPI_CONFIG_PERI_SEL
|
||||
| CADENCE_SPI_CONFIG_REF_CLK);
|
||||
|
||||
val |= CADENCE_SPI_CONFIG_CS(CADENCE_SPI_CS_NONE)
|
||||
| CADENCE_SPI_CONFIG_MSTREN
|
||||
| CADENCE_SPI_CONFIG_MANSTRT;
|
||||
regs->config = val;
|
||||
|
||||
/* Initialize here, will be set for every transfer */
|
||||
regs->txthreshold = 1;
|
||||
/* Set to 1, so we can check when the rx buffer is empty */
|
||||
regs->rxthreshold = 1;
|
||||
|
||||
while (cadence_spi_rx_fifo_not_empty(regs)) {
|
||||
regs->rxdata;
|
||||
}
|
||||
cadence_spi_clear_irq_status(regs);
|
||||
}
|
||||
|
||||
static void cadence_spi_done(cadence_spi_bus *bus)
|
||||
{
|
||||
volatile cadence_spi *regs = bus->regs;
|
||||
regs->spienable = 0;
|
||||
cadence_spi_disable_interrupts(regs);
|
||||
cadence_spi_clear_irq_status(regs);
|
||||
rtems_event_transient_send(bus->task_id);
|
||||
}
|
||||
|
||||
static void cadence_spi_push(cadence_spi_bus *bus, volatile cadence_spi *regs)
|
||||
{
|
||||
while (bus->todo > 0 && bus->in_transfer < CADENCE_SPI_FIFO_SIZE) {
|
||||
uint8_t val = 0;
|
||||
if (bus->tx_buf != NULL) {
|
||||
val = *bus->tx_buf;
|
||||
++bus->tx_buf;
|
||||
}
|
||||
|
||||
--bus->todo;
|
||||
regs->txdata = val;
|
||||
++bus->in_transfer;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cadence_spi_set_chipsel(cadence_spi_bus *bus, uint32_t cs)
|
||||
{
|
||||
|
||||
volatile cadence_spi *regs = bus->regs;
|
||||
uint32_t cs_bit = CADENCE_SPI_CS_NONE;
|
||||
uint32_t config = regs->config;
|
||||
|
||||
if (cs != SPI_NO_CS && cs < CADENCE_SPI_MAX_CHIPSELECTS) {
|
||||
cs_bit >>= (CADENCE_SPI_MAX_CHIPSELECTS - cs + 1);
|
||||
}
|
||||
config = CADENCE_SPI_CONFIG_CS_SET(config, cs_bit);
|
||||
bus->base.cs = cs;
|
||||
|
||||
regs->config = config;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
cadence_spi_baud_divider(cadence_spi_bus *bus,
|
||||
uint32_t speed_hz)
|
||||
{
|
||||
uint32_t div;
|
||||
uint32_t clk_in;
|
||||
|
||||
clk_in = bus->clk_in;
|
||||
|
||||
div = clk_in / speed_hz;
|
||||
div = fls((int) div);
|
||||
|
||||
if (clk_in > (speed_hz << div)) {
|
||||
++div;
|
||||
}
|
||||
|
||||
/* The baud divider needs to be at least 4, i.e. 2^2 */
|
||||
div = MAX(2, div);
|
||||
|
||||
/* 0b111 is the maximum possible divider value */
|
||||
div = MIN(7, div-1);
|
||||
return div;
|
||||
}
|
||||
|
||||
static void cadence_spi_config(
|
||||
cadence_spi_bus *bus,
|
||||
volatile cadence_spi *regs,
|
||||
uint32_t speed_hz,
|
||||
uint32_t mode,
|
||||
uint16_t delay_usecs,
|
||||
uint8_t cs
|
||||
)
|
||||
{
|
||||
spi_bus *base = &bus->base;
|
||||
uint32_t config = regs->config;
|
||||
uint32_t delay;
|
||||
|
||||
regs->spienable = 0;
|
||||
|
||||
if ((mode & SPI_CPHA) != 0) {
|
||||
config |= CADENCE_SPI_CONFIG_CLK_PH;
|
||||
} else {
|
||||
config &= ~CADENCE_SPI_CONFIG_CLK_PH;
|
||||
}
|
||||
|
||||
if ((mode & SPI_CPOL) != 0) {
|
||||
config |= CADENCE_SPI_CONFIG_CLK_POL;
|
||||
} else {
|
||||
config &= ~CADENCE_SPI_CONFIG_CLK_POL;
|
||||
}
|
||||
|
||||
config = CADENCE_SPI_CONFIG_BAUD_DIV_SET(config,
|
||||
cadence_spi_baud_divider(bus, speed_hz));
|
||||
|
||||
regs->config = config;
|
||||
cadence_spi_set_chipsel(bus, cs);
|
||||
|
||||
delay = regs->delay;
|
||||
delay = CADENCE_SPI_DELAY_DBTWN_SET(delay, delay_usecs * bus->clk_per_usecs);
|
||||
regs->delay = delay;
|
||||
|
||||
base->speed_hz = speed_hz;
|
||||
base->mode = mode;
|
||||
base->cs = cs;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
cadence_spi_next_msg(cadence_spi_bus *bus, volatile cadence_spi *regs)
|
||||
{
|
||||
if (bus->msg_todo > 0) {
|
||||
const spi_ioc_transfer *msg;
|
||||
spi_bus *base = &bus->base;
|
||||
|
||||
msg = bus->msg;
|
||||
|
||||
if (
|
||||
msg->speed_hz != base->speed_hz
|
||||
|| msg->mode != base->mode
|
||||
|| msg->cs != base->cs
|
||||
) {
|
||||
cadence_spi_config(
|
||||
bus,
|
||||
regs,
|
||||
msg->speed_hz,
|
||||
msg->mode,
|
||||
msg->delay_usecs,
|
||||
msg->cs
|
||||
);
|
||||
}
|
||||
|
||||
if ((msg->mode & SPI_NO_CS) != 0) {
|
||||
cadence_spi_set_chipsel(bus, CADENCE_SPI_CS_NONE);
|
||||
}
|
||||
|
||||
bus->todo = msg->len;
|
||||
bus->rx_buf = msg->rx_buf;
|
||||
bus->tx_buf = msg->tx_buf;
|
||||
cadence_spi_push(bus, regs);
|
||||
|
||||
cadence_spi_disable_interrupts(regs);
|
||||
if (bus->todo < CADENCE_SPI_FIFO_SIZE) {
|
||||
/* if the msg fits into the FIFO for empty TX buffer */
|
||||
regs->txthreshold = 1;
|
||||
|
||||
} else {
|
||||
/* if the msg does not fit refill tx_buf when the threshold is hit */
|
||||
regs->txthreshold = CADENCE_SPI_FIFO_SIZE / 2;
|
||||
}
|
||||
regs->irqenable = CADENCE_SPI_IXR_TXOW;
|
||||
regs->spienable = 1;
|
||||
} else {
|
||||
cadence_spi_done(bus);
|
||||
}
|
||||
}
|
||||
|
||||
static void cadence_spi_interrupt(void *arg)
|
||||
{
|
||||
cadence_spi_bus *bus;
|
||||
volatile cadence_spi *regs;
|
||||
|
||||
bus = arg;
|
||||
regs = bus->regs;
|
||||
|
||||
/* The RXNEMPTY flag is sometimes not cleared fast
|
||||
* enough between 2 reads which could lead to
|
||||
* reading an extra byte erroneously. Therefore,
|
||||
* also check the in_transfer counter
|
||||
*/
|
||||
while (cadence_spi_rx_fifo_not_empty(regs)
|
||||
&& bus->in_transfer > 0) {
|
||||
uint32_t val = regs->rxdata;
|
||||
if (bus->rx_buf != NULL) {
|
||||
*bus->rx_buf = (uint8_t)val;
|
||||
++bus->rx_buf;
|
||||
}
|
||||
--bus->in_transfer;
|
||||
}
|
||||
|
||||
if (bus->todo > 0) {
|
||||
cadence_spi_push(bus, regs);
|
||||
} else if (bus->in_transfer > 0) {
|
||||
/* Wait until all bytes have been transfered */
|
||||
regs->txthreshold = 1;
|
||||
} else {
|
||||
--bus->msg_todo;
|
||||
++bus->msg;
|
||||
cadence_spi_next_msg(bus, regs);
|
||||
}
|
||||
}
|
||||
|
||||
static int cadence_spi_check_messages(
|
||||
cadence_spi_bus *bus,
|
||||
const spi_ioc_transfer *msg,
|
||||
uint32_t size)
|
||||
{
|
||||
while(size > 0) {
|
||||
if (msg->bits_per_word != 8) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((msg->mode &
|
||||
~(SPI_CPHA | SPI_CPOL | SPI_NO_CS)) != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((msg->mode & SPI_NO_CS) == 0 &&
|
||||
(msg->cs > CADENCE_SPI_MAX_CHIPSELECTS)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
++msg;
|
||||
--size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cadence_spi_transfer(
|
||||
spi_bus *base,
|
||||
const spi_ioc_transfer *msgs,
|
||||
uint32_t n
|
||||
)
|
||||
{
|
||||
cadence_spi_bus *bus;
|
||||
int rv;
|
||||
|
||||
bus = (cadence_spi_bus *) base;
|
||||
|
||||
rv = cadence_spi_check_messages(bus, msgs, n);
|
||||
|
||||
if (rv == 0) {
|
||||
bus->msg_todo = n;
|
||||
bus->msg = &msgs[0];
|
||||
bus->task_id = rtems_task_self();
|
||||
|
||||
cadence_spi_next_msg(bus, bus->regs);
|
||||
rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
cadence_spi_set_chipsel(bus, CADENCE_SPI_CS_NONE);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void cadence_spi_destroy(spi_bus *base)
|
||||
{
|
||||
cadence_spi_bus *bus;
|
||||
|
||||
bus = (cadence_spi_bus *) base;
|
||||
rtems_interrupt_handler_remove(bus->irq, cadence_spi_interrupt, bus);
|
||||
spi_bus_destroy_and_free(&bus->base);
|
||||
}
|
||||
|
||||
static int cadence_spi_setup(spi_bus *base)
|
||||
{
|
||||
cadence_spi_bus *bus;
|
||||
uint32_t mode = base->mode;
|
||||
|
||||
bus = (cadence_spi_bus *) base;
|
||||
|
||||
/* Baud rate divider is at least 4 and at most 256 */
|
||||
if (
|
||||
base->speed_hz > base->max_speed_hz
|
||||
|| base->speed_hz < (bus->clk_in / 256)
|
||||
|| bus->base.bits_per_word > 8
|
||||
) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* SPI_CS_HIGH and SPI_LOOP not supported */
|
||||
if ((mode & SPI_CS_HIGH) || (mode & SPI_LOOP)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cadence_spi_config(
|
||||
bus,
|
||||
bus->regs,
|
||||
base->speed_hz,
|
||||
base->mode,
|
||||
base->delay_usecs,
|
||||
base->cs
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_bus_register_cadence(const char *bus_path,
|
||||
uintptr_t register_base,
|
||||
uint32_t input_clock,
|
||||
rtems_vector_number irq)
|
||||
{
|
||||
cadence_spi_bus *bus;
|
||||
spi_bus *base;
|
||||
int sc;
|
||||
|
||||
bus = (cadence_spi_bus *) spi_bus_alloc_and_init(sizeof(*bus));
|
||||
if (bus == NULL){
|
||||
return -1;
|
||||
}
|
||||
|
||||
base = &bus->base;
|
||||
bus->regs = (volatile cadence_spi *) register_base;
|
||||
bus->clk_in = input_clock;
|
||||
bus->clk_per_usecs = input_clock / 1000000;
|
||||
bus->irq = irq;
|
||||
|
||||
/* The minimum clock divider is 4 */
|
||||
base->max_speed_hz = (input_clock + 3) / 4;
|
||||
base->delay_usecs = 0;
|
||||
base->speed_hz = base->max_speed_hz;
|
||||
base->cs = SPI_NO_CS;
|
||||
|
||||
cadence_spi_reset(bus);
|
||||
cadence_spi_config(
|
||||
bus,
|
||||
bus->regs,
|
||||
base->speed_hz,
|
||||
base->mode,
|
||||
base->delay_usecs,
|
||||
base->cs
|
||||
);
|
||||
|
||||
|
||||
sc = rtems_interrupt_handler_install(
|
||||
bus->irq,
|
||||
"CASPI",
|
||||
RTEMS_INTERRUPT_UNIQUE,
|
||||
cadence_spi_interrupt,
|
||||
bus
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
(*bus->base.destroy)(&bus->base);
|
||||
rtems_set_errno_and_return_minus_one(EAGAIN);
|
||||
}
|
||||
|
||||
bus->base.transfer = cadence_spi_transfer;
|
||||
bus->base.destroy = cadence_spi_destroy;
|
||||
bus->base.setup = cadence_spi_setup;
|
||||
|
||||
return spi_bus_register(&bus->base, bus_path);
|
||||
}
|
||||
402
bsps/arm/shared/spi/xilinx-axi-spi.c
Normal file
402
bsps/arm/shared/spi/xilinx-axi-spi.c
Normal file
@@ -0,0 +1,402 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include <bsp.h>
|
||||
|
||||
#include <rtems/irq-extension.h>
|
||||
#include <sys/param.h> /* MAX() */
|
||||
|
||||
#include <dev/spi/spi.h>
|
||||
#include <bsp/xilinx-axi-spi.h>
|
||||
#include <bsp/xilinx-axi-spi-regs.h>
|
||||
|
||||
#define XILINX_AXI_SPI_CS_NONE 0xFF
|
||||
|
||||
typedef struct xilinx_axi_spi_bus xilinx_axi_spi_bus;
|
||||
|
||||
struct xilinx_axi_spi_bus {
|
||||
spi_bus base;
|
||||
volatile xilinx_axi_spi *regs;
|
||||
uint32_t fifo_size;
|
||||
uint32_t num_cs;
|
||||
uint32_t msg_todo;
|
||||
const spi_ioc_transfer *msg;
|
||||
uint32_t todo;
|
||||
uint32_t in_transfer;
|
||||
uint8_t *rx_buf;
|
||||
const uint8_t *tx_buf;
|
||||
rtems_id task_id;
|
||||
rtems_vector_number irq;
|
||||
};
|
||||
|
||||
|
||||
static void xilinx_axi_spi_disable_interrupts(volatile xilinx_axi_spi *regs)
|
||||
{
|
||||
regs->globalirq = 0;
|
||||
regs->irqenable = 0;
|
||||
}
|
||||
|
||||
static bool xilinx_axi_spi_rx_fifo_not_empty(volatile xilinx_axi_spi *regs)
|
||||
{
|
||||
return (regs->status & XILINX_AXI_SPI_STATUS_RXEMPTY) == 0;
|
||||
}
|
||||
|
||||
static void xilinx_axi_spi_reset(xilinx_axi_spi_bus *bus)
|
||||
{
|
||||
volatile xilinx_axi_spi *regs = bus->regs;
|
||||
uint32_t control;
|
||||
|
||||
/* Initiate soft reset for initial state */
|
||||
regs->reset = XILINX_AXI_SPI_RESET;
|
||||
|
||||
/* Configure as master */
|
||||
control = regs->control;
|
||||
control |= XILINX_AXI_SPI_CONTROL_MSTREN;
|
||||
regs->control = control;
|
||||
}
|
||||
|
||||
static void xilinx_axi_spi_done(xilinx_axi_spi_bus *bus)
|
||||
{
|
||||
volatile xilinx_axi_spi *regs = bus->regs;
|
||||
uint32_t control = regs->control;
|
||||
control &= ~XILINX_AXI_SPI_CONTROL_SPIEN;
|
||||
regs->control = control;
|
||||
|
||||
xilinx_axi_spi_disable_interrupts(regs);
|
||||
rtems_event_transient_send(bus->task_id);
|
||||
}
|
||||
|
||||
static void xilinx_axi_spi_push(xilinx_axi_spi_bus *bus, volatile xilinx_axi_spi *regs)
|
||||
{
|
||||
while (bus->todo > 0 && bus->in_transfer < bus->fifo_size) {
|
||||
uint8_t val = 0;
|
||||
if (bus->tx_buf != NULL) {
|
||||
val = *bus->tx_buf;
|
||||
++bus->tx_buf;
|
||||
}
|
||||
|
||||
--bus->todo;
|
||||
regs->txdata = val;
|
||||
++bus->in_transfer;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xilinx_axi_spi_set_chipsel(xilinx_axi_spi_bus *bus, uint32_t cs)
|
||||
{
|
||||
|
||||
volatile xilinx_axi_spi *regs = bus->regs;
|
||||
uint32_t cs_bit = XILINX_AXI_SPI_CS_NONE;
|
||||
|
||||
if (cs != SPI_NO_CS && cs < bus->num_cs) {
|
||||
cs_bit &= ~(1<<cs);
|
||||
}
|
||||
bus->base.cs = cs;
|
||||
|
||||
regs->cs = cs_bit;
|
||||
}
|
||||
|
||||
static void xilinx_axi_spi_config(
|
||||
xilinx_axi_spi_bus *bus,
|
||||
volatile xilinx_axi_spi *regs,
|
||||
uint32_t mode,
|
||||
uint8_t cs
|
||||
)
|
||||
{
|
||||
spi_bus *base = &bus->base;
|
||||
uint32_t control = regs->control;
|
||||
|
||||
control &= ~XILINX_AXI_SPI_CONTROL_SPIEN;
|
||||
regs->control = control;
|
||||
|
||||
if ((mode & SPI_CPHA) != 0) {
|
||||
control |= XILINX_AXI_SPI_CONTROL_CPHA;
|
||||
} else {
|
||||
control &= ~XILINX_AXI_SPI_CONTROL_CPHA;
|
||||
}
|
||||
|
||||
if ((mode & SPI_CPOL) != 0) {
|
||||
control |= XILINX_AXI_SPI_CONTROL_CPOL;
|
||||
} else {
|
||||
control &= ~XILINX_AXI_SPI_CONTROL_CPOL;
|
||||
}
|
||||
|
||||
if ((mode & SPI_LOOP) != 0) {
|
||||
control |= XILINX_AXI_SPI_CONTROL_LOOP;
|
||||
} else {
|
||||
control &= ~XILINX_AXI_SPI_CONTROL_LOOP;
|
||||
}
|
||||
|
||||
regs->control = control;
|
||||
xilinx_axi_spi_set_chipsel(bus, cs);
|
||||
|
||||
base->mode = mode;
|
||||
base->cs = cs;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
xilinx_axi_spi_next_msg(xilinx_axi_spi_bus *bus, volatile xilinx_axi_spi *regs)
|
||||
{
|
||||
uint32_t control = regs->control;
|
||||
control |= XILINX_AXI_SPI_CONTROL_MST_TRANS_INHIBIT
|
||||
| XILINX_AXI_SPI_CONTROL_RX_FIFO_RESET
|
||||
| XILINX_AXI_SPI_CONTROL_TX_FIFO_RESET;
|
||||
regs->control = control;
|
||||
|
||||
if (bus->msg_todo > 0) {
|
||||
const spi_ioc_transfer *msg;
|
||||
spi_bus *base = &bus->base;
|
||||
|
||||
msg = bus->msg;
|
||||
|
||||
if (
|
||||
msg->mode != base->mode
|
||||
|| msg->cs != base->cs
|
||||
) {
|
||||
xilinx_axi_spi_config(
|
||||
bus,
|
||||
regs,
|
||||
msg->mode,
|
||||
msg->cs
|
||||
);
|
||||
}
|
||||
|
||||
if ((msg->mode & SPI_NO_CS) != 0) {
|
||||
xilinx_axi_spi_set_chipsel(bus, XILINX_AXI_SPI_CS_NONE);
|
||||
}
|
||||
|
||||
bus->todo = msg->len;
|
||||
bus->rx_buf = msg->rx_buf;
|
||||
bus->tx_buf = msg->tx_buf;
|
||||
xilinx_axi_spi_push(bus, regs);
|
||||
|
||||
xilinx_axi_spi_disable_interrupts(regs);
|
||||
if (
|
||||
bus->todo < bus->fifo_size
|
||||
|| bus->fifo_size == 1) {
|
||||
/* if the msg fits into the FIFO, wait for empty TX buffer */
|
||||
regs->irqenable = XILINX_AXI_SPI_IRQ_TXEMPTY;
|
||||
|
||||
} else {
|
||||
/* if the msg does not fit, refill tx_buf when the tx FIFO is half empty */
|
||||
regs->irqenable = XILINX_AXI_SPI_IRQ_TXHALF;
|
||||
}
|
||||
regs->globalirq = XILINX_AXI_SPI_GLOBAL_IRQ_ENABLE;
|
||||
control = regs->control;
|
||||
control |= XILINX_AXI_SPI_CONTROL_SPIEN;
|
||||
control &= ~XILINX_AXI_SPI_CONTROL_MST_TRANS_INHIBIT;
|
||||
regs->control = control;
|
||||
} else {
|
||||
xilinx_axi_spi_done(bus);
|
||||
}
|
||||
}
|
||||
|
||||
static void xilinx_axi_spi_interrupt(void *arg)
|
||||
{
|
||||
xilinx_axi_spi_bus *bus;
|
||||
volatile xilinx_axi_spi *regs;
|
||||
|
||||
bus = arg;
|
||||
regs = bus->regs;
|
||||
|
||||
/* Clear interrupt flag. It's safe, since only one IRQ active at a time */
|
||||
regs->irqstatus = regs->irqenable;
|
||||
|
||||
while (xilinx_axi_spi_rx_fifo_not_empty(regs)) {
|
||||
uint32_t val = regs->rxdata;
|
||||
if (bus->rx_buf != NULL) {
|
||||
*bus->rx_buf = (uint8_t)val;
|
||||
++bus->rx_buf;
|
||||
}
|
||||
--bus->in_transfer;
|
||||
}
|
||||
|
||||
if (bus->todo > 0) {
|
||||
xilinx_axi_spi_push(bus, regs);
|
||||
} else if (bus->in_transfer > 0) {
|
||||
/* Wait until all bytes have been transfered */
|
||||
regs->irqenable = XILINX_AXI_SPI_IRQ_TXEMPTY;
|
||||
} else {
|
||||
--bus->msg_todo;
|
||||
++bus->msg;
|
||||
xilinx_axi_spi_next_msg(bus, regs);
|
||||
}
|
||||
}
|
||||
|
||||
static int xilinx_axi_spi_check_messages(
|
||||
xilinx_axi_spi_bus *bus,
|
||||
const spi_ioc_transfer *msg,
|
||||
uint32_t size)
|
||||
{
|
||||
while(size > 0) {
|
||||
if (msg->bits_per_word != 8) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((msg->mode &
|
||||
~(SPI_CPHA | SPI_CPOL | SPI_NO_CS)) != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((msg->mode & SPI_NO_CS) == 0 &&
|
||||
(msg->cs > bus->num_cs)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
++msg;
|
||||
--size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xilinx_axi_spi_transfer(
|
||||
spi_bus *base,
|
||||
const spi_ioc_transfer *msgs,
|
||||
uint32_t n
|
||||
)
|
||||
{
|
||||
xilinx_axi_spi_bus *bus;
|
||||
int rv;
|
||||
|
||||
bus = (xilinx_axi_spi_bus *) base;
|
||||
|
||||
rv = xilinx_axi_spi_check_messages(bus, msgs, n);
|
||||
|
||||
if (rv == 0) {
|
||||
bus->msg_todo = n;
|
||||
bus->msg = &msgs[0];
|
||||
bus->task_id = rtems_task_self();
|
||||
|
||||
xilinx_axi_spi_next_msg(bus, bus->regs);
|
||||
rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
xilinx_axi_spi_set_chipsel(bus, XILINX_AXI_SPI_CS_NONE);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void xilinx_axi_spi_destroy(spi_bus *base)
|
||||
{
|
||||
xilinx_axi_spi_bus *bus;
|
||||
|
||||
bus = (xilinx_axi_spi_bus *) base;
|
||||
rtems_interrupt_handler_remove(bus->irq, xilinx_axi_spi_interrupt, bus);
|
||||
spi_bus_destroy_and_free(&bus->base);
|
||||
}
|
||||
|
||||
static int xilinx_axi_spi_setup(spi_bus *base)
|
||||
{
|
||||
xilinx_axi_spi_bus *bus;
|
||||
uint32_t mode = base->mode;
|
||||
|
||||
bus = (xilinx_axi_spi_bus *) base;
|
||||
|
||||
if (bus->base.bits_per_word > 8) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* SPI_CS_HIGH not supported */
|
||||
if (mode & SPI_CS_HIGH) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
xilinx_axi_spi_config(
|
||||
bus,
|
||||
bus->regs,
|
||||
base->mode,
|
||||
base->cs
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_bus_register_xilinx_axi(
|
||||
const char *bus_path,
|
||||
uintptr_t register_base,
|
||||
uint32_t fifo_size,
|
||||
uint32_t num_cs,
|
||||
rtems_vector_number irq)
|
||||
{
|
||||
xilinx_axi_spi_bus *bus;
|
||||
spi_bus *base;
|
||||
int sc;
|
||||
|
||||
if (fifo_size != 0 && fifo_size != 16 && fifo_size != 256) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (num_cs > 32) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bus = (xilinx_axi_spi_bus *) spi_bus_alloc_and_init(sizeof(*bus));
|
||||
if (bus == NULL){
|
||||
return -1;
|
||||
}
|
||||
|
||||
base = &bus->base;
|
||||
bus->regs = (volatile xilinx_axi_spi *) register_base;
|
||||
bus->irq = irq;
|
||||
bus->num_cs = num_cs;
|
||||
|
||||
/* For operation without FIFO set fifo_size to 1
|
||||
* so that comparison operators work
|
||||
*/
|
||||
if (fifo_size == 0) {
|
||||
bus->fifo_size = 1;
|
||||
} else {
|
||||
bus->fifo_size = fifo_size;
|
||||
}
|
||||
|
||||
base->cs = SPI_NO_CS;
|
||||
|
||||
xilinx_axi_spi_reset(bus);
|
||||
xilinx_axi_spi_config(
|
||||
bus,
|
||||
bus->regs,
|
||||
base->mode,
|
||||
base->cs
|
||||
);
|
||||
|
||||
|
||||
sc = rtems_interrupt_handler_install(
|
||||
bus->irq,
|
||||
"XSPI",
|
||||
RTEMS_INTERRUPT_UNIQUE,
|
||||
xilinx_axi_spi_interrupt,
|
||||
bus
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
(*bus->base.destroy)(&bus->base);
|
||||
rtems_set_errno_and_return_minus_one(EAGAIN);
|
||||
}
|
||||
|
||||
bus->base.transfer = xilinx_axi_spi_transfer;
|
||||
bus->base.destroy = xilinx_axi_spi_destroy;
|
||||
bus->base.setup = xilinx_axi_spi_setup;
|
||||
|
||||
return spi_bus_register(&bus->base, bus_path);
|
||||
}
|
||||
@@ -34,6 +34,7 @@ include_grlib_HEADERS += ../../bsps/include/grlib/apbuart_termios.h
|
||||
include_grlib_HEADERS += ../../bsps/include/grlib/b1553brm.h
|
||||
include_grlib_HEADERS += ../../bsps/include/grlib/b1553rt.h
|
||||
include_grlib_HEADERS += ../../bsps/include/grlib/bspcommon.h
|
||||
include_grlib_HEADERS += ../../bsps/include/grlib/canbtrs.h
|
||||
include_grlib_HEADERS += ../../bsps/include/grlib/canmux.h
|
||||
include_grlib_HEADERS += ../../bsps/include/grlib/cons.h
|
||||
include_grlib_HEADERS += ../../bsps/include/grlib/debug_defs.h
|
||||
|
||||
@@ -104,48 +104,60 @@ static uint32_t pc386_get_timecount_i8254(struct timecounter *tc)
|
||||
|
||||
/*
|
||||
* Calibrate CPU cycles per tick. Interrupts should be disabled.
|
||||
* Will also set the PIT, so call this before registering the
|
||||
* periodic timer for rtems tick generation
|
||||
*/
|
||||
static void calibrate_tsc(void)
|
||||
{
|
||||
uint64_t begin_time;
|
||||
uint8_t then_lsb, then_msb, now_lsb, now_msb;
|
||||
uint32_t i;
|
||||
uint8_t lsb, msb;
|
||||
uint32_t max_timer_value;
|
||||
uint32_t last_tick, cur_tick;
|
||||
int32_t diff, remaining;
|
||||
|
||||
/*
|
||||
* We just reset the timer, so we know we're at the beginning of a tick.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Count cycles. Watching the timer introduces a several microsecond
|
||||
* uncertaintity, so let it cook for a while and divide by the number of
|
||||
* ticks actually executed.
|
||||
*/
|
||||
/* Set the timer to free running mode */
|
||||
outport_byte(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_INTTC);
|
||||
/* Reset the 16 timer reload value, first LSB, then MSB */
|
||||
outport_byte(TIMER_CNTR0, 0);
|
||||
outport_byte(TIMER_CNTR0, 0);
|
||||
/* We use the full 16 bit */
|
||||
max_timer_value = 0xffff;
|
||||
/* Calibrate for 1s, i.e. TIMER_TICK PIT ticks */
|
||||
remaining = TIMER_TICK;
|
||||
|
||||
begin_time = rdtsc();
|
||||
|
||||
for (i = rtems_clock_get_ticks_per_second() * pc386_isrs_per_tick;
|
||||
i != 0; --i ) {
|
||||
/* We know we've just completed a tick when timer goes from low to high */
|
||||
then_lsb = then_msb = 0xff;
|
||||
do {
|
||||
READ_8254(now_lsb, now_msb);
|
||||
if ((then_msb < now_msb) ||
|
||||
((then_msb == now_msb) && (then_lsb < now_lsb)))
|
||||
break;
|
||||
then_lsb = now_lsb;
|
||||
then_msb = now_msb;
|
||||
} while (1);
|
||||
READ_8254(lsb, msb);
|
||||
last_tick = (msb << 8) | lsb;
|
||||
while(remaining > 0) {
|
||||
READ_8254(lsb, msb);
|
||||
cur_tick = (msb << 8) | lsb;
|
||||
/* PIT counts down, so subtract cur from last */
|
||||
diff = last_tick - cur_tick;
|
||||
last_tick = cur_tick;
|
||||
if (diff < 0) {
|
||||
diff += max_timer_value;
|
||||
}
|
||||
remaining -= diff;
|
||||
}
|
||||
|
||||
pc586_tsc_frequency = rdtsc() - begin_time;
|
||||
|
||||
#if 0
|
||||
printk( "CPU clock at %u MHz\n", (uint32_t)(pc586_tsc_frequency / 1000000));
|
||||
printk( "CPU clock at %u Hz\n", (uint32_t)(pc586_tsc_frequency ));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void clockOn(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* First calibrate the TSC. Do this every time we
|
||||
* turn the clock on in case the CPU clock speed has changed.
|
||||
*/
|
||||
if ( x86_has_tsc() ) {
|
||||
calibrate_tsc();
|
||||
}
|
||||
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
pc386_isrs_per_tick = 1;
|
||||
pc386_microseconds_per_isr = rtems_configuration_get_microseconds_per_tick();
|
||||
@@ -171,13 +183,6 @@ static void clockOn(void)
|
||||
rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
|
||||
|
||||
bsp_interrupt_vector_enable( BSP_PERIODIC_TIMER );
|
||||
|
||||
/*
|
||||
* Now calibrate cycles per tick. Do this every time we
|
||||
* turn the clock on in case the CPU clock speed has changed.
|
||||
*/
|
||||
if ( x86_has_tsc() )
|
||||
calibrate_tsc();
|
||||
}
|
||||
|
||||
bool Clock_isr_enabled = false;
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 Jan Sommer, Deutsches Zentrum für Luft- und Raumfahrt e. V. (DLR)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <rtems/score/smpimpl.h>
|
||||
|
||||
|
||||
@@ -226,9 +226,11 @@ get_checksum(unsigned start, int length)
|
||||
int
|
||||
send_ipi(unsigned int dst, unsigned int v)
|
||||
{
|
||||
int to, send_status;
|
||||
int to, send_status, apicid;
|
||||
|
||||
IMPS_LAPIC_WRITE(LAPIC_ICR+0x10, (dst << 24));
|
||||
apicid = imps_cpu_apic_map[dst];
|
||||
|
||||
IMPS_LAPIC_WRITE(LAPIC_ICR+0x10, (apicid << 24));
|
||||
IMPS_LAPIC_WRITE(LAPIC_ICR, v);
|
||||
|
||||
/* Wait for send to finish */
|
||||
@@ -251,9 +253,11 @@ static int
|
||||
boot_cpu(imps_processor *proc)
|
||||
{
|
||||
int apicid = proc->apic_id, success = 1;
|
||||
int cpuid;
|
||||
unsigned bootaddr;
|
||||
unsigned bios_reset_vector = PHYS_TO_VIRTUAL(BIOS_RESET_VECTOR);
|
||||
|
||||
cpuid = imps_apic_cpu_map[apicid];
|
||||
/*
|
||||
* Copy boot code for secondary CPUs here. Find it in between
|
||||
* "patch_code_start" and "patch_code_end" symbols. The other CPUs
|
||||
@@ -276,7 +280,7 @@ boot_cpu(imps_processor *proc)
|
||||
/* Pass start function, stack region and gdtdescr to AP
|
||||
* see startAP.S for location */
|
||||
reset[1] = (uint32_t)secondary_cpu_initialize;
|
||||
reset[2] = (uint32_t)_Per_CPU_Get_by_index(apicid)->interrupt_stack_high;
|
||||
reset[2] = (uint32_t)_Per_CPU_Get_by_index(cpuid)->interrupt_stack_high;
|
||||
memcpy(
|
||||
(char*) &reset[3],
|
||||
&gdtdesc,
|
||||
@@ -295,13 +299,13 @@ boot_cpu(imps_processor *proc)
|
||||
|
||||
/* assert INIT IPI */
|
||||
send_ipi(
|
||||
apicid,
|
||||
cpuid,
|
||||
LAPIC_ICR_TM_LEVEL | LAPIC_ICR_LEVELASSERT | LAPIC_ICR_DM_INIT
|
||||
);
|
||||
UDELAY(10000);
|
||||
|
||||
/* de-assert INIT IPI */
|
||||
send_ipi(apicid, LAPIC_ICR_TM_LEVEL | LAPIC_ICR_DM_INIT);
|
||||
send_ipi(cpuid, LAPIC_ICR_TM_LEVEL | LAPIC_ICR_DM_INIT);
|
||||
|
||||
UDELAY(10000);
|
||||
|
||||
@@ -312,7 +316,7 @@ boot_cpu(imps_processor *proc)
|
||||
if (proc->apic_ver >= APIC_VER_NEW) {
|
||||
int i;
|
||||
for (i = 1; i <= 2; i++) {
|
||||
send_ipi(apicid, LAPIC_ICR_DM_SIPI | ((bootaddr >> 12) & 0xFF));
|
||||
send_ipi(cpuid, LAPIC_ICR_DM_SIPI | ((bootaddr >> 12) & 0xFF));
|
||||
UDELAY(1000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
@@ -5,9 +7,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (C) 2019 embedded brains GmbH
|
||||
* Copyright (C) 2019 embedded brains GmbH (http://www.embedded-brains.de)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
||||
@@ -1,27 +1,43 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup bsp_interrupt
|
||||
*
|
||||
* @brief Generic BSP interrupt support API.
|
||||
* @brief This header file provides interfaces of the generic interrupt
|
||||
* controller support.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
|
||||
* Copyright (C) 2016 Chris Johns <chrisj@rtems.org>
|
||||
*
|
||||
* Copyright (c) 2008, 2017 embedded brains GmbH.
|
||||
* Copyright (C) 2008, 2017 embedded brains GmbH (http://www.embedded-brains.de)
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The API is based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
|
||||
*/
|
||||
|
||||
#ifndef LIBBSP_SHARED_IRQ_GENERIC_H
|
||||
|
||||
@@ -1,22 +1,37 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup bsp_interrupt
|
||||
*
|
||||
* @brief Generic BSP interrupt information API.
|
||||
* @brief This header file provides interfaces of the generic interrupt
|
||||
* controller support for the RTEMS Shell.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008, 2009
|
||||
* embedded brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* D-82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
* Copyright (C) 2008, 2009 embedded brains GmbH (http://www.embedded-brains.de)
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LIBBSP_SHARED_IRQ_INFO_H
|
||||
|
||||
@@ -21,6 +21,8 @@ extern "C" {
|
||||
struct ahbstat_regs {
|
||||
volatile uint32_t status;
|
||||
volatile uint32_t failing;
|
||||
volatile uint32_t status2;
|
||||
volatile uint32_t failing2;
|
||||
};
|
||||
|
||||
/* AHB fail interrupt callback to user. This function is declared weak so that
|
||||
|
||||
@@ -226,6 +226,25 @@
|
||||
#define GAISLER_SPIMASTER 0x0a6
|
||||
#define GAISLER_SPISLAVE 0x0a7
|
||||
#define GAISLER_GRSRIO 0x0a8
|
||||
#define GAISLER_AHBLM2AHB 0x0a9
|
||||
#define GAISLER_AHBS2NOC 0x0aa
|
||||
#define GAISLER_TCAU 0x0ab
|
||||
#define GAISLER_GRTMDYNVCID 0x0ac
|
||||
#define GAISLER_RNOCIRQPROP 0x0ad
|
||||
#define GAISLER_FTADDR 0x0ae
|
||||
#define GAISLER_ATG 0x0b0
|
||||
#define GAISLER_DFITRACE 0x0b1
|
||||
#define GAISLER_SELFTEST 0x0b2
|
||||
#define GAISLER_DFIERRINJ 0x0b3
|
||||
#define GAISLER_DFICHECK 0x0b4
|
||||
#define GAISLER_GRCANFD 0x0b5
|
||||
#define GAISLER_NIM 0x0b6
|
||||
#define GAISLER_BANDGAP 0x1f0
|
||||
#define GAISLER_MPROT 0x1f1
|
||||
#define GAISLER_ADC 0x1f2
|
||||
#define GAISLER_BO 0x1f3
|
||||
#define GAISLER_DAC 0x1f4
|
||||
#define GAISLER_PLL 0x1f6
|
||||
|
||||
#define GAISLER_PIPEWRAPPER 0xffa
|
||||
#define GAISLER_L2TIME 0xffd /* internal device: leon2 timer */
|
||||
|
||||
94
bsps/include/grlib/canbtrs.h
Normal file
94
bsps/include/grlib/canbtrs.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup can
|
||||
* @brief Common CAN baud-rate routines for OCCAN/GRCAN/GRCANFD controllers
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019, 2020 Cobham Gaisler AB
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __GRLIB_CANBTRS_H__
|
||||
#define __GRLIB_CANBTRS_H__
|
||||
|
||||
/**
|
||||
* @defgroup can CAN
|
||||
*
|
||||
* @ingroup RTEMSBSPsSharedGRLIB
|
||||
*
|
||||
* @brief CAN routines shared between OCCAN, GRCAN and GRCANFD controllers
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* CAN Baud-rate parameters, range of valid parameter values */
|
||||
struct grlib_canbtrs_ranges {
|
||||
unsigned int max_scaler;
|
||||
char has_bpr;
|
||||
unsigned char divfactor;
|
||||
unsigned char min_tseg1;
|
||||
unsigned char max_tseg1;
|
||||
unsigned char min_tseg2;
|
||||
unsigned char max_tseg2;
|
||||
};
|
||||
|
||||
struct grlib_canbtrs_timing {
|
||||
unsigned char scaler;
|
||||
unsigned char ps1;
|
||||
unsigned char ps2;
|
||||
unsigned char rsj;
|
||||
unsigned char bpr;
|
||||
};
|
||||
|
||||
/* @brief Calculate CAN baud-rate generation parameters from requested baud-rate
|
||||
*
|
||||
* @param baud The CAN baud rate requested
|
||||
* @param core_hz Input clock [Hz] to CAN core
|
||||
* @param sampl_pt CAN sample point in %, 80 means 80%
|
||||
* @param br CAN Baud-rate parameters limitations
|
||||
* @param[out] timing result is placed here
|
||||
*
|
||||
* @retval 0 Baud-rate parameters sucessfully calculated
|
||||
* @retval negative Failure to generate parameters with less than 5% error
|
||||
* margin from requested baud-rate
|
||||
*/
|
||||
int grlib_canbtrs_calc_timing(
|
||||
unsigned int baud,
|
||||
unsigned int core_hz,
|
||||
unsigned int sampl_pt,
|
||||
struct grlib_canbtrs_ranges *br,
|
||||
struct grlib_canbtrs_timing *timing
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* @file
|
||||
* @ingroup can
|
||||
* @brief Driver API for the GRLIB GRCAN and GRCANFD controllers
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -25,6 +26,8 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -37,7 +40,13 @@ struct grcan_regs {
|
||||
volatile unsigned int smask; /* 0x18 */
|
||||
volatile unsigned int scode; /* 0x1C */
|
||||
|
||||
volatile unsigned int dummy1[56]; /* 0x20-0xFC */
|
||||
volatile unsigned int dummy1[8]; /* 0x20-0x3C */
|
||||
|
||||
volatile unsigned int nbtr; /* 0x40 */
|
||||
volatile unsigned int fdbtr; /* 0x44 */
|
||||
volatile unsigned int tdelay; /* 0x48 */
|
||||
|
||||
volatile unsigned int dummy1b[45]; /* 0x4C-0xFC */
|
||||
|
||||
volatile unsigned int pimsr; /* 0x100 */
|
||||
volatile unsigned int pimr; /* 0x104 */
|
||||
@@ -82,10 +91,18 @@ struct grcan_timing {
|
||||
unsigned char scaler;
|
||||
unsigned char ps1;
|
||||
unsigned char ps2;
|
||||
unsigned int rsj;
|
||||
unsigned char rsj;
|
||||
unsigned char bpr;
|
||||
};
|
||||
|
||||
struct grcanfd_timing {
|
||||
unsigned char scaler;
|
||||
unsigned char ps1;
|
||||
unsigned char ps2;
|
||||
unsigned char sjw;
|
||||
unsigned char resv_zero;
|
||||
};
|
||||
|
||||
struct grcan_selection {
|
||||
int selection;
|
||||
int enable0;
|
||||
@@ -97,16 +114,34 @@ struct grcan_filter {
|
||||
unsigned long long code;
|
||||
};
|
||||
|
||||
#define GRCAN_FDOPT_NOM 0
|
||||
#define GRCAN_FDOPT_FDBTR 0x01
|
||||
#define GRCAN_FDOPT_FDFRM 0x02
|
||||
#define GRCAN_FDMASK (GRCAN_FDOPT_FDBTR | GRCAN_FDOPT_FDFRM)
|
||||
|
||||
/* CAN MESSAGE */
|
||||
typedef struct {
|
||||
char extended; /* 1= Extended Frame (29-bit id), 0= STD Frame (11-bit id) */
|
||||
char rtr; /* RTR - Remote Transmission Request */
|
||||
char unused; /* unused */
|
||||
char unused; /* Must be 0 to select classic CAN frame */
|
||||
unsigned char len;
|
||||
unsigned char data[8];
|
||||
unsigned int id;
|
||||
} CANMsg;
|
||||
|
||||
/* CAN-FD MESSAGE */
|
||||
typedef struct {
|
||||
uint8_t extended; /* 1= Extended Frame (29-bit id), 0= STD Frame (11-bit id) */
|
||||
uint8_t rtr; /* RTR - Remote Transmission Request */
|
||||
uint8_t fdopts; /* Bit1: 1=Switch bit rate. bit2: 1=FD frame. */
|
||||
uint8_t len; /* 0-8, 12, 16, 20, 24, 32, 48 or 64 bytes */
|
||||
uint32_t id;
|
||||
union {
|
||||
uint64_t dwords[8]; /* up to 64 bytes if FD=1 and len>8 */
|
||||
uint8_t bytes[64]; /* up to 64 bytes if FD=1 and len>8 */
|
||||
} data;
|
||||
} CANFDMsg;
|
||||
|
||||
enum {
|
||||
GRCAN_RET_OK = 0,
|
||||
GRCAN_RET_INVARG = -1,
|
||||
@@ -166,6 +201,26 @@ enum grcan_state {
|
||||
#define GRCAN_RXCTRL_ENABLE 1
|
||||
#define GRCAN_RXCTRL_ONGOING 1
|
||||
|
||||
#define GRCANFD_NBTR_SCALER 0x00ff0000
|
||||
#define GRCANFD_NBTR_PS1 0x0000fc00
|
||||
#define GRCANFD_NBTR_PS2 0x000003e0
|
||||
#define GRCANFD_NBTR_SJW 0x0000001f
|
||||
|
||||
#define GRCANFD_NBTR_SCALER_BIT 16
|
||||
#define GRCANFD_NBTR_PS1_BIT 10
|
||||
#define GRCANFD_NBTR_PS2_BIT 5
|
||||
#define GRCANFD_NBTR_SJW_BIT 0
|
||||
|
||||
#define GRCANFD_FDBTR_SCALER 0x00ff0000
|
||||
#define GRCANFD_FDBTR_PS1 0x00003c00
|
||||
#define GRCANFD_FDBTR_PS2 0x000001e0
|
||||
#define GRCANFD_FDBTR_SJW 0x0000000f
|
||||
|
||||
#define GRCANFD_FDBTR_SCALER_BIT 16
|
||||
#define GRCANFD_FDBTR_PS1_BIT 10
|
||||
#define GRCANFD_FDBTR_PS2_BIT 5
|
||||
#define GRCANFD_FDBTR_SJW_BIT 0
|
||||
|
||||
/* Relative offset of IRQ sources to AMBA Plug&Play */
|
||||
#define GRCAN_IRQ_IRQ 0
|
||||
#define GRCAN_IRQ_TXSYNC 1
|
||||
@@ -229,6 +284,15 @@ extern void *grcan_open_by_name(char *name, int *dev_no);
|
||||
*/
|
||||
extern int grcan_close(void *d);
|
||||
|
||||
/*
|
||||
* Returns if CAN hardware device is CANFD capable.
|
||||
*
|
||||
* dev_no: Device handle
|
||||
* return: 0=Not FD capable, 1=FD capable.
|
||||
* function returns NULL if device can not be opened.
|
||||
*/
|
||||
extern int grcan_canfd_capable(void *d);
|
||||
|
||||
/*
|
||||
* Receive CAN messages
|
||||
*
|
||||
@@ -254,6 +318,31 @@ extern int grcan_read(
|
||||
size_t count
|
||||
);
|
||||
|
||||
/*
|
||||
* Receive CAN messages (only GRCANFD)
|
||||
*
|
||||
* Multiple CAN messages can be received in one call.
|
||||
*
|
||||
* d: Device handle
|
||||
* msg: Pointer to receive messages
|
||||
* count: Number of CAN messages to receive
|
||||
*
|
||||
* return:
|
||||
* >=0: Number of CAN messages received. This can be
|
||||
* less than the count parameter.
|
||||
* GRCAN_RET_INVARG: count parameter less than one or NULL msg.
|
||||
* GRCAN_RET_NOTSTARTED: Device not in started mode
|
||||
* GRCAN_RET_TIMEOUT: Timeout in non-blocking mode
|
||||
* GRCAN_RET_BUSOFF: A read was interrupted by a bus-off error.
|
||||
* Device has left started mode.
|
||||
* GRCAN_RET_AHBERR: Similar to BUSOFF, but was caused by AHB Error.
|
||||
*/
|
||||
extern int grcanfd_read(
|
||||
void *d,
|
||||
CANFDMsg *msg,
|
||||
size_t count
|
||||
);
|
||||
|
||||
/*
|
||||
* Transmit CAN messages
|
||||
*
|
||||
@@ -279,6 +368,31 @@ extern int grcan_write(
|
||||
size_t count
|
||||
);
|
||||
|
||||
/*
|
||||
* Transmit CAN-FD complient messages (only GRCANFD)
|
||||
*
|
||||
* Multiple CAN messages can be transmit in one call.
|
||||
*
|
||||
* d: Device handle
|
||||
* msg: Pointer to messages to transmit
|
||||
* count: Number of CAN messages to transmit
|
||||
*
|
||||
* return:
|
||||
* >=0: Number of CAN messages transmitted. This can be
|
||||
* less than the count parameter.
|
||||
* GRCAN_RET_INVARG: count parameter less than one.
|
||||
* GRCAN_RET_NOTSTARTED: Device not in started mode
|
||||
* GRCAN_RET_TIMEOUT: Timeout in non-blocking mode
|
||||
* GRCAN_RET_BUSOFF: A write was interrupted by a Bus-off error.
|
||||
* Device has left started mode
|
||||
* GRCAN_RET_AHBERR: Similar to BUSOFF, but was caused by AHB Error.
|
||||
*/
|
||||
extern int grcanfd_write(
|
||||
void *d,
|
||||
CANFDMsg *msg,
|
||||
size_t ucount
|
||||
);
|
||||
|
||||
/*
|
||||
* Returns current GRCAN software state
|
||||
*
|
||||
@@ -320,6 +434,16 @@ extern int grcan_set_speed(void *d, unsigned int hz);
|
||||
/* Set baudrate by specifying the timing registers manually */
|
||||
extern int grcan_set_btrs(void *d, const struct grcan_timing *timing);
|
||||
|
||||
/* Set the Nominal and FD baudrate by using driver's baud rate timing
|
||||
* calculation routines
|
||||
*/
|
||||
extern int grcanfd_set_speed(void *d, unsigned int nomhz, unsigned int fdhz);
|
||||
/* Set Nominal and FD baudrate by specifying the timing registers manually*/
|
||||
extern int grcanfd_set_btrs(
|
||||
void *d,
|
||||
const struct grcanfd_timing *nominal,
|
||||
const struct grcanfd_timing *fd);
|
||||
|
||||
/* Functions can be called whenever */
|
||||
/* Enable/disable Blocking on reception (until at least one message has been received) */
|
||||
int grcan_set_rxblock(void* d, int block);
|
||||
|
||||
@@ -100,6 +100,7 @@ typedef struct _greth_regs {
|
||||
#define GRETH_STATUS_TXIRQ 0x00000008 /* Transmit Error IRQ */
|
||||
#define GRETH_STATUS_RXAHBERR 0x00000010 /* Receiver AHB Error */
|
||||
#define GRETH_STATUS_TXAHBERR 0x00000020 /* Transmitter AHB Error */
|
||||
#define GRETH_STATUS_NRD 0x0f000000 /* Number of descriptors */
|
||||
|
||||
/* MDIO Control */
|
||||
#define GRETH_MDIO_WRITE 0x00000001 /* MDIO Write */
|
||||
|
||||
@@ -122,6 +122,16 @@ RTEMS_INLINE_ROUTINE unsigned int grlib_read_uncached32(unsigned int address)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE uint64_t grlib_read_uncached64(uint64_t *address)
|
||||
{
|
||||
uint64_t tmp;
|
||||
__asm__ (" ldda [%1]1, %0 "
|
||||
: "=r"(tmp)
|
||||
: "r"(address)
|
||||
);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#define GRLIB_DMA_IS_CACHE_COHERENT CPU_SPARC_HAS_SNOOPING
|
||||
|
||||
#else
|
||||
|
||||
@@ -150,8 +150,8 @@ typedef enum {
|
||||
SPW_LS_ERRRST = 0,
|
||||
SPW_LS_ERRWAIT = 1,
|
||||
SPW_LS_READY = 2,
|
||||
SPW_LS_CONNECTING = 3,
|
||||
SPW_LS_STARTED = 4,
|
||||
SPW_LS_STARTED = 3,
|
||||
SPW_LS_CONNECTING = 4,
|
||||
SPW_LS_RUN = 5
|
||||
} spw_link_state_t;
|
||||
|
||||
|
||||
@@ -343,6 +343,7 @@ extern int router_port_enable(void *d, int port);
|
||||
extern int router_port_disable(void *d, int port);
|
||||
extern int router_port_link_stop(void *d, int port);
|
||||
extern int router_port_link_start(void *d, int port);
|
||||
extern int router_port_link_div(void *d, int port, int rundiv);
|
||||
extern int router_port_link_receive_spill(void *d, int port);
|
||||
extern int router_port_link_transmit_reset(void *d, int port);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file
|
||||
* @ingroup can
|
||||
* @brief Gaisler wrapper to OpenCores CAN - driver interface
|
||||
* @brief Driver API for GRLIB wrapper to OpenCores CAN
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -91,13 +91,13 @@ SECTIONS
|
||||
* crtn.o are in.
|
||||
*/
|
||||
PROVIDE (_init = .);
|
||||
*crti.o(.init)
|
||||
*(.init)
|
||||
*crtn.o(.init)
|
||||
KEEP (*crti.o(.init))
|
||||
KEEP (*(.init))
|
||||
KEEP (*crtn.o(.init))
|
||||
PROVIDE (_fini = .);
|
||||
*crti.o(.fini)
|
||||
*(.fini)
|
||||
*crtn.o(.fini)
|
||||
KEEP (*crti.o(.fini))
|
||||
KEEP (*(.fini))
|
||||
KEEP (*crtn.o(.fini))
|
||||
|
||||
/*
|
||||
* Special FreeBSD sysctl sections.
|
||||
@@ -122,18 +122,22 @@ SECTIONS
|
||||
* crtend.o. The same comments apply to it.
|
||||
*/
|
||||
. = ALIGN (16);
|
||||
*crtbegin.o(.ctors)
|
||||
*(.ctors)
|
||||
*crtend.o(.ctors)
|
||||
*crtbegin.o(.dtors)
|
||||
*(.dtors)
|
||||
*crtend.o(.dtors)
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*crtbegin?.o(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*crtbegin?.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
|
||||
/*
|
||||
* Exception frame info
|
||||
*/
|
||||
. = ALIGN (16);
|
||||
*(.eh_frame)
|
||||
KEEP (*(.eh_frame))
|
||||
|
||||
/*
|
||||
* Read-only data
|
||||
@@ -141,7 +145,7 @@ SECTIONS
|
||||
. = ALIGN (16);
|
||||
_rodata_start = . ;
|
||||
*(.rodata*)
|
||||
KEEP (*(SORT(.rtemsroset.*)))
|
||||
KEEP (*(SORT(.rtemsroset.*)))
|
||||
*(.gnu.linkonce.r*)
|
||||
|
||||
. = ALIGN (16);
|
||||
@@ -179,7 +183,7 @@ SECTIONS
|
||||
KEEP (*(SORT(.rtemsrwset.*)))
|
||||
*(.gnu.linkonce.d*)
|
||||
*(.gcc_except_table*)
|
||||
*(.jcr)
|
||||
KEEP (*(.jcr))
|
||||
. = ALIGN (16);
|
||||
PROVIDE (_edata = .);
|
||||
PROVIDE (_copy_end = .);
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
#include <rtems.h>
|
||||
#include <bsp.h>
|
||||
#include <bsp/if_mve_pub.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Demo for the mv64360 ethernet quirk:
|
||||
*
|
||||
* $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
|
||||
* $$ buffer segments < 8 bytes must be aligned $$
|
||||
* $$ to 8 bytes but larger segments are not $$
|
||||
* $$ sensitive to alignment. $$
|
||||
* $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
|
||||
*
|
||||
* How to use:
|
||||
*
|
||||
* Init MVE driver on (unused) unit 2:
|
||||
*
|
||||
* mve = mvtst_init(2)
|
||||
*
|
||||
* data = { 1,2,3,4,5,6,7,8,9,0xa,0xb, ... }
|
||||
*
|
||||
* Alloc 2-element mbuf chain (1st holds an
|
||||
* ethernet header which is > 8bytes so we can't
|
||||
* test this with only 1 mbuf. The 2nd mbuf holds
|
||||
* a small fragment of data).
|
||||
*
|
||||
* mb = mvtst_getbuf(mve)
|
||||
*
|
||||
* Copy data into aligned area inside 2nd mbuf,
|
||||
* (so that you can see if the chip starts using
|
||||
* the aligned area rather than the unaligned
|
||||
* buffer pointer). Point mbuf's data pointer
|
||||
* at 'off'set from the aligned area:
|
||||
*
|
||||
* mvtst_putbuf(mb, data, len, offset)
|
||||
*
|
||||
* Send chain off:
|
||||
*
|
||||
* BSP_mve_send_buf(mve, mb, 0, 0)
|
||||
*
|
||||
* Watch raw data:
|
||||
*
|
||||
* tcpdump -XX -vv -s0 ether host <my-ether-addr>
|
||||
*
|
||||
* E.g, if offset = 1, len = 2 then we would like
|
||||
* to see
|
||||
*
|
||||
* GOOD:
|
||||
* < 14 header bytes > 0x02, 0x03
|
||||
|
||||
* but if the chip starts DMA at aligned address
|
||||
* we see instead
|
||||
* BAD:
|
||||
* < 14 header bytes > 0x01, 0x02
|
||||
*/
|
||||
|
||||
static inline void *rmalloc(size_t l) { return malloc(l); }
|
||||
static inline void rfree(void *p) { return free(p); }
|
||||
|
||||
#define _KERNEL
|
||||
#include <sys/param.h>
|
||||
#include <sys/mbuf.h>
|
||||
|
||||
static void
|
||||
cleanup_buf(void *u_b, void *closure, int error)
|
||||
{
|
||||
rtems_bsdnet_semaphore_obtain();
|
||||
m_freem((struct mbuf*)u_b);
|
||||
rtems_bsdnet_semaphore_release();
|
||||
}
|
||||
|
||||
struct mbuf *mvtst_getbuf(struct mveth_private *mp)
|
||||
{
|
||||
struct mbuf *m,*n;
|
||||
|
||||
if ( !mp ) {
|
||||
printf("need driver ptr arg\n");
|
||||
return 0;
|
||||
}
|
||||
rtems_bsdnet_semaphore_obtain();
|
||||
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
||||
MGET(n, M_DONTWAIT, MT_DATA);
|
||||
m->m_next = n;
|
||||
rtems_bsdnet_semaphore_release();
|
||||
/* Ethernet header */
|
||||
memset( mtod(m, unsigned char*), 0xff, 6);
|
||||
BSP_mve_read_eaddr(mp, mtod(m, unsigned char*) + 6);
|
||||
/* Arbitrary; setting to IP but we don't bother
|
||||
* to setup a real IP header. We just watch the
|
||||
* raw packet contents...
|
||||
*/
|
||||
mtod(m, unsigned char*)[12] = 0x08;
|
||||
mtod(m, unsigned char*)[13] = 0x00;
|
||||
m->m_pkthdr.len = m->m_len = 14;
|
||||
n->m_len = 0;
|
||||
return m;
|
||||
}
|
||||
|
||||
int
|
||||
mvtst_putbuf(struct mbuf *m, void *data, int len, int off)
|
||||
{
|
||||
int i;
|
||||
if ( m ) {
|
||||
m->m_pkthdr.len += len;
|
||||
if ( ( m= m->m_next ) ) {
|
||||
m->m_len = len;
|
||||
memcpy(mtod(m, void*), data, 32);
|
||||
m->m_data += off;
|
||||
printf("m.dat: 0x%08x, m.data: 0x%08x\n", m->m_dat, m->m_data);
|
||||
for ( i=0; i< 16; i++ ) {
|
||||
printf(" %02x,",mtod(m, unsigned char*)[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *alloc_rxbuf(int *p_size, unsigned long *paddr)
|
||||
{
|
||||
return *(void**)paddr = rmalloc((*p_size = 1800));
|
||||
}
|
||||
|
||||
static void consume_buf(void *buf, void *closure, int len)
|
||||
{
|
||||
rfree(buf);
|
||||
}
|
||||
|
||||
void *
|
||||
mvtst_init(int unit)
|
||||
{
|
||||
struct mveth_private *mp;
|
||||
mp = BSP_mve_setup(
|
||||
unit, 0,
|
||||
cleanup_buf, 0,
|
||||
alloc_rxbuf,
|
||||
consume_buf, 0,
|
||||
10, 10,
|
||||
0);
|
||||
if ( mp )
|
||||
BSP_mve_init_hw(mp, 0, 0);
|
||||
return mp;
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
#ifndef KERNEL
|
||||
#define KERNEL
|
||||
#endif
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/rtems_bsdnet_internal.h>
|
||||
#include <bsp.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/mbuf.h>
|
||||
|
||||
#include "mv64340_eth_ll.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define RX_SPACING 1
|
||||
#define TX_SPACING 1
|
||||
|
||||
#define RX_RING_SIZE (MV64340_RX_QUEUE_SIZE*RX_SPACING)
|
||||
#define TX_RING_SIZE (MV64340_TX_QUEUE_SIZE*TX_SPACING)
|
||||
|
||||
|
||||
struct eth_rx_desc rx_ring[RX_RING_SIZE] __attribute__((aligned(32)));
|
||||
struct eth_rx_desc rx_ring[RX_RING_SIZE] = {{0},};
|
||||
|
||||
struct eth_tx_desc tx_ring[TX_RING_SIZE] __attribute__((aligned(32)));
|
||||
struct eth_tx_desc tx_ring[TX_RING_SIZE] = {{0},};
|
||||
|
||||
/* packet buffers */
|
||||
char rx_buf[MV64340_RX_QUEUE_SIZE][2048] __attribute__((aligned(8)));
|
||||
char rx_buf[MV64340_RX_QUEUE_SIZE][2048];
|
||||
|
||||
char tx_buf[MV64340_RX_QUEUE_SIZE][2048] __attribute__((aligned(8)));
|
||||
char tx_buf[MV64340_RX_QUEUE_SIZE][2048];
|
||||
|
||||
char BcHeader[22] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* dst */
|
||||
0x00, 0x01, 0xaf, 0x13, 0xb5, 0x3e, /* src */
|
||||
00, 00, /* len */
|
||||
0xAA, /* dsap */
|
||||
0xAA, /* ssap */
|
||||
0x03, /* ctrl */
|
||||
0x08, 0x00, 0x56, /* snap_org [stanford] */
|
||||
0x80, 0x5b, /* snap_type (stanford kernel) */
|
||||
};
|
||||
|
||||
struct mv64340_private mveth = {
|
||||
port_num: 0,
|
||||
port_mac_addr: {0x00,0x01,0xAF,0x13,0xB5,0x3C},
|
||||
/* port_config .. tx_resource_err are set by port_init */
|
||||
0
|
||||
};
|
||||
|
||||
struct pkt_info p0,p1;
|
||||
|
||||
static inline void rx_stopq(int port)
|
||||
{
|
||||
MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port), 0x0000ff00);
|
||||
}
|
||||
|
||||
static inline void tx_stopq(int port)
|
||||
{
|
||||
MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port), 0x0000ff00);
|
||||
}
|
||||
|
||||
#define MV64360_ENET2MEM_SNOOP_NONE 0x0000
|
||||
#define MV64360_ENET2MEM_SNOOP_WT 0x1000
|
||||
#define MV64360_ENET2MEM_SNOOP_WB 0x2000
|
||||
|
||||
#if 0
|
||||
int
|
||||
mveth_init(struct mv64340_private *mp)
|
||||
{
|
||||
int i;
|
||||
mp->p_rx_desc_area = rx_ring;
|
||||
mp->p_tx_desc_area = tx_ring;
|
||||
|
||||
rx_stopq(mp->port_num);
|
||||
tx_stopq(mp->port_num);
|
||||
|
||||
/* MotLoad has cache snooping disabled on the ENET2MEM windows.
|
||||
* Some comments in (linux) indicate that there are errata
|
||||
* which cause problems which is a real bummer.
|
||||
* We try it anyways...
|
||||
*/
|
||||
{
|
||||
unsigned long disbl, bar;
|
||||
disbl = MV_READ(MV64340_ETH_BASE_ADDR_ENABLE_REG);
|
||||
/* disable all 6 windows */
|
||||
MV_WRITE(MV64340_ETH_BASE_ADDR_ENABLE_REG, 0x3f);
|
||||
/* set WB snooping */
|
||||
for ( i=0; i<6*8; i+=8 ) {
|
||||
if ( (bar = MV_READ(MV64340_ETH_BAR_0 + i)) && MV_READ(MV64340_ETH_SIZE_REG_0 + i) ) {
|
||||
MV_WRITE(MV64340_ETH_BAR_0 + i, bar | MV64360_ENET2MEM_SNOOP_WB);
|
||||
/* read back to flush fifo [linux comment] */
|
||||
(void)MV_READ(MV64340_ETH_BAR_0 + i);
|
||||
}
|
||||
}
|
||||
/* restore/re-enable */
|
||||
MV_WRITE(MV64340_ETH_BASE_ADDR_ENABLE_REG, disbl);
|
||||
}
|
||||
|
||||
eth_port_init(mp);
|
||||
|
||||
sleep(1);
|
||||
|
||||
mveth_init_tx_desc_ring(mp);
|
||||
mveth_init_rx_desc_ring(mp);
|
||||
#if 0
|
||||
for ( i = 0; i<MV64340_RX_QUEUE_SIZE; i++ ) {
|
||||
p0.byte_cnt = sizeof(rx_buf[0]);
|
||||
p0.buf_ptr = (dma_addr_t)rx_buf[i];
|
||||
p0.return_info = (void*)i;
|
||||
/* other fields are not used by ll driver */
|
||||
assert ( ETH_OK == eth_rx_return_buff(mp,&p0) );
|
||||
}
|
||||
memset(&p0, 0, sizeof(p0));
|
||||
#endif
|
||||
|
||||
return eth_port_start(mp);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
mveth_stop(struct mv64340_private *mp)
|
||||
{
|
||||
extern void mveth_stop_hw();
|
||||
rtems_bsdnet_semaphore_obtain();
|
||||
mveth_stop_hw(mp);
|
||||
rtems_bsdnet_semaphore_release();
|
||||
}
|
||||
|
||||
extern int mveth_send_mbuf();
|
||||
extern int mveth_swipe_tx();
|
||||
|
||||
int
|
||||
mveth_tx(struct mv64340_private *mp, char *data, int len, int nbufs)
|
||||
{
|
||||
int rval = -1,l;
|
||||
char *p;
|
||||
struct mbuf *m;
|
||||
char *emsg = 0;
|
||||
|
||||
rtems_bsdnet_semaphore_obtain();
|
||||
MGETHDR(m, M_WAIT, MT_DATA);
|
||||
if ( !m ) {
|
||||
emsg="Unable to allocate header\n";
|
||||
goto bail;
|
||||
}
|
||||
MCLGET(m, M_WAIT);
|
||||
if ( !(m->m_flags & M_EXT) ) {
|
||||
m_freem(m);
|
||||
emsg="Unable to allocate cluster\n";
|
||||
goto bail;
|
||||
}
|
||||
p = mtod(m, char *);
|
||||
l = 0;
|
||||
switch (nbufs) {
|
||||
case 3:
|
||||
default:
|
||||
emsg="nbufs arg must be 1..3\n";
|
||||
goto bail;
|
||||
|
||||
case 1:
|
||||
l += sizeof(BcHeader);
|
||||
memcpy(p, &BcHeader, sizeof(BcHeader));
|
||||
p += sizeof(BcHeader);
|
||||
|
||||
case 2:
|
||||
memcpy(p,data,len);
|
||||
l += len;
|
||||
m->m_len = m->m_pkthdr.len = l;
|
||||
if ( 2 == nbufs ) {
|
||||
M_PREPEND(m, sizeof (BcHeader), M_WAIT);
|
||||
if (!m) {
|
||||
emsg = "Unable to prepend\n";
|
||||
goto bail;
|
||||
}
|
||||
p = mtod(m, char*);
|
||||
memcpy(p,&BcHeader,sizeof(BcHeader));
|
||||
l += sizeof(BcHeader);
|
||||
}
|
||||
break;
|
||||
}
|
||||
*(short*)(mtod(m, char*) + 12) = htons(l-14);
|
||||
rval = mveth_send_mbuf(mp,m);
|
||||
|
||||
bail:
|
||||
rtems_bsdnet_semaphore_release();
|
||||
if (emsg)
|
||||
printf(emsg);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Add local net header. If no space in first mbuf,
|
||||
* allocate another.
|
||||
*/
|
||||
M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
|
||||
if (m == 0)
|
||||
senderr(ENOBUFS);
|
||||
eh = mtod(m, struct ether_header *);
|
||||
(void)memcpy(&eh->ether_type, &type,
|
||||
sizeof(eh->ether_type));
|
||||
(void)memcpy(eh->ether_dhost, edst, sizeof (edst));
|
||||
(void)memcpy(eh->ether_shost, ac->ac_enaddr,
|
||||
sizeof(eh->ether_shost));
|
||||
#endif
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
mveth_protected(int (*p)(struct mv64340_private*), struct mv64340_private *mp)
|
||||
{
|
||||
int rval;
|
||||
rtems_bsdnet_semaphore_obtain();
|
||||
rval = p(mp);
|
||||
rtems_bsdnet_semaphore_release();
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
mveth_rx(struct mv64340_private *mp)
|
||||
{
|
||||
extern int mveth_swipe_rx();
|
||||
return mveth_protected(mveth_swipe_rx,mp);
|
||||
}
|
||||
|
||||
int
|
||||
mveth_reclaim(struct mv64340_private *mp)
|
||||
{
|
||||
extern int mveth_swipe_tx();
|
||||
return mveth_protected(mveth_swipe_tx,mp);
|
||||
}
|
||||
|
||||
|
||||
int preth(FILE *f, char *p)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<4; i++)
|
||||
fprintf(f,"%02X:",p[i]);
|
||||
fprintf(f,"%02X",p[i]);
|
||||
return 6;
|
||||
}
|
||||
|
||||
char *errcode2str(st)
|
||||
{
|
||||
char *rval;
|
||||
switch(st) {
|
||||
case ETH_OK:
|
||||
rval = "OK";
|
||||
break;
|
||||
case ETH_ERROR:
|
||||
rval = "Fundamental error.";
|
||||
break;
|
||||
case ETH_RETRY:
|
||||
rval = "Could not process request. Try later.";
|
||||
break;
|
||||
case ETH_END_OF_JOB:
|
||||
rval = "Ring has nothing to process.";
|
||||
break;
|
||||
case ETH_QUEUE_FULL:
|
||||
rval = "Ring resource error.";
|
||||
break;
|
||||
case ETH_QUEUE_LAST_RESOURCE:
|
||||
rval = "Ring resources about to exhaust.";
|
||||
break;
|
||||
default:
|
||||
rval = "UNKNOWN"; break;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
int
|
||||
mveth_rx(struct mv64340_private *mp)
|
||||
{
|
||||
int st;
|
||||
struct pkt_info p;
|
||||
if ( ETH_OK != (st=eth_port_receive(mp, &p)) ) {
|
||||
fprintf(stderr,"receive: %s\n", errcode2str(st));
|
||||
return -1;
|
||||
}
|
||||
printf("%i bytes received from ", p.byte_cnt);
|
||||
preth(stdout,(char*)p.buf_ptr+6);
|
||||
printf(" (desc. stat: 0x%08x)\n", p.cmd_sts);
|
||||
|
||||
p.byte_cnt = sizeof(rx_buf[0]);
|
||||
p.buf_ptr -= RX_BUF_OFFSET;
|
||||
if ( ETH_OK != (st=eth_rx_return_buff(mp,&p) ) ) {
|
||||
fprintf(stderr,"returning buffer: %s\n", errcode2str(st));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
dring()
|
||||
{
|
||||
int i;
|
||||
if (1) {
|
||||
struct eth_rx_desc *pr;
|
||||
printf("RX:\n");
|
||||
for (i=0, pr=rx_ring; i<RX_RING_SIZE; i+=RX_SPACING, pr+=RX_SPACING) {
|
||||
dcbi(pr);
|
||||
printf("cnt: 0x%04x, size: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n",
|
||||
pr->byte_cnt, pr->buf_size, pr->cmd_sts, pr->next_desc_ptr, pr->buf_ptr);
|
||||
}
|
||||
}
|
||||
if (1) {
|
||||
struct eth_tx_desc *pt;
|
||||
printf("TX:\n");
|
||||
for (i=0, pt=tx_ring; i<TX_RING_SIZE; i+=TX_SPACING, pt+=TX_SPACING) {
|
||||
dcbi(pt);
|
||||
printf("cnt: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n",
|
||||
pt->byte_cnt, pt->cmd_sts, pt->next_desc_ptr, pt->buf_ptr);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#include <rtems.h>
|
||||
#include <porting/rtemscompat.h>
|
||||
|
||||
/* CEXP module initialization/finalization */
|
||||
|
||||
/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
|
||||
* License: see LICENSE file.
|
||||
*/
|
||||
|
||||
void
|
||||
_cexpModuleInitialize(void *unused)
|
||||
{
|
||||
extern void NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringup)(char *);
|
||||
METHODSPTR = &METHODS;
|
||||
/*
|
||||
#ifdef DEBUG
|
||||
NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringup)("192.168.2.13/255.255.255.0");
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
|
||||
int
|
||||
_cexpModuleFinalize(void *unused)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
extern int NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringdown)();
|
||||
if (NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringdown)())
|
||||
return -1;
|
||||
METHODSPTR = 0;
|
||||
return 0;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
@@ -50,6 +50,11 @@ extern int BSP_disable_irq_at_pic(const rtems_irq_number irqLine);
|
||||
*/
|
||||
extern int BSP_setup_the_pic(rtems_irq_global_settings* config);
|
||||
|
||||
/*
|
||||
* Set up for the irq-generic.h interface.
|
||||
*/
|
||||
int BSP_rtems_irq_generic_set(rtems_irq_global_settings* config);
|
||||
|
||||
/* IRQ dispatcher to be defined by the PIC driver; note that it MUST
|
||||
* implement shared interrupts.
|
||||
* Note also that the exception frame passed to this handler is not very
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
* Acts as a barrier to ensure all previous I/O accesses have
|
||||
* completed before any further ones are issued.
|
||||
*/
|
||||
static inline void eieio(void)
|
||||
static inline void io_eieio(void)
|
||||
{
|
||||
__asm__ __volatile__ ("eieio");
|
||||
}
|
||||
@@ -59,9 +59,9 @@ static inline void eieio(void)
|
||||
/* Enforce in-order execution of data I/O.
|
||||
* No distinction between read/write on PPC; use eieio for all three.
|
||||
*/
|
||||
#define iobarrier_rw() eieio()
|
||||
#define iobarrier_r() eieio()
|
||||
#define iobarrier_w() eieio()
|
||||
#define iobarrier_rw() io_eieio()
|
||||
#define iobarrier_r() io_eieio()
|
||||
#define iobarrier_w() io_eieio()
|
||||
|
||||
/*
|
||||
* 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
|
||||
@@ -107,6 +107,7 @@ static inline void out_be16(volatile uint16_t *addr, uint16_t val)
|
||||
__asm__ __volatile__("sth%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
|
||||
}
|
||||
|
||||
#ifndef in_le32
|
||||
static inline uint32_t in_le32(const volatile uint32_t *addr)
|
||||
{
|
||||
uint32_t ret;
|
||||
@@ -115,7 +116,9 @@ static inline uint32_t in_le32(const volatile uint32_t *addr)
|
||||
"r" (addr), "m" (*addr));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef in_be32
|
||||
static inline uint32_t in_be32(const volatile uint32_t *addr)
|
||||
{
|
||||
uint32_t ret;
|
||||
@@ -123,17 +126,22 @@ static inline uint32_t in_be32(const volatile uint32_t *addr)
|
||||
__asm__ __volatile__("lwz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef out_le32
|
||||
static inline void out_le32(volatile uint32_t *addr, uint32_t val)
|
||||
{
|
||||
__asm__ __volatile__("stwbrx %1,0,%2; eieio" : "=m" (*addr) :
|
||||
"r" (val), "r" (addr));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef out_be32
|
||||
static inline void out_be32(volatile uint32_t *addr, uint32_t val)
|
||||
{
|
||||
__asm__ __volatile__("stw%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ASM */
|
||||
#endif /* _LIBCPU_IO_H */
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <rtems/bspIo.h>
|
||||
#include <bsp.h>
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
/* to align the pointer to the (next) page boundary */
|
||||
#define PAGE_ALIGN(addr) (((addr) + PAGE_MASK) & ~PAGE_MASK)
|
||||
|
||||
@@ -401,7 +403,7 @@ setup_hw(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
printk("\nRTEMS 4.x/PPC load: ");
|
||||
printk("\nRTEMS " RTEMS_VERSION "/PPC load: ");
|
||||
timer = 0;
|
||||
cp = bd->cmd_line+strlen(bd->cmd_line);
|
||||
while (timer++ < 5*1000) {
|
||||
|
||||
@@ -38,7 +38,9 @@ SECTIONS
|
||||
BYTE(0x75); BYTE(0x78); /* Partition name */
|
||||
. = 0x400;
|
||||
*(.text)
|
||||
*(.text*)
|
||||
*(.sdata2)
|
||||
*(.sdata2*)
|
||||
*(.rodata)
|
||||
*(.rodata*)
|
||||
}
|
||||
@@ -71,13 +73,17 @@ SECTIONS
|
||||
*(.data)
|
||||
*(.data*)
|
||||
*(.sdata)
|
||||
*(.sdata*)
|
||||
. = ALIGN(4);
|
||||
_data_end = .;
|
||||
}
|
||||
.bss :
|
||||
{
|
||||
*(.sbss)
|
||||
*(.sbss*)
|
||||
*(.bss)
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_bss_end = .;
|
||||
}
|
||||
@@ -95,7 +101,7 @@ SECTIONS
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.comment)
|
||||
*(.comment*)
|
||||
*(.debug*)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,11 +31,11 @@
|
||||
#include <rtems.h>
|
||||
#include <libcpu/io.h>
|
||||
#include <bsp/vectors.h>
|
||||
|
||||
|
||||
#ifdef qemu
|
||||
#include <rtems/bspcmdline.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -115,6 +115,36 @@ extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The BSP has PCI devices. Enable support in LibBSD.
|
||||
*/
|
||||
#define BSP_HAS_PC_PCI
|
||||
|
||||
/*
|
||||
* Remap the PCI address space for LibBSD
|
||||
*/
|
||||
#define RTEMS_BSP_PCI_IO_REGION_BASE 0
|
||||
#define RTEMS_BSP_PCI_MEM_REGION_BASE PCI_DRAM_OFFSET
|
||||
|
||||
/*
|
||||
* Remap the PCI address space for LibBSD
|
||||
*/
|
||||
#define RTEMS_BSP_ADDR_PTR(_type) uint ## _type ## _t __volatile*
|
||||
#define RTEMS_BSP_ADDR_CPTR(_type) const RTEMS_BSP_ADDR_PTR(_type)
|
||||
#define RTEMS_BSP_ADDRESS_READ(_addr, _type) \
|
||||
*((RTEMS_BSP_ADDR_CPTR(_type)) (((RTEMS_BSP_ADDR_CPTR(8)) _addr) + PCI_DRAM_OFFSET))
|
||||
#define RTEMS_BSP_ADDRESS_WRITE(_addr, _val, _type) \
|
||||
*((RTEMS_BSP_ADDR_PTR(_type)) (((RTEMS_BSP_ADDR_PTR(8)) _addr) + PCI_DRAM_OFFSET)) = (_val)
|
||||
|
||||
#define RTEMS_BSP_READ_1(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 8)
|
||||
#define RTEMS_BSP_READ_2(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 16)
|
||||
#define RTEMS_BSP_READ_4(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 32)
|
||||
#define RTEMS_BSP_READ_8(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 64)
|
||||
|
||||
#define RTEMS_BSP_WRITE_1(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 8)
|
||||
#define RTEMS_BSP_WRITE_2(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 16)
|
||||
#define RTEMS_BSP_WRITE_4(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 32)
|
||||
#define RTEMS_BSP_WRITE_8(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 64)
|
||||
|
||||
/*
|
||||
* Base address definitions for several devices
|
||||
|
||||
@@ -19,9 +19,17 @@
|
||||
#ifndef BSP_POWERPC_IRQ_H
|
||||
#define BSP_POWERPC_IRQ_H
|
||||
|
||||
#ifndef BSP_SHARED_HANDLER_SUPPORT
|
||||
#define BSP_SHARED_HANDLER_SUPPORT 1
|
||||
#endif
|
||||
|
||||
#include <rtems/irq.h>
|
||||
#include <bsp/irq-default.h>
|
||||
|
||||
/*
|
||||
* Switch to using the generic support. Remove this when all BSPs have
|
||||
* been converted.
|
||||
*/
|
||||
#define BSP_POWERPC_IRQ_GENERIC_SUPPORT 1
|
||||
|
||||
/*
|
||||
* 8259 edge/level control definitions at VIA
|
||||
@@ -107,6 +115,8 @@ extern "C" {
|
||||
#define BSP_IRQ_NUMBER (BSP_MISC_IRQ_MAX_OFFSET + 1)
|
||||
#define BSP_LOWEST_OFFSET (BSP_ISA_IRQ_LOWEST_OFFSET)
|
||||
#define BSP_MAX_OFFSET (BSP_MISC_IRQ_MAX_OFFSET)
|
||||
#define BSP_INTERRUPT_VECTOR_MIN (BSP_LOWEST_OFFSET)
|
||||
#define BSP_INTERRUPT_VECTOR_MAX (BSP_MAX_OFFSET)
|
||||
/*
|
||||
* Some ISA IRQ symbolic name definition
|
||||
*/
|
||||
@@ -191,6 +201,9 @@ int BSP_irq_ack_at_i8259s (const rtems_irq_number irqLine);
|
||||
*/
|
||||
int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine);
|
||||
|
||||
unsigned short BSP_irq_suspend_i8259s(unsigned short mask);
|
||||
void BSP_irq_resume_i8259s(unsigned short in_progress_save);
|
||||
|
||||
extern void BSP_rtems_irq_mng_init(unsigned cpuId);
|
||||
extern void BSP_i8259s_init(void);
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <bsp/pci.h>
|
||||
#include <bsp/openpic.h>
|
||||
#include <bsp/irq.h>
|
||||
#include <bsp/irq-generic.h>
|
||||
#include <libcpu/bat.h>
|
||||
#include <libcpu/pte121.h>
|
||||
#include <libcpu/cpuIdent.h>
|
||||
@@ -334,10 +335,8 @@ static void bsp_early( void )
|
||||
*/
|
||||
bsp_clicks_per_usec = BSP_bus_frequency/(BSP_time_base_divisor * 1000);
|
||||
|
||||
/*
|
||||
* Initalize RTEMS IRQ system
|
||||
*/
|
||||
BSP_rtems_irq_mng_init(0);
|
||||
/* Initialize interrupt support */
|
||||
bsp_interrupt_initialize();
|
||||
|
||||
/* Activate the page table mappings only after
|
||||
* initializing interrupts because the irq_mng_init()
|
||||
|
||||
@@ -12,6 +12,19 @@
|
||||
#include <bsp.h>
|
||||
#include <bsp/irq.h>
|
||||
|
||||
#define PIC_EOSI 0x60 ///< End of Specific Interrupt (EOSI)
|
||||
#define PIC_EOI 0x20 ///< Generic End of Interrupt (EOI)
|
||||
|
||||
/* Operation control word type 3. Bit 3 (0x08) must be set. Even address. */
|
||||
#define PIC_OCW3_RIS 0x01 /* 1 = read IS, 0 = read IR */
|
||||
#define PIC_OCW3_RR 0x02 /* register read */
|
||||
#define PIC_OCW3_P 0x04 /* poll mode command */
|
||||
/* 0x08 must be 1 to select OCW3 vs OCW2 */
|
||||
#define PIC_OCW3_SEL 0x08 /* must be 1 */
|
||||
/* 0x10 must be 0 to select OCW3 vs ICW1 */
|
||||
#define PIC_OCW3_SMM 0x20 /* special mode mask */
|
||||
#define PIC_OCW3_ESMM 0x40 /* enable SMM */
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
| Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register.
|
||||
+--------------------------------------------------------------------------*/
|
||||
@@ -19,91 +32,137 @@
|
||||
* lower byte is interrupt mask on the master PIC.
|
||||
* while upper bits are interrupt on the slave PIC.
|
||||
*/
|
||||
volatile rtems_i8259_masks i8259s_cache = 0xfffb;
|
||||
static rtems_i8259_masks i8259s_imr_cache = 0xFFFB;
|
||||
static rtems_i8259_masks i8259s_in_progress = 0;
|
||||
|
||||
static inline
|
||||
void BSP_i8259s_irq_update_master_imr( void )
|
||||
{
|
||||
rtems_i8259_masks mask = i8259s_in_progress | i8259s_imr_cache;
|
||||
outport_byte( PIC_MASTER_IMR_IO_PORT, mask & 0xff );
|
||||
}
|
||||
|
||||
static inline
|
||||
void BSP_i8259s_irq_update_slave_imr( void )
|
||||
{
|
||||
rtems_i8259_masks mask = i8259s_in_progress | i8259s_imr_cache;
|
||||
outport_byte( PIC_SLAVE_IMR_IO_PORT, ( mask >> 8 ) & 0xff );
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the IRQ valid?
|
||||
*/
|
||||
static inline bool BSP_i8259s_irq_valid(const rtems_irq_number irqLine)
|
||||
{
|
||||
return ((int)irqLine >= BSP_ISA_IRQ_LOWEST_OFFSET) &&
|
||||
((int)irqLine <= BSP_ISA_IRQ_MAX_OFFSET);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the IRR register. The default.
|
||||
*/
|
||||
static inline uint8_t BSP_i8259s_irq_int_request_reg(uint32_t ioport)
|
||||
{
|
||||
uint8_t isr;
|
||||
inport_byte(ioport, isr);
|
||||
return isr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the ISR register. Keep the default of the IRR.
|
||||
*/
|
||||
static inline uint8_t BSP_i8259s_irq_in_service_reg(uint32_t ioport)
|
||||
{
|
||||
uint8_t isr;
|
||||
outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR | PIC_OCW3_RIS);
|
||||
inport_byte(ioport, isr);
|
||||
outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR);
|
||||
return isr;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
| Function: BSP_irq_disable_at_i8259s
|
||||
| Description: Mask IRQ line in appropriate PIC chip.
|
||||
| Global Variables: i8259s_cache
|
||||
| Global Variables: i8259s_imr_cache, i8259s_in_progress
|
||||
| Arguments: vector_offset - number of IRQ line to mask.
|
||||
| Returns: original state or -1 on error.
|
||||
| Returns: 0 is OK.
|
||||
+--------------------------------------------------------------------------*/
|
||||
int BSP_irq_disable_at_i8259s (const rtems_irq_number irqLine)
|
||||
int BSP_irq_disable_at_i8259s(const rtems_irq_number irqLine)
|
||||
{
|
||||
unsigned short mask;
|
||||
rtems_interrupt_level level;
|
||||
int rval;
|
||||
|
||||
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
|
||||
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET)
|
||||
)
|
||||
if (!BSP_i8259s_irq_valid(irqLine))
|
||||
return -1;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
|
||||
mask = 1 << irqLine;
|
||||
rval = i8259s_cache & mask ? 0 : 1;
|
||||
i8259s_cache |= mask;
|
||||
i8259s_imr_cache |= mask;
|
||||
|
||||
if (irqLine < 8)
|
||||
{
|
||||
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
|
||||
BSP_i8259s_irq_update_master_imr();
|
||||
}
|
||||
else
|
||||
{
|
||||
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
|
||||
BSP_i8259s_irq_update_slave_imr();
|
||||
}
|
||||
|
||||
rtems_interrupt_enable(level);
|
||||
|
||||
return rval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
| Function: BSP_irq_enable_at_i8259s
|
||||
| Description: Unmask IRQ line in appropriate PIC chip.
|
||||
| Global Variables: i8259s_cache
|
||||
| Global Variables: i8259s_imr_cache, i8259s_in_progress
|
||||
| Arguments: irqLine - number of IRQ line to mask.
|
||||
| Returns: Nothing.
|
||||
+--------------------------------------------------------------------------*/
|
||||
int BSP_irq_enable_at_i8259s (const rtems_irq_number irqLine)
|
||||
int BSP_irq_enable_at_i8259s(const rtems_irq_number irqLine)
|
||||
{
|
||||
unsigned short mask;
|
||||
rtems_interrupt_level level;
|
||||
unsigned short mask;
|
||||
uint8_t isr;
|
||||
uint8_t irr;
|
||||
|
||||
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
|
||||
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET )
|
||||
)
|
||||
if (!BSP_i8259s_irq_valid(irqLine))
|
||||
return 1;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
|
||||
mask = ~(1 << irqLine);
|
||||
i8259s_cache &= mask;
|
||||
mask = 1 << irqLine;
|
||||
i8259s_imr_cache &= ~mask;
|
||||
|
||||
if (irqLine < 8)
|
||||
{
|
||||
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
|
||||
isr = BSP_i8259s_irq_in_service_reg(PIC_MASTER_COMMAND_IO_PORT);
|
||||
irr = BSP_i8259s_irq_int_request_reg(PIC_MASTER_COMMAND_IO_PORT);
|
||||
BSP_i8259s_irq_update_master_imr();
|
||||
}
|
||||
else
|
||||
{
|
||||
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
|
||||
isr = BSP_i8259s_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
|
||||
irr = BSP_i8259s_irq_int_request_reg(PIC_SLAVE_COMMAND_IO_PORT);
|
||||
BSP_i8259s_irq_update_slave_imr();
|
||||
}
|
||||
|
||||
rtems_interrupt_enable(level);
|
||||
|
||||
return 0;
|
||||
} /* mask_irq */
|
||||
|
||||
int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine)
|
||||
int BSP_irq_enabled_at_i8259s(const rtems_irq_number irqLine)
|
||||
{
|
||||
unsigned short mask;
|
||||
|
||||
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
|
||||
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET)
|
||||
)
|
||||
if (!BSP_i8259s_irq_valid(irqLine))
|
||||
return 1;
|
||||
|
||||
mask = (1 << irqLine);
|
||||
return (~(i8259s_cache & mask));
|
||||
return (~(i8259s_imr_cache & mask));
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
@@ -113,24 +172,47 @@ int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine)
|
||||
| Arguments: irqLine - number of IRQ line to acknowledge.
|
||||
| Returns: Nothing.
|
||||
+--------------------------------------------------------------------------*/
|
||||
int BSP_irq_ack_at_i8259s (const rtems_irq_number irqLine)
|
||||
int BSP_irq_ack_at_i8259s(const rtems_irq_number irqLine)
|
||||
{
|
||||
uint8_t slave_isr = 0;
|
||||
|
||||
if (irqLine >= 8) {
|
||||
outport_byte(PIC_MASTER_COMMAND_IO_PORT, SLAVE_PIC_EOSI);
|
||||
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, (PIC_EOSI | (irqLine - 8)));
|
||||
}
|
||||
else {
|
||||
outport_byte(PIC_MASTER_COMMAND_IO_PORT, (PIC_EOSI | irqLine));
|
||||
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
|
||||
slave_isr = BSP_i8259s_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Only issue the EOI to the master if there are no more interrupts in
|
||||
* service for the slave. i8259a data sheet page 18, The Special Fully Nested
|
||||
* Mode, b.
|
||||
*/
|
||||
if (slave_isr == 0)
|
||||
outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
|
||||
|
||||
return 0;
|
||||
|
||||
} /* ackIRQ */
|
||||
|
||||
unsigned short BSP_irq_suspend_i8259s(unsigned short mask)
|
||||
{
|
||||
unsigned short in_progress_save = i8259s_in_progress;
|
||||
i8259s_in_progress |= mask;
|
||||
BSP_i8259s_irq_update_master_imr();
|
||||
BSP_i8259s_irq_update_slave_imr();
|
||||
return in_progress_save;
|
||||
}
|
||||
|
||||
void BSP_irq_resume_i8259s(unsigned short in_progress_save)
|
||||
{
|
||||
i8259s_in_progress = in_progress_save;
|
||||
BSP_i8259s_irq_update_master_imr();
|
||||
BSP_i8259s_irq_update_slave_imr();
|
||||
}
|
||||
|
||||
void BSP_i8259s_init(void)
|
||||
{
|
||||
/*
|
||||
* init master 8259 interrupt controller
|
||||
* Always mask at least current interrupt to prevent re-entrance
|
||||
*/
|
||||
outport_byte(PIC_MASTER_COMMAND_IO_PORT, 0x11); /* Start init sequence */
|
||||
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x00);/* Vector base = 0 */
|
||||
|
||||
@@ -280,6 +280,7 @@ void BSP_rtems_irq_mng_init(unsigned cpuId)
|
||||
int known_cpi_isa_bridge = 0;
|
||||
#endif
|
||||
int i;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* First initialize the Interrupt management hardware
|
||||
@@ -310,7 +311,7 @@ void BSP_rtems_irq_mng_init(unsigned cpuId)
|
||||
#endif
|
||||
known_cpi_isa_bridge = 1;
|
||||
}
|
||||
if ( currentBoard == MVME_2300 ) {
|
||||
if ( currentBoard == MVME_2300 || currentBoard == MVME_2600_2700_W_MVME761 ) {
|
||||
/* nothing to do for W83C553 bridge */
|
||||
known_cpi_isa_bridge = 1;
|
||||
}
|
||||
@@ -351,7 +352,19 @@ void BSP_rtems_irq_mng_init(unsigned cpuId)
|
||||
initial_config.irqBase = BSP_LOWEST_OFFSET;
|
||||
initial_config.irqPrioTbl = irqPrioTable;
|
||||
|
||||
if (!BSP_rtems_irq_mngt_set(&initial_config)) {
|
||||
#ifdef BSP_POWERPC_IRQ_GENERIC_SUPPORT
|
||||
#ifdef TRACE_IRQ_INIT
|
||||
printk("RTEMS IRQ management: irq-generic\n");
|
||||
#endif
|
||||
r = BSP_rtems_irq_generic_set(&initial_config);
|
||||
#else
|
||||
#ifdef TRACE_IRQ_INIT
|
||||
printk("RTEMS IRQ management: legacy\n");
|
||||
#endif
|
||||
r = BSP_rtems_irq_mngt_set(&initial_config);
|
||||
#endif
|
||||
|
||||
if (!r) {
|
||||
/*
|
||||
* put something here that will show the failure...
|
||||
*/
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <bsp.h>
|
||||
#include <bsp/irq.h>
|
||||
#include <bsp/irq_supp.h>
|
||||
#include <bsp/irq-generic.h>
|
||||
#ifndef BSP_HAS_NO_VME
|
||||
#include <bsp/VMEConfig.h>
|
||||
#endif
|
||||
@@ -214,7 +215,7 @@ int BSP_setup_the_pic(rtems_irq_global_settings* config)
|
||||
/*
|
||||
* Must enable PCI/ISA bridge IRQ
|
||||
*/
|
||||
openpic_enable_irq (BSP_PCI_ISA_BRIDGE_IRQ);
|
||||
openpic_enable_irq (BSP_PCI_ISA_BRIDGE_IRQ - BSP_PCI_IRQ_LOWEST_OFFSET);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -234,15 +235,15 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
|
||||
#if BSP_ISA_IRQ_NUMBER > 0
|
||||
register unsigned isaIntr; /* boolean */
|
||||
register unsigned oldMask = 0; /* old isa pic masks */
|
||||
register unsigned newMask; /* new isa pic masks */
|
||||
#endif
|
||||
|
||||
if (excNum == ASM_DEC_VECTOR) {
|
||||
|
||||
bsp_irq_dispatch_list(rtems_hdl_tbl, BSP_DECREMENTER, default_rtems_entry.hdl);
|
||||
|
||||
#ifdef BSP_POWERPC_IRQ_GENERIC_SUPPORT
|
||||
bsp_interrupt_handler_dispatch(BSP_DECREMENTER);
|
||||
#else
|
||||
bsp_irq_dispatch_list(rtems_hdl_tbl, BSP_DECREMENTER, default_rtems_entry.hdl);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#if BSP_PCI_IRQ_NUMBER > 0
|
||||
@@ -274,7 +275,7 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
|
||||
|
||||
#if BSP_ISA_IRQ_NUMBER > 0
|
||||
#ifdef BSP_PCI_ISA_BRIDGE_IRQ
|
||||
#if 0 == BSP_PCI_IRQ_NUMBER
|
||||
#if 0 == BSP_PCI_IRQ_NUMBER
|
||||
#error "Configuration Error -- BSP w/o PCI IRQs MUST NOT define BSP_PCI_ISA_BRIDGE_IRQ"
|
||||
#endif
|
||||
isaIntr = (irq == BSP_PCI_ISA_BRIDGE_IRQ);
|
||||
@@ -289,11 +290,7 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
|
||||
/*
|
||||
* store current PIC mask
|
||||
*/
|
||||
oldMask = i8259s_cache;
|
||||
newMask = oldMask | irq_mask_or_tbl [irq];
|
||||
i8259s_cache = newMask;
|
||||
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
|
||||
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
|
||||
oldMask = BSP_irq_suspend_i8259s(irq_mask_or_tbl [irq]);
|
||||
BSP_irq_ack_at_i8259s (irq);
|
||||
#if BSP_PCI_IRQ_NUMBER > 0
|
||||
if ( OpenPIC )
|
||||
@@ -303,13 +300,15 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
|
||||
#endif
|
||||
|
||||
/* dispatch handlers */
|
||||
#ifdef BSP_POWERPC_IRQ_GENERIC_SUPPORT
|
||||
bsp_interrupt_handler_dispatch(irq);
|
||||
#else
|
||||
bsp_irq_dispatch_list(rtems_hdl_tbl, irq, default_rtems_entry.hdl);
|
||||
#endif
|
||||
|
||||
#if BSP_ISA_IRQ_NUMBER > 0
|
||||
if (isaIntr) {
|
||||
i8259s_cache = oldMask;
|
||||
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
|
||||
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
|
||||
BSP_irq_resume_i8259s(oldMask);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
117
bsps/powerpc/shared/irq/ppc-irq-generic.c
Normal file
117
bsps/powerpc/shared/irq/ppc-irq-generic.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup RTEMSBSPsPowerPC
|
||||
*
|
||||
* @brief Generic Interrupt suppoer
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2021 Chris Johns. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <rtems.h>
|
||||
#include <stdlib.h>
|
||||
#include <rtems/bspIo.h> /* for printk */
|
||||
#include <libcpu/spr.h>
|
||||
#include <bsp/irq_supp.h>
|
||||
#include <bsp/irq-generic.h>
|
||||
#include <bsp/vectors.h>
|
||||
|
||||
SPR_RW(BOOKE_TSR)
|
||||
SPR_RW(PPC405_TSR)
|
||||
|
||||
/* legacy mode for bookE DEC exception;
|
||||
* to avoid the double layer of function calls
|
||||
* (dec_handler_bookE -> C_dispatch_irq_handler -> user handler)
|
||||
* it is preferrable for the user to hook the DEC
|
||||
* exception directly.
|
||||
* However, the legacy mode works with less modifications
|
||||
* of user code.
|
||||
*/
|
||||
static int C_dispatch_dec_handler_bookE (BSP_Exception_frame *frame, unsigned int excNum)
|
||||
{
|
||||
/* clear interrupt; we must do this
|
||||
* before C_dispatch_irq_handler()
|
||||
* re-enables MSR_EE.
|
||||
* Note that PPC405 uses a different SPR# for TSR
|
||||
*/
|
||||
if (ppc_cpu_is_bookE()==PPC_BOOKE_405)
|
||||
_write_PPC405_TSR( BOOKE_TSR_DIS );
|
||||
else
|
||||
_write_BOOKE_TSR( BOOKE_TSR_DIS );
|
||||
return C_dispatch_irq_handler(frame, ASM_DEC_VECTOR);
|
||||
}
|
||||
|
||||
/*
|
||||
* RTEMS Global Interrupt Handler Management Routines
|
||||
*/
|
||||
int BSP_rtems_irq_generic_set(rtems_irq_global_settings* config)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = BSP_setup_the_pic(config);
|
||||
if (!r)
|
||||
return r;
|
||||
|
||||
ppc_exc_set_handler(ASM_EXT_VECTOR, C_dispatch_irq_handler);
|
||||
if ( ppc_cpu_is_bookE() ) {
|
||||
/* bookE decrementer interrupt needs to be cleared BEFORE
|
||||
* dispatching the user ISR (because the user ISR is called
|
||||
* with EE enabled)
|
||||
* We do this so that existing DEC handlers can be used
|
||||
* with minor modifications.
|
||||
*/
|
||||
ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, C_dispatch_dec_handler_bookE);
|
||||
} else {
|
||||
ppc_exc_set_handler(ASM_DEC_VECTOR, C_dispatch_irq_handler);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void bsp_interrupt_vector_enable(rtems_vector_number vector)
|
||||
{
|
||||
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
|
||||
BSP_enable_irq_at_pic(vector);
|
||||
}
|
||||
|
||||
void bsp_interrupt_vector_disable(rtems_vector_number vector)
|
||||
{
|
||||
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
|
||||
BSP_disable_irq_at_pic(vector);
|
||||
}
|
||||
|
||||
rtems_status_code bsp_interrupt_facility_initialize(void)
|
||||
{
|
||||
/*
|
||||
* Initialize RTEMS IRQ system
|
||||
*/
|
||||
BSP_rtems_irq_mng_init(0);
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
@@ -20,8 +20,11 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/ascs/grascs.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/btimer/gptimer.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/btimer/tlib.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/btimer/tlib_ckinit.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/canbtrs.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/canmux.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/grcan.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/grcanfd.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/grcanstd.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/occan.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/satcan.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/drvmgr/ambapp_bus.c
|
||||
|
||||
@@ -206,6 +206,10 @@ static int gr1553_init2(struct drvmgr_dev *dev)
|
||||
GR1553B_WRITE_REG(®s->rt_cfg, 0x15530000);
|
||||
/* Stop BM logging (just in case) */
|
||||
GR1553B_WRITE_REG(®s->bm_ctrl, 0);
|
||||
/* Set codec version. This is only supported by some devices, i.e. GR740.
|
||||
* It will not have any effect on devices that does not support this bit.
|
||||
*/
|
||||
GR1553B_WRITE_REG(®s->hwcfg, 1<<12);
|
||||
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ struct gr1553bc_priv {
|
||||
*/
|
||||
#define NEXT_MINOR_MARKER 0x01
|
||||
|
||||
/* To separate ASYNC list from SYNC list we mark them differently, but with
|
||||
/* To separate ASYNC list from SYNC list we mark them differently, but with
|
||||
* LSB always set. This can be used to get the list the descriptor is a part
|
||||
* of.
|
||||
*/
|
||||
@@ -71,7 +71,7 @@ struct gr1553bc_priv {
|
||||
|
||||
struct gr1553bc_list_cfg gr1553bc_def_cfg =
|
||||
{
|
||||
.rt_timeout =
|
||||
.rt_timeout =
|
||||
{
|
||||
20, 20, 20, 20,
|
||||
20, 20, 20, 20,
|
||||
@@ -80,7 +80,7 @@ struct gr1553bc_list_cfg gr1553bc_def_cfg =
|
||||
20, 20, 20, 20,
|
||||
20, 20, 20, 20,
|
||||
20, 20, 20, 20,
|
||||
20, 20, 20
|
||||
20, 20, 20
|
||||
},
|
||||
.bc_timeout = 30,
|
||||
.tropt_irq_on_err = 0,
|
||||
@@ -132,7 +132,7 @@ int gr1553bc_list_config
|
||||
|
||||
/* RT Time Tolerances */
|
||||
for (i=0; i<31; i++) {
|
||||
/* 0=14us, 1=18us ... 0xf=74us
|
||||
/* 0=14us, 1=18us ... 0xf=74us
|
||||
* round upwards: 15us will be 18us
|
||||
*/
|
||||
timeout = ((cfg->rt_timeout[i] + 1) - 14) / 4;
|
||||
@@ -167,7 +167,7 @@ void gr1553bc_list_link_major(
|
||||
if ( major ) {
|
||||
major->next = next;
|
||||
if ( next ) {
|
||||
major->minors[major->cfg->minor_cnt-1]->next =
|
||||
major->minors[major->cfg->minor_cnt-1]->next =
|
||||
next->minors[0];
|
||||
} else {
|
||||
major->minors[major->cfg->minor_cnt-1]->next = NULL;
|
||||
@@ -195,7 +195,7 @@ int gr1553bc_list_set_major(
|
||||
prev = list->majors[list->major_cnt-1];
|
||||
}
|
||||
|
||||
/* Link to next Major if not the last one and if there is
|
||||
/* Link to next Major if not the last one and if there is
|
||||
* a next major
|
||||
*/
|
||||
if ( no == list->major_cnt-1 ) {
|
||||
@@ -262,7 +262,7 @@ int gr1553bc_list_table_size(struct gr1553bc_list *list)
|
||||
minor_cnt = major->cfg->minor_cnt;
|
||||
for (j=0; j<minor_cnt; j++) {
|
||||
/* 128-bit Alignment required by HW */
|
||||
size += (GR1553BC_BD_ALIGN -
|
||||
size += (GR1553BC_BD_ALIGN -
|
||||
(size & (GR1553BC_BD_ALIGN-1))) &
|
||||
~(GR1553BC_BD_ALIGN-1);
|
||||
|
||||
@@ -284,6 +284,7 @@ int gr1553bc_list_table_alloc
|
||||
int i, j, minor_cnt, size;
|
||||
unsigned int table;
|
||||
struct gr1553bc_priv *bcpriv = list->bc;
|
||||
int retval = 0;
|
||||
|
||||
/* Free previous allocated descriptor table */
|
||||
gr1553bc_list_table_free(list);
|
||||
@@ -298,8 +299,8 @@ int gr1553bc_list_table_alloc
|
||||
/* Address given in Hardware accessible address, we
|
||||
* convert it into CPU-accessible address.
|
||||
*/
|
||||
list->table_hw = (unsigned int)bdtab_custom & ~0x1;
|
||||
list->_table = bdtab_custom;
|
||||
list->_table = (void*)((unsigned int)bdtab_custom & ~0x1);
|
||||
list->table_hw = (unsigned int)list->_table;
|
||||
drvmgr_translate_check(
|
||||
*bcpriv->pdev,
|
||||
DMAMEM_TO_CPU,
|
||||
@@ -310,16 +311,19 @@ int gr1553bc_list_table_alloc
|
||||
if (bdtab_custom == NULL) {
|
||||
/* Allocate descriptors */
|
||||
list->_table = grlib_malloc(size + (GR1553BC_BD_ALIGN-1));
|
||||
if ( list->_table == NULL )
|
||||
return -1;
|
||||
if ( list->_table == NULL ) {
|
||||
retval = -1;
|
||||
goto err;
|
||||
}
|
||||
/* 128-bit Alignment required by HW */
|
||||
list->table_cpu =
|
||||
(((unsigned int)list->_table + (GR1553BC_BD_ALIGN-1)) &
|
||||
~(GR1553BC_BD_ALIGN-1));
|
||||
} else {
|
||||
/* Custom address, given in CPU-accessible address */
|
||||
list->_table = bdtab_custom;
|
||||
list->table_cpu = (unsigned int)list->_table;
|
||||
}
|
||||
/* 128-bit Alignment required by HW */
|
||||
list->table_cpu =
|
||||
(((unsigned int)list->_table + (GR1553BC_BD_ALIGN-1)) &
|
||||
~(GR1553BC_BD_ALIGN-1));
|
||||
|
||||
/* We got CPU accessible descriptor table address, now we
|
||||
* translate that into an address that the Hardware can
|
||||
@@ -338,6 +342,12 @@ int gr1553bc_list_table_alloc
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify alignment */
|
||||
if (list->table_hw & (GR1553BC_BD_ALIGN-1)) {
|
||||
retval = -2;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Write End-Of-List all over the descriptor table here,
|
||||
* For debugging/safety?
|
||||
*/
|
||||
@@ -359,8 +369,16 @@ int gr1553bc_list_table_alloc
|
||||
table += gr1553bc_minor_table_size(major->minors[j]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
if (retval) {
|
||||
if (list->_table_custom == NULL && list->_table) {
|
||||
free(list->_table);
|
||||
}
|
||||
list->table_hw = 0;
|
||||
list->table_cpu = 0;
|
||||
list->_table = NULL;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void gr1553bc_list_table_free(struct gr1553bc_list *list)
|
||||
@@ -399,7 +417,7 @@ int gr1553bc_list_table_build(struct gr1553bc_list *list)
|
||||
bds = minor->bds;
|
||||
|
||||
/* BD[0..SLOTCNT-1] = message slots
|
||||
* BD[SLOTCNT+0] = END
|
||||
* BD[SLOTCNT+0] = END
|
||||
* BD[SLOTCNT+1] = JUMP
|
||||
*
|
||||
* or if no optional time slot handling:
|
||||
@@ -485,7 +503,7 @@ void gr1553bc_bd_init(
|
||||
((word0 & GR1553BC_BD_TYPE) == 0) ) {
|
||||
/* Don't touch timeslot previously allocated */
|
||||
word0 &= ~GR1553BC_TR_TIME;
|
||||
word0 |= GR1553BC_READ_MEM(&raw->words[0]) &
|
||||
word0 |= GR1553BC_READ_MEM(&raw->words[0]) &
|
||||
GR1553BC_TR_TIME;
|
||||
}
|
||||
GR1553BC_WRITE_MEM(&raw->words[0], word0);
|
||||
@@ -523,7 +541,7 @@ int gr1553bc_major_alloc_skel
|
||||
maj->cfg = cfg;
|
||||
maj->next = NULL;
|
||||
|
||||
/* Create links between minor frames, and from minor frames
|
||||
/* Create links between minor frames, and from minor frames
|
||||
* to configuration structure.
|
||||
*/
|
||||
minor = (struct gr1553bc_minor *)&maj->minors[cfg->minor_cnt];
|
||||
@@ -697,7 +715,7 @@ int gr1553bc_slot_alloc2(
|
||||
set0 = (set0 & ~GR1553BC_TR_TIME) | timefree;
|
||||
GR1553BC_WRITE_MEM(&trbd->settings[0], set0);
|
||||
/* Note: at the moment the minor frame can be executed faster
|
||||
* than expected, we hurry up writing requested
|
||||
* than expected, we hurry up writing requested
|
||||
* descriptor.
|
||||
*/
|
||||
}
|
||||
@@ -886,7 +904,7 @@ int gr1553bc_slot_irq_prepare
|
||||
union gr1553bc_bd *bd;
|
||||
int slot_no, to_mid;
|
||||
|
||||
/* Build unconditional IRQ descriptor. The padding is used
|
||||
/* Build unconditional IRQ descriptor. The padding is used
|
||||
* for identifying the MINOR frame and function and custom data.
|
||||
*
|
||||
* The IRQ is disabled at first, a unconditional jump to next
|
||||
@@ -1115,7 +1133,7 @@ int gr1553bc_slot_update
|
||||
*stat = GR1553BC_READ_MEM(&bd->tr.status);
|
||||
if ( status ) {
|
||||
/* Clear status fields user selects, then
|
||||
* or bit31 if user wants that. The bit31
|
||||
* or bit31 if user wants that. The bit31
|
||||
* may be used to indicate if the BC has
|
||||
* performed the access.
|
||||
*/
|
||||
@@ -1192,7 +1210,7 @@ int gr1553bc_mid_from_bd(
|
||||
found_mid:
|
||||
/* Get MID of JUMP descriptor */
|
||||
bdmid = word2 >> 8;
|
||||
/* Subtract distance from JUMP descriptor to find MID
|
||||
/* Subtract distance from JUMP descriptor to find MID
|
||||
* of requested BD.
|
||||
*/
|
||||
slot_no = GR1553BC_SLOTID_FROM_ID(bdmid);
|
||||
@@ -1445,7 +1463,7 @@ void gr1553bc_device_init(struct gr1553bc_priv *priv)
|
||||
/* Stop BC if not already stopped */
|
||||
GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
|
||||
|
||||
/* Since RT can not be used at the same time as BC, we stop
|
||||
/* Since RT can not be used at the same time as BC, we stop
|
||||
* RT rx, it should already be stopped...
|
||||
*/
|
||||
GR1553BC_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
|
||||
@@ -1463,7 +1481,7 @@ void gr1553bc_device_init(struct gr1553bc_priv *priv)
|
||||
priv->alist = NULL;
|
||||
|
||||
priv->irq_log_base = (uint32_t *)
|
||||
(((uint32_t)priv->irq_log_p + (GR1553BC_IRQLOG_SIZE-1)) &
|
||||
(((uint32_t)priv->irq_log_p + (GR1553BC_IRQLOG_SIZE-1)) &
|
||||
~(GR1553BC_IRQLOG_SIZE-1));
|
||||
/* Translate into a hardware accessible address */
|
||||
drvmgr_translate_check(
|
||||
@@ -1487,7 +1505,7 @@ void gr1553bc_device_uninit(struct gr1553bc_priv *priv)
|
||||
/* Stop BC if not already stopped */
|
||||
GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
|
||||
|
||||
/* Since RT can not be used at the same time as BC, we stop
|
||||
/* Since RT can not be used at the same time as BC, we stop
|
||||
* RT rx, it should already be stopped...
|
||||
*/
|
||||
GR1553BC_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
|
||||
@@ -1518,7 +1536,7 @@ void gr1553bc_isr(void *arg)
|
||||
/* Clear handled IRQs */
|
||||
GR1553BC_WRITE_REG(&priv->regs->irq, irq);
|
||||
|
||||
/* DMA error. This IRQ does not affect the IRQ log.
|
||||
/* DMA error. This IRQ does not affect the IRQ log.
|
||||
* We let standard IRQ handle handle it.
|
||||
*/
|
||||
if ( irq & GR1553B_IRQEN_BCDE ) {
|
||||
@@ -1563,7 +1581,7 @@ void gr1553bc_isr(void *arg)
|
||||
bd = NULL;
|
||||
}
|
||||
|
||||
/* Handle Descriptor that cased IRQ
|
||||
/* Handle Descriptor that cased IRQ
|
||||
*
|
||||
* If someone have inserted an IRQ descriptor and tied
|
||||
* that to a custom function we call that function, otherwise
|
||||
|
||||
@@ -89,7 +89,7 @@ static void gr1553bm_hw_start(struct gr1553bm_priv *priv)
|
||||
|
||||
/* Start logging */
|
||||
priv->regs->bm_ctrl =
|
||||
(priv->cfg.filt_error_options &
|
||||
(priv->cfg.filt_error_options &
|
||||
(GR1553B_BM_CTRL_MANL|GR1553B_BM_CTRL_UDWL|GR1553B_BM_CTRL_IMCL))
|
||||
| GR1553B_BM_CTRL_BMEN;
|
||||
|
||||
@@ -178,6 +178,7 @@ void gr1553bm_close(void *bm)
|
||||
/* Configure the BM driver */
|
||||
int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
|
||||
{
|
||||
int retval = 0;
|
||||
struct gr1553bm_priv *priv = bm;
|
||||
|
||||
if ( priv->started )
|
||||
@@ -193,12 +194,11 @@ int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
|
||||
}
|
||||
priv->buffer_size = cfg->buffer_size & ~0x7; /* on 8 byte bounadry */
|
||||
if ((unsigned int)cfg->buffer_custom & 1) {
|
||||
/* Custom Address Given in Remote address. We need
|
||||
* to convert it intoTranslate into Hardware a
|
||||
* hardware accessible address
|
||||
/* Custom address given in remote address. We need
|
||||
* to convert it into a hardware accessible address
|
||||
*/
|
||||
priv->buffer_base_hw = (unsigned int)cfg->buffer_custom & ~1;
|
||||
priv->buffer = cfg->buffer_custom;
|
||||
priv->buffer = (void*)((unsigned int)cfg->buffer_custom & ~1);
|
||||
priv->buffer_base_hw = (unsigned int)priv->buffer;
|
||||
drvmgr_translate_check(
|
||||
*priv->pdev,
|
||||
DMAMEM_TO_CPU,
|
||||
@@ -209,17 +209,19 @@ int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
|
||||
if (cfg->buffer_custom == NULL) {
|
||||
/* Allocate new buffer dynamically */
|
||||
priv->buffer = grlib_malloc(priv->buffer_size + 8);
|
||||
if (priv->buffer == NULL)
|
||||
return -1;
|
||||
if (priv->buffer == NULL) {
|
||||
retval = -1;
|
||||
goto err;
|
||||
}
|
||||
/* Align to 8 bytes */
|
||||
priv->buffer_base = ((unsigned int)priv->buffer + (8-1)) & ~(8-1);
|
||||
} else {
|
||||
/* Address given in CPU accessible address, no
|
||||
* translation required.
|
||||
*/
|
||||
priv->buffer = cfg->buffer_custom;
|
||||
priv->buffer_base = (unsigned int)priv->buffer;
|
||||
}
|
||||
/* Align to 16 bytes */
|
||||
priv->buffer_base = ((unsigned int)priv->buffer + (8-1)) &
|
||||
~(8-1);
|
||||
/* Translate address of buffer base into address that Hardware must
|
||||
* use to access the buffer.
|
||||
*/
|
||||
@@ -229,13 +231,28 @@ int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
|
||||
(void *)priv->buffer_base,
|
||||
(void **)&priv->buffer_base_hw,
|
||||
priv->buffer_size);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Verify alignment */
|
||||
if (priv->buffer_base_hw & (8-1)) {
|
||||
retval = -2;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Copy valid config */
|
||||
priv->cfg = *cfg;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
if (retval) {
|
||||
if (cfg->buffer_custom == NULL && priv->buffer) {
|
||||
free(priv->buffer);
|
||||
}
|
||||
priv->buffer_base_hw = (unsigned int)NULL;
|
||||
priv->buffer_base = (unsigned int)NULL;
|
||||
priv->buffer = NULL;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Start logging */
|
||||
@@ -249,7 +266,7 @@ int gr1553bm_start(void *bm)
|
||||
return -2;
|
||||
|
||||
/* Start at Time = 0 */
|
||||
priv->regs->bm_ttag =
|
||||
priv->regs->bm_ttag =
|
||||
priv->cfg.time_resolution << GR1553B_BM_TTAG_RES_BIT;
|
||||
|
||||
/* Configure Filters */
|
||||
@@ -282,7 +299,7 @@ void gr1553bm_stop(void *bm)
|
||||
/* Stop Hardware */
|
||||
gr1553bm_hw_stop(priv);
|
||||
|
||||
/* At this point the hardware must be stopped and IRQ
|
||||
/* At this point the hardware must be stopped and IRQ
|
||||
* sources unmasked.
|
||||
*/
|
||||
|
||||
@@ -331,7 +348,7 @@ resample:
|
||||
hwtime2 = priv->regs->bm_ttag & GR1553B_BM_TTAG_VAL;
|
||||
if ( hwtime > hwtime2 ) {
|
||||
/* priv->time and hwtime may be out of sync if
|
||||
* IRQ updated priv->time just after bm_ttag was read
|
||||
* IRQ updated priv->time just after bm_ttag was read
|
||||
* here, we resample if we detect inconsistancy.
|
||||
*/
|
||||
goto resample;
|
||||
|
||||
@@ -147,7 +147,6 @@ static int gr1553rt_list_reg(struct gr1553rt_list *list)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0 /* unused for now */
|
||||
/* Unregister List from device */
|
||||
static void gr1553rt_list_unreg(struct gr1553rt_list *list)
|
||||
{
|
||||
@@ -156,16 +155,15 @@ static void gr1553rt_list_unreg(struct gr1553rt_list *list)
|
||||
priv->lists[list->listid] = NULL;
|
||||
list->listid = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int gr1553rt_bdid(void *rt, struct gr1553rt_sw_bd *bd)
|
||||
{
|
||||
struct gr1553rt_priv *priv = rt;
|
||||
|
||||
|
||||
unsigned short index;
|
||||
|
||||
/* Get Index of Software BD */
|
||||
index = ((unsigned int)bd - (unsigned int)&priv->swbds[0]) /
|
||||
index = ((unsigned int)bd - (unsigned int)&priv->swbds[0]) /
|
||||
sizeof(struct gr1553rt_sw_bd);
|
||||
|
||||
return index;
|
||||
@@ -197,10 +195,9 @@ static int gr1553rt_bd_alloc(void *rt, struct gr1553rt_sw_bd **bd, int cnt)
|
||||
}
|
||||
|
||||
*bd = &priv->swbds[priv->swbd_free];
|
||||
curr = &priv->swbds[priv->swbd_free];
|
||||
for (i=0; i<cnt; i++) {
|
||||
if ( i == 0) {
|
||||
curr = &priv->swbds[priv->swbd_free];
|
||||
} else {
|
||||
if ( i != 0) {
|
||||
curr = &priv->swbds[curr->this_next];
|
||||
}
|
||||
if ( curr->this_next == 0xffff ) {
|
||||
@@ -240,7 +237,7 @@ int gr1553rt_list_init
|
||||
{
|
||||
struct gr1553rt_priv *priv = rt;
|
||||
size_t size;
|
||||
int i;
|
||||
int i, malloc_used;
|
||||
struct gr1553rt_sw_bd *swbd;
|
||||
unsigned short index;
|
||||
struct gr1553rt_list *list;
|
||||
@@ -251,6 +248,7 @@ int gr1553rt_list_init
|
||||
* If the IN/OUT plist argument points to NULL a list
|
||||
* dynamically allocated here.
|
||||
*/
|
||||
malloc_used = 0;
|
||||
list = *plist;
|
||||
if ( list == NULL ) {
|
||||
/* Dynamically allocate LIST */
|
||||
@@ -258,20 +256,27 @@ int gr1553rt_list_init
|
||||
(cfg->bd_cnt * sizeof(list->bds[0]));
|
||||
list = grlib_malloc(size);
|
||||
if ( list == NULL )
|
||||
return -1;
|
||||
return -1; /* Out of Memory */
|
||||
*plist = list;
|
||||
malloc_used = 1;
|
||||
}
|
||||
|
||||
list->rt = rt;
|
||||
list->subadr = -1;
|
||||
list->listid = gr1553rt_list_reg(list);
|
||||
if ( list->listid == -1 )
|
||||
if ( list->listid == -1 ) {
|
||||
if (malloc_used)
|
||||
free(list);
|
||||
return -2; /* Too many lists */
|
||||
}
|
||||
list->cfg = cfg;
|
||||
list->bd_cnt = cfg->bd_cnt;
|
||||
|
||||
/* Allocate all BDs needed by list */
|
||||
if ( gr1553rt_bd_alloc(rt, &swbd, list->bd_cnt) ) {
|
||||
gr1553rt_list_unreg(list);
|
||||
if (malloc_used)
|
||||
free(list);
|
||||
return -3; /* Too few descriptors */
|
||||
}
|
||||
|
||||
@@ -352,7 +357,7 @@ int gr1553rt_bd_init(
|
||||
bd->next = nextbd;
|
||||
SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gr1553rt_bd_update(
|
||||
@@ -410,7 +415,7 @@ int gr1553rt_bd_update(
|
||||
}
|
||||
*dptr = (uint16_t *)tmp;
|
||||
}
|
||||
SPIN_LOCK_IRQ(&priv->devlock, irqflags);
|
||||
SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -727,7 +732,7 @@ void gr1553rt_hw_stop(struct gr1553rt_priv *priv)
|
||||
GR1553RT_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
|
||||
|
||||
/* Stop BC if not already stopped: BC can not be used simultaneously
|
||||
* as the RT anyway
|
||||
* as the RT anyway
|
||||
*/
|
||||
GR1553RT_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
|
||||
|
||||
@@ -766,17 +771,17 @@ void gr1553rt_sw_free(struct gr1553rt_priv *priv)
|
||||
}
|
||||
}
|
||||
|
||||
/* Free dynamically allocated buffers, if any */
|
||||
static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
|
||||
{
|
||||
int size;
|
||||
int retval = 0;
|
||||
|
||||
/* Allocate Event log */
|
||||
if ((unsigned int)priv->cfg.evlog_buffer & 1) {
|
||||
/* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
|
||||
priv->evlog_hw_base = (unsigned int *)
|
||||
priv->evlog_buffer = (void *)
|
||||
((unsigned int)priv->cfg.evlog_buffer & ~0x1);
|
||||
priv->evlog_buffer = priv->cfg.evlog_buffer;
|
||||
priv->evlog_hw_base = (unsigned int*)priv->evlog_buffer;
|
||||
drvmgr_translate_check(
|
||||
*priv->pdev,
|
||||
DMAMEM_TO_CPU,
|
||||
@@ -788,16 +793,19 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
|
||||
if (priv->cfg.evlog_buffer == NULL) {
|
||||
priv->evlog_buffer = grlib_malloc(
|
||||
priv->cfg.evlog_size * 2);
|
||||
if (priv->evlog_buffer == NULL)
|
||||
return -1;
|
||||
if (priv->evlog_buffer == NULL) {
|
||||
retval = -1;
|
||||
goto err;
|
||||
}
|
||||
/* Align to SIZE bytes boundary */
|
||||
priv->evlog_cpu_base = (unsigned int *)
|
||||
(((unsigned int)priv->evlog_buffer +
|
||||
(priv->cfg.evlog_size-1)) & ~(priv->cfg.evlog_size-1));
|
||||
} else {
|
||||
/* Addess already CPU-LOCAL */
|
||||
priv->evlog_buffer = priv->cfg.evlog_buffer;
|
||||
priv->evlog_cpu_base = (unsigned int *)priv->evlog_buffer;
|
||||
}
|
||||
/* Align to SIZE bytes boundary */
|
||||
priv->evlog_cpu_base = (unsigned int *)
|
||||
(((unsigned int)priv->evlog_buffer +
|
||||
(priv->cfg.evlog_size-1)) & ~(priv->cfg.evlog_size-1));
|
||||
|
||||
drvmgr_translate_check(
|
||||
*priv->pdev,
|
||||
@@ -807,6 +815,11 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
|
||||
priv->cfg.evlog_size
|
||||
);
|
||||
}
|
||||
/* Verify alignment */
|
||||
if ((unsigned int)priv->evlog_hw_base & (priv->cfg.evlog_size-1)) {
|
||||
retval = -2;
|
||||
goto err;
|
||||
}
|
||||
priv->evlog_cpu_end = priv->evlog_cpu_base +
|
||||
priv->cfg.evlog_size/sizeof(unsigned int *);
|
||||
|
||||
@@ -815,9 +828,9 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
|
||||
size = priv->bds_cnt * sizeof(struct gr1553rt_bd);
|
||||
if ((unsigned int)priv->cfg.bd_buffer & 1) {
|
||||
/* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
|
||||
priv->bds_hw = (struct gr1553rt_bd *)
|
||||
priv->bd_buffer = (void *)
|
||||
((unsigned int)priv->cfg.bd_buffer & ~0x1);
|
||||
priv->bd_buffer = priv->cfg.bd_buffer;
|
||||
priv->bds_hw = (struct gr1553rt_bd *)priv->bd_buffer;
|
||||
drvmgr_translate_check(
|
||||
*priv->pdev,
|
||||
DMAMEM_TO_CPU,
|
||||
@@ -828,15 +841,18 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
|
||||
} else {
|
||||
if ( priv->cfg.bd_buffer == NULL ) {
|
||||
priv->bd_buffer = grlib_malloc(size + 0xf);
|
||||
if (priv->bd_buffer == NULL)
|
||||
return -1;
|
||||
if (priv->bd_buffer == NULL) {
|
||||
retval = -1;
|
||||
goto err;
|
||||
}
|
||||
/* Align to 16 bytes boundary */
|
||||
priv->bds_cpu = (struct gr1553rt_bd *)
|
||||
(((unsigned int)priv->bd_buffer + 0xf) & ~0xf);
|
||||
} else {
|
||||
/* Addess already CPU-LOCAL */
|
||||
priv->bd_buffer = priv->cfg.bd_buffer;
|
||||
priv->bds_cpu = (struct gr1553rt_bd *)priv->bd_buffer;
|
||||
}
|
||||
/* Align to 16 bytes boundary */
|
||||
priv->bds_cpu = (struct gr1553rt_bd *)
|
||||
(((unsigned int)priv->bd_buffer + 0xf) & ~0xf);
|
||||
|
||||
/* Translate from CPU address to hardware address */
|
||||
drvmgr_translate_check(
|
||||
@@ -847,21 +863,28 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
|
||||
size
|
||||
);
|
||||
}
|
||||
/* Verify alignment */
|
||||
if ((unsigned int)priv->bds_hw & (0xf)) {
|
||||
retval = -2;
|
||||
goto err;
|
||||
}
|
||||
|
||||
#if (RTBD_MAX == 0)
|
||||
/* Allocate software description of */
|
||||
priv->swbds = grlib_malloc(priv->cfg.bd_count * sizeof(*priv->swbds));
|
||||
if ( priv->swbds == NULL ) {
|
||||
return -1;
|
||||
retval = -1;
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Allocate Sub address table */
|
||||
if ((unsigned int)priv->cfg.satab_buffer & 1) {
|
||||
/* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
|
||||
priv->sas_hw = (struct gr1553rt_sa *)
|
||||
priv->satab_buffer = (void *)
|
||||
((unsigned int)priv->cfg.satab_buffer & ~0x1);
|
||||
priv->satab_buffer = priv->cfg.satab_buffer;
|
||||
priv->sas_hw = (struct gr1553rt_sa *)priv->satab_buffer;
|
||||
|
||||
drvmgr_translate_check(
|
||||
*priv->pdev,
|
||||
DMAMEM_TO_CPU,
|
||||
@@ -871,16 +894,18 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
|
||||
} else {
|
||||
if (priv->cfg.satab_buffer == NULL) {
|
||||
priv->satab_buffer = grlib_malloc((16 * 32) * 2);
|
||||
if (priv->satab_buffer == NULL)
|
||||
return -1;
|
||||
if (priv->satab_buffer == NULL) {
|
||||
retval = -1;
|
||||
goto err;
|
||||
}
|
||||
/* Align to 512 bytes boundary */
|
||||
priv->sas_cpu = (struct gr1553rt_sa *)
|
||||
(((unsigned int)priv->satab_buffer + 0x1ff) & ~0x1ff);
|
||||
} else {
|
||||
/* Addess already CPU-LOCAL */
|
||||
priv->satab_buffer = priv->cfg.satab_buffer;
|
||||
priv->sas_cpu = (struct gr1553rt_sa *)priv->satab_buffer;
|
||||
}
|
||||
/* Align to 512 bytes boundary */
|
||||
priv->sas_cpu = (struct gr1553rt_sa *)
|
||||
(((unsigned int)priv->satab_buffer + 0x1ff) &
|
||||
~0x1ff);
|
||||
|
||||
/* Translate Address from CPU-LOCAL to HARDWARE (REMOTE) */
|
||||
drvmgr_translate_check(
|
||||
@@ -890,8 +915,17 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
|
||||
(void **)&priv->sas_hw,
|
||||
16 * 32);
|
||||
}
|
||||
/* Verify alignment */
|
||||
if ((unsigned int)priv->sas_hw & (0x1ff)) {
|
||||
retval = -2;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
if (retval) {
|
||||
gr1553rt_sw_free(priv);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void gr1553rt_sw_init(struct gr1553rt_priv *priv)
|
||||
@@ -937,7 +971,7 @@ void gr1553rt_sw_init(struct gr1553rt_priv *priv)
|
||||
int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg)
|
||||
{
|
||||
struct gr1553rt_priv *priv = rt;
|
||||
|
||||
int retval = 0;
|
||||
if ( priv->started )
|
||||
return -1;
|
||||
|
||||
@@ -949,9 +983,9 @@ int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg)
|
||||
if ( cfg->rtaddress > 30 )
|
||||
return -1;
|
||||
if ( (cfg->evlog_size & (cfg->evlog_size-1)) != 0)
|
||||
return -1; /* SIZE: Not aligned to a power of 2 */
|
||||
return -2; /* SIZE: Not aligned to a power of 2 */
|
||||
if ( ((unsigned int)priv->cfg.evlog_buffer & (cfg->evlog_size-1)) != 0 )
|
||||
return -1; /* Buffer: Not aligned to size */
|
||||
return -2; /* Buffer: Not aligned to size */
|
||||
#if (RTBD_MAX > 0)
|
||||
if ( cfg->bd_count > RTBD_MAX )
|
||||
return -1;
|
||||
@@ -962,8 +996,9 @@ int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg)
|
||||
|
||||
/*** Adapt to new config ***/
|
||||
|
||||
if ( gr1553rt_sw_alloc(priv) != 0 )
|
||||
return -1;
|
||||
if ( (retval=gr1553rt_sw_alloc(priv)) != 0 ) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
gr1553rt_sw_init(priv);
|
||||
|
||||
|
||||
@@ -46,12 +46,20 @@ int (*ahbstat_error)(
|
||||
uint32_t failing_address
|
||||
) __attribute__((weak)) = NULL;
|
||||
|
||||
#define AHBSTAT_STS_ME_BIT 13
|
||||
#define AHBSTAT_STS_FW_BIT 12
|
||||
#define AHBSTAT_STS_CF_BIT 11
|
||||
#define AHBSTAT_STS_AF_BIT 10
|
||||
#define AHBSTAT_STS_CE_BIT 9
|
||||
#define AHBSTAT_STS_NE_BIT 8
|
||||
#define AHBSTAT_STS_HW_BIT 7
|
||||
#define AHBSTAT_STS_HM_BIT 3
|
||||
#define AHBSTAT_STS_HS_BIT 0
|
||||
|
||||
#define AHBSTAT_STS_ME (1 << AHBSTAT_STS_ME_BIT)
|
||||
#define AHBSTAT_STS_FW (1 << AHBSTAT_STS_FW_BIT)
|
||||
#define AHBSTAT_STS_CF (1 << AHBSTAT_STS_CF_BIT)
|
||||
#define AHBSTAT_STS_AF (1 << AHBSTAT_STS_AF_BIT)
|
||||
#define AHBSTAT_STS_CE (1 << AHBSTAT_STS_CE_BIT)
|
||||
#define AHBSTAT_STS_NE (1 << AHBSTAT_STS_NE_BIT)
|
||||
#define AHBSTAT_STS_HW (1 << AHBSTAT_STS_HW_BIT)
|
||||
|
||||
@@ -199,7 +199,26 @@ static ambapp_device_name GAISLER_devices[] =
|
||||
{GAISLER_TCCOP, "TCCOP"},
|
||||
{GAISLER_SPIMASTER, "SPIMASTER"},
|
||||
{GAISLER_SPISLAVE, "SPISLAVE"},
|
||||
{GAISLER_GRSRIO, "GRSRIO"},
|
||||
{GAISLER_GRSRIO, "GRSRIO"},
|
||||
{GAISLER_AHBLM2AHB, "AHBLM2AHB"},
|
||||
{GAISLER_AHBS2NOC, "AHBS2NOC"},
|
||||
{GAISLER_TCAU, "TCAU"},
|
||||
{GAISLER_GRTMDYNVCID, "GRTMDYNVCID"},
|
||||
{GAISLER_RNOCIRQPROP, "RNOCIRQPROP"},
|
||||
{GAISLER_FTADDR, "FTADDR"},
|
||||
{GAISLER_ATG, "ATG"},
|
||||
{GAISLER_DFITRACE, "DFITRACE"},
|
||||
{GAISLER_SELFTEST, "SELFTEST"},
|
||||
{GAISLER_DFIERRINJ, "DFIERRINJ"},
|
||||
{GAISLER_DFICHECK, "DFICHECK"},
|
||||
{GAISLER_GRCANFD, "GRCANFD"},
|
||||
{GAISLER_NIM, "NIM"},
|
||||
{GAISLER_BANDGAP, "BANDGAP"},
|
||||
{GAISLER_MPROT, "MPROT"},
|
||||
{GAISLER_ADC, "ADC"},
|
||||
{GAISLER_BO, "BO"},
|
||||
{GAISLER_DAC, "DAC"},
|
||||
{GAISLER_PLL, "PLL"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -209,15 +209,14 @@ static uint32_t simple_tlib_tc_get_timecount(struct timecounter *tc)
|
||||
|
||||
static rtems_device_driver simple_initialize_counter(void)
|
||||
{
|
||||
uint64_t frequency;
|
||||
unsigned int tick_hz;
|
||||
unsigned int tick_hz, frequency;
|
||||
|
||||
frequency = 1000000;
|
||||
tlib_get_freq(priv.tlib_tick, &frequency, NULL);
|
||||
tick_hz = rtems_configuration_get_microseconds_per_tick();
|
||||
|
||||
rtems_timecounter_simple_install(
|
||||
&priv.tc_simple,
|
||||
frequency,
|
||||
(uint64_t)frequency,
|
||||
tick_hz,
|
||||
simple_tlib_tc_get_timecount
|
||||
);
|
||||
|
||||
144
bsps/shared/grlib/can/canbtrs.c
Normal file
144
bsps/shared/grlib/can/canbtrs.c
Normal file
@@ -0,0 +1,144 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup can
|
||||
*
|
||||
* @brief Common CAN baud-rate routines for OCCAN/GRCAN/GRCANFD controllers
|
||||
*
|
||||
* Implements common routines for calculating CAN baud-rate parameters from
|
||||
* a user provided baud-rate speed.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019, 2020 Cobham Gailer AB
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <grlib/canbtrs.h>
|
||||
|
||||
/*#define GRLIB_CANBTRS_DEBUG*/
|
||||
|
||||
/* Calculate CAN baud-rate generation parameters from requested baud-rate */
|
||||
int grlib_canbtrs_calc_timing(
|
||||
unsigned int baud,
|
||||
unsigned int core_hz,
|
||||
unsigned int sampl_pt,
|
||||
struct grlib_canbtrs_ranges *br,
|
||||
struct grlib_canbtrs_timing *timing
|
||||
)
|
||||
{
|
||||
int best_error = 2000000000, best_tseg=0, best_scaler=0;
|
||||
int tseg=0, tseg1=0, tseg2=0, sc, tmp, error;
|
||||
|
||||
/* Default to 80% sample point */
|
||||
if ((sampl_pt < 50) || (sampl_pt > 99))
|
||||
sampl_pt = 80;
|
||||
|
||||
/* step though all TSEG1+TSEG2 values possible */
|
||||
for (tseg = (br->min_tseg1 + br->min_tseg2);
|
||||
tseg <= (br->max_tseg1 + br->max_tseg2);
|
||||
tseg++) {
|
||||
/* calculate scaler */
|
||||
tmp = ((br->divfactor + tseg) * baud);
|
||||
sc = (core_hz * 2)/ tmp - core_hz / tmp;
|
||||
if (sc <= 0 || sc > br->max_scaler)
|
||||
continue;
|
||||
if (br->has_bpr &&
|
||||
(((sc > 256 * 1) && (sc <= 256 * 2) && (sc & 0x1)) ||
|
||||
((sc > 256 * 2) && (sc <= 256 * 4) && (sc & 0x3)) ||
|
||||
((sc > 256 * 4) && (sc <= 256 * 8) && (sc & 0x7))))
|
||||
continue;
|
||||
|
||||
error = baud - core_hz / (sc * (br->divfactor + tseg));
|
||||
#ifdef GRLIB_CANBTRS_DEBUG
|
||||
printf(" baud=%d, tseg=%d, sc=%d, error=%d\n",
|
||||
baud, tseg, sc, error);
|
||||
#endif
|
||||
if (error < 0)
|
||||
error = -error;
|
||||
|
||||
/* tseg is increasing, so we accept higher tseg with the same
|
||||
* baudrate to get better sampling point.
|
||||
*/
|
||||
if (error <= best_error) {
|
||||
best_error = error;
|
||||
best_tseg = tseg;
|
||||
best_scaler = sc;
|
||||
#ifdef GRLIB_CANBTRS_DEBUG
|
||||
printf(" ! best baud=%d\n",
|
||||
core_hz/(sc * (br->divfactor + tseg)));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* return an error if 5% off baud-rate */
|
||||
if (best_error && (baud / best_error <= 5)) {
|
||||
return -2;
|
||||
} else if (!timing) {
|
||||
return 0; /* nothing to store result in, but a valid bitrate can be calculated */
|
||||
}
|
||||
|
||||
tseg2 = (best_tseg + br->divfactor) -
|
||||
((sampl_pt * (best_tseg + br->divfactor)) / 100);
|
||||
if (tseg2 < br->min_tseg2) {
|
||||
tseg2 = br->min_tseg2;
|
||||
} else if (tseg2 > br->max_tseg2) {
|
||||
tseg2 = br->max_tseg2;
|
||||
}
|
||||
|
||||
tseg1 = best_tseg - tseg2;
|
||||
if (tseg1 > br->max_tseg1) {
|
||||
tseg1 = br->max_tseg1;
|
||||
tseg2 = best_tseg - tseg1;
|
||||
} else if (tseg1 < br->min_tseg1) {
|
||||
tseg1 = br->min_tseg1;
|
||||
tseg2 = best_tseg - tseg1;
|
||||
}
|
||||
|
||||
/* Get scaler and BPR from pseudo SCALER clock */
|
||||
if (best_scaler <= 256) {
|
||||
timing->scaler = best_scaler - 1;
|
||||
timing->bpr = 0;
|
||||
} else if (best_scaler <= 256 * 2) {
|
||||
timing->scaler = ((best_scaler + 1) >> 1) - 1;
|
||||
timing->bpr = 1;
|
||||
} else if (best_scaler <= 256 * 4) {
|
||||
timing->scaler = ((best_scaler + 1) >> 2) - 1;
|
||||
timing->bpr = 2;
|
||||
} else {
|
||||
timing->scaler = ((best_scaler + 1) >> 3) - 1;
|
||||
timing->bpr = 3;
|
||||
}
|
||||
|
||||
timing->ps1 = tseg1;
|
||||
timing->ps2 = tseg2;
|
||||
timing->rsj = 1;
|
||||
|
||||
#ifdef GRLIB_CANBTRS_DEBUG
|
||||
printf(" ! result: sc=%d,bpr=%d,ps1=%d,ps2=%d\n", timing->scaler, timing->bpr, timing->ps1, timing->ps2);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* GRCAN driver
|
||||
*
|
||||
* COPYRIGHT (c) 2007.
|
||||
* COPYRIGHT (c) 2007-2019.
|
||||
* Cobham Gaisler AB.
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
@@ -18,18 +18,17 @@
|
||||
#include <rtems/bspIo.h>
|
||||
|
||||
#include <grlib/grcan.h>
|
||||
#include <grlib/canbtrs.h>
|
||||
#include <drvmgr/drvmgr.h>
|
||||
#include <grlib/ambapp_bus.h>
|
||||
#include <grlib/ambapp.h>
|
||||
|
||||
#include <grlib/grlib_impl.h>
|
||||
#include "grcan_internal.h"
|
||||
|
||||
/* Maximum number of GRCAN devices supported by driver */
|
||||
#define GRCAN_COUNT_MAX 8
|
||||
|
||||
#define WRAP_AROUND_TX_MSGS 1
|
||||
#define WRAP_AROUND_RX_MSGS 2
|
||||
#define GRCAN_MSG_SIZE sizeof(struct grcan_msg)
|
||||
#define BLOCK_SIZE (16*4)
|
||||
|
||||
/* grcan needs to have it buffers aligned to 1k boundaries */
|
||||
@@ -57,15 +56,6 @@
|
||||
#define IRQ_MASK(irqno)
|
||||
#endif
|
||||
|
||||
#ifndef GRCAN_DEFAULT_BAUD
|
||||
/* default to 500kbits/s */
|
||||
#define GRCAN_DEFAULT_BAUD 500000
|
||||
#endif
|
||||
|
||||
#ifndef GRCAN_SAMPLING_POINT
|
||||
#define GRCAN_SAMPLING_POINT 80
|
||||
#endif
|
||||
|
||||
/* Uncomment for debug output */
|
||||
/****************** DEBUG Definitions ********************/
|
||||
#define DBG_TX 2
|
||||
@@ -88,70 +78,10 @@ int state2err[4] = {
|
||||
/* STATE_AHBERR */ GRCAN_RET_AHBERR
|
||||
};
|
||||
|
||||
struct grcan_msg {
|
||||
unsigned int head[2];
|
||||
unsigned char data[8];
|
||||
};
|
||||
|
||||
struct grcan_config {
|
||||
struct grcan_timing timing;
|
||||
struct grcan_selection selection;
|
||||
int abort;
|
||||
int silent;
|
||||
};
|
||||
|
||||
struct grcan_priv {
|
||||
struct drvmgr_dev *dev; /* Driver manager device */
|
||||
char devName[32]; /* Device Name */
|
||||
unsigned int baseaddr, ram_base;
|
||||
struct grcan_regs *regs;
|
||||
int irq;
|
||||
int minor;
|
||||
int open;
|
||||
int started;
|
||||
unsigned int channel;
|
||||
int flushing;
|
||||
unsigned int corefreq_hz;
|
||||
|
||||
/* Circular DMA buffers */
|
||||
void *_rx, *_rx_hw;
|
||||
void *_tx, *_tx_hw;
|
||||
void *txbuf_adr;
|
||||
void *rxbuf_adr;
|
||||
struct grcan_msg *rx;
|
||||
struct grcan_msg *tx;
|
||||
unsigned int rxbuf_size; /* requested RX buf size in bytes */
|
||||
unsigned int txbuf_size; /* requested TX buf size in bytes */
|
||||
|
||||
int txblock, rxblock;
|
||||
int txcomplete, rxcomplete;
|
||||
|
||||
struct grcan_filter sfilter;
|
||||
struct grcan_filter afilter;
|
||||
int config_changed; /* 0=no changes, 1=changes ==> a Core reset is needed */
|
||||
struct grcan_config config;
|
||||
struct grcan_stats stats;
|
||||
|
||||
rtems_id rx_sem, tx_sem, txempty_sem, dev_sem;
|
||||
SPIN_DECLARE(devlock);
|
||||
};
|
||||
|
||||
static void __inline__ grcan_hw_reset(struct grcan_regs *regs);
|
||||
|
||||
static int grcan_hw_read_try(
|
||||
struct grcan_priv *pDev,
|
||||
struct grcan_regs *regs,
|
||||
CANMsg *buffer,
|
||||
int max);
|
||||
|
||||
static int grcan_hw_write_try(
|
||||
struct grcan_priv *pDev,
|
||||
struct grcan_regs *regs,
|
||||
CANMsg *buffer,
|
||||
int count);
|
||||
|
||||
static void grcan_hw_config(
|
||||
struct grcan_regs *regs,
|
||||
struct grcan_priv *pDev,
|
||||
struct grcan_config *conf);
|
||||
|
||||
static void grcan_hw_accept(
|
||||
@@ -164,22 +94,41 @@ static void grcan_hw_sync(
|
||||
|
||||
static void grcan_interrupt(void *arg);
|
||||
|
||||
#ifdef GRCAN_REG_BYPASS_CACHE
|
||||
#define READ_REG(address) grlib_read_uncached32((unsigned int)(address))
|
||||
#else
|
||||
#define READ_REG(address) (*(volatile unsigned int *)(address))
|
||||
#endif
|
||||
|
||||
#ifdef GRCAN_DMA_BYPASS_CACHE
|
||||
#define READ_DMA_WORD(address) grlib_read_uncached32((unsigned int)(address))
|
||||
#define READ_DMA_BYTE(address) grlib_read_uncached8((unsigned int)(address))
|
||||
#else
|
||||
#define READ_DMA_WORD(address) (*(volatile unsigned int *)(address))
|
||||
#define READ_DMA_BYTE(address) (*(volatile unsigned char *)(address))
|
||||
#endif
|
||||
|
||||
#define NELEM(a) ((int) (sizeof (a) / sizeof (a[0])))
|
||||
|
||||
/* GRCAN nominal boundaries for baud-rate paramters */
|
||||
struct grlib_canbtrs_ranges grcan_btrs_ranges = {
|
||||
.max_scaler = 256*8, /* scaler is multiplied by BPR in steps 1,2,4,8 */
|
||||
.has_bpr = 1,
|
||||
.divfactor = 2,
|
||||
.min_tseg1 = 1,
|
||||
.max_tseg1 = 15,
|
||||
.min_tseg2 = 2,
|
||||
.max_tseg2 = 8,
|
||||
};
|
||||
|
||||
/* GRCANFD nominal boundaries */
|
||||
struct grlib_canbtrs_ranges grcanfd_nom_btrs_ranges = {
|
||||
.max_scaler = 256,
|
||||
.has_bpr = 0,
|
||||
.divfactor = 1,
|
||||
.min_tseg1 = 2,
|
||||
.max_tseg1 = 63,
|
||||
.min_tseg2 = 2,
|
||||
.max_tseg2 = 16,
|
||||
};
|
||||
|
||||
/* GRCANFD flexible baud-rate boundaries */
|
||||
struct grlib_canbtrs_ranges grcanfd_fd_btrs_ranges = {
|
||||
.max_scaler = 256,
|
||||
.has_bpr = 0,
|
||||
.divfactor = 1,
|
||||
.min_tseg1 = 1,
|
||||
.max_tseg1 = 15,
|
||||
.min_tseg2 = 2,
|
||||
.max_tseg2 = 8,
|
||||
};
|
||||
|
||||
static int grcan_count = 0;
|
||||
static struct grcan_priv *priv_tab[GRCAN_COUNT_MAX];
|
||||
|
||||
@@ -202,6 +151,7 @@ struct amba_dev_id grcan_ids[] =
|
||||
{
|
||||
{VENDOR_GAISLER, GAISLER_GRCAN},
|
||||
{VENDOR_GAISLER, GAISLER_GRHCAN},
|
||||
{VENDOR_GAISLER, GAISLER_GRCANFD},
|
||||
{0, 0} /* Mark end of table */
|
||||
};
|
||||
|
||||
@@ -294,6 +244,8 @@ int grcan_device_init(struct grcan_priv *pDev)
|
||||
pDev->irq = pnpinfo->irq;
|
||||
pDev->regs = (struct grcan_regs *)pnpinfo->apb_slv->start;
|
||||
pDev->minor = pDev->dev->minor_drv;
|
||||
if (ambadev->id.device == GAISLER_GRCANFD)
|
||||
pDev->fd_capable = 1;
|
||||
|
||||
/* Get frequency in Hz */
|
||||
if ( drvmgr_freq_get(pDev->dev, DEV_APB_SLV, &pDev->corefreq_hz) ) {
|
||||
@@ -373,7 +325,7 @@ static rtems_device_driver grcan_hw_start(struct grcan_priv *pDev)
|
||||
* and Setup timing
|
||||
*/
|
||||
if (pDev->config_changed) {
|
||||
grcan_hw_config(pDev->regs, &pDev->config);
|
||||
grcan_hw_config(pDev, &pDev->config);
|
||||
pDev->config_changed = 0;
|
||||
}
|
||||
|
||||
@@ -456,9 +408,10 @@ static void grcan_sw_stop(struct grcan_priv *pDev)
|
||||
rtems_semaphore_release(pDev->txempty_sem);
|
||||
}
|
||||
|
||||
static void grcan_hw_config(struct grcan_regs *regs, struct grcan_config *conf)
|
||||
static void grcan_hw_config(struct grcan_priv *pDev, struct grcan_config *conf)
|
||||
{
|
||||
unsigned int config = 0;
|
||||
struct grcan_regs *regs = pDev->regs;
|
||||
|
||||
/* Reset HurriCANe Core */
|
||||
regs->ctrl = 0;
|
||||
@@ -479,13 +432,29 @@ static void grcan_hw_config(struct grcan_regs *regs, struct grcan_config *conf)
|
||||
config |= GRCAN_CFG_ENABLE1;
|
||||
|
||||
/* Timing */
|
||||
config |= (conf->timing.bpr << GRCAN_CFG_BPR_BIT) & GRCAN_CFG_BPR;
|
||||
config |= (conf->timing.rsj << GRCAN_CFG_RSJ_BIT) & GRCAN_CFG_RSJ;
|
||||
config |= (conf->timing.ps1 << GRCAN_CFG_PS1_BIT) & GRCAN_CFG_PS1;
|
||||
config |= (conf->timing.ps2 << GRCAN_CFG_PS2_BIT) & GRCAN_CFG_PS2;
|
||||
config |=
|
||||
(conf->timing.scaler << GRCAN_CFG_SCALER_BIT) & GRCAN_CFG_SCALER;
|
||||
|
||||
if (!pDev->fd_capable) {
|
||||
config |= (conf->timing.bpr << GRCAN_CFG_BPR_BIT) &
|
||||
GRCAN_CFG_BPR;
|
||||
config |= (conf->timing.rsj << GRCAN_CFG_RSJ_BIT) &
|
||||
GRCAN_CFG_RSJ;
|
||||
config |= (conf->timing.ps1 << GRCAN_CFG_PS1_BIT) &
|
||||
GRCAN_CFG_PS1;
|
||||
config |= (conf->timing.ps2 << GRCAN_CFG_PS2_BIT) &
|
||||
GRCAN_CFG_PS2;
|
||||
config |= (conf->timing.scaler << GRCAN_CFG_SCALER_BIT) &
|
||||
GRCAN_CFG_SCALER;
|
||||
} else {
|
||||
regs->nbtr =
|
||||
(conf->timing.scaler << GRCANFD_NBTR_SCALER_BIT) |
|
||||
(conf->timing.ps1 << GRCANFD_NBTR_PS1_BIT) |
|
||||
(conf->timing.ps2 << GRCANFD_NBTR_PS2_BIT) |
|
||||
(conf->timing.rsj << GRCANFD_NBTR_SJW_BIT);
|
||||
regs->fdbtr =
|
||||
(conf->timing_fd.scaler << GRCANFD_FDBTR_SCALER_BIT) |
|
||||
(conf->timing_fd.ps1 << GRCANFD_FDBTR_PS1_BIT) |
|
||||
(conf->timing_fd.ps2 << GRCANFD_FDBTR_PS2_BIT) |
|
||||
(conf->timing_fd.sjw << GRCANFD_FDBTR_SJW_BIT);
|
||||
}
|
||||
/* Write configuration */
|
||||
regs->conf = config;
|
||||
|
||||
@@ -520,338 +489,7 @@ static void grcan_hw_sync(struct grcan_regs *regs, struct grcan_filter *sfilter)
|
||||
regs->smask = sfilter->mask;
|
||||
}
|
||||
|
||||
static unsigned int grcan_hw_rxavail(
|
||||
unsigned int rp,
|
||||
unsigned int wp, unsigned int size
|
||||
)
|
||||
{
|
||||
if (rp == wp) {
|
||||
/* read pointer and write pointer is equal only
|
||||
* when RX buffer is empty.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wp > rp) {
|
||||
return (wp - rp) / GRCAN_MSG_SIZE;
|
||||
} else {
|
||||
return (size - (rp - wp)) / GRCAN_MSG_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int grcan_hw_txspace(
|
||||
unsigned int rp,
|
||||
unsigned int wp,
|
||||
unsigned int size
|
||||
)
|
||||
{
|
||||
unsigned int left;
|
||||
|
||||
if (rp == wp) {
|
||||
/* read pointer and write pointer is equal only
|
||||
* when TX buffer is empty.
|
||||
*/
|
||||
return size / GRCAN_MSG_SIZE - WRAP_AROUND_TX_MSGS;
|
||||
}
|
||||
|
||||
/* size - 4 - abs(read-write) */
|
||||
if (wp > rp) {
|
||||
left = size - (wp - rp);
|
||||
} else {
|
||||
left = rp - wp;
|
||||
}
|
||||
|
||||
return left / GRCAN_MSG_SIZE - WRAP_AROUND_TX_MSGS;
|
||||
}
|
||||
|
||||
#define MIN_TSEG1 1
|
||||
#define MIN_TSEG2 2
|
||||
#define MAX_TSEG1 14
|
||||
#define MAX_TSEG2 8
|
||||
|
||||
static int grcan_calc_timing(
|
||||
unsigned int baud, /* The requested BAUD to calculate timing for */
|
||||
unsigned int core_hz, /* Frequency in Hz of GRCAN Core */
|
||||
unsigned int sampl_pt,
|
||||
struct grcan_timing *timing /* result is placed here */
|
||||
)
|
||||
{
|
||||
int best_error = 1000000000;
|
||||
int error;
|
||||
int best_tseg = 0, best_brp = 0, brp = 0;
|
||||
int tseg = 0, tseg1 = 0, tseg2 = 0;
|
||||
int sjw = 1;
|
||||
|
||||
/* Default to 90% */
|
||||
if ((sampl_pt < 50) || (sampl_pt > 99)) {
|
||||
sampl_pt = GRCAN_SAMPLING_POINT;
|
||||
}
|
||||
|
||||
if ((baud < 5000) || (baud > 1000000)) {
|
||||
/* invalid speed mode */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* find best match, return -2 if no good reg
|
||||
* combination is available for this frequency
|
||||
*/
|
||||
|
||||
/* some heuristic specials */
|
||||
if (baud > ((1000000 + 500000) / 2))
|
||||
sampl_pt = 75;
|
||||
|
||||
if (baud < ((12500 + 10000) / 2))
|
||||
sampl_pt = 75;
|
||||
|
||||
/* tseg even = round down, odd = round up */
|
||||
for (
|
||||
tseg = (MIN_TSEG1 + MIN_TSEG2 + 2) * 2;
|
||||
tseg <= (MAX_TSEG2 + MAX_TSEG1 + 2) * 2 + 1;
|
||||
tseg++
|
||||
) {
|
||||
brp = core_hz / ((1 + tseg / 2) * baud) + tseg % 2;
|
||||
if (
|
||||
(brp <= 0) ||
|
||||
((brp > 256 * 1) && (brp <= 256 * 2) && (brp & 0x1)) ||
|
||||
((brp > 256 * 2) && (brp <= 256 * 4) && (brp & 0x3)) ||
|
||||
((brp > 256 * 4) && (brp <= 256 * 8) && (brp & 0x7)) ||
|
||||
(brp > 256 * 8)
|
||||
)
|
||||
continue;
|
||||
|
||||
error = baud - core_hz / (brp * (1 + tseg / 2));
|
||||
if (error < 0) {
|
||||
error = -error;
|
||||
}
|
||||
|
||||
if (error <= best_error) {
|
||||
best_error = error;
|
||||
best_tseg = tseg / 2;
|
||||
best_brp = brp - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_error && (baud / best_error < 10)) {
|
||||
return -2;
|
||||
} else if (!timing)
|
||||
return 0; /* nothing to store result in, but a valid bitrate can be calculated */
|
||||
|
||||
tseg2 = best_tseg - (sampl_pt * (best_tseg + 1)) / 100;
|
||||
|
||||
if (tseg2 < MIN_TSEG2) {
|
||||
tseg2 = MIN_TSEG2;
|
||||
}
|
||||
|
||||
if (tseg2 > MAX_TSEG2) {
|
||||
tseg2 = MAX_TSEG2;
|
||||
}
|
||||
|
||||
tseg1 = best_tseg - tseg2 - 2;
|
||||
|
||||
if (tseg1 > MAX_TSEG1) {
|
||||
tseg1 = MAX_TSEG1;
|
||||
tseg2 = best_tseg - tseg1 - 2;
|
||||
}
|
||||
|
||||
/* Get scaler and BRP from pseudo BRP */
|
||||
if (best_brp <= 256) {
|
||||
timing->scaler = best_brp;
|
||||
timing->bpr = 0;
|
||||
} else if (best_brp <= 256 * 2) {
|
||||
timing->scaler = ((best_brp + 1) >> 1) - 1;
|
||||
timing->bpr = 1;
|
||||
} else if (best_brp <= 256 * 4) {
|
||||
timing->scaler = ((best_brp + 1) >> 2) - 1;
|
||||
timing->bpr = 2;
|
||||
} else {
|
||||
timing->scaler = ((best_brp + 1) >> 3) - 1;
|
||||
timing->bpr = 3;
|
||||
}
|
||||
|
||||
timing->ps1 = tseg1 + 1;
|
||||
timing->ps2 = tseg2;
|
||||
timing->rsj = sjw;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int grcan_hw_read_try(
|
||||
struct grcan_priv *pDev,
|
||||
struct grcan_regs *regs,
|
||||
CANMsg * buffer,
|
||||
int max
|
||||
)
|
||||
{
|
||||
int i, j;
|
||||
CANMsg *dest;
|
||||
struct grcan_msg *source, tmp;
|
||||
unsigned int wp, rp, size, rxmax, addr;
|
||||
int trunk_msg_cnt;
|
||||
|
||||
FUNCDBG();
|
||||
|
||||
wp = READ_REG(®s->rx0wr);
|
||||
rp = READ_REG(®s->rx0rd);
|
||||
|
||||
/*
|
||||
* Due to hardware wrap around simplification write pointer will
|
||||
* never reach the read pointer, at least a gap of 8 bytes.
|
||||
* The only time they are equal is when the read pointer has
|
||||
* reached the write pointer (empty buffer)
|
||||
*
|
||||
*/
|
||||
if (wp != rp) {
|
||||
/* Not empty, we have received chars...
|
||||
* Read as much as possible from DMA buffer
|
||||
*/
|
||||
size = READ_REG(®s->rx0size);
|
||||
|
||||
/* Get number of bytes available in RX buffer */
|
||||
trunk_msg_cnt = grcan_hw_rxavail(rp, wp, size);
|
||||
|
||||
/* truncate size if user space buffer hasn't room for
|
||||
* all received chars.
|
||||
*/
|
||||
if (trunk_msg_cnt > max)
|
||||
trunk_msg_cnt = max;
|
||||
|
||||
/* Read until i is 0 */
|
||||
i = trunk_msg_cnt;
|
||||
|
||||
addr = (unsigned int)pDev->rx;
|
||||
source = (struct grcan_msg *)(addr + rp);
|
||||
dest = buffer;
|
||||
rxmax = addr + (size - GRCAN_MSG_SIZE);
|
||||
|
||||
/* Read as many can messages as possible */
|
||||
while (i > 0) {
|
||||
/* Read CAN message from DMA buffer */
|
||||
tmp.head[0] = READ_DMA_WORD(&source->head[0]);
|
||||
tmp.head[1] = READ_DMA_WORD(&source->head[1]);
|
||||
if (tmp.head[1] & 0x4) {
|
||||
DBGC(DBG_RX, "overrun\n");
|
||||
}
|
||||
if (tmp.head[1] & 0x2) {
|
||||
DBGC(DBG_RX, "bus-off mode\n");
|
||||
}
|
||||
if (tmp.head[1] & 0x1) {
|
||||
DBGC(DBG_RX, "error-passive mode\n");
|
||||
}
|
||||
/* Convert one grcan CAN message to one "software" CAN message */
|
||||
dest->extended = tmp.head[0] >> 31;
|
||||
dest->rtr = (tmp.head[0] >> 30) & 0x1;
|
||||
if (dest->extended) {
|
||||
dest->id = tmp.head[0] & 0x3fffffff;
|
||||
} else {
|
||||
dest->id = (tmp.head[0] >> 18) & 0xfff;
|
||||
}
|
||||
dest->len = tmp.head[1] >> 28;
|
||||
for (j = 0; j < dest->len; j++)
|
||||
dest->data[j] = READ_DMA_BYTE(&source->data[j]);
|
||||
|
||||
/* wrap around if neccessary */
|
||||
source =
|
||||
((unsigned int)source >= rxmax) ?
|
||||
(struct grcan_msg *)addr : source + 1;
|
||||
dest++; /* straight user buffer */
|
||||
i--;
|
||||
}
|
||||
{
|
||||
/* A bus off interrupt may have occured after checking pDev->started */
|
||||
SPIN_IRQFLAGS(oldLevel);
|
||||
|
||||
SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
|
||||
if (pDev->started == STATE_STARTED) {
|
||||
regs->rx0rd = (unsigned int) source - addr;
|
||||
regs->rx0ctrl = GRCAN_RXCTRL_ENABLE;
|
||||
} else {
|
||||
DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
|
||||
trunk_msg_cnt = state2err[pDev->started];
|
||||
}
|
||||
SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
|
||||
}
|
||||
return trunk_msg_cnt;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int grcan_hw_write_try(
|
||||
struct grcan_priv *pDev,
|
||||
struct grcan_regs *regs,
|
||||
CANMsg * buffer,
|
||||
int count
|
||||
)
|
||||
{
|
||||
unsigned int rp, wp, size, txmax, addr;
|
||||
int ret;
|
||||
struct grcan_msg *dest;
|
||||
CANMsg *source;
|
||||
int space_left;
|
||||
unsigned int tmp;
|
||||
int i;
|
||||
|
||||
DBGC(DBG_TX, "\n");
|
||||
/*FUNCDBG(); */
|
||||
|
||||
rp = READ_REG(®s->tx0rd);
|
||||
wp = READ_REG(®s->tx0wr);
|
||||
size = READ_REG(®s->tx0size);
|
||||
|
||||
space_left = grcan_hw_txspace(rp, wp, size);
|
||||
|
||||
/* is circular fifo full? */
|
||||
if (space_left < 1)
|
||||
return 0;
|
||||
|
||||
/* Truncate size */
|
||||
if (space_left > count)
|
||||
space_left = count;
|
||||
ret = space_left;
|
||||
|
||||
addr = (unsigned int)pDev->tx;
|
||||
|
||||
dest = (struct grcan_msg *)(addr + wp);
|
||||
source = (CANMsg *) buffer;
|
||||
txmax = addr + (size - GRCAN_MSG_SIZE);
|
||||
|
||||
while (space_left > 0) {
|
||||
/* Convert and write CAN message to DMA buffer */
|
||||
if (source->extended) {
|
||||
tmp = (1 << 31) | (source->id & 0x3fffffff);
|
||||
} else {
|
||||
tmp = (source->id & 0xfff) << 18;
|
||||
}
|
||||
if (source->rtr)
|
||||
tmp |= (1 << 30);
|
||||
dest->head[0] = tmp;
|
||||
dest->head[1] = source->len << 28;
|
||||
for (i = 0; i < source->len; i++)
|
||||
dest->data[i] = source->data[i];
|
||||
source++; /* straight user buffer */
|
||||
dest =
|
||||
((unsigned int)dest >= txmax) ?
|
||||
(struct grcan_msg *)addr : dest + 1;
|
||||
space_left--;
|
||||
}
|
||||
|
||||
{
|
||||
/* A bus off interrupt may have occured after checking pDev->started */
|
||||
SPIN_IRQFLAGS(oldLevel);
|
||||
|
||||
SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
|
||||
if (pDev->started == STATE_STARTED) {
|
||||
regs->tx0wr = (unsigned int) dest - addr;
|
||||
regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
|
||||
} else {
|
||||
DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
|
||||
ret = state2err[pDev->started];
|
||||
}
|
||||
SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int grcan_wait_rxdata(struct grcan_priv *pDev, int min)
|
||||
int grcan_wait_rxdata(struct grcan_priv *pDev, int min)
|
||||
{
|
||||
unsigned int wp, rp, size, irq;
|
||||
unsigned int irq_trunk, dataavail;
|
||||
@@ -934,7 +572,7 @@ static int grcan_wait_rxdata(struct grcan_priv *pDev, int min)
|
||||
* min must be at least WRAP_AROUND_TX_MSGS less than max buffer capacity
|
||||
* (pDev->txbuf_size/GRCAN_MSG_SIZE) for this algo to work.
|
||||
*/
|
||||
static int grcan_wait_txspace(struct grcan_priv *pDev, int min)
|
||||
int grcan_wait_txspace(struct grcan_priv *pDev, int min)
|
||||
{
|
||||
int wait, state;
|
||||
unsigned int irq, rp, wp, size, space_left;
|
||||
@@ -1007,7 +645,7 @@ static int grcan_wait_txspace(struct grcan_priv *pDev, int min)
|
||||
return state2err[pDev->started];
|
||||
}
|
||||
|
||||
/* At this point the TxIRQ has been masked, we ned not to mask it */
|
||||
/* At this point the TxIRQ has been masked, we need not to mask it */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1211,6 +849,7 @@ void *grcan_open(int dev_no)
|
||||
struct grcan_priv *pDev;
|
||||
void *ret;
|
||||
union drvmgr_key_value *value;
|
||||
struct grlib_canbtrs_ranges *br;
|
||||
|
||||
FUNCDBG();
|
||||
|
||||
@@ -1282,7 +921,13 @@ void *grcan_open(int dev_no)
|
||||
pDev->sfilter.code = 0x00000000;
|
||||
|
||||
/* Calculate default timing register values */
|
||||
grcan_calc_timing(GRCAN_DEFAULT_BAUD,pDev->corefreq_hz,GRCAN_SAMPLING_POINT,&pDev->config.timing);
|
||||
if (pDev->fd_capable)
|
||||
br = &grcanfd_nom_btrs_ranges;
|
||||
else
|
||||
br = &grcan_btrs_ranges;
|
||||
grlib_canbtrs_calc_timing(
|
||||
GRCAN_DEFAULT_BAUD, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
|
||||
br, (struct grlib_canbtrs_timing *)&pDev->config.timing);
|
||||
|
||||
if ( grcan_alloc_buffers(pDev,1,1) ) {
|
||||
ret = NULL;
|
||||
@@ -1316,174 +961,11 @@ int grcan_close(void *d)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int grcan_read(void *d, CANMsg *msg, size_t ucount)
|
||||
int grcan_canfd_capable(void *d)
|
||||
{
|
||||
struct grcan_priv *pDev = d;
|
||||
CANMsg *dest;
|
||||
unsigned int count, left;
|
||||
int nread;
|
||||
int req_cnt;
|
||||
|
||||
FUNCDBG();
|
||||
|
||||
dest = msg;
|
||||
req_cnt = ucount;
|
||||
|
||||
if ( (!dest) || (req_cnt<1) )
|
||||
return GRCAN_RET_INVARG;
|
||||
|
||||
if (pDev->started != STATE_STARTED) {
|
||||
return GRCAN_RET_NOTSTARTED;
|
||||
}
|
||||
|
||||
DBGC(DBG_RX, "grcan_read [%p]: buf: %p len: %u\n", d, msg, (unsigned int) ucount);
|
||||
|
||||
nread = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt);
|
||||
if (nread < 0) {
|
||||
return nread;
|
||||
}
|
||||
count = nread;
|
||||
if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
|
||||
if ( count > 0 ) {
|
||||
/* Successfully received messages (at least one) */
|
||||
return count;
|
||||
}
|
||||
|
||||
/* nothing read, shall we block? */
|
||||
if ( !pDev->rxblock ) {
|
||||
/* non-blocking mode */
|
||||
return GRCAN_RET_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
while (count == 0 || (pDev->rxcomplete && (count!=req_cnt))) {
|
||||
if (!pDev->rxcomplete) {
|
||||
left = 1; /* return as soon as there is one message available */
|
||||
} else {
|
||||
left = req_cnt - count; /* return as soon as all data are available */
|
||||
|
||||
/* never wait for more than the half the maximum size of the receive buffer
|
||||
* Why? We need some time to copy buffer before to catch up with hw,
|
||||
* otherwise we would have to copy everything when the data has been
|
||||
* received.
|
||||
*/
|
||||
if (left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2)){
|
||||
left = (pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
nread = grcan_wait_rxdata(pDev, left);
|
||||
if (nread) {
|
||||
/* The wait has been aborted, probably due to
|
||||
* the device driver has been closed by another
|
||||
* thread or a bus-off. Return error code.
|
||||
*/
|
||||
return nread;
|
||||
}
|
||||
|
||||
/* Try read bytes from circular buffer */
|
||||
nread = grcan_hw_read_try(
|
||||
pDev,
|
||||
pDev->regs,
|
||||
dest+count,
|
||||
req_cnt-count);
|
||||
|
||||
if (nread < 0) {
|
||||
/* The read was aborted by bus-off. */
|
||||
return nread;
|
||||
}
|
||||
count += nread;
|
||||
}
|
||||
/* no need to unmask IRQ as IRQ Handler do that for us. */
|
||||
return count;
|
||||
}
|
||||
|
||||
int grcan_write(void *d, CANMsg *msg, size_t ucount)
|
||||
{
|
||||
struct grcan_priv *pDev = d;
|
||||
CANMsg *source;
|
||||
unsigned int count, left;
|
||||
int nwritten;
|
||||
int req_cnt;
|
||||
|
||||
DBGC(DBG_TX,"\n");
|
||||
|
||||
if ((pDev->started != STATE_STARTED) || pDev->config.silent || pDev->flushing)
|
||||
return GRCAN_RET_NOTSTARTED;
|
||||
|
||||
req_cnt = ucount;
|
||||
source = (CANMsg *) msg;
|
||||
|
||||
/* check proper length and buffer pointer */
|
||||
if (( req_cnt < 1) || (source == NULL) ){
|
||||
return GRCAN_RET_INVARG;
|
||||
}
|
||||
|
||||
nwritten = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt);
|
||||
if (nwritten < 0) {
|
||||
return nwritten;
|
||||
}
|
||||
count = nwritten;
|
||||
if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
|
||||
if ( count > 0 ) {
|
||||
/* Successfully transmitted chars (at least one char) */
|
||||
return count;
|
||||
}
|
||||
|
||||
/* nothing written, shall we block? */
|
||||
if ( !pDev->txblock ) {
|
||||
/* non-blocking mode */
|
||||
return GRCAN_RET_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
/* if in txcomplete mode we need to transmit all chars */
|
||||
while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){
|
||||
/*** block until room to fit all or as much of transmit buffer as possible
|
||||
* IRQ comes. Set up a valid IRQ point so that an IRQ is received
|
||||
* when we can put a chunk of data into transmit fifo
|
||||
*/
|
||||
if ( !pDev->txcomplete ){
|
||||
left = 1; /* wait for anything to fit buffer */
|
||||
}else{
|
||||
left = req_cnt - count; /* wait for all data to fit in buffer */
|
||||
|
||||
/* never wait for more than the half the maximum size of the transmit
|
||||
* buffer
|
||||
* Why? We need some time to fill buffer before hw catches up.
|
||||
*/
|
||||
if ( left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2) ){
|
||||
left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2;
|
||||
}
|
||||
}
|
||||
|
||||
nwritten = grcan_wait_txspace(pDev,left);
|
||||
/* Wait until more room in transmit buffer */
|
||||
if ( nwritten ) {
|
||||
/* The wait has been aborted, probably due to
|
||||
* the device driver has been closed by another
|
||||
* thread. To avoid deadlock we return directly
|
||||
* with error status.
|
||||
*/
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
/* Try read bytes from circular buffer */
|
||||
nwritten = grcan_hw_write_try(
|
||||
pDev,
|
||||
pDev->regs,
|
||||
source+count,
|
||||
req_cnt-count);
|
||||
|
||||
if (nwritten < 0) {
|
||||
/* Write was aborted by bus-off. */
|
||||
return nwritten;
|
||||
}
|
||||
count += nwritten;
|
||||
}
|
||||
/* no need to unmask IRQ as IRQ Handler do that for us. */
|
||||
|
||||
return count;
|
||||
return pDev->fd_capable;
|
||||
}
|
||||
|
||||
int grcan_start(void *d)
|
||||
@@ -1712,51 +1194,6 @@ int grcan_clr_stats(void *d)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int grcan_set_speed(void *d, unsigned int speed)
|
||||
{
|
||||
struct grcan_priv *pDev = d;
|
||||
struct grcan_timing timing;
|
||||
int ret;
|
||||
|
||||
FUNCDBG();
|
||||
|
||||
/* cannot change speed during run mode */
|
||||
if (pDev->started == STATE_STARTED)
|
||||
return -1;
|
||||
|
||||
/* get speed rate from argument */
|
||||
ret = grcan_calc_timing(speed, pDev->corefreq_hz, GRCAN_SAMPLING_POINT, &timing);
|
||||
if ( ret )
|
||||
return -2;
|
||||
|
||||
/* save timing/speed */
|
||||
pDev->config.timing = timing;
|
||||
pDev->config_changed = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int grcan_set_btrs(void *d, const struct grcan_timing *timing)
|
||||
{
|
||||
struct grcan_priv *pDev = d;
|
||||
|
||||
FUNCDBG();
|
||||
|
||||
/* Set BTR registers manually
|
||||
* Read GRCAN/HurriCANe Manual.
|
||||
*/
|
||||
if (pDev->started == STATE_STARTED)
|
||||
return -1;
|
||||
|
||||
if ( !timing )
|
||||
return -2;
|
||||
|
||||
pDev->config.timing = *timing;
|
||||
pDev->config_changed = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int grcan_set_afilter(void *d, const struct grcan_filter *filter)
|
||||
{
|
||||
struct grcan_priv *pDev = d;
|
||||
|
||||
140
bsps/shared/grlib/can/grcan_internal.h
Normal file
140
bsps/shared/grlib/can/grcan_internal.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* GRCAN driver
|
||||
*
|
||||
* COPYRIGHT (c) 2007-2019.
|
||||
* Cobham Gaisler AB.
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifndef GRCAN_DEFAULT_BAUD
|
||||
/* default to 500kbits/s */
|
||||
#define GRCAN_DEFAULT_BAUD 500000
|
||||
#endif
|
||||
|
||||
#ifndef GRCAN_SAMPLING_POINT
|
||||
#define GRCAN_SAMPLING_POINT 80
|
||||
#endif
|
||||
|
||||
#define WRAP_AROUND_TX_MSGS 1
|
||||
#define WRAP_AROUND_RX_MSGS 2
|
||||
#define GRCAN_MSG_SIZE sizeof(struct grcan_msg)
|
||||
|
||||
struct grcan_msg {
|
||||
unsigned int head[2];
|
||||
unsigned char data[8];
|
||||
};
|
||||
|
||||
struct grcan_config {
|
||||
struct grcan_timing timing;
|
||||
struct grcanfd_timing timing_fd;
|
||||
struct grcan_selection selection;
|
||||
int abort;
|
||||
int silent;
|
||||
};
|
||||
|
||||
struct grcan_priv {
|
||||
struct drvmgr_dev *dev; /* Driver manager device */
|
||||
char devName[32]; /* Device Name */
|
||||
unsigned int baseaddr, ram_base;
|
||||
struct grcan_regs *regs;
|
||||
int irq;
|
||||
int minor;
|
||||
int open;
|
||||
int started;
|
||||
unsigned int channel;
|
||||
int flushing;
|
||||
unsigned int corefreq_hz;
|
||||
int fd_capable;
|
||||
|
||||
/* Circular DMA buffers */
|
||||
void *_rx, *_rx_hw;
|
||||
void *_tx, *_tx_hw;
|
||||
void *txbuf_adr;
|
||||
void *rxbuf_adr;
|
||||
struct grcan_msg *rx;
|
||||
struct grcan_msg *tx;
|
||||
unsigned int rxbuf_size; /* requested RX buf size in bytes */
|
||||
unsigned int txbuf_size; /* requested TX buf size in bytes */
|
||||
|
||||
int txblock, rxblock;
|
||||
int txcomplete, rxcomplete;
|
||||
|
||||
struct grcan_filter sfilter;
|
||||
struct grcan_filter afilter;
|
||||
int config_changed; /* 0=no changes, 1=changes ==> a Core reset is needed */
|
||||
struct grcan_config config;
|
||||
struct grcan_stats stats;
|
||||
|
||||
rtems_id rx_sem, tx_sem, txempty_sem, dev_sem;
|
||||
SPIN_DECLARE(devlock);
|
||||
};
|
||||
|
||||
#ifdef GRCAN_REG_BYPASS_CACHE
|
||||
#define READ_REG(address) grlib_read_uncached32((unsigned int)(address))
|
||||
#else
|
||||
#define READ_REG(address) (*(volatile unsigned int *)(address))
|
||||
#endif
|
||||
|
||||
#ifdef GRCAN_DMA_BYPASS_CACHE
|
||||
#define READ_DMA_DOUBLE(address) grlib_read_uncached64((uint64_t *)(address))
|
||||
#define READ_DMA_WORD(address) grlib_read_uncached32((unsigned int)(address))
|
||||
#define READ_DMA_BYTE(address) grlib_read_uncached8((unsigned int)(address))
|
||||
#else
|
||||
#define READ_DMA_DOUBLE(address) (*(volatile uint64_t *)(address))
|
||||
#define READ_DMA_WORD(address) (*(volatile unsigned int *)(address))
|
||||
#define READ_DMA_BYTE(address) (*(volatile unsigned char *)(address))
|
||||
#endif
|
||||
|
||||
extern int state2err[4];
|
||||
extern struct grlib_canbtrs_ranges grcan_btrs_ranges;
|
||||
extern struct grlib_canbtrs_ranges grcanfd_nom_btrs_ranges;
|
||||
extern struct grlib_canbtrs_ranges grcanfd_fd_btrs_ranges;
|
||||
|
||||
int grcan_wait_rxdata(struct grcan_priv *pDev, int min);
|
||||
int grcan_wait_txspace(struct grcan_priv *pDev, int min);
|
||||
|
||||
static inline unsigned int grcan_hw_rxavail(
|
||||
unsigned int rp,
|
||||
unsigned int wp,
|
||||
unsigned int size)
|
||||
{
|
||||
if (rp == wp) {
|
||||
/* read pointer and write pointer is equal only
|
||||
* when RX buffer is empty.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wp > rp) {
|
||||
return (wp - rp) / GRCAN_MSG_SIZE;
|
||||
} else {
|
||||
return (size - (rp - wp)) / GRCAN_MSG_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned int grcan_hw_txspace(
|
||||
unsigned int rp,
|
||||
unsigned int wp,
|
||||
unsigned int size)
|
||||
{
|
||||
unsigned int left;
|
||||
|
||||
if (rp == wp) {
|
||||
/* read pointer and write pointer is equal only
|
||||
* when TX buffer is empty.
|
||||
*/
|
||||
return size / GRCAN_MSG_SIZE - WRAP_AROUND_TX_MSGS;
|
||||
}
|
||||
|
||||
/* size - 4 - abs(read-write) */
|
||||
if (wp > rp) {
|
||||
left = size - (wp - rp);
|
||||
} else {
|
||||
left = rp - wp;
|
||||
}
|
||||
|
||||
return left / GRCAN_MSG_SIZE - WRAP_AROUND_TX_MSGS;
|
||||
}
|
||||
535
bsps/shared/grlib/can/grcanfd.c
Normal file
535
bsps/shared/grlib/can/grcanfd.c
Normal file
@@ -0,0 +1,535 @@
|
||||
/*
|
||||
* FD extenstions to the GRCAN driver
|
||||
*
|
||||
* COPYRIGHT (c) 2007-2019.
|
||||
* Cobham Gaisler AB.
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <bsp.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <rtems/bspIo.h>
|
||||
|
||||
#include <grlib/grcan.h>
|
||||
#include <grlib/canbtrs.h>
|
||||
#include <drvmgr/drvmgr.h>
|
||||
#include <grlib/ambapp_bus.h>
|
||||
#include <grlib/ambapp.h>
|
||||
|
||||
#include <grlib/grlib_impl.h>
|
||||
#include "grcan_internal.h"
|
||||
|
||||
/* Uncomment for debug output */
|
||||
/****************** DEBUG Definitions ********************/
|
||||
#define DBG_TX 2
|
||||
#define DBG_RX 4
|
||||
#define DBG_STATE 8
|
||||
|
||||
#define DEBUG_FLAGS (DBG_STATE | DBG_RX | DBG_TX )
|
||||
/*
|
||||
#define DEBUG
|
||||
#define DEBUGFUNCS
|
||||
*/
|
||||
#include <grlib/debug_defs.h>
|
||||
|
||||
/*********************************************************/
|
||||
|
||||
struct grcanfd_bd0 {
|
||||
uint32_t head[2];
|
||||
uint64_t data0; /* variable size, from 1 to 8 dwords */
|
||||
};
|
||||
|
||||
struct grcanfd_bd1 {
|
||||
unsigned long long data[2];
|
||||
};
|
||||
|
||||
static uint8_t dlc2len[16] = {
|
||||
0, 1, 2, 3,
|
||||
4, 5, 6, 7,
|
||||
8, 12, 16, 20,
|
||||
24, 32, 48, 64
|
||||
};
|
||||
|
||||
static uint8_t len2fddlc[14] = {
|
||||
/* 12,13 */ 0x9,
|
||||
/* 16,17 */ 0xA,
|
||||
/* 20,21 */ 0xB,
|
||||
/* 24,25 */ 0xC,
|
||||
/* 28,29 */ -1,
|
||||
/* 32,33 */ 0xD,
|
||||
/* 36,37 */ -1,
|
||||
/* 40,41 */ -1,
|
||||
/* 44,45 */ -1,
|
||||
/* 48,49 */ 0xE,
|
||||
/* 52,53 */ -1,
|
||||
/* 56,57 */ -1,
|
||||
/* 60,61 */ -1,
|
||||
/* 64,65 */ 0xF,
|
||||
};
|
||||
|
||||
/* Convert length in bytes to descriptor length field */
|
||||
static inline uint8_t grcan_len2dlc(int len)
|
||||
{
|
||||
if (len <= 8)
|
||||
return len;
|
||||
if (len > 64)
|
||||
return -1;
|
||||
if (len & 0x3)
|
||||
return -1;
|
||||
return len2fddlc[(len - 12) >> 2];
|
||||
}
|
||||
|
||||
static inline int grcan_numbds(int len)
|
||||
{
|
||||
return 1 + ((len + 7) >> 4);
|
||||
}
|
||||
|
||||
static int grcan_hw_read_try_fd(
|
||||
struct grcan_priv *pDev,
|
||||
struct grcan_regs *regs,
|
||||
CANFDMsg * buffer,
|
||||
int max)
|
||||
{
|
||||
int j;
|
||||
CANFDMsg *dest;
|
||||
struct grcanfd_bd0 *source, tmp, *rxmax;
|
||||
unsigned int wp, rp, size, addr;
|
||||
int bds_hw_avail, bds_tot, bds, ret, dlc;
|
||||
uint64_t *dp;
|
||||
SPIN_IRQFLAGS(oldLevel);
|
||||
|
||||
FUNCDBG();
|
||||
|
||||
wp = READ_REG(®s->rx0wr);
|
||||
rp = READ_REG(®s->rx0rd);
|
||||
|
||||
/*
|
||||
* Due to hardware wrap around simplification write pointer will
|
||||
* never reach the read pointer, at least a gap of 8 bytes.
|
||||
* The only time they are equal is when the read pointer has
|
||||
* reached the write pointer (empty buffer)
|
||||
*
|
||||
*/
|
||||
if (wp != rp) {
|
||||
/* Not empty, we have received chars...
|
||||
* Read as much as possible from DMA buffer
|
||||
*/
|
||||
size = READ_REG(®s->rx0size);
|
||||
|
||||
/* Get number of bytes available in RX buffer */
|
||||
bds_hw_avail = grcan_hw_rxavail(rp, wp, size);
|
||||
|
||||
addr = (unsigned int)pDev->rx;
|
||||
source = (struct grcanfd_bd0 *)(addr + rp);
|
||||
dest = buffer;
|
||||
rxmax = (struct grcanfd_bd0 *)(addr + size);
|
||||
ret = bds_tot = 0;
|
||||
|
||||
/* Read as many can messages as possible */
|
||||
while ((ret < max) && (bds_tot < bds_hw_avail)) {
|
||||
/* Read CAN message from DMA buffer */
|
||||
*(uint64_t *)&tmp = READ_DMA_DOUBLE(source);
|
||||
if (tmp.head[1] & 0x4) {
|
||||
DBGC(DBG_RX, "overrun\n");
|
||||
}
|
||||
if (tmp.head[1] & 0x2) {
|
||||
DBGC(DBG_RX, "bus-off mode\n");
|
||||
}
|
||||
if (tmp.head[1] & 0x1) {
|
||||
DBGC(DBG_RX, "error-passive mode\n");
|
||||
}
|
||||
/* Convert one grcan CAN message to one "software" CAN message */
|
||||
dest->extended = tmp.head[0] >> 31;
|
||||
dest->rtr = (tmp.head[0] >> 30) & 0x1;
|
||||
if (dest->extended) {
|
||||
dest->id = tmp.head[0] & 0x3fffffff;
|
||||
} else {
|
||||
dest->id = (tmp.head[0] >> 18) & 0xfff;
|
||||
}
|
||||
dest->fdopts = (tmp.head[1] >> 25) & GRCAN_FDMASK;
|
||||
dlc = tmp.head[1] >> 28;
|
||||
if (dest->fdopts & GRCAN_FDOPT_FDFRM) {
|
||||
dest->len = dlc2len[dlc];
|
||||
} else {
|
||||
dest->len = dlc;
|
||||
if (dlc > 8)
|
||||
dest->len = 8;
|
||||
}
|
||||
|
||||
dp = (uint64_t *)&source->data0;
|
||||
for (j = 0; j < ((dest->len + 7) / 8); j++) {
|
||||
dest->data.dwords[j] = READ_DMA_DOUBLE(dp);
|
||||
if (++dp >= (uint64_t *)rxmax)
|
||||
dp = (uint64_t *)addr; /* wrap around */
|
||||
}
|
||||
|
||||
/* wrap around if neccessary */
|
||||
bds = grcan_numbds(dest->len);
|
||||
source += bds;
|
||||
if (source >= rxmax) {
|
||||
source = (struct grcanfd_bd0 *)
|
||||
((void *)source - size);
|
||||
}
|
||||
dest++; /* straight user buffer */
|
||||
ret++;
|
||||
bds_tot += bds;
|
||||
}
|
||||
|
||||
/* A bus off interrupt may have occured after checking pDev->started */
|
||||
SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
|
||||
if (pDev->started == STATE_STARTED) {
|
||||
regs->rx0rd = (unsigned int) source - addr;
|
||||
regs->rx0ctrl = GRCAN_RXCTRL_ENABLE;
|
||||
} else {
|
||||
DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
|
||||
ret = state2err[pDev->started];
|
||||
}
|
||||
SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
|
||||
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int grcanfd_read(void *d, CANFDMsg *msg, size_t ucount)
|
||||
{
|
||||
struct grcan_priv *pDev = d;
|
||||
CANFDMsg *dest;
|
||||
unsigned int count, left;
|
||||
int nread;
|
||||
int req_cnt;
|
||||
|
||||
FUNCDBG();
|
||||
|
||||
dest = msg;
|
||||
req_cnt = ucount;
|
||||
|
||||
if ( (!dest) || (req_cnt<1) )
|
||||
return GRCAN_RET_INVARG;
|
||||
|
||||
if (pDev->started != STATE_STARTED) {
|
||||
return GRCAN_RET_NOTSTARTED;
|
||||
}
|
||||
|
||||
DBGC(DBG_RX, "grcan_read [%p]: buf: %p len: %u\n", d, msg, (unsigned int) ucount);
|
||||
|
||||
nread = grcan_hw_read_try_fd(pDev,pDev->regs,dest,req_cnt);
|
||||
if (nread < 0) {
|
||||
return nread;
|
||||
}
|
||||
count = nread;
|
||||
if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
|
||||
if ( count > 0 ) {
|
||||
/* Successfully received messages (at least one) */
|
||||
return count;
|
||||
}
|
||||
|
||||
/* nothing read, shall we block? */
|
||||
if ( !pDev->rxblock ) {
|
||||
/* non-blocking mode */
|
||||
return GRCAN_RET_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
while (count == 0 || (pDev->rxcomplete && (count!=req_cnt))) {
|
||||
if (!pDev->rxcomplete) {
|
||||
left = 1; /* return as soon as there is one message available */
|
||||
} else {
|
||||
left = req_cnt - count; /* return as soon as all data are available */
|
||||
|
||||
/* never wait for more than the half the maximum size of the receive buffer
|
||||
* Why? We need some time to copy buffer before to catch up with hw,
|
||||
* otherwise we would have to copy everything when the data has been
|
||||
* received.
|
||||
*/
|
||||
if (left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2)){
|
||||
left = (pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
nread = grcan_wait_rxdata(pDev, left);
|
||||
if (nread) {
|
||||
/* The wait has been aborted, probably due to
|
||||
* the device driver has been closed by another
|
||||
* thread or a bus-off. Return error code.
|
||||
*/
|
||||
return nread;
|
||||
}
|
||||
|
||||
/* Try read bytes from circular buffer */
|
||||
nread = grcan_hw_read_try_fd(
|
||||
pDev,
|
||||
pDev->regs,
|
||||
dest+count,
|
||||
req_cnt-count);
|
||||
|
||||
if (nread < 0) {
|
||||
/* The read was aborted by bus-off. */
|
||||
return nread;
|
||||
}
|
||||
count += nread;
|
||||
}
|
||||
/* no need to unmask IRQ as IRQ Handler do that for us. */
|
||||
return count;
|
||||
}
|
||||
|
||||
static int grcan_hw_write_try_fd(
|
||||
struct grcan_priv *pDev,
|
||||
struct grcan_regs *regs,
|
||||
CANFDMsg *buffer,
|
||||
int count)
|
||||
{
|
||||
unsigned int rp, wp, size, addr;
|
||||
int ret;
|
||||
struct grcanfd_bd0 *dest, *txmax;
|
||||
CANFDMsg *source = (CANFDMsg *) buffer;
|
||||
int space_left;
|
||||
unsigned int tmp;
|
||||
int i, bds;
|
||||
uint64_t *dp;
|
||||
uint8_t dlc;
|
||||
SPIN_IRQFLAGS(oldLevel);
|
||||
|
||||
DBGC(DBG_TX, "\n");
|
||||
|
||||
rp = READ_REG(®s->tx0rd);
|
||||
wp = READ_REG(®s->tx0wr);
|
||||
size = READ_REG(®s->tx0size);
|
||||
space_left = grcan_hw_txspace(rp, wp, size);
|
||||
|
||||
addr = (unsigned int)pDev->tx;
|
||||
dest = (struct grcanfd_bd0 *)(addr + wp);
|
||||
txmax = (struct grcanfd_bd0 *)(addr + size);
|
||||
ret = 0;
|
||||
|
||||
while (source < &buffer[count]) {
|
||||
/* Get the number of descriptors to wait for */
|
||||
if (source->fdopts & GRCAN_FDOPT_FDFRM)
|
||||
bds = grcan_numbds(source->len); /* next msg's buffers */
|
||||
else
|
||||
bds = 1;
|
||||
if (space_left < bds)
|
||||
break;
|
||||
|
||||
/* Convert and write CAN message to DMA buffer */
|
||||
dlc = grcan_len2dlc(source->len);
|
||||
if (dlc < 0) {
|
||||
/* Bad user input. Report the number of written messages
|
||||
* or an error when non sent.
|
||||
*/
|
||||
if (ret <= 0)
|
||||
return GRCAN_RET_INVARG;
|
||||
break;
|
||||
}
|
||||
dest->head[1] = (dlc << 28) |
|
||||
((source->fdopts & GRCAN_FDMASK) << 25);
|
||||
dp = &dest->data0;
|
||||
for (i = 0; i < ((source->len + 7) / 8); i++) {
|
||||
*dp++ = source->data.dwords[i];
|
||||
if (dp >= (uint64_t *)txmax)
|
||||
dp = (uint64_t *)addr; /* wrap around */
|
||||
}
|
||||
if (source->extended) {
|
||||
tmp = (1 << 31) | (source->id & 0x3fffffff);
|
||||
} else {
|
||||
tmp = (source->id & 0xfff) << 18;
|
||||
}
|
||||
if (source->rtr)
|
||||
tmp |= (1 << 30);
|
||||
dest->head[0] = tmp;
|
||||
source++; /* straight user buffer */
|
||||
dest += bds;
|
||||
if (dest >= txmax)
|
||||
dest = (struct grcanfd_bd0 *)((void *)dest - size);
|
||||
space_left -= bds;
|
||||
ret++;
|
||||
}
|
||||
|
||||
/* A bus off interrupt may have occured after checking pDev->started */
|
||||
SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
|
||||
if (pDev->started == STATE_STARTED) {
|
||||
regs->tx0wr = (unsigned int) dest - addr;
|
||||
regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
|
||||
} else {
|
||||
DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
|
||||
ret = state2err[pDev->started];
|
||||
}
|
||||
SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int grcanfd_write(
|
||||
void *d,
|
||||
CANFDMsg *msg,
|
||||
size_t ucount)
|
||||
{
|
||||
struct grcan_priv *pDev = d;
|
||||
CANFDMsg *source, *curr;
|
||||
unsigned int count, left;
|
||||
int nwritten;
|
||||
int req_cnt;
|
||||
|
||||
DBGC(DBG_TX,"\n");
|
||||
|
||||
if ((pDev->started != STATE_STARTED) || pDev->config.silent || pDev->flushing)
|
||||
return GRCAN_RET_NOTSTARTED;
|
||||
|
||||
req_cnt = ucount;
|
||||
curr = source = (CANFDMsg *) msg;
|
||||
|
||||
/* check proper length and buffer pointer */
|
||||
if (( req_cnt < 1) || (source == NULL) ){
|
||||
return GRCAN_RET_INVARG;
|
||||
}
|
||||
|
||||
nwritten = grcan_hw_write_try_fd(pDev,pDev->regs,source,req_cnt);
|
||||
if (nwritten < 0) {
|
||||
return nwritten;
|
||||
}
|
||||
count = nwritten;
|
||||
if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
|
||||
if ( count > 0 ) {
|
||||
/* Successfully transmitted chars (at least one char) */
|
||||
return count;
|
||||
}
|
||||
|
||||
/* nothing written, shall we block? */
|
||||
if ( !pDev->txblock ) {
|
||||
/* non-blocking mode */
|
||||
return GRCAN_RET_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
/* if in txcomplete mode we need to transmit all chars */
|
||||
while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){
|
||||
/*** block until room to fit all or as much of transmit buffer
|
||||
* as possible before IRQ comes. Set up a valid IRQ point so
|
||||
* that an IRQ is triggered when we can put a chunk of data
|
||||
* into transmit fifo.
|
||||
*/
|
||||
|
||||
/* Get the number of descriptors to wait for */
|
||||
curr = &source[count];
|
||||
if (curr->fdopts & GRCAN_FDOPT_FDFRM)
|
||||
left = grcan_numbds(curr->len); /* next msg's buffers */
|
||||
else
|
||||
left = 1;
|
||||
|
||||
if (pDev->txcomplete) {
|
||||
/* Wait for all messages to fit into descriptor table.
|
||||
* Assume all following msgs are single descriptors.
|
||||
*/
|
||||
left += req_cnt - count - 1;
|
||||
if (left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2)) {
|
||||
left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nwritten = grcan_wait_txspace(pDev,left);
|
||||
/* Wait until more room in transmit buffer */
|
||||
if ( nwritten ) {
|
||||
/* The wait has been aborted, probably due to
|
||||
* the device driver has been closed by another
|
||||
* thread. To avoid deadlock we return directly
|
||||
* with error status.
|
||||
*/
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
/* Try read bytes from circular buffer */
|
||||
nwritten = grcan_hw_write_try_fd(
|
||||
pDev,
|
||||
pDev->regs,
|
||||
source+count,
|
||||
req_cnt-count);
|
||||
|
||||
if (nwritten < 0) {
|
||||
/* Write was aborted by bus-off. */
|
||||
return nwritten;
|
||||
}
|
||||
count += nwritten;
|
||||
}
|
||||
/* no need to unmask IRQ as IRQ Handler do that for us. */
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int grcanfd_set_speed(void *d, unsigned int nom_hz, unsigned int fd_hz)
|
||||
{
|
||||
struct grcan_priv *pDev = d;
|
||||
struct grlib_canbtrs_timing nom, fd;
|
||||
int ret;
|
||||
|
||||
FUNCDBG();
|
||||
|
||||
/* cannot change speed during run mode */
|
||||
if ((pDev->started == STATE_STARTED) || !pDev->fd_capable)
|
||||
return -1;
|
||||
|
||||
/* get speed rate from argument */
|
||||
ret = grlib_canbtrs_calc_timing(
|
||||
nom_hz, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
|
||||
&grcanfd_nom_btrs_ranges, &nom);
|
||||
if ( ret )
|
||||
return -2;
|
||||
ret = grlib_canbtrs_calc_timing(
|
||||
fd_hz, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
|
||||
&grcanfd_fd_btrs_ranges, &fd);
|
||||
if ( ret )
|
||||
return -2;
|
||||
|
||||
/* save timing/speed */
|
||||
pDev->config.timing = *(struct grcan_timing *)&nom;
|
||||
pDev->config.timing_fd.scaler = fd.scaler;
|
||||
pDev->config.timing_fd.ps1 = fd.ps1;
|
||||
pDev->config.timing_fd.ps2 = fd.ps2;
|
||||
pDev->config.timing_fd.sjw = fd.rsj;
|
||||
pDev->config.timing_fd.resv_zero = 0;
|
||||
pDev->config_changed = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int grcanfd_set_btrs(
|
||||
void *d,
|
||||
const struct grcanfd_timing *nominal,
|
||||
const struct grcanfd_timing *fd)
|
||||
{
|
||||
struct grcan_priv *pDev = d;
|
||||
|
||||
FUNCDBG();
|
||||
|
||||
/* Set BTR registers manually
|
||||
* Read GRCAN/HurriCANe Manual.
|
||||
*/
|
||||
if ((pDev->started == STATE_STARTED) || !pDev->fd_capable)
|
||||
return -1;
|
||||
|
||||
if (!nominal)
|
||||
return -2;
|
||||
|
||||
pDev->config.timing.scaler = nominal->scaler;
|
||||
pDev->config.timing.ps1 = nominal->ps1;
|
||||
pDev->config.timing.ps2 = nominal->ps2;
|
||||
pDev->config.timing.rsj = nominal->sjw;
|
||||
pDev->config.timing.bpr = 0;
|
||||
if (fd) {
|
||||
pDev->config.timing_fd = *fd;
|
||||
} else {
|
||||
memset(&pDev->config.timing_fd, 0,
|
||||
sizeof(struct grcanfd_timing));
|
||||
}
|
||||
pDev->config_changed = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
435
bsps/shared/grlib/can/grcanstd.c
Normal file
435
bsps/shared/grlib/can/grcanstd.c
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* non-FD specific function for GRCAN driver
|
||||
*
|
||||
* COPYRIGHT (c) 2007-2019.
|
||||
* Cobham Gaisler AB.
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <bsp.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <rtems/bspIo.h>
|
||||
|
||||
#include <grlib/grcan.h>
|
||||
#include <grlib/canbtrs.h>
|
||||
#include <drvmgr/drvmgr.h>
|
||||
#include <grlib/ambapp_bus.h>
|
||||
#include <grlib/ambapp.h>
|
||||
|
||||
#include <grlib/grlib_impl.h>
|
||||
#include "grcan_internal.h"
|
||||
|
||||
/* Uncomment for debug output */
|
||||
/****************** DEBUG Definitions ********************/
|
||||
#define DBG_TX 2
|
||||
#define DBG_RX 4
|
||||
#define DBG_STATE 8
|
||||
|
||||
#define DEBUG_FLAGS (DBG_STATE | DBG_RX | DBG_TX )
|
||||
/*
|
||||
#define DEBUG
|
||||
#define DEBUGFUNCS
|
||||
*/
|
||||
#include <grlib/debug_defs.h>
|
||||
|
||||
static int grcan_hw_read_try(
|
||||
struct grcan_priv *pDev,
|
||||
struct grcan_regs *regs,
|
||||
CANMsg * buffer,
|
||||
int max
|
||||
)
|
||||
{
|
||||
int i, j;
|
||||
CANMsg *dest;
|
||||
struct grcan_msg *source, tmp;
|
||||
unsigned int wp, rp, size, rxmax, addr;
|
||||
int trunk_msg_cnt;
|
||||
|
||||
FUNCDBG();
|
||||
|
||||
wp = READ_REG(®s->rx0wr);
|
||||
rp = READ_REG(®s->rx0rd);
|
||||
|
||||
/*
|
||||
* Due to hardware wrap around simplification write pointer will
|
||||
* never reach the read pointer, at least a gap of 8 bytes.
|
||||
* The only time they are equal is when the read pointer has
|
||||
* reached the write pointer (empty buffer)
|
||||
*
|
||||
*/
|
||||
if (wp != rp) {
|
||||
/* Not empty, we have received chars...
|
||||
* Read as much as possible from DMA buffer
|
||||
*/
|
||||
size = READ_REG(®s->rx0size);
|
||||
|
||||
/* Get number of bytes available in RX buffer */
|
||||
trunk_msg_cnt = grcan_hw_rxavail(rp, wp, size);
|
||||
|
||||
/* truncate size if user space buffer hasn't room for
|
||||
* all received chars.
|
||||
*/
|
||||
if (trunk_msg_cnt > max)
|
||||
trunk_msg_cnt = max;
|
||||
|
||||
/* Read until i is 0 */
|
||||
i = trunk_msg_cnt;
|
||||
|
||||
addr = (unsigned int)pDev->rx;
|
||||
source = (struct grcan_msg *)(addr + rp);
|
||||
dest = buffer;
|
||||
rxmax = addr + (size - GRCAN_MSG_SIZE);
|
||||
|
||||
/* Read as many can messages as possible */
|
||||
while (i > 0) {
|
||||
/* Read CAN message from DMA buffer */
|
||||
tmp.head[0] = READ_DMA_WORD(&source->head[0]);
|
||||
tmp.head[1] = READ_DMA_WORD(&source->head[1]);
|
||||
if (tmp.head[1] & 0x4) {
|
||||
DBGC(DBG_RX, "overrun\n");
|
||||
}
|
||||
if (tmp.head[1] & 0x2) {
|
||||
DBGC(DBG_RX, "bus-off mode\n");
|
||||
}
|
||||
if (tmp.head[1] & 0x1) {
|
||||
DBGC(DBG_RX, "error-passive mode\n");
|
||||
}
|
||||
/* Convert one grcan CAN message to one "software" CAN message */
|
||||
dest->extended = tmp.head[0] >> 31;
|
||||
dest->rtr = (tmp.head[0] >> 30) & 0x1;
|
||||
if (dest->extended) {
|
||||
dest->id = tmp.head[0] & 0x3fffffff;
|
||||
} else {
|
||||
dest->id = (tmp.head[0] >> 18) & 0xfff;
|
||||
}
|
||||
dest->len = tmp.head[1] >> 28;
|
||||
for (j = 0; j < dest->len; j++)
|
||||
dest->data[j] = READ_DMA_BYTE(&source->data[j]);
|
||||
|
||||
/* wrap around if neccessary */
|
||||
source =
|
||||
((unsigned int)source >= rxmax) ?
|
||||
(struct grcan_msg *)addr : source + 1;
|
||||
dest++; /* straight user buffer */
|
||||
i--;
|
||||
}
|
||||
{
|
||||
/* A bus off interrupt may have occured after checking pDev->started */
|
||||
SPIN_IRQFLAGS(oldLevel);
|
||||
|
||||
SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
|
||||
if (pDev->started == STATE_STARTED) {
|
||||
regs->rx0rd = (unsigned int) source - addr;
|
||||
regs->rx0ctrl = GRCAN_RXCTRL_ENABLE;
|
||||
} else {
|
||||
DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
|
||||
trunk_msg_cnt = state2err[pDev->started];
|
||||
}
|
||||
SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
|
||||
}
|
||||
return trunk_msg_cnt;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int grcan_hw_write_try(
|
||||
struct grcan_priv *pDev,
|
||||
struct grcan_regs *regs,
|
||||
CANMsg * buffer,
|
||||
int count
|
||||
)
|
||||
{
|
||||
unsigned int rp, wp, size, txmax, addr;
|
||||
int ret;
|
||||
struct grcan_msg *dest;
|
||||
CANMsg *source;
|
||||
int space_left;
|
||||
unsigned int tmp;
|
||||
int i;
|
||||
|
||||
DBGC(DBG_TX, "\n");
|
||||
/*FUNCDBG(); */
|
||||
|
||||
rp = READ_REG(®s->tx0rd);
|
||||
wp = READ_REG(®s->tx0wr);
|
||||
size = READ_REG(®s->tx0size);
|
||||
|
||||
space_left = grcan_hw_txspace(rp, wp, size);
|
||||
|
||||
/* is circular fifo full? */
|
||||
if (space_left < 1)
|
||||
return 0;
|
||||
|
||||
/* Truncate size */
|
||||
if (space_left > count)
|
||||
space_left = count;
|
||||
ret = space_left;
|
||||
|
||||
addr = (unsigned int)pDev->tx;
|
||||
|
||||
dest = (struct grcan_msg *)(addr + wp);
|
||||
source = (CANMsg *) buffer;
|
||||
txmax = addr + (size - GRCAN_MSG_SIZE);
|
||||
|
||||
while (space_left > 0) {
|
||||
/* Convert and write CAN message to DMA buffer */
|
||||
if (source->extended) {
|
||||
tmp = (1 << 31) | (source->id & 0x3fffffff);
|
||||
} else {
|
||||
tmp = (source->id & 0xfff) << 18;
|
||||
}
|
||||
if (source->rtr)
|
||||
tmp |= (1 << 30);
|
||||
dest->head[0] = tmp;
|
||||
dest->head[1] = source->len << 28;
|
||||
for (i = 0; i < source->len; i++)
|
||||
dest->data[i] = source->data[i];
|
||||
source++; /* straight user buffer */
|
||||
dest =
|
||||
((unsigned int)dest >= txmax) ?
|
||||
(struct grcan_msg *)addr : dest + 1;
|
||||
space_left--;
|
||||
}
|
||||
|
||||
{
|
||||
/* A bus off interrupt may have occured after checking pDev->started */
|
||||
SPIN_IRQFLAGS(oldLevel);
|
||||
|
||||
SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
|
||||
if (pDev->started == STATE_STARTED) {
|
||||
regs->tx0wr = (unsigned int) dest - addr;
|
||||
regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
|
||||
} else {
|
||||
DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
|
||||
ret = state2err[pDev->started];
|
||||
}
|
||||
SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int grcan_read(void *d, CANMsg *msg, size_t ucount)
|
||||
{
|
||||
struct grcan_priv *pDev = d;
|
||||
CANMsg *dest;
|
||||
unsigned int count, left;
|
||||
int nread;
|
||||
int req_cnt;
|
||||
|
||||
FUNCDBG();
|
||||
|
||||
dest = msg;
|
||||
req_cnt = ucount;
|
||||
|
||||
if ( (!dest) || (req_cnt<1) )
|
||||
return GRCAN_RET_INVARG;
|
||||
|
||||
if (pDev->started != STATE_STARTED) {
|
||||
return GRCAN_RET_NOTSTARTED;
|
||||
}
|
||||
|
||||
DBGC(DBG_RX, "grcan_read [%p]: buf: %p len: %u\n", d, msg, (unsigned int) ucount);
|
||||
|
||||
nread = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt);
|
||||
if (nread < 0) {
|
||||
return nread;
|
||||
}
|
||||
count = nread;
|
||||
if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
|
||||
if ( count > 0 ) {
|
||||
/* Successfully received messages (at least one) */
|
||||
return count;
|
||||
}
|
||||
|
||||
/* nothing read, shall we block? */
|
||||
if ( !pDev->rxblock ) {
|
||||
/* non-blocking mode */
|
||||
return GRCAN_RET_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
while (count == 0 || (pDev->rxcomplete && (count!=req_cnt))) {
|
||||
if (!pDev->rxcomplete) {
|
||||
left = 1; /* return as soon as there is one message available */
|
||||
} else {
|
||||
left = req_cnt - count; /* return as soon as all data are available */
|
||||
|
||||
/* never wait for more than the half the maximum size of the receive buffer
|
||||
* Why? We need some time to copy buffer before to catch up with hw,
|
||||
* otherwise we would have to copy everything when the data has been
|
||||
* received.
|
||||
*/
|
||||
if (left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2)){
|
||||
left = (pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
nread = grcan_wait_rxdata(pDev, left);
|
||||
if (nread) {
|
||||
/* The wait has been aborted, probably due to
|
||||
* the device driver has been closed by another
|
||||
* thread or a bus-off. Return error code.
|
||||
*/
|
||||
return nread;
|
||||
}
|
||||
|
||||
/* Try read bytes from circular buffer */
|
||||
nread = grcan_hw_read_try(
|
||||
pDev,
|
||||
pDev->regs,
|
||||
dest+count,
|
||||
req_cnt-count);
|
||||
|
||||
if (nread < 0) {
|
||||
/* The read was aborted by bus-off. */
|
||||
return nread;
|
||||
}
|
||||
count += nread;
|
||||
}
|
||||
/* no need to unmask IRQ as IRQ Handler do that for us. */
|
||||
return count;
|
||||
}
|
||||
|
||||
int grcan_write(void *d, CANMsg *msg, size_t ucount)
|
||||
{
|
||||
struct grcan_priv *pDev = d;
|
||||
CANMsg *source;
|
||||
unsigned int count, left;
|
||||
int nwritten;
|
||||
int req_cnt;
|
||||
|
||||
DBGC(DBG_TX,"\n");
|
||||
|
||||
if ((pDev->started != STATE_STARTED) || pDev->config.silent || pDev->flushing)
|
||||
return GRCAN_RET_NOTSTARTED;
|
||||
|
||||
req_cnt = ucount;
|
||||
source = (CANMsg *) msg;
|
||||
|
||||
/* check proper length and buffer pointer */
|
||||
if (( req_cnt < 1) || (source == NULL) ){
|
||||
return GRCAN_RET_INVARG;
|
||||
}
|
||||
|
||||
nwritten = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt);
|
||||
if (nwritten < 0) {
|
||||
return nwritten;
|
||||
}
|
||||
count = nwritten;
|
||||
if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
|
||||
if ( count > 0 ) {
|
||||
/* Successfully transmitted chars (at least one char) */
|
||||
return count;
|
||||
}
|
||||
|
||||
/* nothing written, shall we block? */
|
||||
if ( !pDev->txblock ) {
|
||||
/* non-blocking mode */
|
||||
return GRCAN_RET_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
/* if in txcomplete mode we need to transmit all chars */
|
||||
while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){
|
||||
/*** block until room to fit all or as much of transmit buffer as possible
|
||||
* IRQ comes. Set up a valid IRQ point so that an IRQ is received
|
||||
* when we can put a chunk of data into transmit fifo
|
||||
*/
|
||||
if ( !pDev->txcomplete ){
|
||||
left = 1; /* wait for anything to fit buffer */
|
||||
}else{
|
||||
left = req_cnt - count; /* wait for all data to fit in buffer */
|
||||
|
||||
/* never wait for more than the half the maximum size of the transmit
|
||||
* buffer
|
||||
* Why? We need some time to fill buffer before hw catches up.
|
||||
*/
|
||||
if ( left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2) ){
|
||||
left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2;
|
||||
}
|
||||
}
|
||||
|
||||
nwritten = grcan_wait_txspace(pDev,left);
|
||||
/* Wait until more room in transmit buffer */
|
||||
if ( nwritten ) {
|
||||
/* The wait has been aborted, probably due to
|
||||
* the device driver has been closed by another
|
||||
* thread. To avoid deadlock we return directly
|
||||
* with error status.
|
||||
*/
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
/* Try read bytes from circular buffer */
|
||||
nwritten = grcan_hw_write_try(
|
||||
pDev,
|
||||
pDev->regs,
|
||||
source+count,
|
||||
req_cnt-count);
|
||||
|
||||
if (nwritten < 0) {
|
||||
/* Write was aborted by bus-off. */
|
||||
return nwritten;
|
||||
}
|
||||
count += nwritten;
|
||||
}
|
||||
/* no need to unmask IRQ as IRQ Handler do that for us. */
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int grcan_set_speed(void *d, unsigned int speed)
|
||||
{
|
||||
struct grcan_priv *pDev = d;
|
||||
struct grcan_timing timing;
|
||||
int ret;
|
||||
|
||||
FUNCDBG();
|
||||
|
||||
/* cannot change speed during run mode */
|
||||
if ((pDev->started == STATE_STARTED) || pDev->fd_capable)
|
||||
return -1;
|
||||
|
||||
/* get speed rate from argument */
|
||||
ret = grlib_canbtrs_calc_timing(
|
||||
speed, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
|
||||
&grcan_btrs_ranges, (struct grlib_canbtrs_timing *)&timing);
|
||||
if (ret)
|
||||
return -2;
|
||||
|
||||
/* save timing/speed */
|
||||
pDev->config.timing = timing;
|
||||
pDev->config_changed = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int grcan_set_btrs(void *d, const struct grcan_timing *timing)
|
||||
{
|
||||
struct grcan_priv *pDev = d;
|
||||
|
||||
FUNCDBG();
|
||||
|
||||
/* Set BTR registers manually
|
||||
* Read GRCAN/HurriCANe Manual.
|
||||
*/
|
||||
if ((pDev->started == STATE_STARTED) || pDev->fd_capable)
|
||||
return -1;
|
||||
|
||||
if ( !timing )
|
||||
return -2;
|
||||
|
||||
pDev->config.timing = *timing;
|
||||
pDev->config_changed = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <drvmgr/drvmgr.h>
|
||||
#include <grlib/ambapp_bus.h>
|
||||
#include <grlib/occan.h>
|
||||
#include <grlib/canbtrs.h>
|
||||
|
||||
#include <grlib/grlib_impl.h>
|
||||
|
||||
@@ -185,19 +186,20 @@ typedef struct {
|
||||
#define pelican_regs pelican32_regs
|
||||
#endif
|
||||
|
||||
/* Default sampling point in % */
|
||||
#define OCCAN_SAMPLING_POINT 90
|
||||
|
||||
#define MAX_TSEG2 7
|
||||
#define MAX_TSEG1 15
|
||||
/* OCCAN baud-rate paramter boundaries */
|
||||
struct grlib_canbtrs_ranges occan_btrs_ranges = {
|
||||
.max_scaler = 64,
|
||||
.has_bpr = 0,
|
||||
.divfactor = 1,
|
||||
.min_tseg1 = 1,
|
||||
.max_tseg1 = 16,
|
||||
.min_tseg2 = 1,
|
||||
.max_tseg2 = 8,
|
||||
};
|
||||
|
||||
#if 0
|
||||
typedef struct {
|
||||
unsigned char brp;
|
||||
unsigned char sjw;
|
||||
unsigned char tseg1;
|
||||
unsigned char tseg2;
|
||||
unsigned char sam;
|
||||
} occan_speed_regs;
|
||||
#endif
|
||||
typedef struct {
|
||||
unsigned char btr0;
|
||||
unsigned char btr1;
|
||||
@@ -251,7 +253,9 @@ static CANMsg *occan_fifo_claim_get(occan_fifo *fifo);
|
||||
static void occan_fifo_clr(occan_fifo *fifo);
|
||||
|
||||
/**** Hardware related Interface ****/
|
||||
static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result);
|
||||
static void convert_timing_to_btrs(
|
||||
struct grlib_canbtrs_timing *t,
|
||||
occan_speed_regs *btrs);
|
||||
static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing);
|
||||
static void pelican_init(occan_priv *priv);
|
||||
static void pelican_open(occan_priv *priv);
|
||||
@@ -765,6 +769,7 @@ static void pelican_init(occan_priv *priv){
|
||||
|
||||
static void pelican_open(occan_priv *priv){
|
||||
int ret;
|
||||
struct grlib_canbtrs_timing timing;
|
||||
|
||||
/* Set defaults */
|
||||
priv->speed = OCCAN_SPEED_250K;
|
||||
@@ -783,13 +788,19 @@ static void pelican_open(occan_priv *priv){
|
||||
*/
|
||||
WRITE_REG(priv, &priv->regs->clkdiv, (1<<PELICAN_CDR_MODE_BITS) | (DEFAULT_CLKDIV & PELICAN_CDR_DIV));
|
||||
|
||||
ret = occan_calc_speedregs(priv->sys_freq_hz,priv->speed,&priv->timing);
|
||||
if ( ret ){
|
||||
ret = grlib_canbtrs_calc_timing(
|
||||
priv->speed, priv->sys_freq_hz,
|
||||
OCCAN_SAMPLING_POINT, &occan_btrs_ranges,
|
||||
(struct grlib_canbtrs_timing *)&timing);
|
||||
if ( ret ) {
|
||||
/* failed to set speed for this system freq, try with 50K instead */
|
||||
priv->speed = OCCAN_SPEED_50K;
|
||||
occan_calc_speedregs(priv->sys_freq_hz, priv->speed,
|
||||
&priv->timing);
|
||||
grlib_canbtrs_calc_timing(
|
||||
priv->speed, priv->sys_freq_hz,
|
||||
OCCAN_SAMPLING_POINT, &occan_btrs_ranges,
|
||||
(struct grlib_canbtrs_timing *)&timing);
|
||||
}
|
||||
convert_timing_to_btrs(&timing, &priv->timing);
|
||||
|
||||
/* disable all interrupts */
|
||||
WRITE_REG(priv, &priv->regs->inten, 0);
|
||||
@@ -983,97 +994,13 @@ static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned
|
||||
WRITE_REG(priv, amask3, amask[3]);
|
||||
}
|
||||
|
||||
|
||||
/* This function calculates BTR0 and BTR1 values for a given bitrate.
|
||||
*
|
||||
* Set communication parameters.
|
||||
* \param clock_hz OC_CAN Core frequency in Hz.
|
||||
* \param rate Requested baud rate in bits/second.
|
||||
* \param result Pointer to where resulting BTRs will be stored.
|
||||
* \return zero if successful to calculate a baud rate.
|
||||
*/
|
||||
static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result)
|
||||
static void convert_timing_to_btrs(
|
||||
struct grlib_canbtrs_timing *t,
|
||||
occan_speed_regs *btrs)
|
||||
{
|
||||
int best_error = 1000000000;
|
||||
int error;
|
||||
int best_tseg=0, best_brp=0, brp=0;
|
||||
int tseg=0, tseg1=0, tseg2=0;
|
||||
int sjw = 0;
|
||||
int clock = clock_hz / 2;
|
||||
int sampl_pt = 90;
|
||||
|
||||
if ( (rate<5000) || (rate>1000000) ){
|
||||
/* invalid speed mode */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* find best match, return -2 if no good reg
|
||||
* combination is available for this frequency */
|
||||
|
||||
/* some heuristic specials */
|
||||
if (rate > ((1000000 + 500000) / 2))
|
||||
sampl_pt = 75;
|
||||
|
||||
if (rate < ((12500 + 10000) / 2))
|
||||
sampl_pt = 75;
|
||||
|
||||
if (rate < ((100000 + 125000) / 2))
|
||||
sjw = 1;
|
||||
|
||||
/* tseg even = round down, odd = round up */
|
||||
for (tseg = (0 + 0 + 2) * 2;
|
||||
tseg <= (MAX_TSEG2 + MAX_TSEG1 + 2) * 2 + 1;
|
||||
tseg++)
|
||||
{
|
||||
brp = clock / ((1 + tseg / 2) * rate) + tseg % 2;
|
||||
if ((brp == 0) || (brp > 64))
|
||||
continue;
|
||||
|
||||
error = rate - clock / (brp * (1 + tseg / 2));
|
||||
if (error < 0)
|
||||
{
|
||||
error = -error;
|
||||
}
|
||||
|
||||
if (error <= best_error)
|
||||
{
|
||||
best_error = error;
|
||||
best_tseg = tseg/2;
|
||||
best_brp = brp-1;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_error && (rate / best_error < 10))
|
||||
{
|
||||
printk("OCCAN: bitrate %d is not possible with %d Hz clock\n\r",rate, clock);
|
||||
return -2;
|
||||
}else if ( !result )
|
||||
return 0; /* nothing to store result in, but a valid bitrate can be calculated */
|
||||
|
||||
tseg2 = best_tseg - (sampl_pt * (best_tseg + 1)) / 100;
|
||||
|
||||
if (tseg2 < 0)
|
||||
{
|
||||
tseg2 = 0;
|
||||
}
|
||||
|
||||
if (tseg2 > MAX_TSEG2)
|
||||
{
|
||||
tseg2 = MAX_TSEG2;
|
||||
}
|
||||
|
||||
tseg1 = best_tseg - tseg2 - 2;
|
||||
|
||||
if (tseg1 > MAX_TSEG1)
|
||||
{
|
||||
tseg1 = MAX_TSEG1;
|
||||
tseg2 = best_tseg - tseg1 - 2;
|
||||
}
|
||||
|
||||
result->btr0 = (sjw<<OCCAN_BUSTIM_SJW_BIT) | (best_brp&OCCAN_BUSTIM_BRP);
|
||||
result->btr1 = (0<<7) | (tseg2<<OCCAN_BUSTIM_TSEG2_BIT) | tseg1;
|
||||
|
||||
return 0;
|
||||
btrs->btr0 = (t->rsj << OCCAN_BUSTIM_SJW_BIT) |
|
||||
(t->scaler & OCCAN_BUSTIM_BRP);
|
||||
btrs->btr1 = (0<<7) | (t->ps2 << OCCAN_BUSTIM_TSEG2_BIT) | t->ps1;
|
||||
}
|
||||
|
||||
static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing)
|
||||
@@ -1441,7 +1368,7 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de
|
||||
static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
|
||||
{
|
||||
int ret;
|
||||
occan_speed_regs timing;
|
||||
struct grlib_canbtrs_timing timing;
|
||||
occan_priv *can;
|
||||
struct drvmgr_dev *dev;
|
||||
unsigned int speed;
|
||||
@@ -1467,7 +1394,11 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
|
||||
|
||||
/* get speed rate from argument */
|
||||
speed = (unsigned int)ioarg->buffer;
|
||||
ret = occan_calc_speedregs(can->sys_freq_hz,speed,&timing);
|
||||
/* Calculate default timing register values */
|
||||
ret = grlib_canbtrs_calc_timing(
|
||||
speed, can->sys_freq_hz,
|
||||
OCCAN_SAMPLING_POINT, &occan_btrs_ranges,
|
||||
(struct grlib_canbtrs_timing *)&timing);
|
||||
if ( ret )
|
||||
return RTEMS_INVALID_NAME; /* EINVAL */
|
||||
|
||||
@@ -1476,7 +1407,7 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
|
||||
|
||||
/* save timing/speed */
|
||||
can->speed = speed;
|
||||
can->timing = timing;
|
||||
convert_timing_to_btrs(&timing, &can->timing);
|
||||
break;
|
||||
|
||||
case OCCAN_IOC_SET_BTRS:
|
||||
|
||||
@@ -188,8 +188,8 @@ static int genirq_set_active(
|
||||
return 1;
|
||||
}
|
||||
e = isrentry;
|
||||
} else {
|
||||
enabled += isrentry->enabled;
|
||||
} else if ( isrentry->enabled ) {
|
||||
enabled = 1;
|
||||
}
|
||||
isrentry = isrentry->next;
|
||||
}
|
||||
|
||||
@@ -894,9 +894,9 @@ int l2cache_diag_tag( int way, int index, struct l2cache_tag * tag)
|
||||
return L2CACHE_ERR_EINVAL;
|
||||
}
|
||||
|
||||
unsigned int val = l2cache_reg_diagtag(way,index);
|
||||
|
||||
if (tag){
|
||||
unsigned int val = l2cache_reg_diagtag(way,index);
|
||||
|
||||
tag->tag = l2cache_get_tag(val);
|
||||
tag->valid = l2cache_tag_valid(val);
|
||||
tag->dirty = l2cache_tag_dirty(val);
|
||||
|
||||
@@ -186,6 +186,7 @@ struct greth_softc
|
||||
unsigned int advmodes; /* advertise ethernet speed modes. 0 = all modes. */
|
||||
struct timespec auto_neg_time;
|
||||
int mc_available;
|
||||
int num_descs;
|
||||
|
||||
/*
|
||||
* Statistics
|
||||
@@ -422,7 +423,7 @@ greth_initialize_hardware (struct greth_softc *sc)
|
||||
int tmp2;
|
||||
struct timespec tstart, tnow;
|
||||
greth_regs *regs;
|
||||
unsigned int advmodes, speed;
|
||||
unsigned int advmodes, speed, tabsize;
|
||||
|
||||
regs = sc->regs;
|
||||
|
||||
@@ -616,8 +617,9 @@ auto_neg_done:
|
||||
/* Initialize rx/tx descriptor table pointers. Due to alignment we
|
||||
* always allocate maximum table size.
|
||||
*/
|
||||
sc->txdesc = (greth_rxtxdesc *) almalloc(0x800, 0x400);
|
||||
sc->rxdesc = (greth_rxtxdesc *) &sc->txdesc[128];
|
||||
tabsize = sc->num_descs * 8;
|
||||
sc->txdesc = (greth_rxtxdesc *) almalloc(tabsize * 2, tabsize);
|
||||
sc->rxdesc = (greth_rxtxdesc *) (tabsize + (void *)sc->txdesc);
|
||||
sc->tx_ptr = 0;
|
||||
sc->tx_dptr = 0;
|
||||
sc->tx_cnt = 0;
|
||||
@@ -631,8 +633,8 @@ auto_neg_done:
|
||||
CPUMEM_TO_DMA,
|
||||
(void *)sc->txdesc,
|
||||
(void **)&sc->txdesc_remote,
|
||||
0x800);
|
||||
sc->rxdesc_remote = sc->txdesc_remote + 0x400;
|
||||
tabsize * 2);
|
||||
sc->rxdesc_remote = sc->txdesc_remote + tabsize;
|
||||
regs->txdesc = (int) sc->txdesc_remote;
|
||||
regs->rxdesc = (int) sc->rxdesc_remote;
|
||||
|
||||
@@ -1555,6 +1557,7 @@ int greth_device_init(struct greth_softc *sc)
|
||||
struct ambapp_core *pnpinfo;
|
||||
union drvmgr_key_value *value;
|
||||
unsigned int speed;
|
||||
int i, nrd;
|
||||
|
||||
/* Get device information from AMBA PnP information */
|
||||
ambadev = (struct amba_dev_info *)sc->dev->businfo;
|
||||
@@ -1608,12 +1611,17 @@ int greth_device_init(struct greth_softc *sc)
|
||||
sc->rxbufs = 32;
|
||||
sc->phyaddr = -1;
|
||||
|
||||
/* Probe the number of descriptors available the */
|
||||
nrd = (sc->regs->status & GRETH_STATUS_NRD) >> 24;
|
||||
for (sc->num_descs = 128, i = 0; i < nrd; i++)
|
||||
sc->num_descs = sc->num_descs * 2;
|
||||
|
||||
value = drvmgr_dev_key_get(sc->dev, "txDescs", DRVMGR_KT_INT);
|
||||
if ( value && (value->i <= 128) )
|
||||
if ( value && (value->i <= sc->num_descs) )
|
||||
sc->txbufs = value->i;
|
||||
|
||||
value = drvmgr_dev_key_get(sc->dev, "rxDescs", DRVMGR_KT_INT);
|
||||
if ( value && (value->i <= 128) )
|
||||
if ( value && (value->i <= sc->num_descs) )
|
||||
sc->rxbufs = value->i;
|
||||
|
||||
value = drvmgr_dev_key_get(sc->dev, "phyAdr", DRVMGR_KT_INT);
|
||||
|
||||
@@ -261,6 +261,7 @@ static void check_rx_errors(GRSPW_DEV *pDev, int ctrl);
|
||||
static void grspw_rxnext(GRSPW_DEV *pDev);
|
||||
static void grspw_interrupt(void *arg);
|
||||
static int grspw_buffer_alloc(GRSPW_DEV *pDev);
|
||||
static int grspw_dmatables_alloc(GRSPW_DEV *pDev);
|
||||
|
||||
static rtems_device_driver grspw_initialize(
|
||||
rtems_device_major_number major,
|
||||
@@ -553,6 +554,8 @@ int grspw_device_init(GRSPW_DEV *pDev)
|
||||
|
||||
if (grspw_buffer_alloc(pDev))
|
||||
return RTEMS_NO_MEMORY;
|
||||
if (grspw_dmatables_alloc(pDev))
|
||||
return RTEMS_NO_MEMORY;
|
||||
|
||||
/* Create semaphores */
|
||||
rtems_semaphore_create(
|
||||
@@ -678,7 +681,11 @@ static int grspw_buffer_alloc(GRSPW_DEV *pDev)
|
||||
(void **)&pDev->ptr_txhbuf0_remote,
|
||||
pDev->txhbufsize * pDev->txbufcnt);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int grspw_dmatables_alloc(GRSPW_DEV *pDev)
|
||||
{
|
||||
/* DMA DESCRIPTOR TABLES */
|
||||
if (pDev->bd_dma_area & 1) {
|
||||
/* Address given in remote address */
|
||||
|
||||
@@ -1431,6 +1431,11 @@ int router_port_link_start(void *d, int port)
|
||||
return router_port_ctrl_rmw(d, port, NULL, PCTRL_LD | PCTRL_LS, PCTRL_LS);
|
||||
}
|
||||
|
||||
int router_port_link_div(void *d, int port, int rundiv)
|
||||
{
|
||||
return router_port_ctrl_rmw(d, port, NULL, PCTRL_RD, (rundiv << PCTRL_RD_BIT) & PCTRL_RD);
|
||||
}
|
||||
|
||||
int router_port_link_receive_spill(void *d, int port)
|
||||
{
|
||||
struct router_priv *priv = d;
|
||||
|
||||
@@ -1,15 +1,37 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup bsp_interrupt
|
||||
*
|
||||
* @brief This source file contains the default implementation of
|
||||
* bsp_interrupt_handler_default().
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2012 embedded brains GmbH. All rights reserved.
|
||||
* Copyright (C) 2008, 2012 embedded brains GmbH (http://www.embedded-brains.de)
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup RTEMSBSPsShared
|
||||
* @ingroup bsp_interrupt
|
||||
*
|
||||
* @brief This source file contains the default implementation of
|
||||
* bsp_interrupt_vector_enable(), bsp_interrupt_vector_disable(), and
|
||||
* bsp_interrupt_facility_initialize().
|
||||
*/
|
||||
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (C) 2019 embedded brains GmbH
|
||||
* Copyright (C) 2019 embedded brains GmbH (http://www.embedded-brains.de)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
||||
@@ -1,25 +1,37 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup bsp_interrupt
|
||||
*
|
||||
* @brief Generic BSP interrupt support implementation.
|
||||
* @brief This source file contains the generic interrupt controller support
|
||||
* implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
|
||||
* Copyright (C) 2008, 2018 embedded brains GmbH (http://www.embedded-brains.de)
|
||||
*
|
||||
* Copyright (c) 2008, 2018 embedded brains GmbH.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <bsp/irq-generic.h>
|
||||
|
||||
@@ -1,22 +1,37 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup bsp_interrupt
|
||||
*
|
||||
* @brief Generic BSP interrupt information implementation.
|
||||
* @brief This source file contains the implementation of
|
||||
* bsp_interrupt_report() and bsp_interrupt_report_with_plugin().
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010
|
||||
* embedded brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* D-82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
* Copyright (C) 2008, 2010 embedded brains GmbH (http://www.embedded-brains.de)
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
@@ -1,22 +1,37 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup bsp_interrupt
|
||||
*
|
||||
* @brief Generic BSP interrupt support legacy implementation.
|
||||
* @brief This source file contains the legacy interrupt controller support
|
||||
* implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008, 2009
|
||||
* embedded brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* D-82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
* Copyright (C) 2008, 2009 embedded brains GmbH (http://www.embedded-brains.de)
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -1,25 +1,37 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup bsp_interrupt
|
||||
*
|
||||
* @brief BSP interrupt support lock implementation.
|
||||
* @brief This source file contains the implementation of
|
||||
* bsp_interrupt_lock() and bsp_interrupt_unlock().
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
|
||||
* Copyright (C) 2008, 2018 embedded brains GmbH (http://www.embedded-brains.de)
|
||||
*
|
||||
* Copyright (c) 2008, 2018 embedded brains GmbH.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <bsp/irq-generic.h>
|
||||
|
||||
@@ -1,26 +1,40 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup bsp_interrupt
|
||||
*
|
||||
* @brief Generic BSP interrupt server implementation.
|
||||
* @brief This source file contains the interrupt server implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009, 2019 embedded brains GmbH. All rights reserved.
|
||||
* Copyright (C) 2009, 2020 embedded brains GmbH (http://www.embedded-brains.de)
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/chain.h>
|
||||
@@ -30,54 +44,43 @@
|
||||
|
||||
#define BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR (BSP_INTERRUPT_VECTOR_MAX + 1)
|
||||
|
||||
typedef struct {
|
||||
RTEMS_INTERRUPT_LOCK_MEMBER(lock);
|
||||
rtems_chain_control entries;
|
||||
rtems_id server;
|
||||
unsigned errors;
|
||||
} bsp_interrupt_server_context;
|
||||
static rtems_interrupt_server_control bsp_interrupt_server_default;
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
static bsp_interrupt_server_context *bsp_interrupt_server_instances;
|
||||
#else
|
||||
static bsp_interrupt_server_context bsp_interrupt_server_instance;
|
||||
#endif
|
||||
static rtems_chain_control bsp_interrupt_server_chain =
|
||||
RTEMS_CHAIN_INITIALIZER_EMPTY(bsp_interrupt_server_chain);
|
||||
|
||||
static bsp_interrupt_server_context *bsp_interrupt_server_get_context(
|
||||
static rtems_interrupt_server_control *bsp_interrupt_server_get_context(
|
||||
uint32_t server_index,
|
||||
rtems_status_code *sc
|
||||
)
|
||||
{
|
||||
#if defined(RTEMS_SMP)
|
||||
if (bsp_interrupt_server_instances == NULL) {
|
||||
*sc = RTEMS_INCORRECT_STATE;
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
if (bsp_interrupt_server_instance.server == RTEMS_ID_NONE) {
|
||||
*sc = RTEMS_INCORRECT_STATE;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
rtems_chain_node *node;
|
||||
|
||||
if (server_index >= rtems_scheduler_get_processor_maximum()) {
|
||||
*sc = RTEMS_INVALID_ID;
|
||||
return NULL;
|
||||
bsp_interrupt_lock();
|
||||
node = rtems_chain_first(&bsp_interrupt_server_chain);
|
||||
|
||||
while (node != rtems_chain_tail(&bsp_interrupt_server_chain)) {
|
||||
rtems_interrupt_server_control *s;
|
||||
|
||||
s = RTEMS_CONTAINER_OF(node, rtems_interrupt_server_control, node);
|
||||
if (s->index == server_index) {
|
||||
bsp_interrupt_unlock();
|
||||
return s;
|
||||
}
|
||||
|
||||
node = rtems_chain_next(node);
|
||||
}
|
||||
|
||||
*sc = RTEMS_SUCCESSFUL;
|
||||
#if defined(RTEMS_SMP)
|
||||
return &bsp_interrupt_server_instances[server_index];
|
||||
#else
|
||||
return &bsp_interrupt_server_instance;
|
||||
#endif
|
||||
bsp_interrupt_unlock();
|
||||
*sc = RTEMS_INVALID_ID;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void bsp_interrupt_server_trigger(void *arg)
|
||||
{
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
rtems_interrupt_server_entry *e = arg;
|
||||
bsp_interrupt_server_context *s = e->server;
|
||||
rtems_interrupt_server_control *s = e->server;
|
||||
|
||||
if (bsp_interrupt_is_valid_vector(e->vector)) {
|
||||
bsp_interrupt_vector_disable(e->vector);
|
||||
@@ -137,7 +140,7 @@ static rtems_interrupt_server_entry *bsp_interrupt_server_query_entry(
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
bsp_interrupt_server_context *server;
|
||||
rtems_interrupt_server_control *server;
|
||||
rtems_vector_number vector;
|
||||
rtems_option options;
|
||||
rtems_interrupt_handler handler;
|
||||
@@ -281,7 +284,7 @@ static void bsp_interrupt_server_remove_helper(void *arg)
|
||||
}
|
||||
|
||||
static rtems_status_code bsp_interrupt_server_call_helper(
|
||||
bsp_interrupt_server_context *s,
|
||||
rtems_interrupt_server_control *s,
|
||||
rtems_vector_number vector,
|
||||
rtems_option options,
|
||||
rtems_interrupt_handler handler,
|
||||
@@ -314,7 +317,7 @@ static rtems_status_code bsp_interrupt_server_call_helper(
|
||||
}
|
||||
|
||||
static rtems_interrupt_server_entry *bsp_interrupt_server_get_entry(
|
||||
bsp_interrupt_server_context *s
|
||||
rtems_interrupt_server_control *s
|
||||
)
|
||||
{
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
@@ -337,7 +340,7 @@ static rtems_interrupt_server_entry *bsp_interrupt_server_get_entry(
|
||||
|
||||
static void bsp_interrupt_server_task(rtems_task_argument arg)
|
||||
{
|
||||
bsp_interrupt_server_context *s = (bsp_interrupt_server_context *) arg;
|
||||
rtems_interrupt_server_control *s = (rtems_interrupt_server_control *) arg;
|
||||
|
||||
while (true) {
|
||||
rtems_event_set events;
|
||||
@@ -377,7 +380,7 @@ rtems_status_code rtems_interrupt_server_handler_install(
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
bsp_interrupt_server_context *s;
|
||||
rtems_interrupt_server_control *s;
|
||||
|
||||
s = bsp_interrupt_server_get_context(server_index, &sc);
|
||||
if (s == NULL) {
|
||||
@@ -402,7 +405,7 @@ rtems_status_code rtems_interrupt_server_handler_remove(
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
bsp_interrupt_server_context *s;
|
||||
rtems_interrupt_server_control *s;
|
||||
|
||||
s = bsp_interrupt_server_get_context(server_index, &sc);
|
||||
if (s == NULL) {
|
||||
@@ -464,7 +467,7 @@ rtems_status_code rtems_interrupt_server_handler_iterate(
|
||||
{
|
||||
rtems_status_code sc;
|
||||
bsp_interrupt_server_handler_iterate_helper_data hihd;
|
||||
bsp_interrupt_server_context *s;
|
||||
rtems_interrupt_server_control *s;
|
||||
|
||||
s = bsp_interrupt_server_get_context(server_index, &sc);
|
||||
if (s == NULL) {
|
||||
@@ -487,6 +490,90 @@ rtems_status_code rtems_interrupt_server_handler_iterate(
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* The default server is statically allocated. Just clear the structure so
|
||||
* that it can be re-initialized.
|
||||
*/
|
||||
static void bsp_interrupt_server_destroy_default(
|
||||
rtems_interrupt_server_control *s
|
||||
)
|
||||
{
|
||||
memset(s, 0, sizeof(*s));
|
||||
}
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
static void bsp_interrupt_server_destroy_secondary(
|
||||
rtems_interrupt_server_control *s
|
||||
)
|
||||
{
|
||||
free(s);
|
||||
}
|
||||
#endif
|
||||
|
||||
static rtems_status_code bsp_interrupt_server_create(
|
||||
rtems_interrupt_server_control *s,
|
||||
rtems_task_priority priority,
|
||||
size_t stack_size,
|
||||
rtems_mode modes,
|
||||
rtems_attribute attributes,
|
||||
uint32_t cpu_index
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
#if defined(RTEMS_SMP)
|
||||
rtems_id scheduler;
|
||||
cpu_set_t cpu;
|
||||
#endif
|
||||
|
||||
sc = rtems_task_create(
|
||||
rtems_build_name('I', 'R', 'Q', 'S'),
|
||||
priority,
|
||||
stack_size,
|
||||
modes,
|
||||
attributes,
|
||||
&s->server
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
(*s->destroy)(s);
|
||||
return sc;
|
||||
}
|
||||
|
||||
rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
|
||||
rtems_chain_initialize_empty(&s->entries);
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
sc = rtems_scheduler_ident_by_processor(cpu_index, &scheduler);
|
||||
|
||||
/*
|
||||
* If a scheduler exists for the processor, then move it to this scheduler
|
||||
* and try to set the affinity to the processor, otherwise keep the scheduler
|
||||
* of the executing thread.
|
||||
*/
|
||||
if (sc == RTEMS_SUCCESSFUL) {
|
||||
sc = rtems_task_set_scheduler(s->server, scheduler, priority);
|
||||
_Assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
/* Set the task to processor affinity on a best-effort basis */
|
||||
CPU_ZERO(&cpu);
|
||||
CPU_SET(cpu_index, &cpu);
|
||||
(void) rtems_task_set_affinity(s->server, sizeof(cpu), &cpu);
|
||||
}
|
||||
#else
|
||||
(void) cpu_index;
|
||||
#endif
|
||||
|
||||
rtems_chain_append_unprotected(&bsp_interrupt_server_chain, &s->node);
|
||||
|
||||
sc = rtems_task_start(
|
||||
s->server,
|
||||
bsp_interrupt_server_task,
|
||||
(rtems_task_argument) s
|
||||
);
|
||||
_Assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
rtems_status_code rtems_interrupt_server_initialize(
|
||||
rtems_task_priority priority,
|
||||
size_t stack_size,
|
||||
@@ -495,95 +582,166 @@ rtems_status_code rtems_interrupt_server_initialize(
|
||||
uint32_t *server_count
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
rtems_interrupt_server_control *s;
|
||||
uint32_t cpu_index;
|
||||
#if defined(RTEMS_SMP)
|
||||
uint32_t cpu_count;
|
||||
uint32_t dummy;
|
||||
bsp_interrupt_server_context *instances;
|
||||
#endif
|
||||
|
||||
if (server_count == NULL) {
|
||||
server_count = &dummy;
|
||||
cpu_index = 0;
|
||||
s = &bsp_interrupt_server_default;
|
||||
|
||||
bsp_interrupt_lock();
|
||||
|
||||
if (s->server != 0) {
|
||||
sc = RTEMS_INCORRECT_STATE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
s->destroy = bsp_interrupt_server_destroy_default;
|
||||
sc = bsp_interrupt_server_create(
|
||||
s,
|
||||
priority,
|
||||
stack_size,
|
||||
modes,
|
||||
attributes,
|
||||
cpu_index
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
cpu_index = 1;
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
cpu_count = rtems_scheduler_get_processor_maximum();
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
instances = calloc(cpu_count, sizeof(*instances));
|
||||
if (instances == NULL) {
|
||||
return RTEMS_NO_MEMORY;
|
||||
}
|
||||
#else
|
||||
instances = &bsp_interrupt_server_instance;
|
||||
#endif
|
||||
while (cpu_index < cpu_count) {
|
||||
s = calloc(1, sizeof(*s));
|
||||
|
||||
for (cpu_index = 0; cpu_index < cpu_count; ++cpu_index) {
|
||||
bsp_interrupt_server_context *s = &instances[cpu_index];
|
||||
rtems_status_code sc;
|
||||
#if defined(RTEMS_SMP)
|
||||
rtems_id scheduler;
|
||||
cpu_set_t cpu;
|
||||
#endif
|
||||
if (s == NULL) {
|
||||
sc = RTEMS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
|
||||
rtems_chain_initialize_empty(&s->entries);
|
||||
|
||||
sc = rtems_task_create(
|
||||
rtems_build_name('I', 'R', 'Q', 'S'),
|
||||
s->destroy = bsp_interrupt_server_destroy_secondary;
|
||||
s->index = cpu_index;
|
||||
sc = bsp_interrupt_server_create(
|
||||
s,
|
||||
priority,
|
||||
stack_size,
|
||||
modes,
|
||||
attributes,
|
||||
&s->server
|
||||
cpu_index
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
*server_count = cpu_index;
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
if (cpu_index > 0) {
|
||||
bsp_interrupt_server_instances = instances;
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
free(instances);
|
||||
#endif
|
||||
|
||||
return RTEMS_TOO_MANY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
sc = rtems_scheduler_ident_by_processor(cpu_index, &scheduler);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
/* Do not start an interrupt server on a processor without a scheduler */
|
||||
continue;
|
||||
}
|
||||
|
||||
sc = rtems_task_set_scheduler(s->server, scheduler, priority);
|
||||
_Assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
/* Set the task to processor affinity on a best-effort basis */
|
||||
CPU_ZERO(&cpu);
|
||||
CPU_SET(cpu_index, &cpu);
|
||||
(void) rtems_task_set_affinity(s->server, sizeof(cpu), &cpu);
|
||||
++cpu_index;
|
||||
}
|
||||
#endif
|
||||
|
||||
sc = rtems_task_start(
|
||||
s->server,
|
||||
bsp_interrupt_server_task,
|
||||
(rtems_task_argument) s
|
||||
);
|
||||
_Assert(sc == RTEMS_SUCCESSFUL);
|
||||
done:
|
||||
bsp_interrupt_unlock();
|
||||
|
||||
if (server_count != NULL) {
|
||||
*server_count = cpu_index;
|
||||
}
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
bsp_interrupt_server_instances = instances;
|
||||
#endif
|
||||
*server_count = cpu_index;
|
||||
return sc;
|
||||
}
|
||||
|
||||
rtems_status_code rtems_interrupt_server_create(
|
||||
rtems_interrupt_server_control *s,
|
||||
const rtems_interrupt_server_config *config,
|
||||
uint32_t *server_index
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
|
||||
sc = rtems_task_create(
|
||||
config->name,
|
||||
config->priority,
|
||||
config->storage_size,
|
||||
config->modes,
|
||||
config->attributes,
|
||||
&s->server
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
return sc;
|
||||
}
|
||||
|
||||
rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
|
||||
rtems_chain_initialize_empty(&s->entries);
|
||||
s->destroy = config->destroy;
|
||||
s->index = rtems_object_id_get_index(s->server)
|
||||
+ rtems_scheduler_get_processor_maximum();
|
||||
*server_index = s->index;
|
||||
|
||||
bsp_interrupt_lock();
|
||||
rtems_chain_initialize_node(&s->node);
|
||||
rtems_chain_append_unprotected(&bsp_interrupt_server_chain, &s->node);
|
||||
bsp_interrupt_unlock();
|
||||
|
||||
sc = rtems_task_start(
|
||||
s->server,
|
||||
bsp_interrupt_server_task,
|
||||
(rtems_task_argument) s
|
||||
);
|
||||
_Assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
static void bsp_interrupt_server_destroy_helper(void *arg)
|
||||
{
|
||||
bsp_interrupt_server_helper_data *hd = arg;
|
||||
rtems_interrupt_server_control *s = hd->server;
|
||||
rtems_status_code sc;
|
||||
|
||||
bsp_interrupt_lock();
|
||||
rtems_chain_extract_unprotected(&s->node);
|
||||
bsp_interrupt_unlock();
|
||||
|
||||
rtems_interrupt_lock_destroy(&s->lock);
|
||||
|
||||
if (s->destroy != NULL) {
|
||||
(*s->destroy)(s);
|
||||
}
|
||||
|
||||
sc = rtems_event_transient_send(hd->task);
|
||||
_Assert(sc == RTEMS_SUCCESSFUL);
|
||||
(void) sc;
|
||||
|
||||
rtems_task_exit();
|
||||
}
|
||||
|
||||
rtems_status_code rtems_interrupt_server_delete(uint32_t server_index)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
rtems_interrupt_server_control *s;
|
||||
|
||||
s = bsp_interrupt_server_get_context(server_index, &sc);
|
||||
if (s == NULL) {
|
||||
return sc;
|
||||
}
|
||||
|
||||
bsp_interrupt_server_call_helper(
|
||||
s,
|
||||
BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
bsp_interrupt_server_destroy_helper
|
||||
);
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static void bsp_interrupt_server_entry_initialize(
|
||||
rtems_interrupt_server_entry *entry,
|
||||
bsp_interrupt_server_context *s
|
||||
rtems_interrupt_server_control *s
|
||||
)
|
||||
{
|
||||
rtems_chain_set_off_chain(&entry->node);
|
||||
@@ -611,7 +769,7 @@ rtems_status_code rtems_interrupt_server_entry_initialize(
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
bsp_interrupt_server_context *s;
|
||||
rtems_interrupt_server_control *s;
|
||||
|
||||
s = bsp_interrupt_server_get_context(server_index, &sc);
|
||||
if (s == NULL) {
|
||||
@@ -645,7 +803,7 @@ rtems_status_code rtems_interrupt_server_entry_move(
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
bsp_interrupt_server_context *s;
|
||||
rtems_interrupt_server_control *s;
|
||||
|
||||
s = bsp_interrupt_server_get_context(destination_server_index, &sc);
|
||||
if (s == NULL) {
|
||||
@@ -667,7 +825,7 @@ void rtems_interrupt_server_entry_destroy(
|
||||
rtems_interrupt_server_entry *entry
|
||||
)
|
||||
{
|
||||
bsp_interrupt_server_context *s;
|
||||
rtems_interrupt_server_control *s;
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
|
||||
s = entry->server;
|
||||
@@ -698,7 +856,7 @@ rtems_status_code rtems_interrupt_server_request_initialize(
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
bsp_interrupt_server_context *s;
|
||||
rtems_interrupt_server_control *s;
|
||||
|
||||
s = bsp_interrupt_server_get_context(server_index, &sc);
|
||||
if (s == NULL) {
|
||||
@@ -727,8 +885,8 @@ static void bsp_interrupt_server_handler_move_helper(void *arg)
|
||||
e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
|
||||
if (e != NULL) {
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
bsp_interrupt_server_context *src = e->server;
|
||||
bsp_interrupt_server_context *dst = hihd->arg;
|
||||
rtems_interrupt_server_control *src = e->server;
|
||||
rtems_interrupt_server_control *dst = hihd->arg;
|
||||
bool pending;
|
||||
|
||||
/* The source server is only used in SMP configurations for the lock */
|
||||
@@ -763,8 +921,8 @@ rtems_status_code rtems_interrupt_server_move(
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
bsp_interrupt_server_context *src;
|
||||
bsp_interrupt_server_context *dst;
|
||||
rtems_interrupt_server_control *src;
|
||||
rtems_interrupt_server_control *dst;
|
||||
bsp_interrupt_server_handler_iterate_helper_data hihd;
|
||||
|
||||
src = bsp_interrupt_server_get_context(source_server_index, &sc);
|
||||
@@ -810,7 +968,7 @@ static void bsp_interrupt_server_entry_suspend_helper(void *arg)
|
||||
rtems_status_code rtems_interrupt_server_suspend(uint32_t server_index)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
bsp_interrupt_server_context *s;
|
||||
rtems_interrupt_server_control *s;
|
||||
|
||||
s = bsp_interrupt_server_get_context(server_index, &sc);
|
||||
if (s == NULL) {
|
||||
@@ -831,7 +989,7 @@ rtems_status_code rtems_interrupt_server_suspend(uint32_t server_index)
|
||||
rtems_status_code rtems_interrupt_server_resume(uint32_t server_index)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
bsp_interrupt_server_context *s;
|
||||
rtems_interrupt_server_control *s;
|
||||
|
||||
s = bsp_interrupt_server_get_context(server_index, &sc);
|
||||
if (s == NULL) {
|
||||
@@ -858,7 +1016,7 @@ rtems_status_code rtems_interrupt_server_set_affinity(
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
bsp_interrupt_server_context *s;
|
||||
rtems_interrupt_server_control *s;
|
||||
rtems_id scheduler;
|
||||
|
||||
s = bsp_interrupt_server_get_context(server_index, &sc);
|
||||
|
||||
@@ -1,22 +1,37 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup bsp_interrupt
|
||||
*
|
||||
* @brief Generic BSP interrupt shell implementation.
|
||||
* @brief This source file contains the definition of
|
||||
* ::bsp_interrupt_shell_command.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009
|
||||
* embedded brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* D-82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
* Copyright (C) 2009 embedded brains GmbH (http://www.embedded-brains.de)
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -34,18 +34,6 @@ struct ambapp_bus ambapp_plb;
|
||||
#include <drvmgr/drvmgr.h>
|
||||
#include <grlib/ambapp_bus_grlib.h>
|
||||
|
||||
extern void gptimer_register_drv (void);
|
||||
extern void apbuart_cons_register_drv(void);
|
||||
/* All drivers included by BSP, this is overridden by the user by including
|
||||
* the drvmgr_confdefs.h. By default the Timer and UART driver are included.
|
||||
*/
|
||||
drvmgr_drv_reg_func drvmgr_drivers[] __attribute__((weak)) =
|
||||
{
|
||||
gptimer_register_drv,
|
||||
apbuart_cons_register_drv,
|
||||
NULL /* End array with NULL */
|
||||
};
|
||||
|
||||
/* Driver resources configuration for AMBA root bus. It is declared weak
|
||||
* so that the user may override it, if the defualt settings are not
|
||||
* enough.
|
||||
|
||||
@@ -60,7 +60,10 @@ static void leon3_counter_initialize(void)
|
||||
counter->counter_register = &gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].value;
|
||||
|
||||
/* Enable timer just in case no clock driver is configured */
|
||||
gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].ctrl |= GPTIMER_TIMER_CTRL_EN;
|
||||
gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].reload = 0xffffffff;
|
||||
gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].ctrl |= GPTIMER_TIMER_CTRL_EN |
|
||||
GPTIMER_TIMER_CTRL_RS |
|
||||
GPTIMER_TIMER_CTRL_LD;
|
||||
|
||||
leon3_counter_frequency = ambapp_freq_get(&ambapp_plb, LEON3_Timer_Adev) /
|
||||
(gpt->scaler_reload + 1);
|
||||
|
||||
28
bsps/sparc/leon3/start/drvmgr_def_drivers.c
Normal file
28
bsps/sparc/leon3/start/drvmgr_def_drivers.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Default BSP drivers when Driver Manager enabled
|
||||
*
|
||||
* COPYRIGHT (c) 2019.
|
||||
* Cobham Gaisler
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
#include <bsp.h>
|
||||
|
||||
#ifdef RTEMS_DRVMGR_STARTUP
|
||||
#include <drvmgr/drvmgr.h>
|
||||
|
||||
extern void gptimer_register_drv (void);
|
||||
extern void apbuart_cons_register_drv(void);
|
||||
/* All drivers included by BSP, this is overridden by the user by including
|
||||
* the drvmgr_confdefs.h. By default the Timer and UART driver are included.
|
||||
*/
|
||||
drvmgr_drv_reg_func drvmgr_drivers[] __attribute__((weak)) =
|
||||
{
|
||||
gptimer_register_drv,
|
||||
apbuart_cons_register_drv,
|
||||
NULL /* End array with NULL */
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -71,6 +71,10 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/clock/clock-a9mpcore.
|
||||
# I2C
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/xilinx-zynq/i2c/cadence-i2c.c
|
||||
|
||||
# SPI
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/spi/cadence-spi.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/spi/xilinx-axi-spi.c
|
||||
|
||||
# Cache
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/cache/cache-l2c-310.c
|
||||
|
||||
|
||||
@@ -66,6 +66,10 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/serial/zynq-uart-poll
|
||||
# Clock
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/clock/clock-generic-timer.c
|
||||
|
||||
# SPI
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/spi/cadence-spi.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/spi/xilinx-axi-spi.c
|
||||
|
||||
# Cache
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/cache/cache-cp15.c
|
||||
|
||||
|
||||
@@ -92,9 +92,10 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/btimer/btimer-ppc
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/mmu/bat.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/mmu/mmuAsm.S
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/mmu/pte121.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/irq/ppc-irq-legacy.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/irq/ppc-irq-generic.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/irq/irq-default-handler.c
|
||||
|
||||
include $(srcdir)/../../../../../../bsps/shared/irq-default-sources.am
|
||||
include $(srcdir)/../../../../../../bsps/shared/irq-sources.am
|
||||
include $(srcdir)/../../../../../../bsps/shared/shared-sources.am
|
||||
include $(top_srcdir)/../../../../automake/subdirs.am
|
||||
include $(srcdir)/../../../../../../bsps/powerpc/shared/shared-sources.am
|
||||
|
||||
@@ -38,6 +38,7 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/start/bspreset-empty.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/leon3/start/cpucounter.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/shared/start/bsp_fatal_exit.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/leon3/start/bsp_fatal_halt.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/leon3/start/drvmgr_def_drivers.c
|
||||
|
||||
# gnatsupp
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/leon3/gnatsupp/gnatsupp.c
|
||||
|
||||
@@ -930,6 +930,7 @@ librtemscpu_a_SOURCES += score/src/schedulercbssetparameters.c
|
||||
librtemscpu_a_SOURCES += score/src/schedulercbsreleasejob.c
|
||||
librtemscpu_a_SOURCES += score/src/schedulercbsunblock.c
|
||||
librtemscpu_a_SOURCES += score/src/stackallocator.c
|
||||
librtemscpu_a_SOURCES += score/src/stackallocatorforidle.c
|
||||
librtemscpu_a_SOURCES += score/src/pheapallocate.c
|
||||
librtemscpu_a_SOURCES += score/src/pheapextend.c
|
||||
librtemscpu_a_SOURCES += score/src/pheapfree.c
|
||||
@@ -1483,6 +1484,10 @@ librtemscpu_a_SOURCES += libmisc/shell/login_prompt.c
|
||||
librtemscpu_a_SOURCES += libmisc/shell/login_check.c
|
||||
librtemscpu_a_SOURCES += libmisc/shell/fdisk.c
|
||||
librtemscpu_a_SOURCES += libmisc/shell/main_rtc.c
|
||||
librtemscpu_a_SOURCES += libmisc/shell/main_spi.c
|
||||
librtemscpu_a_SOURCES += libmisc/shell/main_i2cdetect.c
|
||||
librtemscpu_a_SOURCES += libmisc/shell/main_i2cset.c
|
||||
librtemscpu_a_SOURCES += libmisc/shell/main_i2cget.c
|
||||
librtemscpu_a_SOURCES += libmisc/shell/dd-args.c
|
||||
librtemscpu_a_SOURCES += libmisc/shell/main_dd.c
|
||||
librtemscpu_a_SOURCES += libmisc/shell/dd-conv.c
|
||||
|
||||
@@ -416,6 +416,7 @@ include_rtems_score_HEADERS += include/rtems/score/threadimpl.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/threadmp.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/threadq.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/threadqimpl.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/threadqops.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/timecounter.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/timecounterimpl.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/timespec.h
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
#include <stdint.h>
|
||||
#include <rtems/rtl/rtl-obj-fwd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum sections
|
||||
{
|
||||
rap_text = 0,
|
||||
@@ -76,4 +80,8 @@ int _rtld_linkmap_add (rtems_rtl_obj* obj);
|
||||
* Remove link map from the list.
|
||||
*/
|
||||
void _rtld_linkmap_delete (rtems_rtl_obj* obj);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _LINK_ELF_H_ */
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
|
||||
#include <rtems/score/rbtree.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define rb_node RBTree_Node
|
||||
|
||||
#define rb_left Node.rbe_left
|
||||
@@ -96,7 +100,7 @@ static inline struct rb_node *rb_last( struct rb_root *root )
|
||||
|
||||
static inline void rb_replace_node(
|
||||
struct rb_node *victim,
|
||||
struct rb_node *replacement,
|
||||
struct rb_node *replacement,
|
||||
struct rb_root *root
|
||||
)
|
||||
{
|
||||
@@ -138,4 +142,8 @@ static inline struct rb_node *rb_parent( struct rb_node *node )
|
||||
node = next \
|
||||
)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_RBTREE_H */
|
||||
|
||||
@@ -838,7 +838,7 @@ rtems_capture_task_flags (rtems_tcb* tcb)
|
||||
static inline rtems_capture_control*
|
||||
rtems_capture_task_control (rtems_tcb* tcb)
|
||||
{
|
||||
return tcb->Capture.control;
|
||||
return (rtems_capture_control*) tcb->Capture.control;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -853,7 +853,7 @@ rtems_capture_task_control (rtems_tcb* tcb)
|
||||
static inline uint32_t
|
||||
rtems_capture_task_control_flags (rtems_tcb* tcb)
|
||||
{
|
||||
rtems_capture_control* control = tcb->Capture.control;
|
||||
rtems_capture_control* control = rtems_capture_task_control (tcb);
|
||||
if (!control)
|
||||
return 0;
|
||||
return control->flags;
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
#error "Do not include this file directly, use <rtems/confdefs.h> instead"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Select PCI Configuration Library
|
||||
*/
|
||||
@@ -67,4 +71,8 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _RTEMS_CONFDEFS_LIBPCI_H */
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
* @ingroup RTEMSApplicationConfiguration
|
||||
*
|
||||
* @brief Evaluate MPCI Configuration Options
|
||||
*
|
||||
* This header file defines _CONFIGURE_MPCI_RECEIVE_SERVER_COUNT for use by
|
||||
* other configuration header files.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -49,6 +46,8 @@
|
||||
|
||||
#ifdef CONFIGURE_MP_APPLICATION
|
||||
|
||||
#include <rtems/confdefs/threads.h>
|
||||
|
||||
#ifndef CONFIGURE_EXTRA_MPCI_RECEIVE_SERVER_STACK
|
||||
#define CONFIGURE_EXTRA_MPCI_RECEIVE_SERVER_STACK 0
|
||||
#endif
|
||||
@@ -83,8 +82,6 @@
|
||||
#error "CONFIGURE_MP_NODE_NUMBER must be less than or equal to CONFIGURE_MP_MAXIMUM_NODES"
|
||||
#endif
|
||||
|
||||
#define _CONFIGURE_MPCI_RECEIVE_SERVER_COUNT 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -126,10 +123,6 @@ RTEMS_SECTION( ".rtemsstack.mpci" );
|
||||
}
|
||||
#endif
|
||||
|
||||
#else /* CONFIGURE_MP_APPLICATION */
|
||||
|
||||
#define _CONFIGURE_MPCI_RECEIVE_SERVER_COUNT 0
|
||||
|
||||
#endif /* CONFIGURE_MP_APPLICATION */
|
||||
|
||||
#else /* RTEMS_MULTIPROCESSING */
|
||||
@@ -138,8 +131,6 @@ RTEMS_SECTION( ".rtemsstack.mpci" );
|
||||
#error "CONFIGURE_MP_APPLICATION must not be defined if multiprocessing is disabled"
|
||||
#endif
|
||||
|
||||
#define _CONFIGURE_MPCI_RECEIVE_SERVER_COUNT 0
|
||||
|
||||
#endif /* RTEMS_MULTIPROCESSING */
|
||||
|
||||
#endif /* CONFIGURE_INIT */
|
||||
|
||||
@@ -133,11 +133,19 @@ RTEMS_DEFINE_GLOBAL_SYMBOL(
|
||||
|
||||
const size_t _Thread_Idle_stack_size = CONFIGURE_IDLE_TASK_STACK_SIZE;
|
||||
|
||||
char _Thread_Idle_stacks[
|
||||
_CONFIGURE_MAXIMUM_PROCESSORS
|
||||
* ( CONFIGURE_IDLE_TASK_STACK_SIZE + CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE )
|
||||
] RTEMS_ALIGNED( CPU_INTERRUPT_STACK_ALIGNMENT )
|
||||
RTEMS_SECTION( ".rtemsstack.idle" );
|
||||
/*
|
||||
* If the user provides a custom idle stack allocator, then we do not need
|
||||
* memory reserved for the stacks but the symbol is still referenced in
|
||||
* threadcreateidle.c. The code path just never uses it. Make it minimal
|
||||
* size to proceed.
|
||||
*/
|
||||
#ifndef CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE
|
||||
char _Thread_Idle_stacks[
|
||||
_CONFIGURE_MAXIMUM_PROCESSORS
|
||||
* ( CONFIGURE_IDLE_TASK_STACK_SIZE + CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE )
|
||||
] RTEMS_ALIGNED( CPU_INTERRUPT_STACK_ALIGNMENT )
|
||||
RTEMS_SECTION( ".rtemsstack.idle" );
|
||||
#endif
|
||||
|
||||
#if defined(CONFIGURE_IDLE_TASK_INITIALIZES_APPLICATION) && \
|
||||
!defined(CONFIGURE_IDLE_TASK_BODY)
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
|
||||
#include <rtems/confdefs/bdbuf.h>
|
||||
#include <rtems/confdefs/extensions.h>
|
||||
#include <rtems/confdefs/mpci.h>
|
||||
#include <rtems/confdefs/percpu.h>
|
||||
#include <rtems/confdefs/scheduler.h>
|
||||
#include <rtems/confdefs/unlimited.h>
|
||||
@@ -197,6 +196,12 @@ const size_t _Thread_Initial_thread_count =
|
||||
rtems_resource_maximum_per_allocation( _CONFIGURE_TASKS ) +
|
||||
rtems_resource_maximum_per_allocation( CONFIGURE_MAXIMUM_POSIX_THREADS );
|
||||
|
||||
#if defined(RTEMS_MULTIPROCESSING) && defined(CONFIGURE_MP_APPLICATION)
|
||||
#define _CONFIGURE_MPCI_RECEIVE_SERVER_COUNT 1
|
||||
#else
|
||||
#define _CONFIGURE_MPCI_RECEIVE_SERVER_COUNT 0
|
||||
#endif
|
||||
|
||||
THREAD_INFORMATION_DEFINE(
|
||||
_Thread,
|
||||
OBJECTS_INTERNAL_API,
|
||||
|
||||
@@ -132,12 +132,14 @@ const uintptr_t _Stack_Space_size = _CONFIGURE_STACK_SPACE_SIZE;
|
||||
|
||||
#if defined(CONFIGURE_TASK_STACK_ALLOCATOR) \
|
||||
&& defined(CONFIGURE_TASK_STACK_DEALLOCATOR)
|
||||
/* Custom allocator may or may not use the work space. */
|
||||
#ifdef CONFIGURE_TASK_STACK_ALLOCATOR_AVOIDS_WORK_SPACE
|
||||
const bool _Stack_Allocator_avoids_workspace = true;
|
||||
#else
|
||||
const bool _Stack_Allocator_avoids_workspace = false;
|
||||
#endif
|
||||
|
||||
/* Custom allocator may or may not need initialization. */
|
||||
#ifdef CONFIGURE_TASK_STACK_ALLOCATOR_INIT
|
||||
const Stack_Allocator_initialize _Stack_Allocator_initialize =
|
||||
CONFIGURE_TASK_STACK_ALLOCATOR_INIT;
|
||||
@@ -145,16 +147,30 @@ const uintptr_t _Stack_Space_size = _CONFIGURE_STACK_SPACE_SIZE;
|
||||
const Stack_Allocator_initialize _Stack_Allocator_initialize = NULL;
|
||||
#endif
|
||||
|
||||
/* Custom allocator must include allocate and free */
|
||||
const Stack_Allocator_allocate _Stack_Allocator_allocate =
|
||||
CONFIGURE_TASK_STACK_ALLOCATOR;
|
||||
|
||||
const Stack_Allocator_free _Stack_Allocator_free =
|
||||
CONFIGURE_TASK_STACK_DEALLOCATOR;
|
||||
|
||||
/*
|
||||
* Must provide both a custom stack allocator and deallocator
|
||||
*/
|
||||
#elif defined(CONFIGURE_TASK_STACK_ALLOCATOR) \
|
||||
|| defined(CONFIGURE_TASK_STACK_DEALLOCATOR)
|
||||
#error "CONFIGURE_TASK_STACK_ALLOCATOR and CONFIGURE_TASK_STACK_DEALLOCATOR must be both defined or both undefined"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Custom IDLE thread stacks allocator. If this is provided, it is assumed
|
||||
* that the allocator is providing its own memory for these stacks.
|
||||
*/
|
||||
#ifdef CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE
|
||||
const Stack_Allocator_allocate_for_idle _Stack_Allocator_allocate_for_idle =
|
||||
CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIGURE_DIRTY_MEMORY
|
||||
RTEMS_SYSINIT_ITEM(
|
||||
_Memory_Dirty_free_areas,
|
||||
|
||||
@@ -129,6 +129,9 @@ uint32_t rtems_configuration_get_maximum_extensions( void );
|
||||
#define rtems_configuration_get_stack_free_hook() \
|
||||
(_Stack_Allocator_free)
|
||||
|
||||
#define rtems_configuration_get_stack_allocate_for_idle_hook() \
|
||||
(_Stack_Allocator_allocate_for_idle)
|
||||
|
||||
/**
|
||||
* This macro assists in accessing the field which indicates whether
|
||||
* RTEMS is responsible for zeroing the Executive Workspace.
|
||||
|
||||
@@ -214,6 +214,9 @@ typedef struct {
|
||||
/**
|
||||
* @brief Converter implementation for new file system instance.
|
||||
*
|
||||
* Note: If you pass a converter to mount, you have to destroy it yourself if
|
||||
* mount failed. In a good case it is destroyed at unmount.
|
||||
*
|
||||
* Before converters have been added to the RTEMS implementation of the FAT
|
||||
* file system, the implementation was:
|
||||
* - Short names were saved in code page format (as is still the case).
|
||||
@@ -270,6 +273,10 @@ typedef struct {
|
||||
* RTEMS_FILESYSTEM_READ_WRITE,
|
||||
* &mount_opts
|
||||
* );
|
||||
*
|
||||
* if (rv != 0) {
|
||||
* (*mount_opts.converter->handler->destroy)(mount_opts.converter);
|
||||
* }
|
||||
* } else {
|
||||
* rv = -1;
|
||||
* errno = ENOMEM;
|
||||
|
||||
@@ -9,13 +9,7 @@
|
||||
/*
|
||||
* Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
|
||||
*
|
||||
* Copyright (C) 2008, 2019 embedded brains GmbH
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
* Copyright (C) 2008, 2020 embedded brains GmbH (http://www.embedded-brains.de)
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
@@ -259,6 +253,76 @@ typedef struct rtems_interrupt_server_action {
|
||||
*/
|
||||
#define RTEMS_INTERRUPT_SERVER_DEFAULT 0
|
||||
|
||||
/**
|
||||
* @brief An interrupt server control.
|
||||
*
|
||||
* This structure must be treated as an opaque data type. Members must not be
|
||||
* accessed directly.
|
||||
*
|
||||
* @see rtems_interrupt_server_create()
|
||||
*/
|
||||
typedef struct rtems_interrupt_server_control {
|
||||
RTEMS_INTERRUPT_LOCK_MEMBER( lock )
|
||||
rtems_chain_control entries;
|
||||
rtems_id server;
|
||||
unsigned long errors;
|
||||
uint32_t index;
|
||||
rtems_chain_node node;
|
||||
void ( *destroy )( struct rtems_interrupt_server_control * );
|
||||
} rtems_interrupt_server_control;
|
||||
|
||||
/**
|
||||
* @brief An interrupt server configuration.
|
||||
*
|
||||
* @see rtems_interrupt_server_create()
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief The task name of the interrupt server.
|
||||
*/
|
||||
rtems_name name;
|
||||
|
||||
/**
|
||||
* @brief The initial task priority of the interrupt server.
|
||||
*/
|
||||
rtems_task_priority priority;
|
||||
|
||||
/**
|
||||
* @brief The task storage area of the interrupt server.
|
||||
*
|
||||
* It shall be NULL for interrupt servers created by
|
||||
* rtems_interrupt_server_create().
|
||||
*/
|
||||
void *storage_area;
|
||||
|
||||
/**
|
||||
* @brief The task storage size of the interrupt server.
|
||||
*
|
||||
* For interrupt servers created by rtems_interrupt_server_create() this is
|
||||
* the task stack size.
|
||||
*/
|
||||
size_t storage_size;
|
||||
|
||||
/**
|
||||
* @brief The initial task modes of the interrupt server.
|
||||
*/
|
||||
rtems_mode modes;
|
||||
|
||||
/**
|
||||
* @brief The task attributes of the interrupt server.
|
||||
*/
|
||||
rtems_attribute attributes;
|
||||
|
||||
/**
|
||||
* @brief An optional handler to destroy the interrupt server control handed
|
||||
* over to rtems_interrupt_server_create().
|
||||
*
|
||||
* This handler is called in the context of the interrupt server to be
|
||||
* deleted, see also rtems_interrupt_server_delete().
|
||||
*/
|
||||
void ( *destroy )( rtems_interrupt_server_control * );
|
||||
} rtems_interrupt_server_config;
|
||||
|
||||
/**
|
||||
* @brief An interrupt server entry.
|
||||
*
|
||||
@@ -309,16 +373,19 @@ typedef struct {
|
||||
*
|
||||
* The server count pointer @a server_count may be @a NULL.
|
||||
*
|
||||
* The task name of interrupt servers created by this function is
|
||||
* rtems_build_name( 'I', 'R', 'Q', 'S' ).
|
||||
*
|
||||
* This function may block.
|
||||
*
|
||||
* @see rtems_task_create().
|
||||
* @retval RTEMS_SUCCESSFUL The operation was successful.
|
||||
*
|
||||
* @retval RTEMS_SUCCESSFUL Successful operation.
|
||||
* @retval RTEMS_INCORRECT_STATE The interrupt servers are not initialized.
|
||||
* @retval RTEMS_NO_MEMORY Not enough memory.
|
||||
* @retval RTEMS_TOO_MANY No free task available to create at least one server task.
|
||||
* @retval RTEMS_UNSATISFIED Task stack size too large.
|
||||
* @retval RTEMS_INVALID_PRIORITY Invalid task priority.
|
||||
* @retval RTEMS_INCORRECT_STATE The interrupt servers were already initialized.
|
||||
*
|
||||
* @return The function uses rtems_task_create(). If this operation is not
|
||||
* successful, then its status code is returned.
|
||||
*
|
||||
* @see rtems_interrupt_server_create() and rtems_interrupt_server_delete().
|
||||
*/
|
||||
rtems_status_code rtems_interrupt_server_initialize(
|
||||
rtems_task_priority priority,
|
||||
@@ -328,6 +395,54 @@ rtems_status_code rtems_interrupt_server_initialize(
|
||||
uint32_t *server_count
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Creates an interrupt server.
|
||||
*
|
||||
* This function may block.
|
||||
*
|
||||
* @param[out] control is the interrupt server control. The ownership of this
|
||||
* structure is transferred from the caller of this function to the interrupt
|
||||
* server management.
|
||||
*
|
||||
* @param config is the interrupt server configuration.
|
||||
*
|
||||
* @param[out] server_index is the pointer to a server index variable. The
|
||||
* index of the built interrupt server will be stored in the referenced
|
||||
* variable if the operation was successful.
|
||||
*
|
||||
* @retval RTEMS_SUCCESSFUL The operation was successful.
|
||||
*
|
||||
* @return The function uses rtems_task_create(). If this operation is not
|
||||
* successful, then its status code is returned.
|
||||
*
|
||||
* @see rtems_interrupt_server_initialize() and
|
||||
* rtems_interrupt_server_delete().
|
||||
*/
|
||||
rtems_status_code rtems_interrupt_server_create(
|
||||
rtems_interrupt_server_control *control,
|
||||
const rtems_interrupt_server_config *config,
|
||||
uint32_t *server_index
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Destroys the interrupt server.
|
||||
*
|
||||
* This function may block.
|
||||
*
|
||||
* The interrupt server deletes itself, so after the return of the function the
|
||||
* interrupt server may be still in the termination process depending on the
|
||||
* task priorities of the system.
|
||||
*
|
||||
* @param server_index is the index of the interrupt server to destroy. Use
|
||||
* ::RTEMS_INTERRUPT_SERVER_DEFAULT to specify the default server.
|
||||
*
|
||||
* @retval RTEMS_SUCCESSFUL The operation was successful.
|
||||
* @retval RTEMS_INVALID_ID The interrupt server index was invalid.
|
||||
*
|
||||
* @see rtems_interrupt_server_create()
|
||||
*/
|
||||
rtems_status_code rtems_interrupt_server_delete( uint32_t server_index );
|
||||
|
||||
/**
|
||||
* @brief Installs the interrupt handler routine @a handler for the interrupt
|
||||
* vector with number @a vector on the server @a server.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user