xlnx-versal: Connect Xilinx VERSAL CANFD controllers

Connect CANFD0 and CANFD1 on the Versal-virt machine and update xlnx-versal-virt
document with CANFD command line examples.

Signed-off-by: Vikram Garhwal <vikram.garhwal@amd.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Francisco Iglesias <frasse.iglesias@gmail.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Vikram Garhwal 2023-06-06 10:19:30 +01:00 committed by Peter Maydell
parent 32dbebcc7e
commit 042d6b0255
4 changed files with 133 additions and 0 deletions

View File

@ -34,6 +34,7 @@ Implemented devices:
- DDR memory
- BBRAM (36 bytes of Battery-backed RAM)
- eFUSE (3072 bytes of one-time field-programmable bit array)
- 2 CANFDs
QEMU does not yet model any other devices, including the PL and the AI Engine.
@ -224,3 +225,33 @@ To use a different index value, N, from default of 1, add:
Better yet, do not use actual product data when running guest image
on this Xilinx Versal Virt board.
Using CANFDs for Versal Virt
""""""""""""""""""""""""""""
Versal CANFD controller is developed based on SocketCAN and QEMU CAN bus
implementation. Bus connection and socketCAN connection for each CAN module
can be set through command lines.
To connect both CANFD0 and CANFD1 on the same bus:
.. code-block:: bash
-object can-bus,id=canbus -machine canbus0=canbus -machine canbus1=canbus
To connect CANFD0 and CANFD1 to separate buses:
.. code-block:: bash
-object can-bus,id=canbus0 -object can-bus,id=canbus1 \
-machine canbus0=canbus0 -machine canbus1=canbus1
The SocketCAN interface can connect to a Physical or a Virtual CAN interfaces on
the host machine. Please check this document to learn about CAN interface on
Linux: docs/system/devices/can.rst
To connect CANFD0 and CANFD1 to host machine's CAN interface can0:
.. code-block:: bash
-object can-bus,id=canbus -machine canbus0=canbus -machine canbus1=canbus
-object can-host-socketcan,id=canhost0,if=can0,canbus=canbus

View File

@ -40,9 +40,11 @@ struct VersalVirt {
uint32_t clk_25Mhz;
uint32_t usb;
uint32_t dwc;
uint32_t canfd[2];
} phandle;
struct arm_boot_info binfo;
CanBusState *canbus[XLNX_VERSAL_NR_CANFD];
struct {
bool secure;
} cfg;
@ -235,6 +237,38 @@ static void fdt_add_uart_nodes(VersalVirt *s)
}
}
static void fdt_add_canfd_nodes(VersalVirt *s)
{
uint64_t addrs[] = { MM_CANFD1, MM_CANFD0 };
uint32_t size[] = { MM_CANFD1_SIZE, MM_CANFD0_SIZE };
unsigned int irqs[] = { VERSAL_CANFD1_IRQ_0, VERSAL_CANFD0_IRQ_0 };
const char clocknames[] = "can_clk\0s_axi_aclk";
int i;
/* Create and connect CANFD0 and CANFD1 nodes to canbus0. */
for (i = 0; i < ARRAY_SIZE(addrs); i++) {
char *name = g_strdup_printf("/canfd@%" PRIx64, addrs[i]);
qemu_fdt_add_subnode(s->fdt, name);
qemu_fdt_setprop_cell(s->fdt, name, "rx-fifo-depth", 0x40);
qemu_fdt_setprop_cell(s->fdt, name, "tx-mailbox-count", 0x20);
qemu_fdt_setprop_cells(s->fdt, name, "clocks",
s->phandle.clk_25Mhz, s->phandle.clk_25Mhz);
qemu_fdt_setprop(s->fdt, name, "clock-names",
clocknames, sizeof(clocknames));
qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
GIC_FDT_IRQ_TYPE_SPI, irqs[i],
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
2, addrs[i], 2, size[i]);
qemu_fdt_setprop_string(s->fdt, name, "compatible",
"xlnx,canfd-2.0");
g_free(name);
}
}
static void fdt_add_fixed_link_nodes(VersalVirt *s, char *gemname,
uint32_t phandle)
{
@ -639,12 +673,17 @@ static void versal_virt_init(MachineState *machine)
TYPE_XLNX_VERSAL);
object_property_set_link(OBJECT(&s->soc), "ddr", OBJECT(machine->ram),
&error_abort);
object_property_set_link(OBJECT(&s->soc), "canbus0", OBJECT(s->canbus[0]),
&error_abort);
object_property_set_link(OBJECT(&s->soc), "canbus1", OBJECT(s->canbus[1]),
&error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_fatal);
fdt_create(s);
create_virtio_regions(s);
fdt_add_gem_nodes(s);
fdt_add_uart_nodes(s);
fdt_add_canfd_nodes(s);
fdt_add_gic_nodes(s);
fdt_add_timer_nodes(s);
fdt_add_zdma_nodes(s);
@ -712,6 +751,20 @@ static void versal_virt_init(MachineState *machine)
static void versal_virt_machine_instance_init(Object *obj)
{
VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj);
/*
* User can set canbus0 and canbus1 properties to can-bus object and connect
* to socketcan(optional) interface via command line.
*/
object_property_add_link(obj, "canbus0", TYPE_CAN_BUS,
(Object **)&s->canbus[0],
object_property_allow_set_link,
0);
object_property_add_link(obj, "canbus1", TYPE_CAN_BUS,
(Object **)&s->canbus[1],
object_property_allow_set_link,
0);
}
static void versal_virt_machine_class_init(ObjectClass *oc, void *data)

View File

@ -184,6 +184,38 @@ static void versal_create_uarts(Versal *s, qemu_irq *pic)
}
}
static void versal_create_canfds(Versal *s, qemu_irq *pic)
{
int i;
uint32_t irqs[] = { VERSAL_CANFD0_IRQ_0, VERSAL_CANFD1_IRQ_0};
uint64_t addrs[] = { MM_CANFD0, MM_CANFD1 };
for (i = 0; i < ARRAY_SIZE(s->lpd.iou.canfd); i++) {
char *name = g_strdup_printf("canfd%d", i);
SysBusDevice *sbd;
MemoryRegion *mr;
object_initialize_child(OBJECT(s), name, &s->lpd.iou.canfd[i],
TYPE_XILINX_CANFD);
sbd = SYS_BUS_DEVICE(&s->lpd.iou.canfd[i]);
object_property_set_int(OBJECT(&s->lpd.iou.canfd[i]), "ext_clk_freq",
XLNX_VERSAL_CANFD_REF_CLK , &error_abort);
object_property_set_link(OBJECT(&s->lpd.iou.canfd[i]), "canfdbus",
OBJECT(s->lpd.iou.canbus[i]),
&error_abort);
sysbus_realize(sbd, &error_fatal);
mr = sysbus_mmio_get_region(sbd, 0);
memory_region_add_subregion(&s->mr_ps, addrs[i], mr);
sysbus_connect_irq(sbd, 0, pic[irqs[i]]);
g_free(name);
}
}
static void versal_create_usbs(Versal *s, qemu_irq *pic)
{
DeviceState *dev;
@ -718,6 +750,7 @@ static void versal_realize(DeviceState *dev, Error **errp)
versal_create_apu_gic(s, pic);
versal_create_rpu_cpus(s);
versal_create_uarts(s, pic);
versal_create_canfds(s, pic);
versal_create_usbs(s, pic);
versal_create_gems(s, pic);
versal_create_admas(s, pic);
@ -757,6 +790,10 @@ static void versal_init(Object *obj)
static Property versal_properties[] = {
DEFINE_PROP_LINK("ddr", Versal, cfg.mr_ddr, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_LINK("canbus0", Versal, lpd.iou.canbus[0],
TYPE_CAN_BUS, CanBusState *),
DEFINE_PROP_LINK("canbus1", Versal, lpd.iou.canbus[1],
TYPE_CAN_BUS, CanBusState *),
DEFINE_PROP_END_OF_LIST()
};

View File

@ -31,6 +31,7 @@
#include "hw/dma/xlnx_csu_dma.h"
#include "hw/misc/xlnx-versal-crl.h"
#include "hw/misc/xlnx-versal-pmc-iou-slcr.h"
#include "hw/net/xlnx-versal-canfd.h"
#define TYPE_XLNX_VERSAL "xlnx-versal"
OBJECT_DECLARE_SIMPLE_TYPE(Versal, XLNX_VERSAL)
@ -43,6 +44,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(Versal, XLNX_VERSAL)
#define XLNX_VERSAL_NR_SDS 2
#define XLNX_VERSAL_NR_XRAM 4
#define XLNX_VERSAL_NR_IRQS 192
#define XLNX_VERSAL_NR_CANFD 2
#define XLNX_VERSAL_CANFD_REF_CLK (24 * 1000 * 1000)
struct Versal {
/*< private >*/
@ -73,6 +76,8 @@ struct Versal {
CadenceGEMState gem[XLNX_VERSAL_NR_GEMS];
XlnxZDMA adma[XLNX_VERSAL_NR_ADMAS];
VersalUsb2 usb;
CanBusState *canbus[XLNX_VERSAL_NR_CANFD];
XlnxVersalCANFDState canfd[XLNX_VERSAL_NR_CANFD];
} iou;
/* Real-time Processing Unit. */
@ -133,6 +138,8 @@ struct Versal {
#define VERSAL_CRL_IRQ 10
#define VERSAL_UART0_IRQ_0 18
#define VERSAL_UART1_IRQ_0 19
#define VERSAL_CANFD0_IRQ_0 20
#define VERSAL_CANFD1_IRQ_0 21
#define VERSAL_USB0_IRQ_0 22
#define VERSAL_GEM0_IRQ_0 56
#define VERSAL_GEM0_WAKE_IRQ_0 57
@ -163,6 +170,11 @@ struct Versal {
#define MM_UART1 0xff010000U
#define MM_UART1_SIZE 0x10000
#define MM_CANFD0 0xff060000U
#define MM_CANFD0_SIZE 0x10000
#define MM_CANFD1 0xff070000U
#define MM_CANFD1_SIZE 0x10000
#define MM_GEM0 0xff0c0000U
#define MM_GEM0_SIZE 0x10000
#define MM_GEM1 0xff0d0000U