1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00
VILLASnode/lib/fpga/ips/switch.c

206 lines
5 KiB
C

/** AXI Stream interconnect related helper functions
*
* These functions present a simpler interface to Xilinx' AXI Stream switch driver (XAxis_Switch_*)
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Steffen Vogel
**********************************************************************************/
#include "list.h"
#include "log.h"
#include "log_config.h"
#include "plugin.h"
#include "fpga/ip.h"
#include "fpga/card.h"
#include "fpga/ips/switch.h"
int switch_start(struct fpga_ip *c)
{
int ret;
struct fpga_card *f = c->card;
struct sw *sw = c->_vd;
XAxis_Switch *xsw = &sw->inst;
if (c != f->sw)
error("There can be only one AXI4-Stream interconnect per FPGA");
/* Setup AXI-stream switch */
XAxis_Switch_Config sw_cfg = {
.BaseAddress = (uintptr_t) f->map + c->baseaddr,
.MaxNumMI = sw->num_ports,
.MaxNumSI = sw->num_ports
};
ret = XAxisScr_CfgInitialize(xsw, &sw_cfg, (uintptr_t) c->card->map + c->baseaddr);
if (ret != XST_SUCCESS)
return -1;
/* Disable all masters */
XAxisScr_RegUpdateDisable(xsw);
XAxisScr_MiPortDisableAll(xsw);
XAxisScr_RegUpdateEnable(xsw);
switch_init_paths(c);
return 0;
}
int switch_init_paths(struct fpga_ip *c)
{
int ret;
struct sw *sw = c->_vd;
XAxis_Switch *xsw = &sw->inst;
XAxisScr_RegUpdateDisable(xsw);
XAxisScr_MiPortDisableAll(xsw);
for (size_t i = 0; i < list_length(&sw->paths); i++) {
struct sw_path *p = list_at(&sw->paths, i);
struct fpga_ip *mi, *si;
mi = list_lookup(&c->card->ips, p->out);
si = list_lookup(&c->card->ips, p->in);
if (!mi || !si || mi->port == -1 || si->port == -1)
error("Invalid path configuration for FPGA");
ret = switch_connect(c, mi, si);
if (ret)
error("Failed to configure switch");
}
XAxisScr_RegUpdateEnable(xsw);
return 0;
}
int switch_destroy(struct fpga_ip *c)
{
struct sw *sw = c->_vd;
list_destroy(&sw->paths, NULL, true);
return 0;
}
int switch_parse(struct fpga_ip *c)
{
struct fpga_card *f = c->card;
struct sw *sw = c->_vd;
list_init(&sw->paths);
config_setting_t *cfg_sw, *cfg_path;
if (!config_setting_lookup_int(c->cfg, "num_ports", &sw->num_ports))
cerror(c->cfg, "Switch IP '%s' requires 'num_ports' option", c->name);
cfg_sw = config_setting_get_member(f->cfg, "paths");
if (!cfg_sw)
return 0; /* no switch config available */
for (int i = 0; i < config_setting_length(cfg_sw); i++) {
cfg_path = config_setting_get_elem(cfg_sw, i);
struct sw_path path;
int reverse;
if (!config_setting_lookup_bool(cfg_path, "reverse", &reverse))
reverse = 0;
if (!config_setting_lookup_string(cfg_path, "in", &path.in) &&
!config_setting_lookup_string(cfg_path, "from", &path.in) &&
!config_setting_lookup_string(cfg_path, "src", &path.in) &&
!config_setting_lookup_string(cfg_path, "source", &path.in))
cerror(cfg_path, "Path is missing 'in' setting");
if (!config_setting_lookup_string(cfg_path, "out", &path.out) &&
!config_setting_lookup_string(cfg_path, "to", &path.out) &&
!config_setting_lookup_string(cfg_path, "dst", &path.out) &&
!config_setting_lookup_string(cfg_path, "dest", &path.out) &&
!config_setting_lookup_string(cfg_path, "sink", &path.out))
cerror(cfg_path, "Path is missing 'out' setting");
list_push(&sw->paths, memdup(&path, sizeof(path)));
if (reverse) {
const char *tmp = path.in;
path.in = path.out;
path.out = tmp;
list_push(&sw->paths, memdup(&path, sizeof(path)));
}
}
return 0;
}
int switch_connect(struct fpga_ip *c, struct fpga_ip *mi, struct fpga_ip *si)
{
struct sw *sw = c->_vd;
XAxis_Switch *xsw = &sw->inst;
uint32_t mux, port;
/* Check if theres already something connected */
for (int i = 0; i < sw->num_ports; i++) {
mux = XAxisScr_ReadReg(xsw->Config.BaseAddress, XAXIS_SCR_MI_MUX_START_OFFSET + i * 4);
if (!(mux & XAXIS_SCR_MI_X_DISABLE_MASK)) {
port = mux & ~XAXIS_SCR_MI_X_DISABLE_MASK;
if (port == si->port) {
warn("Switch: Slave port %s (%u) has been connected already to port %u. Disconnecting...", si->name, si->port, i);
XAxisScr_RegUpdateDisable(xsw);
XAxisScr_MiPortDisable(xsw, i);
XAxisScr_RegUpdateEnable(xsw);
}
}
}
/* Reconfigure switch */
XAxisScr_RegUpdateDisable(xsw);
XAxisScr_MiPortEnable(xsw, mi->port, si->port);
XAxisScr_RegUpdateEnable(xsw);
/* Reset IPs */
/*ip_reset(mi);
ip_reset(si);*/
debug(8, "FPGA: Switch connected %s (%u) to %s (%u)", mi->name, mi->port, si->name, si->port);
return 0;
}
int switch_disconnect(struct fpga_ip *c, struct fpga_ip *mi, struct fpga_ip *si)
{
struct sw *sw = c->_vd;
XAxis_Switch *xsw = &sw->inst;
if (!XAxisScr_IsMiPortEnabled(xsw, mi->port, si->port))
return -1;
XAxisScr_MiPortDisable(xsw, mi->port);
return 0;
}
static struct plugin p = {
.name = "Xilinx's AXI4-Stream switch",
.description = "",
.type = PLUGIN_TYPE_FPGA_IP,
.ip = {
.vlnv = { "xilinx.com", "ip", "axis_interconnect", NULL },
.type = FPGA_IP_TYPE_MISC,
.start = switch_start,
.destroy = switch_destroy,
.parse = switch_parse,
.size = sizeof(struct sw)
}
};
REGISTER_PLUGIN(&p)