2021-10-15 15:52:40 +02:00

223 lines
6.9 KiB
C

// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#include "LocalLinkInterface.h"
#include "HardwareMMappingDefs.h"
#include "clogger.h"
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
void Local_LocalLinkInterface(struct LocalLinkInterface *ll,
unsigned int ll_fifo_badr) {
LOG(logDEBUG1, ("Initialize PLB LL FIFOs\n"));
ll->ll_fifo_base = 0;
ll->ll_fifo_ctrl_reg = 0;
if (Local_Init(ll, ll_fifo_badr)) {
Local_Reset(ll);
LOG(logDEBUG1,
("\tFIFO Status : 0x%08x\n\n\n", Local_StatusVector(ll)));
} else
LOG(logERROR,
("\tCould not map LocalLink : 0x%08x\n\n\n", ll_fifo_badr));
}
int Local_Init(struct LocalLinkInterface *ll, unsigned int ll_fifo_badr) {
int fd;
void *plb_ll_fifo_ptr;
if ((fd = open("/dev/mem", O_RDWR)) < 0) {
LOG(logERROR, ("Could not open /dev/mem for local link\n"));
return 0;
}
plb_ll_fifo_ptr = mmap(0, getpagesize(), PROT_READ | PROT_WRITE,
MAP_FILE | MAP_SHARED, fd, ll_fifo_badr);
close(fd);
if (plb_ll_fifo_ptr == MAP_FAILED) {
LOG(logERROR, ("mmap error for local link\n"));
return 0;
}
ll->ll_fifo_base = (xfs_u32)plb_ll_fifo_ptr;
ll->ll_fifo_ctrl_reg = 0;
return 1;
}
int Local_Reset(struct LocalLinkInterface *ll) {
return Local_Reset1(ll, PLB_LL_FIFO_CTRL_RESET_STD);
}
int Local_Reset1(struct LocalLinkInterface *ll, unsigned int rst_mask) {
ll->ll_fifo_ctrl_reg |= rst_mask;
LOG(logDEBUG1, ("\tCTRL Register bits: 0x%08x\n", ll->ll_fifo_ctrl_reg));
HWIO_xfs_out32(ll->ll_fifo_base + 4 * PLB_LL_FIFO_REG_CTRL,
ll->ll_fifo_ctrl_reg);
HWIO_xfs_out32(ll->ll_fifo_base + 4 * PLB_LL_FIFO_REG_CTRL,
ll->ll_fifo_ctrl_reg);
HWIO_xfs_out32(ll->ll_fifo_base + 4 * PLB_LL_FIFO_REG_CTRL,
ll->ll_fifo_ctrl_reg);
HWIO_xfs_out32(ll->ll_fifo_base + 4 * PLB_LL_FIFO_REG_CTRL,
ll->ll_fifo_ctrl_reg);
ll->ll_fifo_ctrl_reg &= (~rst_mask);
HWIO_xfs_out32(ll->ll_fifo_base + 4 * PLB_LL_FIFO_REG_CTRL,
ll->ll_fifo_ctrl_reg);
return 1;
}
unsigned int Local_StatusVector(struct LocalLinkInterface *ll) {
return HWIO_xfs_in32(ll->ll_fifo_base + 4 * PLB_LL_FIFO_REG_STATUS);
}
int Local_Write(struct LocalLinkInterface *ll, unsigned int buffer_len,
void *buffer) {
// note: buffer must be word (4 byte) aligned
// frame_len in byte
int vacancy = 0;
int words_send = 0;
int last_word;
unsigned int *word_ptr;
unsigned int fifo_ctrl;
xfs_u32 status;
if (buffer_len < 1) {
return -1;
}
last_word = (buffer_len - 1) / 4;
word_ptr = (unsigned int *)buffer;
LOG(logDEBUG1, ("LL Write - Len: %2d - If: %X - Data: ", buffer_len,
ll->ll_fifo_base));
for (int i = 0; i < buffer_len / 4; i++)
LOG(logDEBUG1, ("%.8X ", *(((unsigned *)buffer) + i)));
while (words_send <= last_word) {
while (!vacancy) // wait for Fifo to be empty again
{
status =
HWIO_xfs_in32(ll->ll_fifo_base + 4 * PLB_LL_FIFO_REG_STATUS);
if ((status & PLB_LL_FIFO_STATUS_ALMOSTFULL) == 0)
vacancy = 1;
if (vacancy == 0) {
LOG(logERROR, ("Fifo full!\n"));
}
}
// Just to know: #define PLB_LL_FIFO_ALMOST_FULL_THRESHOLD_WORDS 100
for (int i = 0; ((i < PLB_LL_FIFO_ALMOST_FULL_THRESHOLD_WORDS) &&
(words_send <= last_word));
i++) {
fifo_ctrl = 0;
if (words_send == 0) {
fifo_ctrl =
PLB_LL_FIFO_CTRL_LL_SOF; // announce the start of file
}
if (words_send == last_word) {
fifo_ctrl |=
(PLB_LL_FIFO_CTRL_LL_EOF |
(((buffer_len - 1) << PLB_LL_FIFO_CTRL_LL_REM_SHIFT) &
PLB_LL_FIFO_CTRL_LL_REM));
}
Local_ctrl_reg_write_mask(ll, PLB_LL_FIFO_CTRL_LL_MASK, fifo_ctrl);
HWIO_xfs_out32(ll->ll_fifo_base + 4 * PLB_LL_FIFO_REG_FIFO,
word_ptr[words_send++]);
}
}
return buffer_len;
}
int Local_Read(struct LocalLinkInterface *ll, unsigned int buffer_len,
void *buffer) {
static unsigned int buffer_ptr = 0;
// note: buffer must be word (4 byte) aligned
// frame_len in byte
int len;
unsigned int *word_ptr;
unsigned int status;
volatile unsigned int fifo_val;
int sof = 0;
LOG(logDEBUG1, ("LL Read - If: %X - Data: ", ll->ll_fifo_base));
word_ptr = (unsigned int *)buffer;
do {
status = HWIO_xfs_in32(ll->ll_fifo_base + 4 * PLB_LL_FIFO_REG_STATUS);
if (!(status & PLB_LL_FIFO_STATUS_EMPTY)) {
if (status & PLB_LL_FIFO_STATUS_LL_SOF) {
if (buffer_ptr) {
buffer_ptr = 0;
return -1; // buffer overflow
}
buffer_ptr = 0;
sof = 1;
}
fifo_val = HWIO_xfs_in32(
ll->ll_fifo_base + 4 * PLB_LL_FIFO_REG_FIFO); // read from fifo
if ((buffer_ptr > 0) || sof) {
if ((buffer_len >> 2) > buffer_ptr) {
LOG(logDEBUG1, ("%.8X ", fifo_val));
word_ptr[buffer_ptr++] = fifo_val; // write to buffer
} else {
buffer_ptr = 0;
return -2; // buffer overflow
}
if (status & PLB_LL_FIFO_STATUS_LL_EOF) {
len = (buffer_ptr << 2) - 3 +
((status & PLB_LL_FIFO_STATUS_LL_REM) >>
PLB_LL_FIFO_STATUS_LL_REM_SHIFT);
LOG(logDEBUG1, ("Len: %d\n", len));
buffer_ptr = 0;
return len;
}
}
}
} while (!(status & PLB_LL_FIFO_STATUS_EMPTY));
return 0;
}
int Local_ctrl_reg_write_mask(struct LocalLinkInterface *ll, unsigned int mask,
unsigned int val) {
ll->ll_fifo_ctrl_reg &= (~mask);
ll->ll_fifo_ctrl_reg |= (mask & val);
HWIO_xfs_out32(ll->ll_fifo_base + 4 * PLB_LL_FIFO_REG_CTRL,
ll->ll_fifo_ctrl_reg);
return 1;
}
int Local_Test(struct LocalLinkInterface *ll, unsigned int buffer_len,
void *buffer) {
int len;
unsigned int rec_buff_len = 4096;
unsigned int rec_buffer[4097];
Local_Write(ll, buffer_len, buffer);
usleep(10000);
do {
len = Local_Read(ll, rec_buff_len, rec_buffer);
LOG(logDEBUG1, ("receive length: %i\n", len));
if (len > 0) {
rec_buffer[len] = 0;
LOG(logINFO, ("%s\n", (char *)rec_buffer));
}
} while (len > 0);
return 1;
}