From nobody Sat Nov 15 19:03:56 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1748433483; cv=none; d=zohomail.com; s=zohoarc; b=NgJvElvzXw3HYESzsN1UmrqFkle1JSHqPk89Nz5Fn6hZYAr3+866ymYLX6Ans19uIlPxjiEXwe14Bc0H8l9PGUOovZOvHuqMbl1Vdc0JKS6taUZZA0BHtWNsaspR3YP54GhRtJglvDdBVC7S6D3Y3SwPbUH3sdfWunjN50075KM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1748433483; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=fisQ+8QCdS9nxNFzHyafkXNtwsla/8bZWJ+Rll2Vklk=; b=SZU3ab89o/ykrX4ZiCvALMPAd1ZJ1gHjx5WLf53b1xAU385fJDOk7Bwg4GfA7tOLpd3evXYkA7xMhqRVcIvSSUhCffMkC8Oa4bjrIMva4JGBJHQJg8n6yIgIaOU410mQgrS+qhYtEa3BpC32kGjJbk6gCygc6BxBvB8w2Zdf68k= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1748433483269151.25317291503973; Wed, 28 May 2025 04:58:03 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uKFOg-0001KT-PC; Wed, 28 May 2025 07:56:38 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uKFOe-0001Jq-Dr for qemu-devel@nongnu.org; Wed, 28 May 2025 07:56:36 -0400 Received: from smtpx1.feld.cvut.cz ([147.32.210.191]) by eggs.gnu.org with esmtps (TLS1.2:DHE_RSA_CHACHA20_POLY1305:256) (Exim 4.90_1) (envelope-from ) id 1uKFOX-0000ZM-Aq for qemu-devel@nongnu.org; Wed, 28 May 2025 07:56:35 -0400 Received: from smtpx.fel.cvut.cz (smtpx.feld.cvut.cz [147.32.210.153]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtpx1.feld.cvut.cz (Postfix) with ESMTPS id 50D64266DA; Wed, 28 May 2025 13:50:50 +0200 (CEST) Received: from localhost (unknown [192.168.200.27]) by smtpx.fel.cvut.cz (Postfix) with ESMTP id 4DE572D4B9; Wed, 28 May 2025 13:50:50 +0200 (CEST) Received: from smtpx.fel.cvut.cz ([192.168.200.2]) by localhost (cerokez-250.feld.cvut.cz [192.168.200.27]) (amavis, port 10060) with ESMTP id 04sGjujQWYYI; Wed, 28 May 2025 13:50:48 +0200 (CEST) Received: from fel.cvut.cz (unknown [147.32.86.213]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pisa) by smtpx.fel.cvut.cz (Postfix) with ESMTPSA id 1A9DE2D388; Wed, 28 May 2025 13:39:05 +0200 (CEST) X-Virus-Scanned: IMAP STYX AMAVIS To: qemu-devel@nongnu.org, Peter Maydell , Gustavo Romero Cc: Paolo Bonzini , Oliver Hartkopp , Ondrej Ille , Jiri Novak , Pavel Pisa Subject: [PATCH v1 1/3] hw/net/can: CTU CAN FD IP core mapping to the platform bus Date: Wed, 28 May 2025 13:39:28 +0200 Message-Id: X-Mailer: git-send-email 2.39.5 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=147.32.210.191; envelope-from=SRS0=7BZW=YM=cmp.felk.cvut.cz=pisa@fel.cvut.cz; helo=smtpx1.feld.cvut.cz X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Pavel Pisa From: Pavel Pisa via Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1748433485959116600 Content-Type: text/plain; charset="utf-8" The system/platform bus mapping alternative to PCI/PCIe mapping. In this case, the platform bus is used to match FPGA design for Xilinx Zynq MZ_APO education kit with four CTU CAN FD cores on branch mz_apo-2x-xcan-4x-ctu of repo https://gitlab.fel.cvut.cz/canbus/zynq/zynq-can-sja1000-top The system is started by command qemu-system-arm -m 1G -M xilinx-zynq-a9 \ -kernel kernel-zynq \ -dtb zynq-microzed-uart1-2x-xcan-4x-ctu-axi.dtb \ -initrd ramdisk.cpio \ -serial null -serial mon:stdio \ -nographic \ -object can-bus,id=3Dcanbus0-bus \ -object can-host-socketcan,if=3Dcan0,canbus=3Dcanbus0-bus,id=3Dcanbus= 0-socketcan \ -device ctucan_mm,iobase=3D0x43c30000,irqnum=3D29,irqctrl=3D/machine/= unattached/device[3],canbus=3Dcanbus0-bus \ -device ctucan_mm,iobase=3D0x43c70000,irqnum=3D30,irqctrl=3D/machine/= unattached/device[3],canbus=3Dcanbus0-bus \ -device ctucan_mm,iobase=3D0x43bf0000,irqnum=3D31,irqctrl=3D/machine/= unattached/device[3],canbus=3Dcanbus0-bus \ -device ctucan_mm,iobase=3D0x43bb0000,irqnum=3D32,irqctrl=3D/machine/= unattached/device[3],canbus=3Dcanbus0-bus Signed-off-by: Pavel Pisa --- hw/net/can/ctucan_mm.c | 258 +++++++++++++++++++++++++++++++++++++++++ hw/net/can/meson.build | 1 + 2 files changed, 259 insertions(+) create mode 100644 hw/net/can/ctucan_mm.c diff --git a/hw/net/can/ctucan_mm.c b/hw/net/can/ctucan_mm.c new file mode 100644 index 0000000000..b5686882c1 --- /dev/null +++ b/hw/net/can/ctucan_mm.c @@ -0,0 +1,258 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * CTU CAN FD memory mapped device emulation + * http://canbus.pages.fel.cvut.cz/ + * + * Copyright (c) 2024 Pavel Pisa (pisa@cmp.felk.cvut.cz) + * + * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by + * Jin Yang and Pavel Pisa + */ + +#include "qemu/osdep.h" +#include "qemu/event_notifier.h" +#include "qemu/module.h" +#include "qemu/thread.h" +#include "qemu/sockets.h" +#include "qapi/error.h" +#include "chardev/char.h" +#include "hw/irq.h" +#include "hw/sysbus.h" +#include "hw/qdev-properties.h" +#include "migration/vmstate.h" +#include "net/can_emu.h" + +#include "ctucan_core.h" + +#define TYPE_CTUCAN_MM_DEV "ctucan_mm" + +typedef struct CtuCanMmState CtuCanMmState; +DECLARE_INSTANCE_CHECKER(CtuCanMmState, CTUCAN_MM_DEV, + TYPE_CTUCAN_MM_DEV) + +#define CTUCAN_MM_CORE_COUNT 1 +#define CTUCAN_MM_CORE_RANGE 0x1000 + +#define CTUCAN_MM_BYTES_PER_CORE 0x1000 + +struct CtuCanMmState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + struct { + uint64_t iobase; + uint32_t irqnum; + char *irqctrl; + } cfg; + + MemoryRegion ctucan_io_region; + + CtuCanCoreState ctucan_state[CTUCAN_MM_CORE_COUNT]; + qemu_irq irq; + + char *model; + CanBusState *canbus[CTUCAN_MM_CORE_COUNT]; +}; + +static void ctucan_mm_reset(DeviceState *dev) +{ + CtuCanMmState *d =3D CTUCAN_MM_DEV(dev); + int i; + + for (i =3D 0 ; i < CTUCAN_MM_CORE_COUNT; i++) { + ctucan_hardware_reset(&d->ctucan_state[i]); + } +} + +static uint64_t ctucan_mm_cores_io_read(void *opaque, hwaddr addr, + unsigned size) +{ + CtuCanMmState *d =3D opaque; + CtuCanCoreState *s; + hwaddr core_num =3D addr / CTUCAN_MM_BYTES_PER_CORE; + + if (core_num >=3D CTUCAN_MM_CORE_COUNT) { + return 0; + } + + s =3D &d->ctucan_state[core_num]; + + return ctucan_mem_read(s, addr % CTUCAN_MM_BYTES_PER_CORE, size); +} + +static void ctucan_mm_cores_io_write(void *opaque, hwaddr addr, uint64_t d= ata, + unsigned size) +{ + CtuCanMmState *d =3D opaque; + CtuCanCoreState *s; + hwaddr core_num =3D addr / CTUCAN_MM_BYTES_PER_CORE; + + if (core_num >=3D CTUCAN_MM_CORE_COUNT) { + return; + } + + s =3D &d->ctucan_state[core_num]; + + return ctucan_mem_write(s, addr % CTUCAN_MM_BYTES_PER_CORE, data, size= ); +} + +static const MemoryRegionOps ctucan_mm_cores_io_ops =3D { + .read =3D ctucan_mm_cores_io_read, + .write =3D ctucan_mm_cores_io_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .impl.min_access_size =3D 1, + .impl.max_access_size =3D 4, + .valid.min_access_size =3D 1, + .valid.max_access_size =3D 4, +}; + +static void ctucan_mm_realize(DeviceState *dev, Error **errp) +{ + CtuCanMmState *d =3D CTUCAN_MM_DEV(dev); + SysBusDevice *sbd =3D SYS_BUS_DEVICE(dev); + int i; + + for (i =3D 0 ; i < CTUCAN_MM_CORE_COUNT; i++) { + ctucan_init(&d->ctucan_state[i], d->irq); + } + + for (i =3D 0 ; i < CTUCAN_MM_CORE_COUNT; i++) { + if (ctucan_connect_to_bus(&d->ctucan_state[i], d->canbus[i]) < 0) { + error_setg(errp, "ctucan_connect_to_bus failed"); + return; + } + } + + if (d->cfg.iobase !=3D 0) { + sysbus_mmio_map(sbd, 0, d->cfg.iobase); + } + if (d->cfg.irqnum !=3D 0) { + char *id =3D d->cfg.irqctrl; + Object *obj; + DeviceState *gicdev; + + if (!id) { + error_setg(errp, "irqctrl object path is mandatory when" + "irqnum is specified"); + return; + } + + obj =3D object_resolve_path_at(object_resolve_path_at(qdev_get_mac= hine(), + "peripheral"), id); + if (!obj) { + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", id); + return; + } + gicdev =3D (DeviceState *)object_dynamic_cast(obj, TYPE_DEVICE); + if (!gicdev) { + error_setg(errp, "%s is not a hotpluggable device", id); + return; + } + sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(gicdev, d->cfg.irqnum)= ); + } + for (i =3D 0 ; i < CTUCAN_MM_CORE_COUNT; i++) { + ctucan_init(&d->ctucan_state[i], d->irq); + } +} + +static void ctucan_mm_reset_init(Object *obj, ResetType type) +{ + CtuCanMmState *d =3D CTUCAN_MM_DEV(obj); + unsigned int i; + + for (i =3D 0 ; i < CTUCAN_MM_CORE_COUNT; i++) { + ctucan_init(&d->ctucan_state[i], d->irq); + } +} + +static void ctucan_mm_reset_hold(Object *obj, ResetType type) +{ + CtuCanMmState *d =3D CTUCAN_MM_DEV(obj); + unsigned int i; + + for (i =3D 0 ; i < CTUCAN_MM_CORE_COUNT; i++) { + ctucan_init(&d->ctucan_state[i], d->irq); + } +} + +static const VMStateDescription vmstate_ctucan_mm =3D { + .name =3D "ctucan_mm", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (const VMStateField[]) { + VMSTATE_STRUCT(ctucan_state[0], CtuCanMmState, 0, vmstate_ctucan, + CtuCanCoreState), +#if CTUCAN_MM_CORE_COUNT >=3D 2 + VMSTATE_STRUCT(ctucan_state[1], CtuCanMmState, 0, vmstate_ctucan, + CtuCanCoreState), +#endif + VMSTATE_END_OF_LIST() + } +}; + +static void ctucan_mm_instance_init(Object *obj) +{ + CtuCanMmState *d =3D CTUCAN_MM_DEV(obj); + SysBusDevice *sbd =3D SYS_BUS_DEVICE(obj); + +#if CTUCAN_MM_CORE_COUNT <=3D 1 + object_property_add_link(obj, "canbus", TYPE_CAN_BUS, + (Object **)&d->canbus[0], + qdev_prop_allow_set_link_before_realize, 0); +#else /* CTUCAN_MM_CORE_COUNT >=3D 2 */ + object_property_add_link(obj, "canbus0", TYPE_CAN_BUS, + (Object **)&d->canbus[0], + qdev_prop_allow_set_link_before_realize, 0); + object_property_add_link(obj, "canbus1", TYPE_CAN_BUS, + (Object **)&d->canbus[1], + qdev_prop_allow_set_link_before_realize, 0); +#endif + memory_region_init_io(&d->ctucan_io_region, OBJECT(d), + &ctucan_mm_cores_io_ops, d, + "ctucan_mm", CTUCAN_MM_CORE_RANGE); + + sysbus_init_mmio(sbd, &d->ctucan_io_region); + sysbus_init_irq(sbd, &d->irq); +} + +static const Property ctucan_mm_properties[] =3D { + DEFINE_PROP_UINT64("iobase", CtuCanMmState, cfg.iobase, 0), + DEFINE_PROP_UINT32("irqnum", CtuCanMmState, cfg.irqnum, 0), + DEFINE_PROP_STRING("irqctrl", CtuCanMmState, cfg.irqctrl), +}; + +static void ctucan_mm_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + rc->phases.enter =3D ctucan_mm_reset_init; + rc->phases.hold =3D ctucan_mm_reset_hold; + dc->realize =3D ctucan_mm_realize; + /* ->exit =3D ctucan_mm_exit; */ + dc->desc =3D "CTU CAN MM"; + dc->vmsd =3D &vmstate_ctucan_mm; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->user_creatable =3D true; + /* dc->reset =3D ctucan_mm_reset; */ + device_class_set_legacy_reset(dc, ctucan_mm_reset); + + device_class_set_props(dc, ctucan_mm_properties); +} + +static const TypeInfo ctucan_mm_info =3D { + .name =3D TYPE_CTUCAN_MM_DEV, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(CtuCanMmState), + .class_init =3D ctucan_mm_class_init, + .instance_init =3D ctucan_mm_instance_init, +}; + +static void ctucan_mm_register_types(void) +{ + type_register_static(&ctucan_mm_info); +} + +type_init(ctucan_mm_register_types) diff --git a/hw/net/can/meson.build b/hw/net/can/meson.build index 7382344628..de25fdbd1c 100644 --- a/hw/net/can/meson.build +++ b/hw/net/can/meson.build @@ -3,6 +3,7 @@ system_ss.add(when: 'CONFIG_CAN_PCI', if_true: files('can_k= vaser_pci.c')) system_ss.add(when: 'CONFIG_CAN_PCI', if_true: files('can_pcm3680_pci.c')) system_ss.add(when: 'CONFIG_CAN_PCI', if_true: files('can_mioe3680_pci.c')) system_ss.add(when: 'CONFIG_CAN_CTUCANFD', if_true: files('ctucan_core.c')) +system_ss.add(when: 'CONFIG_CAN_CTUCANFD', if_true: files('ctucan_mm.c')) system_ss.add(when: 'CONFIG_CAN_CTUCANFD_PCI', if_true: files('ctucan_pci.= c')) system_ss.add(when: 'CONFIG_XLNX_ZYNQMP', if_true: files('xlnx-zynqmp-can.= c')) system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-canf= d.c')) --=20 2.39.5