mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-16 00:00:02 +01:00
205 lines
4.6 KiB
C
205 lines
4.6 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, json_t *cfg)
|
|
{
|
|
struct sw *sw = c->_vd;
|
|
|
|
int ret;
|
|
size_t index;
|
|
json_error_t err;
|
|
json_t *cfg_path, *cfg_paths = NULL;
|
|
|
|
list_init(&sw->paths);
|
|
|
|
ret = json_unpack_ex(cfg, &err, 0, "{ s: i, s?: o }",
|
|
"num_ports", &sw->num_ports,
|
|
"paths", &cfg_paths
|
|
);
|
|
if (ret)
|
|
jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name);
|
|
|
|
if (!cfg_paths)
|
|
return 0; /* no switch config available */
|
|
|
|
if (!json_is_array(cfg_paths))
|
|
error("Setting 'paths' of FPGA IP '%s' should be an array of JSON objects", c->name);
|
|
|
|
json_array_foreach(cfg_paths, index, cfg_path) {
|
|
struct sw_path *p = alloc(sizeof(struct sw_path));
|
|
int reverse = 0;
|
|
|
|
ret = json_unpack_ex(cfg_path, &err, 0, "{ s?: b, s: s, s: s }",
|
|
"reverse", &reverse,
|
|
"in", &p->in,
|
|
"out", &p->out
|
|
);
|
|
if (ret)
|
|
jerror(&err, "Failed to parse path %zu of FPGA IP '%s'", index, c->name);
|
|
|
|
list_push(&sw->paths, p);
|
|
|
|
if (reverse) {
|
|
struct sw_path *r = memdup(p, sizeof(struct sw_path));
|
|
|
|
r->in = p->out;
|
|
r->out = p->in;
|
|
|
|
list_push(&sw->paths, r);
|
|
}
|
|
}
|
|
|
|
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)
|