From nobody Sat May 30 17:31:18 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; 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=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1779988685; cv=none; d=zohomail.com; s=zohoarc; b=aVZWy/Jr//PdbGLVKm2qDSU+0zFfQGgNH5mkIQn4Z+WRyBXNrTHWYXJPtesO0d4KHjJVGuBTYsfySqZMMnXGlgQ6jZ1PEaIdYqIvxOLlQ70brN9pmKE1nz+nzeXNxholh0vziYq3HTznvyr4+h8r8/sk7YxSyv4p0TuGCJ5THF8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779988685; h=Content-Type: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:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=HArTwgODQoYaXXWISLaGAP/t/ZOAHV1MrGfG2day6lw=; b=je5UKqWxp9+tiymKgf7xzYxHmfWOCVmhcD1hMORXCxw/Xhc+BQPLSdStlzuriSD8E5MaFubQspjF/cT8Uctr4fyv7vYi9nYfWNFPy/ZGu0uOBVJcH24HnqL9l19B4VOtcOSnVvvNOSNLpHpfRw5TlJG16jbyv+dvYG6hKzdUCFg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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 lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779988685687604.0855209177274; Thu, 28 May 2026 10:18:05 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wSeMl-0006cS-Db; Thu, 28 May 2026 13:17:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wSeMM-0006TR-PR for qemu-devel@nongnu.org; Thu, 28 May 2026 13:17:33 -0400 Received: from mail-wm1-x32c.google.com ([2a00:1450:4864:20::32c]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wSeMJ-00046Z-Pz for qemu-devel@nongnu.org; Thu, 28 May 2026 13:17:30 -0400 Received: by mail-wm1-x32c.google.com with SMTP id 5b1f17b1804b1-4891c0620bcso84192165e9.1 for ; Thu, 28 May 2026 10:17:27 -0700 (PDT) Received: from acidburn.pod.cvut.cz (acidburn.pod.cvut.cz. [147.32.90.2]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49092968066sm53774085e9.15.2026.05.28.10.17.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2026 10:17:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779988646; x=1780593446; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=HArTwgODQoYaXXWISLaGAP/t/ZOAHV1MrGfG2day6lw=; b=Afp90UcRSByqxn8a3+HUxQt6poAfoY4iV3X4S4Jsia/AjU/yMZVeFEJV8dNarNpf8+ tuN2hXtbVgyzs8Pw4sJWAMXb55HMTZfYba47UZCqnxz+Od2e2YcaM5fINwkOVTUYGYV5 I1ZDvBHCrjbzz7XkbX5ZqXUDhMwCe16fMoBAisAAwEhxTMRFOuV3PxEdWeyhJo+O32PQ 9arXEEKbZ7BGxG5LnerYjUHHhCRBn8bg/k4NLcM0xOH7rJYbkz4Cwm8FxAZMgoNJGu1V N2ojKSTfkTw1u7pXMSgSLT9wb88UK5JQmQRgugCPT1/IaOCjeN1YczZheQmpKWAwoBIq k3Qw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779988646; x=1780593446; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=HArTwgODQoYaXXWISLaGAP/t/ZOAHV1MrGfG2day6lw=; b=kf2mhX+1km7KuxwZP1HPiD6genpal5wwN5WRB4z1P/v7NpiDoZqsSmrud0Y6hDgCor RoT/zLYL/Z2abFUkvZNqHmwXOxO9wJqJ1BjhKWUKVGPlHoKwc2Njh6QryEhSU8+xQpIe 6MkftlRZaU6CUX3QjXTQej1ug8v6uqU84+KCXUFAgImspdeVLdPTpEUjhNjknIdU+xGz /2HNV6hr2+LFN3Ejgmk0khbQunQ89oP7P7zZDS6YlFNEbC487lj7Qw7hhcrV4G5zZlN/ xEFQEZEap7NFqOEcsWYctVBQPdNzU6y9ETN1Gc3Rjpbd8LEQw4Ofe7OZCi9DaAIyMfqw 0iNA== X-Gm-Message-State: AOJu0Yzcx7J1kqGOt5PnFMrYrNM3DYtUF+kcO4a7ua1nALf0zbtCMex3 r88DcpPqNrpndlKyPMjG3DCmFNVWuTf/YKDN6LH9jrNjNFX2aeT0FoC9qFfq68Ek X-Gm-Gg: Acq92OH+NltaXtDamzssI1IHzACGWUKDmDcFgxOxx+i5Ynry8R7mUQhXcm4UxzIv3tS Z1YdRCtM02n/a8jyJBqKJzF1Wa43q+4vBmtX4t3HO+O3aQkzJzPOe2PreqIfjPf/S66L/5G9591 4ls3L9lNWEz6WvJ3KPn7IFgjRQsXNN0BU2EbNgdoK2d/MO5F1ovi87S/2HsqP2ygZLb+NZvgfoz RxywgJt4e7Rwybp/2iHblF1UF2+HTcZgfLO75pHLCFH4EpHQGoNthZhk1wY+jevTrsmzXJ6/NGV 6KoX0scz2ZHthpUUFQx0hlxwxzT4UjL438ZutOWZThiGeMuX1ffAJgx603KdCuUoOKWhU3K1x5u LZCG/C51pW4Cyo8SprjsaSJ+EAT5ZjNhsurBGggaqsUcMB8woILipOQeQWJ2itgX2taJ3EvtTkt Jct4abtdTef0IQ/q/CoF6MUJZ9CIb1kkA1qpps2f3SZ1KhBg0JP70YE6TkyZN+hFpN X-Received: by 2002:a05:600c:c3cd:20b0:48a:58ae:993b with SMTP id 5b1f17b1804b1-490428c97a1mr328552935e9.16.1779988646074; Thu, 28 May 2026 10:17:26 -0700 (PDT) From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Bobek?= To: qemu-devel@nongnu.org, Matyas Bobek , Pavel Pisa , Bernhard Beschow Cc: qemu-arm@nongnu.org, Marc Kleine-Budde , Oliver Hartkopp , Nikita Ostrenkov , Peter Maydell , Andrey Volkov , =?UTF-8?q?Maty=C3=A1=C5=A1=20Bobek?= Subject: [PATCH v4 1/7] hw/arm/sabrelite: Open code DEFINE_MACHINE_ARM Date: Thu, 28 May 2026 19:17:11 +0200 Message-ID: <8c31da0ef6b6c49d9f43979040f0a723632c6c4e.1779986496.git.matyas.bobek@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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=lists1p.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::32c; envelope-from=matyas.bobek@gmail.com; helo=mail-wm1-x32c.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1779988687680158500 Open code the DEFINE_MACHINE_ARM macro in preparation of creating SabreliteMachineState class. Signed-off-by: Maty=C3=A1=C5=A1 Bobek Signed-off-by: Pavel Pisa Tested-by: Pavel Pisa Reviewed-by: Bernhard Beschow Reviewed-by: Pavel Pisa --- hw/arm/sabrelite.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c index db5669c5c2..04484aaa14 100644 --- a/hw/arm/sabrelite.c +++ b/hw/arm/sabrelite.c @@ -104,8 +104,10 @@ static void sabrelite_init(MachineState *machine) } } =20 -static void sabrelite_machine_init(MachineClass *mc) +static void sabrelite_machine_class_init(ObjectClass *oc, const void *data) { + MachineClass *mc =3D MACHINE_CLASS(oc); + mc->desc =3D "Freescale i.MX6 Quad SABRE Lite Board (Cortex-A9)"; mc->init =3D sabrelite_init; mc->max_cpus =3D FSL_IMX6_NUM_CPUS; @@ -114,4 +116,18 @@ static void sabrelite_machine_init(MachineClass *mc) mc->auto_create_sdcard =3D true; } =20 -DEFINE_MACHINE_ARM("sabrelite", sabrelite_machine_init) +static const TypeInfo sabrelite_machine_init_typeinfo =3D { + .name =3D MACHINE_TYPE_NAME("sabrelite"), + .parent =3D TYPE_MACHINE, + .class_init =3D sabrelite_machine_class_init, + .instance_size =3D sizeof(MachineState), + .abstract =3D false, + .interfaces =3D arm_machine_interfaces, +}; + +static void sabrelite_machine_init_register_types(void) +{ + type_register_static(&sabrelite_machine_init_typeinfo); +} + +type_init(sabrelite_machine_init_register_types) --=20 2.54.0 From nobody Sat May 30 17:31:18 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; 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=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1779988687; cv=none; d=zohomail.com; s=zohoarc; b=j27NdbtNoknUsDY3tRCVxl43W8aGeoCv936zgJn8hN7BXcHQN0nZen2kjaYKaQ/BFElR/PVr7WU30035lQTIgbkEtdhsTvPYUGJwDb2D4WlOLPawjAWA9EymUXjweVkwJBJYlIEMqKaoGSck/K9fAYyARyysQEBkUwiK2zk+FMQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779988687; h=Content-Type: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:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=naAjGDZPbJ67GvzkWP49qsFsJVwJRVlvC8LloXp3eNQ=; b=MZM7lfReGiLOUNR2gbGMP0WhZsO444UfPsdDofDwBRk7UEa2rhlBka1ov/n1AuL6ChM3C/1VQdpSHwZPk6mrUDE2KWf4tbgS4sEMx3DKlUGQQunZxpWgy+nl4ybuZcbI4rGBgJ3U/NW+evjBUPTJwxUNC87Vo84g4ND/pOklQGA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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 lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779988687133712.2875387156417; Thu, 28 May 2026 10:18:07 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wSeMe-0006Xj-1d; Thu, 28 May 2026 13:17:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wSeMM-0006TS-Rx for qemu-devel@nongnu.org; Thu, 28 May 2026 13:17:34 -0400 Received: from mail-wm1-x32a.google.com ([2a00:1450:4864:20::32a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wSeMK-00046q-EW for qemu-devel@nongnu.org; Thu, 28 May 2026 13:17:30 -0400 Received: by mail-wm1-x32a.google.com with SMTP id 5b1f17b1804b1-4891b0786beso87121225e9.1 for ; Thu, 28 May 2026 10:17:28 -0700 (PDT) Received: from acidburn.pod.cvut.cz (acidburn.pod.cvut.cz. [147.32.90.2]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49092968066sm53774085e9.15.2026.05.28.10.17.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2026 10:17:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779988647; x=1780593447; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=naAjGDZPbJ67GvzkWP49qsFsJVwJRVlvC8LloXp3eNQ=; b=XM+NVbO0YEw3uuFDOEmQBzZaS67KdEl05/0oRqkz3m+Qyg12YZP3O2mSzV8sDCwXhV dnCEU8lrQUnxM6L5YVClLlp18pN8LpSvCK6BIFQc17hPGN1kZvvx9qms7H8xgx7L1RAq 0HXk3hPM5wErxPONiDokucCE0gwXqWs8yA0Kp0P8VEI/iZ21AuM+JQxae6OMiaeqTEcZ D9v6B5BgsGe9xqhXiIqLgH4ugBWNg1F3zfOCxUFzPhcginGo1ERNhHulyqJ6sBkRdzY7 GSkGq1XWFCvKFhoBxdVTj43QiBuMRwx4E1uF1/4gs6eUGCloVj6lqB86GVaHuysTmjvy o6Ww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779988647; x=1780593447; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=naAjGDZPbJ67GvzkWP49qsFsJVwJRVlvC8LloXp3eNQ=; b=o41vumfeVO8PDeIOqFgARu6VvdRyjf0DoTjdo9K0jKSt7KbhfJg2ykYsXx7L3TIKpc 9sDQksx2z2VU/w7Tp/+rhxQcVbrMlis1d88qhWr82viXaef80LruXtFIBgadsU3+2JB+ 43v29K17cV6Mf2ASKN6+igqbSL/23VKTsjgUpRV3AqrWmsXgfk0dXfz348wwSsI/wx8x sfl38dO24svgdeA02P4r8rB03rqMfkp6fLMgS9UtHcDU4gNNsR5HWSd4HZvbgSzFI82u PSFtxjdu2hYTXtfzve6Vh6tKEKv2URWURazWkvoIQCcvu3l4/njqUM9w2/rkO5WhpkED tf7w== X-Gm-Message-State: AOJu0YwarwoPk/FaSMBZusRHuxyNfHV8u1y56xMb3Q/IHVFIlZEqp6z1 WGiWPb57zSMef79EH/RNH5C4Z4kxJgp3uU8nRkXtFz6UoNPCPaLZEY3OKy2s0F2D X-Gm-Gg: Acq92OGAACsPZHiHP/3sN9GYlxgHz2fZK/o6QMCjvDIE+fFwKsAVkITanxPT4ldiobS z6GSKqXMI3/16NvlONfHH5ZeI2ngr92PcFIafG0hlnhIERHaQVSmDmQnY7o1qmTYy1RLa0I1NlU 5g9ssVVGvQY3u5c14w4+diV9jPEAO+Zu/7DbeyBNdmEiETKv9tIbXMF9xE8RZWhU9ZfBdgX1t/s HpNuYLhtoQ/7Y3/Ggq8kN2ZuORr2xZ/brpcrjDRDgvjLY0DAv0y+xBg7IVL/V7acIX506ypPM9e iadFMHDvFbTP5J5Zj833vUmEHMBu0OMXS7rovIvUZ+DNKXGoglbTqzZb+vIK2901Es5k3FDORZu /kpcgXfPUHPgCrIqz4ICzulTIrrkGtcWtMY0Wo+LDOJq+UJ74HPNkq694KTcgy53EpYWW53TBnX 50Wm0GTt8871X+rOUUhfULShD9/bcZ35dBPV+jpQMv7h0gPrb+ByXFBeKIqAiCNa8eqXU4Qf09I Lw= X-Received: by 2002:a05:600c:1c0b:b0:488:b187:3c with SMTP id 5b1f17b1804b1-490426aa7acmr513786875e9.14.1779988647059; Thu, 28 May 2026 10:17:27 -0700 (PDT) From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Bobek?= To: qemu-devel@nongnu.org, Matyas Bobek , Pavel Pisa , Bernhard Beschow Cc: qemu-arm@nongnu.org, Marc Kleine-Budde , Oliver Hartkopp , Nikita Ostrenkov , Peter Maydell , Andrey Volkov , =?UTF-8?q?Maty=C3=A1=C5=A1=20Bobek?= Subject: [PATCH v4 2/7] hw/arm/sabrelite: Introduce class SabreliteMachineState Date: Thu, 28 May 2026 19:17:12 +0200 Message-ID: <838e241ffe451b508403a716ff200cb7ae3af564.1779986496.git.matyas.bobek@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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=lists1p.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::32a; envelope-from=matyas.bobek@gmail.com; helo=mail-wm1-x32a.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, 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: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1779988688307158500 Create full class SabreliteMachineState extending MachineState. Previously, Sabrelite board MachineState was declared indirectly by the DEFINE_MACHINE_ARM macro. FslIMX6State was only instantiated in the sabrelite_init function. For FlexCAN device, machine properties will be used to select QEMU CAN buses. A custom class is therefore required, so the CanBusState "connections" can then be added as fields. Signed-off-by: Maty=C3=A1=C5=A1 Bobek Signed-off-by: Pavel Pisa Tested-by: Pavel Pisa Reviewed-by: Bernhard Beschow Reviewed-by: Pavel Pisa --- hw/arm/sabrelite.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c index 04484aaa14..7e036e6388 100644 --- a/hw/arm/sabrelite.c +++ b/hw/arm/sabrelite.c @@ -20,6 +20,15 @@ #include "qemu/error-report.h" #include "system/qtest.h" =20 +struct SabreliteMachineState { + MachineState parent_obj; + + FslIMX6State soc; +}; + +#define TYPE_SABRELITE_MACHINE MACHINE_TYPE_NAME("sabrelite") +OBJECT_DECLARE_SIMPLE_TYPE(SabreliteMachineState, SABRELITE_MACHINE) + static struct arm_boot_info sabrelite_binfo =3D { /* DDR memory start */ .loader_start =3D FSL_IMX6_MMDC_ADDR, @@ -41,7 +50,7 @@ static void sabrelite_reset_secondary(ARMCPU *cpu, =20 static void sabrelite_init(MachineState *machine) { - FslIMX6State *s; + SabreliteMachineState *s =3D SABRELITE_MACHINE(machine); =20 /* Check the amount of memory is compatible with the SOC */ if (machine->ram_size > FSL_IMX6_MMDC_SIZE) { @@ -50,13 +59,12 @@ static void sabrelite_init(MachineState *machine) exit(1); } =20 - s =3D FSL_IMX6(object_new(TYPE_FSL_IMX6)); - object_property_add_child(OBJECT(machine), "soc", OBJECT(s)); + object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_FSL_IMX6= ); =20 /* Ethernet PHY address is 6 */ - object_property_set_int(OBJECT(s), "fec-phy-num", 6, &error_fatal); + object_property_set_int(OBJECT(&s->soc), "fec-phy-num", 6, &error_fata= l); =20 - qdev_realize(DEVICE(s), NULL, &error_fatal); + qdev_realize(DEVICE(&s->soc), NULL, &error_fatal); =20 memory_region_add_subregion(get_system_memory(), FSL_IMX6_MMDC_ADDR, machine->ram); @@ -70,7 +78,7 @@ static void sabrelite_init(MachineState *machine) /* Add the sst25vf016b NOR FLASH memory to first SPI */ Object *spi_dev; =20 - spi_dev =3D object_resolve_path_component(OBJECT(s), "spi1"); + spi_dev =3D object_resolve_path_component(OBJECT(&s->soc), "spi1"); if (spi_dev) { SSIBus *spi_bus; =20 @@ -89,7 +97,7 @@ static void sabrelite_init(MachineState *machine) qdev_realize_and_unref(flash_dev, BUS(spi_bus), &error_fat= al); =20 cs_line =3D qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS,= 0); - qdev_connect_gpio_out(DEVICE(&s->gpio[2]), 19, cs_line); + qdev_connect_gpio_out(DEVICE(&s->soc.gpio[2]), 19, cs_line= ); } } } @@ -100,7 +108,7 @@ static void sabrelite_init(MachineState *machine) sabrelite_binfo.secondary_cpu_reset_hook =3D sabrelite_reset_secondary; =20 if (!qtest_enabled()) { - arm_load_kernel(&s->cpu[0], machine, &sabrelite_binfo); + arm_load_kernel(&s->soc.cpu[0], machine, &sabrelite_binfo); } } =20 @@ -117,10 +125,10 @@ static void sabrelite_machine_class_init(ObjectClass = *oc, const void *data) } =20 static const TypeInfo sabrelite_machine_init_typeinfo =3D { - .name =3D MACHINE_TYPE_NAME("sabrelite"), + .name =3D TYPE_SABRELITE_MACHINE, .parent =3D TYPE_MACHINE, .class_init =3D sabrelite_machine_class_init, - .instance_size =3D sizeof(MachineState), + .instance_size =3D sizeof(SabreliteMachineState), .abstract =3D false, .interfaces =3D arm_machine_interfaces, }; --=20 2.54.0 From nobody Sat May 30 17:31:18 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; 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=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1779988806; cv=none; d=zohomail.com; s=zohoarc; b=EbtavUTi4dh/lVa9MN1Z1pw+JscIUdRhQXhGJZD6QAsVhqeMUKh3j0mSIfkWWqJluvr1dyD3PRs2CuOangYKDFnjRWFlFVWqS4lIt2pIj0UQz1ee4snfPGHVcdKUKmVeRe7DvtSRJx4wKtd9C/DcjbQ04orR+UEMS3FbU+Wd+z8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779988806; h=Content-Type: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:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=v7B7MPlm8lxhhWU0KcQHkTsOfZGkRsES1ICXN/vP+BI=; b=ahR8P5a0IJSEWka/9QaDYxaaV+AYPmkCvrLZ8fbCVfx6gMdpp8Z/7YJla5yRQADkjXPyDAKt5YVep3phRjTzCSQeonQB3ZeTHq4co52e2eb8d8g0Euzbs10Qn7DsX+LqIb2v9RtBXyzMzr2he0lMVbQoDeeoUbGhnR/D01XfmZU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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 lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779988806644786.0637807118054; Thu, 28 May 2026 10:20:06 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wSeMg-0006ZY-3w; Thu, 28 May 2026 13:17:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wSeMO-0006TV-80 for qemu-devel@nongnu.org; Thu, 28 May 2026 13:17:34 -0400 Received: from mail-wm1-x331.google.com ([2a00:1450:4864:20::331]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wSeML-000476-Sk for qemu-devel@nongnu.org; Thu, 28 May 2026 13:17:31 -0400 Received: by mail-wm1-x331.google.com with SMTP id 5b1f17b1804b1-490388fd0dbso74102125e9.0 for ; Thu, 28 May 2026 10:17:29 -0700 (PDT) Received: from acidburn.pod.cvut.cz (acidburn.pod.cvut.cz. [147.32.90.2]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49092968066sm53774085e9.15.2026.05.28.10.17.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2026 10:17:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779988648; x=1780593448; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=v7B7MPlm8lxhhWU0KcQHkTsOfZGkRsES1ICXN/vP+BI=; b=k5lfQDh68Eff5vNYgHTR+A6PGqRma7oohYu5/UDzENReMNn3TEBqWx2dMteZHpLxIN wo9VIl/G8QDLZLt/J+9oJI3yRhwFyqUS9l+VlBuzHQCIYIgrteBcTPi/5hQ63f7jPr3/ TvTHP/5DjnUZl8ASAR8YrDYNf91lBuEF5l4S8zjL7dp4c1LgQ75jK73Yz9wrdekGjl4J O9GXtD7d83dB38+nVN4t4sjO+Hw72qH+xqOK8VFGH9VdIOKMMbcuJeFeUUKFs2vN2Wn5 FP0I3hYxE4iLs4tTF7u/lDoPLiCsUoRpNXot9onHLtCPGUzegmuWE+vlbQv0MmI4jWaN kE+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779988648; x=1780593448; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=v7B7MPlm8lxhhWU0KcQHkTsOfZGkRsES1ICXN/vP+BI=; b=LN3wXNT6Rx0hSg7af5geFuQ3+x5HzV32JBQmVHgQUfFAMa90qFPGdwKh1N94YEWmNw NUTQtFUhk2Z4rJdnuIuXyYt93aM1N0+XKubUnYLMRXJPdwE6yawTxycjrvmcTTe6R6RG v+Om29HmxSnAJ4XHdedxABxqNghnMenCqxshsnHF9qCshFfp90LBVUl8bQfgVult4ajz 0WmvFgYvO2kWc957ABTVSAJnc1WkCD2FXpJ2JAbMGJ3Y1T0a5DTh1lCx9m3jUmhLaa1h ZL4iu2Bh1FVShwjqEjzgbczAhwH6nm9L5LF9sbpWXqbnR7E4XRw6j/QuEGD1aWFlgZok xpSg== X-Gm-Message-State: AOJu0YyE8lgzr+7HEOLlibrQwj+phWASNY6yPTI7Oy9XWsb8Y7QSX3bK LZoDZAMuEMxyN7Gat1b0h+emOJtu5P25vmjzVmSim6fgixfuLVB6I0F73ciCMBAk X-Gm-Gg: Acq92OHTWMXLp2bHwWXc3xQkYBxUze1rQn7iDJsTPEOAUZNw+xNk21FqOn3P8z6nPwF BDn7M0qwg4eioKR0k8BZ8o9STzuxTPgywc6mFGC6CKOks4xsXnrWGCXzp4jgjsfh5JbAV4o4inX eQo7KUz3nJBitO1kxONYIaKGRnrq17XwgYP1wPT2M/ZN6AaCqyxdm6Ehy+GSnYt3wV2OQhtTe8r BxqyHoXJ6nzTk8YcT1GQIdlPDbDYDeqpezPzXhAXMJsagWX/uLcFtNg7r6/Oc5UMXG9BkaBPeaa wf5SWG1VJGdgCoOyDOZrPj+1ZX88jNiJS3bOo+bo1dENwi5FWPN0ta9xSjiFPeKl3DT4GCfdhsV +k3bDEHo7uCyhbFaugouWU8RmoZvNNP0rzUyyn5ajzGdOqr/A9DOtmJZZRumjsm8W4jRz4NzUJz 4NgvvcJuv7z3TO6+gm1PaCXzcap1QDWrFZODaPWbRHbOFirCiB9H1YKul0J4LNDAQq X-Received: by 2002:a05:600c:3e0c:b0:488:ac01:72de with SMTP id 5b1f17b1804b1-49042489c30mr534509905e9.5.1779988648089; Thu, 28 May 2026 10:17:28 -0700 (PDT) From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Bobek?= To: qemu-devel@nongnu.org, Matyas Bobek , Pavel Pisa , Bernhard Beschow Cc: qemu-arm@nongnu.org, Marc Kleine-Budde , Oliver Hartkopp , Nikita Ostrenkov , Peter Maydell , Andrey Volkov , =?UTF-8?q?Maty=C3=A1=C5=A1=20Bobek?= Subject: [PATCH v4 3/7] hw/misc/imx6_ccm: Add PLL3 and CAN clock Date: Thu, 28 May 2026 19:17:13 +0200 Message-ID: <2b93d12e6c19930cbfbabd2a257925fcaa9149aa.1779986496.git.matyas.bobek@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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=lists1p.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::331; envelope-from=matyas.bobek@gmail.com; helo=mail-wm1-x331.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1779988808723154100 Add fixed frequency (480 MHz) PLL3, of which the FlexCAN clock is derived, and compute FlexCAN frequency based on the divider configuration (CCM_CSCMR2). The clock frequency will be used for computing timestamps in FlexCAN emulator. Signed-off-by: Maty=C3=A1=C5=A1 Bobek Signed-off-by: Pavel Pisa Tested-by: Pavel Pisa Reviewed-by: Bernhard Beschow Reviewed-by: Pavel Pisa --- hw/misc/imx6_ccm.c | 24 ++++++++++++++++++++++++ hw/misc/trace-events | 2 ++ include/hw/misc/imx6_ccm.h | 4 ++++ include/hw/misc/imx_ccm.h | 1 + 4 files changed, 31 insertions(+) diff --git a/hw/misc/imx6_ccm.c b/hw/misc/imx6_ccm.c index a10b67d396..45fdd0d5a8 100644 --- a/hw/misc/imx6_ccm.c +++ b/hw/misc/imx6_ccm.c @@ -257,6 +257,15 @@ static uint64_t imx6_analog_get_pll2_clk(IMX6CCMState = *dev) return freq; } =20 +static uint64_t imx6_analog_get_pll3_clk(IMX6CCMState *dev) +{ + uint64_t freq =3D 480000000; + + trace_imx6_analog_get_pll3_clk(freq); + + return freq; +} + static uint64_t imx6_analog_get_pll2_pfd0_clk(IMX6CCMState *dev) { uint64_t freq =3D 0; @@ -344,6 +353,18 @@ static uint64_t imx6_ccm_get_per_clk(IMX6CCMState *dev) return freq; } =20 +static uint64_t imx6_ccm_get_can_clk(IMX6CCMState *dev) +{ + uint64_t freq =3D 0; + + freq =3D imx6_analog_get_pll3_clk(dev) / 8; + freq /=3D (1 + EXTRACT(dev->ccm[CCM_CSCMR2], CAN_CLK_PODF)); + + trace_imx6_ccm_get_can_clk(freq); + + return freq; +} + static uint32_t imx6_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk cloc= k) { uint32_t freq =3D 0; @@ -358,6 +379,9 @@ static uint32_t imx6_ccm_get_clock_frequency(IMXCCMStat= e *dev, IMXClk clock) case CLK_IPG_HIGH: freq =3D imx6_ccm_get_per_clk(s); break; + case CLK_CAN: + freq =3D imx6_ccm_get_can_clk(s); + break; case CLK_32k: freq =3D CKIL_FREQ; break; diff --git a/hw/misc/trace-events b/hw/misc/trace-events index b88accc437..99910fc068 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -242,11 +242,13 @@ imx6_analog_get_periph_clk(uint32_t freq) "freq =3D %= u Hz" imx6_analog_get_pll2_clk(uint32_t freq) "freq =3D %u Hz" imx6_analog_get_pll2_pfd0_clk(uint32_t freq) "freq =3D %u Hz" imx6_analog_get_pll2_pfd2_clk(uint32_t freq) "freq =3D %u Hz" +imx6_analog_get_pll3_clk(uint32_t freq) "freq =3D %u Hz" imx6_analog_read(const char *reg, uint32_t value) "reg[%s] =3D> 0x%" PRIx32 imx6_analog_write(const char *reg, uint32_t value) "reg[%s] <=3D 0x%" PRIx= 32 imx6_ccm_get_ahb_clk(uint32_t freq) "freq =3D %u Hz" imx6_ccm_get_ipg_clk(uint32_t freq) "freq =3D %u Hz" imx6_ccm_get_per_clk(uint32_t freq) "freq =3D %u Hz" +imx6_ccm_get_can_clk(uint32_t freq) "freq =3D %u Hz" imx6_ccm_get_clock_frequency(unsigned clock, uint32_t freq) "(Clock =3D %d= ) =3D %u" imx6_ccm_read(const char *reg, uint32_t value) "reg[%s] =3D> 0x%" PRIx32 imx6_ccm_reset(void) "" diff --git a/include/hw/misc/imx6_ccm.h b/include/hw/misc/imx6_ccm.h index ccf46d7353..a54b940686 100644 --- a/include/hw/misc/imx6_ccm.h +++ b/include/hw/misc/imx6_ccm.h @@ -164,6 +164,10 @@ #define PERCLK_PODF_SHIFT (0) #define PERCLK_PODF_LENGTH (6) =20 +/* CCM_CSCMR2 */ +#define CAN_CLK_PODF_SHIFT (2) +#define CAN_CLK_PODF_LENGTH (6) + /* CCM_ANALOG_PFD_528 */ #define PFD0_FRAC_SHIFT (0) #define PFD0_FRAC_LENGTH (6) diff --git a/include/hw/misc/imx_ccm.h b/include/hw/misc/imx_ccm.h index c4212d04ea..6839716ea3 100644 --- a/include/hw/misc/imx_ccm.h +++ b/include/hw/misc/imx_ccm.h @@ -46,6 +46,7 @@ typedef enum { CLK_EXT, CLK_HIGH_DIV, CLK_HIGH, + CLK_CAN, } IMXClk; =20 struct IMXCCMClass { --=20 2.54.0 From nobody Sat May 30 17:31:18 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; 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=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1779988783; cv=none; d=zohomail.com; s=zohoarc; b=HdGPgUaN40Qdi0mblxaHhhi1gD6rtRwIkqTrbPuAMaeVV9Ef9LhGFieAAUkxUEx0nAMgmMRZvzepthwLHedRiZYRdIkK/6goiNWkWlIxx3AmP662MIGTDuLUge7yTNUC+af8lCheUim55LFoe+cqjZY3+1/ds+BETzwygEoe6Hc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779988783; h=Content-Type: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:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=dHjuwu7m0ZobnYT01ll75sxqoF3pTZJdT0OTzaL/UTY=; b=cfxeCXf6ISZXOWmdYaH3KMPbFPsbsGb5iuTfHk99zvbn8If3Zq0zz6KZKMS0kBKH8/D12ngp8j+10uQkqCwGEcHNsMPTQOpimVbfG1TygjOTOUVBK8W85zbU3UlAh3JSXe4wYkhXJsingehluLaQ+EeAwu75CpqzCn45NOYekro= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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 lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779988782886826.7291888104419; Thu, 28 May 2026 10:19:42 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wSeMp-0006hM-Fy; Thu, 28 May 2026 13:17:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wSeMT-0006VT-0N for qemu-devel@nongnu.org; Thu, 28 May 2026 13:17:38 -0400 Received: from mail-wm1-x32b.google.com ([2a00:1450:4864:20::32b]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wSeMN-000480-Er for qemu-devel@nongnu.org; Thu, 28 May 2026 13:17:36 -0400 Received: by mail-wm1-x32b.google.com with SMTP id 5b1f17b1804b1-4896c22fcbaso112179205e9.0 for ; Thu, 28 May 2026 10:17:31 -0700 (PDT) Received: from acidburn.pod.cvut.cz (acidburn.pod.cvut.cz. [147.32.90.2]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49092968066sm53774085e9.15.2026.05.28.10.17.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2026 10:17:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779988650; x=1780593450; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=dHjuwu7m0ZobnYT01ll75sxqoF3pTZJdT0OTzaL/UTY=; b=JJW/0EEKFVqv3PT7U4X3yWmxQDo9rp5sAX04v9+zaNRJusAmhOwoews7gwHMuWCzOf Pe0ukqIy6SWNQgNnjYXL+5p1FBpsPDh6OTF4lLxpZojPI0IBjDvKEs6VJtkbdufKnAlq CPnEQqSkKU2FYfC4unImxfEclCRzBLVApNQsf4QL9lQ57wGRY/yzFF5mHjPuPrvLypv2 zW8G1L3W/SoZPYjPat5AhmFlVDVZQbJhW8EdtApcK74rbJOYD6eoE38KKQ9eNkvKM8iP qifMSoh2Wg2Ad15kLTZ20Dy7tnOTGPm/x8ORGeivVWezjsc4Q0WpyxYT3aU8fzbc0P6I 9iPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779988650; x=1780593450; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=dHjuwu7m0ZobnYT01ll75sxqoF3pTZJdT0OTzaL/UTY=; b=dXV0RftjgBuOUs+zWtLC7vhITfXKfwc0xhbKw09oKuTFFNLCPUmxLNppJUsSObJHic 1CLZ4VZ+dv0M5YyS1V155r/SDlpbNzrIDPbfBCy+r3dIxj7Hgt/+ckzkl7JDcrhBc3sR RcQtaH7hyoeMkk2R7WyOPlKQejAb9IwzhCwUdkCRrM6bvnj7xT3U2nwq7VMW/pyNfyWr K3oMTU80/SashYsslhLaXtMiKQrEoHQmOmgNEchufn1URdrvIwaUbANyznSnOGmeTlBj jSJN/C9yvkJaCUC8IC2JnKrNPcrFOLIu35HQ15FjRWtVMZPeAGQXJsebeX1YbeBGCBLI gurA== X-Gm-Message-State: AOJu0YxqlT7HVX6Im57TG8OYvVvlcS9iqZzlg2wYn42RCjG4w6eS60h8 btvnwvyMKzRhrbNf4QMDE2Fdb/ru2LUjToVPvwXmwLX9oJZYhU+b5km6Yedh9ilm X-Gm-Gg: Acq92OFO2dleG7i+gMXKamZCkxpJzA1MVlEVN/KERMzH+izyO1UaDg4MN7WM51vNa57 0zu/ouCdXmILtmZtSjMG+bO4Z4zEfVTWVqUicmpNbnANgZaIY6L729GUqPMrvgkq9YkDRFCXXeC eBYKiAvv1lnTc7eJVeC8m+G8QhUdCEeIMpzoCXZWwIxKSphD7XgIezb/neBBFIhg6PD4hYkBLfb 8GXjyZ71HNQvmre2REtpqdRAUUa5rTUCv8xI5JuGqnQNGYJstjNj7PimVlIPeKYxbsMW1ttbKWh ZbrFv9QWpPgNPXgdkZ3zv88/NAERcR9HrchY+Qp4QTinXIpJYKrs7BLVSlUYRbwWq0/X5EOnIsp lvUP0g6MJ9G/txx/dXeJ11GtTjA2jhMD3zNu01S5t/s0Dz48x7vcSeh/yg9Zb6dI95Tw1o5kDLd S5qsQg63ljNV4fAwOr2Qe5iQLxbd+kECqQ5zqvgfqbLUzaAD2h8P/Pl57AAmhadI8G X-Received: by 2002:a05:600c:6085:b0:490:6869:ef13 with SMTP id 5b1f17b1804b1-4906869f118mr313416565e9.14.1779988649293; Thu, 28 May 2026 10:17:29 -0700 (PDT) From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Bobek?= To: qemu-devel@nongnu.org, Matyas Bobek , Pavel Pisa , Bernhard Beschow Cc: qemu-arm@nongnu.org, Marc Kleine-Budde , Oliver Hartkopp , Nikita Ostrenkov , Peter Maydell , Andrey Volkov , =?UTF-8?q?Maty=C3=A1=C5=A1=20Bobek?= Subject: [PATCH v4 4/7] hw/net/can/flexcan: NXP FlexCAN core emulation Date: Thu, 28 May 2026 19:17:14 +0200 Message-ID: <51fe163b259b9ff315377b952d38665a18351b0d.1779986496.git.matyas.bobek@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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=lists1p.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::32b; envelope-from=matyas.bobek@gmail.com; helo=mail-wm1-x32b.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, 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: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1779988784970158500 Added the FlexCAN2 emulator implementation core, with CAN_FLEXCAN Kconfig flag and MAINTAINERS entry. FlexCAN2 version can be found in i.MX6 SoCs and others. More information about the implementation can be found in [1]. Some macro and struct defintions were borrowed from the Linux kernel. The original authors agreed with relicensing them to GPL-2.0-or-later on the qemu-devel mailing list. [1] http://dspace.cvut.cz/bitstream/handle/10467/122654/F3-BP-2025-Bobek-Ma= tyas-BP_Bobek_FlexCAN_final_4.pdf Signed-off-by: Maty=C3=A1=C5=A1 Bobek Signed-off-by: Pavel Pisa Tested-by: Pavel Pisa Reviewed-by: Bernhard Beschow Reviewed-by: Pavel Pisa --- MAINTAINERS | 8 + hw/net/Kconfig | 5 + hw/net/can/flexcan.c | 1395 +++++++++++++++++++++++++++++++++++++ hw/net/can/flexcan_regs.h | 196 ++++++ hw/net/can/meson.build | 1 + hw/net/can/trace-events | 18 + include/hw/net/flexcan.h | 144 ++++ 7 files changed, 1767 insertions(+) create mode 100644 hw/net/can/flexcan.c create mode 100644 hw/net/can/flexcan_regs.h create mode 100644 include/hw/net/flexcan.h diff --git a/MAINTAINERS b/MAINTAINERS index 7eb5823da6..36e056309b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2101,6 +2101,14 @@ F: hw/net/can/xlnx-* F: include/hw/net/xlnx-* F: tests/qtest/xlnx-can*-test* =20 +FlexCAN +M: Matyas Bobek +M: Pavel Pisa +S: Maintained +F: hw/net/can/flexcan.c +F: hw/net/can/flexcan_regs.h +F: include/hw/net/flexcan.h + EDU M: Jiri Slaby S: Maintained diff --git a/hw/net/Kconfig b/hw/net/Kconfig index f9a1dfb80d..b56a173eed 100644 --- a/hw/net/Kconfig +++ b/hw/net/Kconfig @@ -157,3 +157,8 @@ config CAN_CTUCANFD_PCI default y if PCI_DEVICES depends on PCI && CAN_CTUCANFD select CAN_BUS + +config CAN_FLEXCAN + bool + depends on IMX + select CAN_BUS diff --git a/hw/net/can/flexcan.c b/hw/net/can/flexcan.c new file mode 100644 index 0000000000..61a59e6086 --- /dev/null +++ b/hw/net/can/flexcan.c @@ -0,0 +1,1395 @@ +/* + * QEMU model of the NXP FLEXCAN device. + * + * This implementation is based on the following reference manual: + * i.MX 6Dual/6Quad Applications Processor Reference Manual + * Document Number: IMX6DQRM, Rev. 6, 05/2020 + * + * Copyright (c) 2025 Matyas Bobek + * + * Based on CTU CAN FD emulation implemented by Jan Charvat. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/core/sysbus.h" +#include "qapi/error.h" +#include "hw/core/irq.h" +#include "migration/vmstate.h" +#include "net/can_emu.h" +#include "hw/core/qdev-properties.h" +#include "trace.h" + +#include "hw/net/flexcan.h" +#include "flexcan_regs.h" +#include "qemu/timer.h" + +/* + * Indicates MB w/ received frame has not been serviced yet + * This is an emulator-only flag in position of unused (reserved) bit + * of message buffer control register + */ +#define FLEXCAN_MB_CNT_NOT_SRV BIT(23) +/** + * if no MB is locked, FlexcanState.locked_mb + * is set to FLEXCAN_NO_MB_LOCKED + */ +#define FLEXCAN_NO_MB_LOCKED -1 +/** + * if no frame is waiting in the SMB, FlexcanState.smb_target_mbid + * is set to FLEXCAN_SMB_EMPTY + */ +#define FLEXCAN_SMB_EMPTY -1 +/** + * When the module is disabled or in freeze mode, + * the timer is not running. That is indicated by setting + * FlexcanState.timer_start to FLEXCAN_TIMER_STOPPED. + */ +#define FLEXCAN_TIMER_STOPPED -1 + +/* These constants are returned by flexcan_fifo_rx() and flexcan_mb_rx(), = */ +enum FlexcanRx { +/* Retry the other receiving mechanism (ie. message bufer or mailbox). */ + FLEXCAN_RX_SEARCH_RETRY, +/* The frame was received and stored. */ + FLEXCAN_RX_SEARCH_ACCEPT, +/* The frame was filtered out and dropped. */ + FLEXCAN_RX_SEARCH_DROPPED, +}; + +/* + * These constants are returned by flexcan_mb_rx_check_mb(). + * See flexcan_mb_rx_check_mb() kerneldoc for details. + */ +enum FlexcanCheck { + FLEXCAN_CHECK_MB_NIL =3D 0, + FLEXCAN_CHECK_MB_MATCH =3D 3, + FLEXCAN_CHECK_MB_MATCH_NON_FREE =3D 1, + FLEXCAN_CHECK_MB_MATCH_LOCKED =3D 5, +}; + +static const FlexcanRegs flexcan_regs_write_mask =3D { + .mcr =3D 0xF6EB337F, + .ctrl =3D 0xFFFFFFFF, + .timer =3D 0xFFFFFFFF, + .tcr =3D 0xFFFFFFFF, + .rxmgmask =3D 0xFFFFFFFF, + .rx14mask =3D 0xFFFFFFFF, + .rx15mask =3D 0xFFFFFFFF, + .ecr =3D 0xFFFFFFFF, + .esr =3D 0xFFFFFFFF, + .imask2 =3D 0xFFFFFFFF, + .imask1 =3D 0xFFFFFFFF, + .iflag2 =3D 0, + .iflag1 =3D 0, + .ctrl2 =3D 0xFFFFFFFF, + .esr2 =3D 0, + .imeur =3D 0, + .lrfr =3D 0, + .crcr =3D 0, + .rxfgmask =3D 0xFFFFFFFF, + .rxfir =3D 0, + .cbt =3D 0, + ._reserved2 =3D 0, + .dbg1 =3D 0, + .dbg2 =3D 0, + .mbs =3D { [0 ... 63] =3D { + .can_ctrl =3D 0xFFFFFFFF & ~FLEXCAN_MB_CNT_NOT_SRV, + .can_id =3D 0xFFFFFFFF, + .data =3D { 0xFFFFFFFF, 0xFFFFFFFF }, + } }, + ._reserved4 =3D {0}, + .rximr =3D { [0 ... 63] =3D 0xFFFFFFFF }, + ._reserved5 =3D {0}, + .gfwr_mx6 =3D 0xFFFFFFFF, + ._reserved6 =3D {0}, + ._reserved8 =3D {0}, + .rx_smb0_raw =3D {0, 0, 0, 0}, + .rx_smb1 =3D {0, 0, 0, 0}, +}; +static const FlexcanRegs flexcan_regs_reset_mask =3D { + .mcr =3D 0x80000000, + .ctrl =3D 0xFFFFFFFF, + .timer =3D 0, + .tcr =3D 0, + .rxmgmask =3D 0xFFFFFFFF, + .rx14mask =3D 0xFFFFFFFF, + .rx15mask =3D 0xFFFFFFFF, + .ecr =3D 0, + .esr =3D 0, + .imask2 =3D 0, + .imask1 =3D 0, + .iflag2 =3D 0, + .iflag1 =3D 0, + .ctrl2 =3D 0xFFFFFFFF, + .esr2 =3D 0, + .imeur =3D 0, + .lrfr =3D 0, + .crcr =3D 0, + .rxfgmask =3D 0xFFFFFFFF, + .rxfir =3D 0xFFFFFFFF, + .cbt =3D 0, + ._reserved2 =3D 0, + .dbg1 =3D 0, + .dbg2 =3D 0, + .mb =3D {0xFFFFFFFF}, + ._reserved4 =3D {0}, + .rximr =3D {0xFFFFFFFF}, + ._reserved5 =3D {0}, + .gfwr_mx6 =3D 0, + ._reserved6 =3D {0}, + ._reserved8 =3D {0}, + .rx_smb0_raw =3D {0, 0, 0, 0}, + .rx_smb1 =3D {0, 0, 0, 0}, +}; + +/* length of buffer used to format register names in trace output */ +#define FLEXCAN_DBG_BUF_LEN 16 + +/** + * flexcan_dbg_mb_code_strs - Readable names for CODE field codes + * + * Readable names for possible values of CODE field in message buffer + * control word. + */ +static const char *flexcan_dbg_mb_code_strs[16] =3D { + "INACTIVE_RX", + "FULL", + "EMPTY", + "OVERRUN", + "INACTIVE_TX", + "RANSWER", + "DATA", + "TANSWER" +}; + +/** + * flexcan_dbg_mb_code() - Get the string representation of a mailbox code + * @mb_ctrl: The mailbox control register value + * @buf: The buffer to store the string representation + * + * Return: Either constant string or string formatted into @buf + */ +static const char *flexcan_dbg_mb_code(uint32_t mb_ctrl, char *buf) +{ + uint32_t code =3D mb_ctrl & FLEXCAN_MB_CODE_MASK; + uint32_t code_idx =3D code >> 24; + if (code =3D=3D FLEXCAN_MB_CODE_TX_ABORT) { + return "ABORT"; + } else { + const char *code_str =3D flexcan_dbg_mb_code_strs[code_idx >> 1]; + if (code_idx & 1) { + g_snprintf(buf, FLEXCAN_DBG_BUF_LEN, "%s+BUSY", code_str); + return buf; + } + + return code_str; + } +} + +static const char *flexcan_dbg_reg_name_fixed(hwaddr addr) +{ + switch (addr) { + case offsetof(FlexcanRegs, mcr): + return "MCR"; + case offsetof(FlexcanRegs, ctrl): + return "CTRL"; + case offsetof(FlexcanRegs, timer): + return "TIMER"; + case offsetof(FlexcanRegs, esr): + return "ESR"; + case offsetof(FlexcanRegs, rxmgmask): + return "RXMGMASK"; + case offsetof(FlexcanRegs, rx14mask): + return "RX14MASK"; + case offsetof(FlexcanRegs, rx15mask): + return "RX15MASK"; + case offsetof(FlexcanRegs, rxfgmask): + return "RXFGMASK"; + case offsetof(FlexcanRegs, ecr): + return "ECR"; + case offsetof(FlexcanRegs, ctrl2): + return "CTRL2"; + case offsetof(FlexcanRegs, imask2): + return "IMASK2"; + case offsetof(FlexcanRegs, imask1): + return "IMASK1"; + case offsetof(FlexcanRegs, iflag2): + return "IFLAG2"; + case offsetof(FlexcanRegs, iflag1): + return "IFLAG1"; + } + return NULL; +} + +static inline void flexcan_trace_mem_op(FlexcanState *s, hwaddr addr, + uint32_t value, int size, bool is_= wr) +{ + if (trace_event_get_state_backends(TRACE_FLEXCAN_MEM_OP)) { + const char *reg_name =3D "unknown"; + char reg_name_buf[FLEXCAN_DBG_BUF_LEN] =3D { 0 }; + const char *reg_name_fixed =3D flexcan_dbg_reg_name_fixed(addr); + const char *op_string =3D is_wr ? "write" : "read"; + + if (reg_name_fixed) { + reg_name =3D reg_name_fixed; + } else if (addr >=3D 0x80 && addr < 0x480) { + int mbidx =3D (addr - 0x80) / 16; + g_snprintf(reg_name_buf, sizeof(reg_name_buf), "MB%i", mbidx); + reg_name =3D reg_name_buf; + } else if (addr >=3D 0x880 && addr < 0x9e0) { + int id =3D (addr - 0x880) / 4; + g_snprintf(reg_name_buf, sizeof(reg_name_buf), "RXIMR%i", id); + reg_name =3D reg_name_buf; + } + + trace_flexcan_mem_op(DEVICE(s)->canonical_path, op_string, value, = addr, + reg_name, size); + } +} + +static enum FlexcanRx flexcan_mb_rx(FlexcanState *s, + const qemu_can_frame *frame); +static void flexcan_mb_unlock(FlexcanState *s); + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Mailbox Utils =3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D */ + +/** + * flexcan_mailbox_count() - Get number of enabled mailboxes + * @s: FlexCAN device pointer + * + * Count is based on MCR[MAXMB] field. Note that some of those mailboxes + * might be part of queue or queue ID filters or ordinary message buffers. + */ +static inline int flexcan_enabled_mailbox_count(const FlexcanState *s) +{ + return (s->regs.mcr & FLEXCAN_MCR_MAXMB(UINT32_MAX)) + 1; +} + +/** + * flexcan_get_first_message_buffer() - Get pointer to first message buffer + * @s: FlexCAN device pointer + * + * In context of this function, message buffer means a mailbox which is not + * a queue element nor a queue filter. Note this function does not take + * MCR[MAXMB] into account, meaning that the returned mailbox + * might be disabled. + */ +static FlexcanRegsMessageBuffer *flexcan_get_first_message_buffer( + FlexcanState *s) +{ + if (s->regs.mcr & FLEXCAN_MCR_FEN) { + int rffn =3D (s->regs.ctrl2 & FLEXCAN_CTRL2_RFFN(UINT32_MAX)) >> 2= 4; + return s->regs.mbs + 8 + 2 * rffn; + } + + return s->regs.mbs; +} + +/** + * flexcan_get_last_enabled_mailbox() - Get pointer to last enabled mailbo= x. + * @s: FlexCAN device pointer + * + * When used with flexcan_get_first_message_buffer(), all mailboxes *ptr in + * range `first_message_buffer() <=3D ptr <=3D last_enabled_mailbox` are v= alid + * message buffer mailboxes. + * + * Return: Last enabled mailbox in MCR[MAXMB] sense. The mailbox might be + * of any type. + */ +static inline FlexcanRegsMessageBuffer *flexcan_get_last_enabled_mailbox( + FlexcanState *s) +{ + return s->regs.mbs + flexcan_enabled_mailbox_count(s); +} + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Free-running Timer =3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D */ +static inline int64_t flexcan_get_time(void) +{ + return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +} + +/** + * flexcan_get_bitrate() - Calculate CAN bitrate (in Hz) + * @s: FlexCAN device pointer + * + * The bitrate is determined by FlexCAN configuration in CTRL1 register, + * and CCM co + */ +static uint32_t flexcan_get_bitrate(FlexcanState *s) +{ + uint32_t conf_presdiv =3D (s->regs.ctrl & FLEXCAN_CTRL_PRESDIV_MASK) >= > 24; + uint32_t conf_pseg1 =3D (s->regs.ctrl & FLEXCAN_CTRL_PSEG1_MASK) >> 19; + uint32_t conf_pseg2 =3D (s->regs.ctrl & FLEXCAN_CTRL_PSEG2_MASK) >> 16; + uint32_t conf_propseg =3D s->regs.ctrl & FLEXCAN_CTRL_PROPSEG_MASK; + + /* N of time quanta for segments */ + uint32_t tseg1 =3D 2 + conf_pseg1 + conf_propseg; + uint32_t tseg2 =3D 1 + conf_pseg2; + uint32_t total_qpb =3D 1 + tseg1 + tseg2; + + uint32_t pe_freq, s_freq, bitrate; + + assert(s->ccm); + + /* s_freq: CAN clock from CCM divided by the prescaler */ + pe_freq =3D imx_ccm_get_clock_frequency(s->ccm, CLK_CAN); + s_freq =3D pe_freq / (1 + conf_presdiv); + bitrate =3D s_freq / total_qpb; + + trace_flexcan_get_bitrate(DEVICE(s)->canonical_path, pe_freq, + 1 + conf_presdiv, s_freq, tseg1, tseg2, tota= l_qpb, + bitrate); + return bitrate; +} + +/** + * int128_mul_6464() - Multiply two 64-bit integers into a 128-bit one + */ +static Int128 int128_muls_6464(int64_t ai, int64_t bi) +{ + uint64_t l, h; + + muls64(&l, &h, ai, bi); + return int128_make128(l, h); +} + +/** + * flexcan_get_timestamp() - Get current value of the 16-bit free-running = timer + * @s: FlexCAN device pointer + * @mk_unique: if true, make the timestamp unique by incrementing it if ne= eded + */ +static uint32_t flexcan_get_timestamp(FlexcanState *s, bool mk_unique) +{ + const Int128 nanoseconds_in_second =3D int128_makes64((int64_t)1e9); + Int128 ncycles, cycles128; + int64_t current_time, elapsed_time_ns; + uint64_t cycles; + uint32_t rv, shift =3D 0; + + if (s->timer_start =3D=3D FLEXCAN_TIMER_STOPPED) { + /* timer is not running, return last value */ + trace_flexcan_get_timestamp(DEVICE(s)->canonical_path, -1, 0, 0, 0, + s->regs.timer); + return s->regs.timer; + } + + current_time =3D flexcan_get_time(); + elapsed_time_ns =3D current_time - s->timer_start; + if (elapsed_time_ns < 0) { + trace_flexcan_timer_overflow(DEVICE(s)->canonical_path, current_ti= me, + s->timer_start, elapsed_time_ns); + return 0xFFFF; + } + + ncycles =3D int128_muls_6464(s->timer_freq, elapsed_time_ns); + cycles128 =3D int128_divs(ncycles, nanoseconds_in_second); + /* 64 bits hold for over 50k years at 10MHz */ + cycles =3D int128_getlo(cycles128); + + if (mk_unique && cycles <=3D s->last_rx_timer_cycles) { + shift =3D 1; + cycles =3D s->last_rx_timer_cycles + shift; + } + + s->last_rx_timer_cycles =3D cycles; + rv =3D (uint32_t)cycles & 0xFFFF; + + trace_flexcan_get_timestamp(DEVICE(s)->canonical_path, + elapsed_time_ns / (uint32_t)1e6, + s->timer_freq, cycles, shift, rv); + return rv; +} + +/** + * flexcan_timer_start() - Start the free-running timer + * @s: FlexCAN device pointer + * + * This should be called when the module leaves freeze mode. + */ +static void flexcan_timer_start(FlexcanState *s) +{ + s->timer_freq =3D flexcan_get_bitrate(s); + s->timer_start =3D flexcan_get_time(); + s->last_rx_timer_cycles =3D 0; + + trace_flexcan_timer_start(DEVICE(s)->canonical_path, s->timer_freq, + s->regs.timer); +} + +/** + * flexcan_timer_stop() - Stop the free-running timer + * @s: FlexCAN device pointer + * + * This should be called when the module enters freeze mode. + * Stores the current timestamp in the TIMER register. + */ +static void flexcan_timer_stop(FlexcanState *s) +{ + s->regs.timer =3D flexcan_get_timestamp(s, false); + s->timer_start =3D FLEXCAN_TIMER_STOPPED; + + trace_flexcan_timer_stop(DEVICE(s)->canonical_path, s->timer_freq, + s->regs.timer); +} + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D IRQ handling =3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D */ +/** + * flexcan_irq_update() - Update qemu_irq line based on interrupt registers + * @s: FlexCAN device pointer + */ +static void flexcan_irq_update(FlexcanState *s) +{ + uint32_t mb_irqs[2]; + int irq_pending; + /* these are all interrupt sources from FlexCAN */ + /* mailbox interrupt sources */ + mb_irqs[0] =3D s->regs.iflag1 & s->regs.imask1; + mb_irqs[1] =3D s->regs.iflag2 & s->regs.imask2; + + /** + * these interrupts aren't currently used and they can never be raised + * + * bool irq_wake_up =3D (s->regs.mcr & FLEXCAN_MCR_WAK_MSK) && + * (s->regs.ecr & FLEXCAN_ESR_WAK_INT); + * bool irq_bus_off =3D (s->regs.ctrl & FLEXCAN_CTRL_BOFF_MSK) && + * (s->regs.ecr & FLEXCAN_ESR_BOFF_INT); + * bool irq_error =3D (s->regs.ctrl & FLEXCAN_CTRL_ERR_MSK) && + * (s->regs.ecr & FLEXCAN_ESR_ERR_INT); + * bool irq_tx_warn =3D (s->regs.ctrl & FLEXCAN_CTRL_TWRN_MSK) && + * (s->regs.ecr & FLEXCAN_ESR_TWRN_INT); + * bool irq_rx_warn =3D (s->regs.ctrl & FLEXCAN_CTRL_RWRN_MSK) && + * (s->regs.ecr & FLEXCAN_ESR_RWRN_INT); + */ + + irq_pending =3D (mb_irqs[0] || mb_irqs[1]) ? 1 : 0; + trace_flexcan_irq_update(DEVICE(s)->canonical_path, mb_irqs[0], mb_irq= s[1], + irq_pending); + + qemu_set_irq(s->irq, irq_pending); +} + +/** + * flexcan_irq_iflag_set() - Set IFLAG bit corresponding to MB mbidx + * @s: FlexCAN device pointer + * @mbidx: mailbox index + */ +static void flexcan_irq_iflag_set(FlexcanState *s, int mbidx) +{ + if (mbidx < 32) { + s->regs.iflag1 |=3D BIT(mbidx); + } else { + s->regs.iflag2 |=3D BIT(mbidx - 32); + } +} + +/** + * flexcan_irq_iflag_clear() - Clear IFLAG bit corresponding to MB mbidx + * @s: FlexCAN device pointer + * @mbidx: mailbox index + */ +static void flexcan_irq_iflag_clear(FlexcanState *s, int mbidx) +{ + if (mbidx < 32) { + s->regs.iflag1 &=3D ~BIT(mbidx); + } else { + s->regs.iflag2 &=3D ~BIT(mbidx - 32); + } +} + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RESET =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D */ +static void flexcan_reset_local_state(FlexcanState *s) +{ + uint32_t *reset_mask =3D (uint32_t *)&flexcan_regs_reset_mask; + for (int i =3D 0; i < (sizeof(FlexcanRegs) / 4); i++) { + s->regs_raw[i] &=3D reset_mask[i]; + } + + s->regs.mcr |=3D 0x5980000F; + s->locked_mbidx =3D FLEXCAN_NO_MB_LOCKED; + s->smb_target_mbidx =3D FLEXCAN_SMB_EMPTY; + s->timer_start =3D FLEXCAN_TIMER_STOPPED; + + trace_flexcan_reset(DEVICE(s)->canonical_path); +} + +static void flexcan_reset_enter(Object *obj, ResetType type) +{ + FlexcanState *s =3D CAN_FLEXCAN(obj); + + memset(&s->regs, 0, sizeof(s->regs)); + flexcan_reset_local_state(s); +} + +static void flexcan_reset_hold(Object *obj, ResetType type) +{ + FlexcanState *s =3D CAN_FLEXCAN(obj); + + flexcan_irq_update(s); +} + + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Operation mode control =3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D */ +/** + * flexcan_update_esr() - Update ESR based on mode and CAN bus connection = state + * @s: FlexCAN device pointer + */ +static void flexcan_update_esr(FlexcanState *s) +{ + bool is_running =3D (s->regs.mcr & FLEXCAN_MCR_NOT_RDY) =3D=3D 0; + /* potentially, there could be other influences on ESR[SYNCH] */ + + if (is_running && s->canbus) { + s->regs.esr |=3D FLEXCAN_ESR_SYNCH | FLEXCAN_ESR_IDLE; + } else { + s->regs.esr &=3D ~(FLEXCAN_ESR_SYNCH | FLEXCAN_ESR_IDLE); + } +} + +/** + * flexcan_update_esr() - Process MCR write + * @s: FlexCAN device pointer + * @pv: previously set MCR value + * + * This function expects the new MCR value to be already written in s->reg= s.mcr. + */ +static void flexcan_set_mcr(FlexcanState *s, const uint32_t pv) +{ + uint32_t cv =3D s->regs.mcr; + + /* -- module disable mode -- */ + if (!(pv & FLEXCAN_MCR_MDIS) && (cv & FLEXCAN_MCR_MDIS)) { + /* transition to Module Disable mode */ + cv |=3D FLEXCAN_MCR_LPM_ACK; + } else if ((pv & FLEXCAN_MCR_MDIS) && !(cv & FLEXCAN_MCR_MDIS)) { + /* transition from Module Disable mode */ + cv &=3D ~FLEXCAN_MCR_LPM_ACK; + } + + /* -- soft reset -- */ + if (!(cv & FLEXCAN_MCR_LPM_ACK) && (cv & FLEXCAN_MCR_SOFTRST)) { + if (s->regs.mcr & FLEXCAN_MCR_LPM_ACK) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid soft reset request in low-power mod= e", + DEVICE(s)->canonical_path); + } + + flexcan_reset_local_state(s); + cv =3D s->regs.mcr; + } + + /* -- freeze mode -- */ + if (!(cv & FLEXCAN_MCR_LPM_ACK) && + (cv & FLEXCAN_MCR_FRZ) && + (cv & FLEXCAN_MCR_HALT)) { + cv |=3D FLEXCAN_MCR_FRZ_ACK; + } else { + cv &=3D ~FLEXCAN_MCR_FRZ_ACK; + } + + /* -- fifo mode -- */ + if ( + ((pv & FLEXCAN_MCR_FEN) && !(cv & FLEXCAN_MCR_FEN)) || + (!(pv & FLEXCAN_MCR_FEN) && (cv & FLEXCAN_MCR_FEN)) + ) { + /* clear iflags used by fifo */ + s->regs.iflag1 &=3D ~( + FLEXCAN_IFLAG_RX_FIFO_AVAILABLE | + FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | + FLEXCAN_IFLAG_RX_FIFO_WARN + ); + } + if (!(pv & FLEXCAN_MCR_FEN) && (cv & FLEXCAN_MCR_FEN)) { + /* zero out fifo region, we rely on zeroed can_ctrl for empty slot= s */ + memset(s->regs.mbs, 0, + FLEXCAN_FIFO_DEPTH * sizeof(FlexcanRegsMessageBuffer)); + } + + /* + * assert NOT_RDY bit if in disable, + * stop (not implemented) or freeze mode + */ + if ((cv & FLEXCAN_MCR_LPM_ACK) || (cv & FLEXCAN_MCR_FRZ_ACK)) { + cv |=3D FLEXCAN_MCR_NOT_RDY; + } else { + cv &=3D ~FLEXCAN_MCR_NOT_RDY; + } + + if ((pv & FLEXCAN_MCR_NOT_RDY) && !(cv & FLEXCAN_MCR_NOT_RDY)) { + /* module went up, start the timer */ + flexcan_timer_start(s); + } else if (!(pv & FLEXCAN_MCR_NOT_RDY) && (cv & FLEXCAN_MCR_NOT_RDY)) { + /* module went down, store the current timer value */ + flexcan_timer_stop(s); + } + + s->regs.mcr =3D cv; + flexcan_update_esr(s); + trace_flexcan_set_mcr( + DEVICE(s)->canonical_path, + cv & FLEXCAN_MCR_LPM_ACK ? "DISABLED" : "ENABLED", + (cv & FLEXCAN_MCR_FRZ_ACK || cv & FLEXCAN_MCR_LPM_ACK) ? + "FROZEN" : "RUNNING", + cv & FLEXCAN_MCR_FEN ? "FIFO" : "MAILBOX", + cv & FLEXCAN_MCR_NOT_RDY ? "NOT_RDY" : "RDY", + s->regs.esr & FLEXCAN_ESR_SYNCH ? "SYNC" : "NOSYNC" + ); +} + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D TX =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D */ +static void flexcan_transmit(FlexcanState *s, int mbidx) +{ + FlexcanRegsMessageBuffer *mb =3D &s->regs.mbs[mbidx]; + qemu_can_frame frame =3D { + .flags =3D 0, + }; + uint32_t *frame_data =3D (uint32_t *)&frame.data; + uint32_t timestamp =3D flexcan_get_timestamp(s, true); + + if ((s->regs.ctrl & FLEXCAN_CTRL_LOM) || + (s->regs.mcr & FLEXCAN_MCR_NOT_RDY)) { + /* no transmiting in listen-only, freeze or low-power mode */ + return; + } + + if (mb->can_ctrl & FLEXCAN_MB_CNT_IDE) { + /* 29b ID stored in bits [0, 29) */ + uint32_t id =3D mb->can_id & 0x1FFFFFFF; + frame.can_id =3D id | QEMU_CAN_EFF_FLAG; + } else { + /* 11b ID stored in bits [18, 29) */ + uint32_t id =3D (mb->can_id & (0x7FF << 18)) >> 18; + frame.can_id =3D id; + } + + frame.can_dlc =3D (mb->can_ctrl & (0xF << 16)) >> 16; + + for (int i =3D 0; i < 2; i++) { + stl_be_p(&frame_data[i], mb->data[i]); + } + + if (!(s->regs.mcr & FLEXCAN_MCR_SRX_DIS)) { + /* self-reception */ + flexcan_mb_rx(s, &frame); + } + if (!(s->regs.ctrl & FLEXCAN_CTRL_LPB)) { + /* send to bus if not in loopback mode */ + if (s->canbus) { + can_bus_client_send(&s->bus_client, &frame, 1); + } else { + /* todo: raise error (no ack) */ + } + } + + mb->can_ctrl &=3D ~(FLEXCAN_MB_CODE_MASK | FLEXCAN_MB_CNT_TIMESTAMP_MA= SK); + mb->can_ctrl |=3D FLEXCAN_MB_CODE_TX_INACTIVE | + FLEXCAN_MB_CNT_TIMESTAMP(timestamp); + + /* todo: compute the CRC */ + s->regs.crcr =3D FLEXCAN_CRCR_TXCRC(0) | FLEXCAN_CRCR_MBCRC(mbidx); + + flexcan_irq_iflag_set(s, mbidx); +} + +static void flexcan_mb_write(FlexcanState *s, int mbid) +{ + FlexcanRegsMessageBuffer *mb =3D &s->regs.mbs[mbid]; + + bool is_mailbox =3D (mb <=3D flexcan_get_last_enabled_mailbox(s)) && + (mb >=3D flexcan_get_first_message_buffer(s)); + + if (trace_event_get_state_backends(TRACE_FLEXCAN_MB_WRITE)) { + char code_str_buf[FLEXCAN_DBG_BUF_LEN] =3D { 0 }; + const char *code_str =3D flexcan_dbg_mb_code(mb->can_ctrl, code_st= r_buf); + trace_flexcan_mb_write(DEVICE(s)->canonical_path, mbid, code_str, + is_mailbox, mb->can_ctrl, mb->can_id); + } + + if (!is_mailbox) { + /** + * Disabled mailbox or mailbox in region of queue filters + * was updated. Either way there is nothing to do. + */ + return; + } + + /* any write to message buffer clears the not_serviced flag */ + mb->can_ctrl &=3D ~FLEXCAN_MB_CNT_NOT_SRV; + + /** + * todo: search for active tx mbs on transition from freeze/disable mo= de + */ + switch (mb->can_ctrl & FLEXCAN_MB_CODE_MASK) { + case FLEXCAN_MB_CODE_TX_INACTIVE: + QEMU_FALLTHROUGH; + case FLEXCAN_MB_CODE_RX_INACTIVE: + QEMU_FALLTHROUGH; + case FLEXCAN_MB_CODE_RX_EMPTY: + QEMU_FALLTHROUGH; + case FLEXCAN_MB_CODE_RX_FULL: + QEMU_FALLTHROUGH; + case FLEXCAN_MB_CODE_RX_RANSWER: + break; + + case FLEXCAN_MB_CODE_TX_DATA: + flexcan_transmit(s, mbid); + break; + case FLEXCAN_MB_CODE_TX_ABORT: + /* + * as transmission is instant, it can never be aborted + * we need to set CODE in C/S back to the previous code + */ + mb->can_ctrl &=3D ~FLEXCAN_MB_CODE(1); + break; + case FLEXCAN_MB_CODE_TX_TANSWER: + break; + default: + /* prevent setting the busy bit */ + mb->can_ctrl &=3D ~FLEXCAN_MB_CODE_RX_BUSY_BIT; + break; + } + +} + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RX =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D */ +static void flexcan_mb_move_in(FlexcanState *s, const qemu_can_frame *fram= e, + FlexcanRegsMessageBuffer *target_mb) +{ + uint32_t frame_len =3D frame->can_dlc; + uint32_t *frame_data =3D (uint32_t *)&frame->data; + int timestamp =3D flexcan_get_timestamp(s, true); + uint32_t new_code =3D 0; + + memset(target_mb, 0, sizeof(FlexcanRegsMessageBuffer)); + + if (frame_len > 8) { + frame_len =3D 8; + } + for (int i =3D 0; i < 2; i++) { + target_mb->data[i] =3D ldl_be_p(&frame_data[i]); + } + + switch (target_mb->can_ctrl & FLEXCAN_MB_CODE_MASK) { + case FLEXCAN_MB_CODE_RX_FULL: + case FLEXCAN_MB_CODE_RX_OVERRUN: + if (target_mb->can_ctrl & FLEXCAN_MB_CNT_NOT_SRV) { + new_code =3D FLEXCAN_MB_CODE_RX_OVERRUN; + } else { + new_code =3D FLEXCAN_MB_CODE_RX_FULL; + } + break; + case FLEXCAN_MB_CODE_RX_RANSWER: + assert(s->regs.ctrl2 & FLEXCAN_CTRL2_RRS); + new_code =3D FLEXCAN_MB_CODE_TX_TANSWER; + break; + default: + new_code =3D FLEXCAN_MB_CODE_RX_FULL; + } + + target_mb->can_ctrl =3D new_code + | FLEXCAN_MB_CNT_TIMESTAMP(timestamp) + | FLEXCAN_MB_CNT_LENGTH(frame_len) + | FLEXCAN_MB_CNT_NOT_SRV + | FLEXCAN_MB_CNT_SRR; /* always set for received frames */ + if (frame->can_id & QEMU_CAN_RTR_FLAG) { + target_mb->can_ctrl |=3D FLEXCAN_MB_CNT_RTR; + } + + if (frame->can_id & QEMU_CAN_EFF_FLAG) { + target_mb->can_ctrl |=3D FLEXCAN_MB_CNT_IDE; + target_mb->can_id |=3D frame->can_id & QEMU_CAN_EFF_MASK; + } else { + target_mb->can_id |=3D (frame->can_id & QEMU_CAN_SFF_MASK) << 18; + } +} +static void flexcan_mb_lock(FlexcanState *s, int mbidx) +{ + FlexcanRegsMessageBuffer *mb =3D &s->regs.mbs[mbidx]; + if ((mb > flexcan_get_last_enabled_mailbox(s)) || + (mb < flexcan_get_first_message_buffer(s))) { + return; + } + switch (mb->can_ctrl & FLEXCAN_MB_CODE_MASK) { + case FLEXCAN_MB_CODE_RX_FULL: + QEMU_FALLTHROUGH; + case FLEXCAN_MB_CODE_RX_OVERRUN: + QEMU_FALLTHROUGH; + case FLEXCAN_MB_CODE_RX_RANSWER: + /* continue */ + trace_flexcan_mb_lock(DEVICE(s)->canonical_path, mbidx, 1); + break; + default: + trace_flexcan_mb_lock(DEVICE(s)->canonical_path, mbidx, 0); + return; + } + + s->locked_mbidx =3D mbidx; +} + +static void flexcan_mb_unlock(FlexcanState *s) +{ + int locked_mbidx =3D s->locked_mbidx; + bool has_pending_frame =3D locked_mbidx =3D=3D s->smb_target_mbidx; + + if (s->locked_mbidx =3D=3D FLEXCAN_NO_MB_LOCKED) { + return; + } + + assert(locked_mbidx >=3D 0 && locked_mbidx < FLEXCAN_MAILBOX_COUNT); + FlexcanRegsMessageBuffer *locked_mb =3D &s->regs.mbs[locked_mbidx]; + s->locked_mbidx =3D FLEXCAN_NO_MB_LOCKED; + + if (locked_mb >=3D flexcan_get_first_message_buffer(s) && + locked_mb <=3D flexcan_get_last_enabled_mailbox(s) + ) { + /* mark the message buffer as serviced */ + locked_mb->can_ctrl &=3D ~FLEXCAN_MB_CNT_NOT_SRV; + } + + /* try move in from SMB */ + trace_flexcan_mb_unlock(DEVICE(s)->canonical_path, locked_mbidx, + has_pending_frame ? " PENDING FRAME IN SMB" : = ""); + + /* todo: in low-power modes, this should be postponed until exit */ + if (has_pending_frame) { + FlexcanRegsMessageBuffer *target_mb =3D &s->regs.mbs[locked_mbidx]; + memcpy(target_mb, &s->regs.rx_smb0, sizeof(FlexcanRegsMessageBuffe= r)); + + memset(&s->regs.rx_smb0, 0, sizeof(FlexcanRegsMessageBuffer)); + s->locked_mbidx =3D FLEXCAN_SMB_EMPTY; + + flexcan_irq_iflag_set(s, locked_mbidx); + } +} + +static bool flexcan_can_receive(CanBusClientState *client) +{ + FlexcanState *s =3D container_of(client, FlexcanState, bus_client); + return !(s->regs.mcr & FLEXCAN_MCR_NOT_RDY); +} + +/* --------- RX FIFO ---------- */ + +/** + * flexcan_fifo_pop() - Pop message from FIFO and update IRQs + * @s: FlexCAN device pointer + * + * Does not require the queue to be non-empty. + */ +static void flexcan_fifo_pop(FlexcanState *s) +{ + if (s->regs.fifo.mb_back.can_ctrl !=3D 0) { + /* move queue elements forward */ + memmove(&s->regs.fifo.mb_back, &s->regs.fifo.mbs_queue[0], + sizeof(s->regs.fifo.mbs_queue)); + + /* clear the first-in slot */ + memset(&s->regs.mbs[FLEXCAN_FIFO_DEPTH - 1], 0, + sizeof(FlexcanRegsMessageBuffer)); + + trace_flexcan_fifo_pop(DEVICE(s)->canonical_path, 1, + s->regs.fifo.mb_back.can_ctrl !=3D 0); + } else { + trace_flexcan_fifo_pop(DEVICE(s)->canonical_path, 0, 0); + } + + if (s->regs.fifo.mb_back.can_ctrl !=3D 0) { + flexcan_irq_iflag_set(s, I_FIFO_AVAILABLE); + } else { + flexcan_irq_iflag_clear(s, I_FIFO_AVAILABLE); + } +} + +/** + * flexcan_fifo_find_free_slot() - Find the first free slot in the FIFO + * @s: FlexCAN device pointer + * + * Return: Pointer to the first free slot in the FIFO, + * or NULL if the queue is full. + */ +static FlexcanRegsMessageBuffer *flexcan_fifo_find_free_slot(FlexcanState = *s) +{ + for (int i =3D 0; i < FLEXCAN_FIFO_DEPTH; i++) { + FlexcanRegsMessageBuffer *mb =3D &s->regs.mbs[i]; + if (mb->can_ctrl =3D=3D 0) { + return mb; + } + } + return NULL; +} + +/** + * flexcan_fifo_push() - Update FIFO IRQs after frame move-in + * @s: FlexCAN device pointer + * @slot: Target FIFO slot + * + * The usage is as follows: + * 1. Get free slot pointer using flexcan_fifo_find_free_slot() + * 2. Move the frame in if not NULL + * 3. Call flexcan_fifo_push() regardless of the NULL pointer + */ +static void flexcan_fifo_push(FlexcanState *s, FlexcanRegsMessageBuffer *s= lot) +{ + if (slot) { + int n_occupied =3D slot - s->regs.mbs; + if (n_occupied =3D=3D 4) { /* 4 means the 5th slot was filled in */ + /* + * fifo occupancy increased from 4 to 5, + * raising FIFO_WARN interrupt + */ + flexcan_irq_iflag_set(s, I_FIFO_WARN); + } + flexcan_irq_iflag_set(s, I_FIFO_AVAILABLE); + + trace_flexcan_fifo_push(DEVICE(s)->canonical_path, n_occupied); + } else { + flexcan_irq_iflag_set(s, I_FIFO_OVERFLOW); + + trace_flexcan_fifo_push(DEVICE(s)->canonical_path, -1); + } +} + +static enum FlexcanRx flexcan_fifo_rx(FlexcanState *s, + const qemu_can_frame *buf) +{ + /* todo: filtering. return FLEXCAN_FIFO_RX_RETRY if filtered out */ + if ((s->regs.mcr & FLEXCAN_MCR_IDAM_MASK) =3D=3D FLEXCAN_MCR_IDAM_D) { + /* all frames rejected */ + return FLEXCAN_RX_SEARCH_RETRY; + } else { + /* push message to queue if not full */ + FlexcanRegsMessageBuffer *slot =3D flexcan_fifo_find_free_slot(s); + if (slot) { + flexcan_mb_move_in(s, buf, slot); + } + flexcan_fifo_push(s, slot); + + return slot ? FLEXCAN_RX_SEARCH_ACCEPT : FLEXCAN_RX_SEARCH_DROPPED; + } +} + +/* --------- RX message buffer ---------- */ + +/** + * flexcan_mb_rx_check_mb() - Check if a mb matches a received frame + * @s: FlexCAN device pointer + * @buf: Frame to be received from CAN subsystem + * @mbid: Target mailbox index. The mailbox must be a valid message buffer. + * + * Return: FLEXCAN_CHECK_MB_NIL if the message buffer does not match. + * FLEXCAN_CHECK_MB_MATCH if the message buffer matches the receiv= ed + * frame and is free-to-receive, + * FLEXCAN_CHECK_MB_MATCH_LOCKED if the message buffer matches, + * but is locked, + * FLEXCAN_CHECK_MB_MATCH_NON_FREE if the message buffer matches, + * but is not free-to-receive + * for some other reason. + */ +static enum FlexcanCheck flexcan_mb_rx_check_mb(FlexcanState *s, + const qemu_can_frame *buf, + int mbid) +{ + FlexcanRegsMessageBuffer *mb =3D &s->regs.mbs[mbid]; + const bool is_rtr =3D !!(buf->can_id & QEMU_CAN_RTR_FLAG); + const bool is_serviced =3D !(mb->can_ctrl & FLEXCAN_MB_CNT_NOT_SRV); + const bool is_locked =3D s->locked_mbidx =3D=3D mbid; + + bool is_free_to_receive =3D false; + bool is_matched =3D false; + + switch (mb->can_ctrl & FLEXCAN_MB_CODE_MASK) { + case FLEXCAN_MB_CODE_RX_RANSWER: + if (is_rtr && !(s->regs.ctrl2 & FLEXCAN_CTRL2_RRS)) { + /* todo: do the actual matching/filtering and RTR answer */ + is_matched =3D true; + } + break; + case FLEXCAN_MB_CODE_RX_FULL: + QEMU_FALLTHROUGH; + case FLEXCAN_MB_CODE_RX_OVERRUN: + is_free_to_receive =3D is_serviced; + /* todo: do the actual matching/filtering */ + is_matched =3D true; + break; + case FLEXCAN_MB_CODE_RX_EMPTY: + is_free_to_receive =3D true; + /* todo: do the actual matching/filtering */ + is_matched =3D true; + break; + default: + break; + } + + if (trace_event_get_state_backends(TRACE_FLEXCAN_MB_RX_CHECK_MB)) { + char code_str_buf[FLEXCAN_DBG_BUF_LEN] =3D { 0 }; + const char *code_str =3D flexcan_dbg_mb_code(mb->can_ctrl, code_st= r_buf); + trace_flexcan_mb_rx_check_mb(DEVICE(s)->canonical_path, mbid, code= _str, + is_matched, is_free_to_receive, + is_serviced, is_locked); + } + + if (!is_matched) { + return FLEXCAN_CHECK_MB_NIL; + } + + if (is_locked) { + return FLEXCAN_CHECK_MB_MATCH_LOCKED; + } + + if (is_free_to_receive) { + return FLEXCAN_CHECK_MB_MATCH; + } + + return FLEXCAN_CHECK_MB_MATCH_NON_FREE; +} + +static enum FlexcanRx flexcan_mb_rx(FlexcanState *s, const qemu_can_frame = *buf) +{ + int last_not_free_to_receive_mbid =3D -1; + bool last_not_free_to_receive_locked =3D false; + + FlexcanRegsMessageBuffer *first_mb =3D flexcan_get_first_message_buffe= r(s); + FlexcanRegsMessageBuffer *last_mb =3D flexcan_get_last_enabled_mailbox= (s); + + for (FlexcanRegsMessageBuffer *mb =3D first_mb; + mb <=3D last_mb; mb++) { + int mbid =3D mb - s->regs.mbs; + enum FlexcanCheck r =3D flexcan_mb_rx_check_mb(s, buf, mbid); + if (r =3D=3D FLEXCAN_CHECK_MB_MATCH) { + flexcan_mb_move_in(s, buf, mb); + flexcan_irq_iflag_set(s, mbid); + return FLEXCAN_RX_SEARCH_ACCEPT; + } + + if (r =3D=3D FLEXCAN_CHECK_MB_MATCH_NON_FREE) { + last_not_free_to_receive_mbid =3D mbid; + last_not_free_to_receive_locked =3D false; + } else if (r =3D=3D FLEXCAN_CHECK_MB_MATCH_LOCKED) { + /* + * message buffer is locked, + * we can move in the message after it's unlocked + */ + last_not_free_to_receive_mbid =3D mbid; + last_not_free_to_receive_locked =3D true; + } + } + + if (last_not_free_to_receive_mbid >=3D -1) { + if (last_not_free_to_receive_locked) { + /* + * copy to temporary mailbox (SMB) + * it will be moved in when the mailbox is unlocked + */ + s->regs.rx_smb0.can_ctrl =3D + s->regs.mbs[last_not_free_to_receive_mbid].can_id; + flexcan_mb_move_in(s, buf, &s->regs.rx_smb0); + s->smb_target_mbidx =3D last_not_free_to_receive_mbid; + return FLEXCAN_RX_SEARCH_ACCEPT; + } + + if (s->regs.mcr & FLEXCAN_MCR_IRMQ) { + flexcan_mb_move_in(s, buf, + &s->regs.mbs[last_not_free_to_receive_mbid]= ); + flexcan_irq_iflag_set(s, last_not_free_to_receive_mbid); + return FLEXCAN_RX_SEARCH_ACCEPT; + } + } + + return FLEXCAN_RX_SEARCH_RETRY; +} + +static ssize_t flexcan_receive(CanBusClientState *client, + const qemu_can_frame *frames, size_t frames= _cnt) +{ + FlexcanState *s =3D container_of(client, FlexcanState, bus_client); + trace_flexcan_receive(DEVICE(s)->canonical_path, frames_cnt); + + if (frames_cnt =3D=3D 0) { + return 0; + } + + /* clear the SMB, as it would be overriden in hardware */ + memset(&s->regs.rx_smb0, 0, sizeof(FlexcanRegsMessageBuffer)); + s->smb_target_mbidx =3D FLEXCAN_SMB_EMPTY; + + for (size_t i =3D 0; i < frames_cnt; i++) { + int r; + const qemu_can_frame *frame =3D &frames[i]; + if (frame->can_id & QEMU_CAN_ERR_FLAG) { + /* todo: error frame handling */ + continue; + } + if (frame->flags & QEMU_CAN_FRMF_TYPE_FD) { + /* CAN FD supported only in later FlexCAN version */ + continue; + } + + /* todo: this order logic is not complete and needs further work */ + if (s->regs.mcr & FLEXCAN_MCR_FEN && + s->regs.ctrl2 & FLEXCAN_CTRL2_MRP) { + r =3D flexcan_mb_rx(s, frame); + if (r =3D=3D FLEXCAN_RX_SEARCH_RETRY) { + flexcan_fifo_rx(s, frame); + } + } else if (s->regs.mcr & FLEXCAN_MCR_FEN) { + r =3D flexcan_fifo_rx(s, frame); + if (r =3D=3D FLEXCAN_RX_SEARCH_RETRY) { + flexcan_mb_rx(s, frame); + } + } else { + flexcan_mb_rx(s, frame); + } + } + + flexcan_irq_update(s); + return 1; +} + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D I/O handling =3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D */ +static void flexcan_mem_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + FlexcanState *s =3D opaque; + uint32_t write_mask =3D ((const uint32_t *) + &flexcan_regs_write_mask)[addr / 4]; + uint32_t old_value =3D s->regs_raw[addr / 4]; + + /* + * 0 for bits that can "only be written in Freeze mode as it is blocked + * by hardware in other modes" + */ + const uint32_t freeze_mask_mcr =3D 0xDF54CC80; + const uint32_t freeze_mask_ctrl1 =3D 0x0000E740; + + flexcan_trace_mem_op(s, addr, val, size, true); + switch (addr) { + case offsetof(FlexcanRegs, mcr): + if (!(s->regs.mcr & FLEXCAN_MCR_FRZ_ACK)) { + write_mask &=3D freeze_mask_mcr; + } + s->regs.mcr =3D (val & write_mask) | (old_value & ~write_mask); + flexcan_set_mcr(s, old_value); + break; + case offsetof(FlexcanRegs, ctrl): + if (!(s->regs.mcr & FLEXCAN_MCR_FRZ_ACK)) { + write_mask &=3D freeze_mask_ctrl1; + } + s->regs.ctrl =3D (val & write_mask) | (old_value & ~write_mask); + break; + case offsetof(FlexcanRegs, iflag1): + s->regs.iflag1 &=3D ~val; + if ((s->regs.mcr & FLEXCAN_MCR_FEN) && + (val & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE)) { + flexcan_fifo_pop(s); + } + break; + case offsetof(FlexcanRegs, iflag2): + s->regs.iflag2 &=3D ~val; + break; + case offsetof(FlexcanRegs, ctrl2): + QEMU_FALLTHROUGH; + case offsetof(FlexcanRegs, ecr): + QEMU_FALLTHROUGH; + case offsetof(FlexcanRegs, rxmgmask): + QEMU_FALLTHROUGH; + case offsetof(FlexcanRegs, rx14mask): + QEMU_FALLTHROUGH; + case offsetof(FlexcanRegs, rx15mask): + QEMU_FALLTHROUGH; + case offsetof(FlexcanRegs, rxfgmask): + QEMU_FALLTHROUGH; + case offsetof(FlexcanRegs, rximr[0]) ... offsetof(FlexcanRegs, rximr[6= 3]): + /* these registers can only be written in freeze mode */ + if (!(s->regs.mcr & FLEXCAN_MCR_FRZ_ACK)) { + break; + } + QEMU_FALLTHROUGH; + default: + s->regs_raw[addr / 4] =3D (val & write_mask) | (old_value & ~write= _mask); + + if (addr >=3D offsetof(FlexcanRegs, mb) && + addr < offsetof(FlexcanRegs, _reserved4)) { + /* access to mailbox */ + int mbid =3D (addr - offsetof(FlexcanRegs, mb)) / + sizeof(FlexcanRegsMessageBuffer); + + if (s->locked_mbidx =3D=3D mbid) { + flexcan_mb_unlock(s); + } + + /* check for invalid writes into FIFO region */ + if (s->regs.mcr & FLEXCAN_MCR_FEN && mbid < FLEXCAN_FIFO_DEPTH= ) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Invalid write to Rx-FIFO structure", + DEVICE(s)->canonical_path); + return; + } + + /* run mailbox processing function on write to control word */ + if ((addr & 0xF) =3D=3D 0) { + flexcan_mb_write(s, mbid); + } + } + break; + } + + flexcan_irq_update(s); +} + +static uint64_t flexcan_mem_read(void *opqaue, hwaddr addr, unsigned size) +{ + FlexcanState *s =3D opqaue; + uint32_t rv =3D s->regs_raw[addr >> 2]; + + if (addr >=3D offsetof(FlexcanRegs, mb) && + addr < offsetof(FlexcanRegs, _reserved4)) { + /* reading from mailbox */ + hwaddr offset =3D addr - offsetof(FlexcanRegs, mb); + int mbid =3D offset / sizeof(FlexcanRegsMessageBuffer); + + if (addr % 16 =3D=3D 0 && s->locked_mbidx !=3D mbid) { + /* reading control word locks the mailbox */ + flexcan_mb_unlock(s); + flexcan_mb_lock(s, mbid); + flexcan_irq_update(s); + rv =3D s->regs.mbs[mbid].can_ctrl & ~FLEXCAN_MB_CNT_NOT_SRV; + } + } else if (addr =3D=3D offsetof(FlexcanRegs, timer)) { + flexcan_mb_unlock(s); + flexcan_irq_update(s); + rv =3D flexcan_get_timestamp(s, false); + } + + flexcan_trace_mem_op(s, addr, rv, size, false); + return rv; +} + +static bool flexcan_mem_accepts(void *opaque, hwaddr addr, + unsigned size, bool is_write, + MemTxAttrs attrs) +{ + FlexcanState *s =3D opaque; + + if ((s->regs.ctrl2 & FLEXCAN_CTRL2_WRMFRZ) && + (s->regs.mcr & FLEXCAN_MCR_FRZ_ACK)) { + /* unrestricted access to FlexCAN memory in freeze mode */ + return true; + } else if (attrs.user && (s->regs.mcr & FLEXCAN_MCR_SUPV)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Invalid user-mode access to restricted register= ", + DEVICE(s)->canonical_path); + return false; + } else if (attrs.user && is_write && addr < 4) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Invalid user-mode access to MCR", + DEVICE(s)->canonical_path); + return false; + } + + return true; +} + +static const struct MemoryRegionOps flexcan_ops =3D { + .read =3D flexcan_mem_read, + .write =3D flexcan_mem_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .valid =3D { + .min_access_size =3D 1, + .max_access_size =3D 4, + .unaligned =3D true, + .accepts =3D flexcan_mem_accepts + }, + .impl =3D { + .min_access_size =3D 4, + .max_access_size =3D 4, + .unaligned =3D false + }, +}; + +static CanBusClientInfo flexcan_bus_client_info =3D { + .can_receive =3D flexcan_can_receive, + .receive =3D flexcan_receive, +}; + +static int flexcan_connect_to_bus(FlexcanState *s, CanBusState *bus) +{ + s->bus_client.info =3D &flexcan_bus_client_info; + + if (can_bus_insert_client(bus, &s->bus_client) < 0) { + return -1; + } + return 0; +} + +static void flexcan_init(Object *obj) +{ + FlexcanState *s =3D CAN_FLEXCAN(obj); + + memory_region_init_io( + &s->iomem, obj, &flexcan_ops, s, TYPE_CAN_FLEXCAN, + offsetof(FlexcanRegs, _reserved6) + ); +} + +static void flexcan_realize(DeviceState *dev, Error **errp) +{ + FlexcanState *s =3D CAN_FLEXCAN(dev); + + if (s->canbus) { + if (flexcan_connect_to_bus(s, s->canbus) < 0) { + error_setg(errp, "%s: flexcan_connect_to_bus failed", + dev->canonical_path); + return; + } + } + + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); + sysbus_init_irq(SYS_BUS_DEVICE(SYS_BUS_DEVICE(dev)), &s->irq); +} + +static const VMStateDescription vmstate_can =3D { + .name =3D TYPE_CAN_FLEXCAN, + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (const VMStateField[]) { + VMSTATE_INT64(timer_start, FlexcanState), + VMSTATE_UINT32_ARRAY(regs_raw, FlexcanState, sizeof(FlexcanRegs) /= 4), + VMSTATE_INT32(locked_mbidx, FlexcanState), + VMSTATE_INT32(smb_target_mbidx, FlexcanState), + VMSTATE_END_OF_LIST(), + }, +}; + +static const Property flexcan_properties[] =3D { + DEFINE_PROP_LINK("canbus", FlexcanState, canbus, TYPE_CAN_BUS, + CanBusState *), +}; + +static void flexcan_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + rc->phases.enter =3D flexcan_reset_enter; + rc->phases.hold =3D flexcan_reset_hold; + dc->realize =3D flexcan_realize; + device_class_set_props(dc, flexcan_properties); + dc->vmsd =3D &vmstate_can; + dc->desc =3D "i.MX FLEXCAN Controller"; +} + +static const TypeInfo flexcan_info =3D { + .name =3D TYPE_CAN_FLEXCAN, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(FlexcanState), + .class_init =3D flexcan_class_init, + .instance_init =3D flexcan_init, +}; + +static void can_register_types(void) +{ + type_register_static(&flexcan_info); +} +type_init(can_register_types) diff --git a/hw/net/can/flexcan_regs.h b/hw/net/can/flexcan_regs.h new file mode 100644 index 0000000000..cc32a2f035 --- /dev/null +++ b/hw/net/can/flexcan_regs.h @@ -0,0 +1,196 @@ +/* + * Field bitmasks and register structs definitions for FlexCAN + * + * This implementation is based on the following datasheet: + * i.MX 6Dual/6Quad Applications Processor Reference Manual + * Document Number: IMX6DQRM, Rev. 6, 05/2020 + * + * Copyright (c) 2025 Matyas Bobek + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include "qemu/bitops.h" + +#ifndef HW_CAN_FLEXCAN_REGS_H +#define HW_CAN_FLEXCAN_REGS_H + +#define FLEXCAN_GENMASK(h, l) (((~(uint32_t)0) >> (31 - (h) + (l))) << (l)) + +/** + * The following macros were originally written for the Linux kernel by: + * Andrey Volkov + * Sascha Hauer + * Marc Kleine-Budde + * David Jander + */ + +/* FLEXCAN module configuration register (CANMCR) bits */ +#define FLEXCAN_MCR_MDIS BIT(31) +#define FLEXCAN_MCR_FRZ BIT(30) +#define FLEXCAN_MCR_FEN BIT(29) +#define FLEXCAN_MCR_HALT BIT(28) +#define FLEXCAN_MCR_NOT_RDY BIT(27) +#define FLEXCAN_MCR_WAK_MSK BIT(26) +#define FLEXCAN_MCR_SOFTRST BIT(25) +#define FLEXCAN_MCR_FRZ_ACK BIT(24) +#define FLEXCAN_MCR_SUPV BIT(23) +#define FLEXCAN_MCR_SLF_WAK BIT(22) +#define FLEXCAN_MCR_WRN_EN BIT(21) +#define FLEXCAN_MCR_LPM_ACK BIT(20) +#define FLEXCAN_MCR_WAK_SRC BIT(19) +#define FLEXCAN_MCR_DOZE BIT(18) +#define FLEXCAN_MCR_SRX_DIS BIT(17) +#define FLEXCAN_MCR_IRMQ BIT(16) +#define FLEXCAN_MCR_LPRIO_EN BIT(13) +#define FLEXCAN_MCR_AEN BIT(12) +#define FLEXCAN_MCR_FDEN BIT(11) +#define FLEXCAN_MCR_MAXMB(x) ((x) & 0x7f) +#define FLEXCAN_MCR_IDAM_A (0x0 << 8) +#define FLEXCAN_MCR_IDAM_B (0x1 << 8) +#define FLEXCAN_MCR_IDAM_C (0x2 << 8) +#define FLEXCAN_MCR_IDAM_D (0x3 << 8) +#define FLEXCAN_MCR_IDAM_MASK (0x3 << 8) + +/* FLEXCAN control register (CANCTRL) bits */ +#define FLEXCAN_CTRL_PRESDIV(x) (((x) & 0xFF) << 24) +#define FLEXCAN_CTRL_PRESDIV_MASK FLEXCAN_CTRL_PRESDIV(UINT32_MAX) +#define FLEXCAN_CTRL_RJW(x) (((x) & 0x03) << 22) +#define FLEXCAN_CTRL_RJW_MASK FLEXCAN_CTRL_RJW(UINT32_MAX) +#define FLEXCAN_CTRL_PSEG1(x) (((x) & 0x07) << 19) +#define FLEXCAN_CTRL_PSEG1_MASK FLEXCAN_CTRL_PSEG1(UINT32_MAX) +#define FLEXCAN_CTRL_PSEG2(x) (((x) & 0x07) << 16) +#define FLEXCAN_CTRL_PSEG2_MASK FLEXCAN_CTRL_PSEG2(UINT32_MAX) +#define FLEXCAN_CTRL_BOFF_MSK BIT(15) +#define FLEXCAN_CTRL_ERR_MSK BIT(14) +#define FLEXCAN_CTRL_CLK_SRC BIT(13) +#define FLEXCAN_CTRL_LPB BIT(12) +#define FLEXCAN_CTRL_TWRN_MSK BIT(11) +#define FLEXCAN_CTRL_RWRN_MSK BIT(10) +#define FLEXCAN_CTRL_SMP BIT(7) +#define FLEXCAN_CTRL_BOFF_REC BIT(6) +#define FLEXCAN_CTRL_TSYN BIT(5) +#define FLEXCAN_CTRL_LBUF BIT(4) +#define FLEXCAN_CTRL_LOM BIT(3) +#define FLEXCAN_CTRL_PROPSEG(x) ((x) & 0x07) +#define FLEXCAN_CTRL_PROPSEG_MASK FLEXCAN_CTRL_PROPSEG(UINT32_MAX) +#define FLEXCAN_CTRL_ERR_BUS (FLEXCAN_CTRL_ERR_MSK) +#define FLEXCAN_CTRL_ERR_STATE \ + (FLEXCAN_CTRL_TWRN_MSK | FLEXCAN_CTRL_RWRN_MSK | \ + FLEXCAN_CTRL_BOFF_MSK) +#define FLEXCAN_CTRL_ERR_ALL \ + (FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE) + +/* FLEXCAN control register 2 (CTRL2) bits */ +#define FLEXCAN_CTRL2_ECRWRE BIT(29) +#define FLEXCAN_CTRL2_WRMFRZ BIT(28) +#define FLEXCAN_CTRL2_RFFN(x) (((x) & 0x0f) << 24) +#define FLEXCAN_CTRL2_TASD(x) (((x) & 0x1f) << 19) +#define FLEXCAN_CTRL2_MRP BIT(18) +#define FLEXCAN_CTRL2_RRS BIT(17) +#define FLEXCAN_CTRL2_EACEN BIT(16) +#define FLEXCAN_CTRL2_ISOCANFDEN BIT(12) + +/* FLEXCAN memory error control register (MECR) bits */ +#define FLEXCAN_MECR_ECRWRDIS BIT(31) +#define FLEXCAN_MECR_HANCEI_MSK BIT(19) +#define FLEXCAN_MECR_FANCEI_MSK BIT(18) +#define FLEXCAN_MECR_CEI_MSK BIT(16) +#define FLEXCAN_MECR_HAERRIE BIT(15) +#define FLEXCAN_MECR_FAERRIE BIT(14) +#define FLEXCAN_MECR_EXTERRIE BIT(13) +#define FLEXCAN_MECR_RERRDIS BIT(9) +#define FLEXCAN_MECR_ECCDIS BIT(8) +#define FLEXCAN_MECR_NCEFAFRZ BIT(7) + +/* FLEXCAN error and status register (ESR) bits */ +#define FLEXCAN_ESR_SYNCH BIT(18) +#define FLEXCAN_ESR_TWRN_INT BIT(17) +#define FLEXCAN_ESR_RWRN_INT BIT(16) +#define FLEXCAN_ESR_BIT1_ERR BIT(15) +#define FLEXCAN_ESR_BIT0_ERR BIT(14) +#define FLEXCAN_ESR_ACK_ERR BIT(13) +#define FLEXCAN_ESR_CRC_ERR BIT(12) +#define FLEXCAN_ESR_FRM_ERR BIT(11) +#define FLEXCAN_ESR_STF_ERR BIT(10) +#define FLEXCAN_ESR_TX_WRN BIT(9) +#define FLEXCAN_ESR_RX_WRN BIT(8) +#define FLEXCAN_ESR_IDLE BIT(7) +#define FLEXCAN_ESR_BOFF_INT BIT(2) +#define FLEXCAN_ESR_ERR_INT BIT(1) +#define FLEXCAN_ESR_WAK_INT BIT(0) + +/* FLEXCAN Bit Timing register (CBT) bits */ +#define FLEXCAN_CBT_BTF BIT(31) +#define FLEXCAN_CBT_EPRESDIV_MASK FLEXCAN_GENMASK(30, 21) +#define FLEXCAN_CBT_ERJW_MASK FLEXCAN_GENMASK(20, 16) +#define FLEXCAN_CBT_EPROPSEG_MASK FLEXCAN_GENMASK(15, 10) +#define FLEXCAN_CBT_EPSEG1_MASK FLEXCAN_GENMASK(9, 5) +#define FLEXCAN_CBT_EPSEG2_MASK FLEXCAN_GENMASK(4, 0) + +/* FLEXCAN FD control register (FDCTRL) bits */ +#define FLEXCAN_FDCTRL_FDRATE BIT(31) +#define FLEXCAN_FDCTRL_MBDSR1 FLEXCAN_GENMASK(20, 19) +#define FLEXCAN_FDCTRL_MBDSR0 FLEXCAN_GENMASK(17, 16) +#define FLEXCAN_FDCTRL_MBDSR_8 0x0 +#define FLEXCAN_FDCTRL_MBDSR_12 0x1 +#define FLEXCAN_FDCTRL_MBDSR_32 0x2 +#define FLEXCAN_FDCTRL_MBDSR_64 0x3 +#define FLEXCAN_FDCTRL_TDCEN BIT(15) +#define FLEXCAN_FDCTRL_TDCFAIL BIT(14) +#define FLEXCAN_FDCTRL_TDCOFF FLEXCAN_GENMASK(12, 8) +#define FLEXCAN_FDCTRL_TDCVAL FLEXCAN_GENMASK(5, 0) + +/* FLEXCAN FD Bit Timing register (FDCBT) bits */ +#define FLEXCAN_FDCBT_FPRESDIV_MASK FLEXCAN_GENMASK(29, 20) +#define FLEXCAN_FDCBT_FRJW_MASK FLEXCAN_GENMASK(18, 16) +#define FLEXCAN_FDCBT_FPROPSEG_MASK FLEXCAN_GENMASK(14, 10) +#define FLEXCAN_FDCBT_FPSEG1_MASK FLEXCAN_GENMASK(7, 5) +#define FLEXCAN_FDCBT_FPSEG2_MASK FLEXCAN_GENMASK(2, 0) + +/* FLEXCAN CRC Register (CRCR) bits */ +#define FLEXCAN_CRCR_MBCRC_MASK FLEXCAN_GENMASK(22, 16) +#define FLEXCAN_CRCR_MBCRC(x) (((x) & FLEXCAN_CRCR_MBCRC_MASK) <= < 16) +#define FLEXCAN_CRCR_TXCRC_MASK FLEXCAN_GENMASK(14, 0) +#define FLEXCAN_CRCR_TXCRC(x) ((x) & FLEXCAN_CRCR_TXCRC_MASK) + +/* FLEXCAN interrupt flag register (IFLAG) bits */ +/* Errata ERR005829 step7: Reserve first valid MB */ +#define I_FIFO_OVERFLOW 7 +#define I_FIFO_WARN 6 +#define I_FIFO_AVAILABLE 5 + +#define FLEXCAN_TX_MB_RESERVED_RX_FIFO 8 +#define FLEXCAN_TX_MB_RESERVED_RX_MAILBOX 0 +#define FLEXCAN_RX_MB_RX_MAILBOX_FIRST (FLEXCAN_TX_MB_RESERVED_RX_MAILBOX= + 1) +#define FLEXCAN_IFLAG_MB(x) BIT_ULL(x) +#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(I_FIFO_OVERFLOW) +#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(I_FIFO_WARN) +#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(I_FIFO_AVAILABLE) + +/* FLEXCAN message buffers */ +#define FLEXCAN_MB_CODE_RX_BUSY_BIT (0x1 << 24) +#define FLEXCAN_MB_CODE_RX_INACTIVE (0x0 << 24) +#define FLEXCAN_MB_CODE_RX_EMPTY (0x4 << 24) +#define FLEXCAN_MB_CODE_RX_FULL (0x2 << 24) +#define FLEXCAN_MB_CODE_RX_OVERRUN (0x6 << 24) +#define FLEXCAN_MB_CODE_RX_RANSWER (0xa << 24) + +#define FLEXCAN_MB_CODE_TX_INACTIVE (0x8 << 24) +#define FLEXCAN_MB_CODE_TX_ABORT (0x9 << 24) +#define FLEXCAN_MB_CODE_TX_DATA (0xc << 24) +#define FLEXCAN_MB_CODE_TX_TANSWER (0xe << 24) + +#define FLEXCAN_MB_CODE(x) (((x) & 0xF) << 24) +#define FLEXCAN_MB_CODE_MASK FLEXCAN_MB_CODE(UINT32_MAX) + +#define FLEXCAN_MB_CNT_EDL BIT(31) +#define FLEXCAN_MB_CNT_BRS BIT(30) +#define FLEXCAN_MB_CNT_ESI BIT(29) +#define FLEXCAN_MB_CNT_SRR BIT(22) +#define FLEXCAN_MB_CNT_IDE BIT(21) +#define FLEXCAN_MB_CNT_RTR BIT(20) +#define FLEXCAN_MB_CNT_LENGTH(x) (((x) & 0xF) << 16) +#define FLEXCAN_MB_CNT_TIMESTAMP(x) ((x) & 0xFFFF) +#define FLEXCAN_MB_CNT_TIMESTAMP_MASK FLEXCAN_MB_CNT_TIMESTAMP(UINT32_MA= X) + +#endif diff --git a/hw/net/can/meson.build b/hw/net/can/meson.build index 7382344628..401afde2e4 100644 --- a/hw/net/can/meson.build +++ b/hw/net/can/meson.build @@ -6,3 +6,4 @@ system_ss.add(when: 'CONFIG_CAN_CTUCANFD', if_true: files('= ctucan_core.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')) +system_ss.add(when: 'CONFIG_CAN_FLEXCAN', if_true: files('flexcan.c')) diff --git a/hw/net/can/trace-events b/hw/net/can/trace-events index de64ac1b31..7500f10d7a 100644 --- a/hw/net/can/trace-events +++ b/hw/net/can/trace-events @@ -1,3 +1,21 @@ +# flexcan.c +flexcan_irq_update(const char *inst, uint32_t mb_irqs1, uint32_t mb_irqs2,= int setting) "%s: irqs1 0x%08x irqs2 0x%08x request %i" +flexcan_set_mcr(const char *inst, const char *enabled, const char *freeze,= const char *fifo, const char *rdy, const char *sync) "%s: %s %s %s %s %s" +flexcan_mb_write(const char *inst, int mbidx, const char *code, int is_mai= lbox, uint32_t ctrl, uint32_t id) "%s: mbidx %i code %s is_mailbox %i ctrl = 0x%08x id 0x%08x" +flexcan_mb_lock(const char *inst, int mbidx, int had_rx_code) "%s: mbidx %= i had_rx_code %i" +flexcan_mb_unlock(const char *inst, int mbidx, const char *pending_frame) = "%s: mbidx %i%s" +flexcan_fifo_pop(const char *inst, int non_empty_before, int non_empty_aft= er) "%s: non_empty before %i non_empty_after %i" +flexcan_fifo_push(const char *inst, int n_occupied) "%s: n_slots_occupied = %i" +flexcan_reset(const char *inst) "%s: resetting" +flexcan_mem_op(const char *inst, const char *op, uint32_t v, int offset, c= onst char *reg_name, int size) "%s: %s 0x%08x at offset %i register %s size= %i" +flexcan_get_timestamp(const char *inst, int64_t time_elapsed_ms, uint32_t = bitrate, uint64_t cycles, uint32_t shift, uint32_t timestamp) "%s: time_ela= psed %" PRIi64 "ms bitrate %ub/s cycles %" PRIu64 " shift %u timestamp 0x%0= 4x" +flexcan_get_bitrate(const char *inst, uint32_t pe_freq, uint32_t prediv, u= int32_t s_freq, uint32_t tseg1, uint32_t tseg2, uint32_t quata_per_bit, uin= t32_t bitrate) "%s: pe_freq %uHz prescaler %u s_freq %uHz tseg1 %uq tseg2 %= uq total %uq/b bitrate %ub/s" +flexcan_timer_start(const char *inst, uint32_t bitrate, uint32_t value) "%= s: bitrate %ub/s value 0x%04x" +flexcan_timer_stop(const char *inst, uint32_t bitrate, uint32_t value) "%s= : bitrate %ub/s value 0x%04x" +flexcan_timer_overflow(const char *inst, int64_t current_time, int64_t tim= er_start, int64_t elapsed_ns) "%s: current_time %" PRIi64 "timer_start %" P= RIi64 "elapsed_ns %" PRIi64 +flexcan_mb_rx_check_mb(const char *inst, int mbidx, const char *code, int = is_matched, int is_ftr, int is_serviced, int is_locked) "%s: checking mb %i= code %s is_matched %i is_free_to_receive %i is_serviced %i is_locked %i" +flexcan_receive(const char *inst, size_t n_frames) "%s: received %zu frame= s" + # xlnx-zynqmp-can.c xlnx_can_update_irq(uint32_t isr, uint32_t ier, uint32_t irq) "ISR: 0x%08x= IER: 0x%08x IRQ: 0x%08x" xlnx_can_reset(uint32_t val) "Resetting controller with value =3D 0x%08x" diff --git a/include/hw/net/flexcan.h b/include/hw/net/flexcan.h new file mode 100644 index 0000000000..0be60ed8cb --- /dev/null +++ b/include/hw/net/flexcan.h @@ -0,0 +1,144 @@ +/* + * QEMU model of the NXP FLEXCAN device. + * + * Copyright (c) 2025 Matyas Bobek + * + * Based on CTU CAN FD emulation implemented by Jan Charvat. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_CAN_FLEXCAN_H +#define HW_CAN_FLEXCAN_H + +#include "net/can_emu.h" +#include "qom/object.h" +#include "hw/misc/imx_ccm.h" + +#define FLEXCAN_FIFO_DEPTH 6 +#define FLEXCAN_MAILBOX_COUNT 64 + +/** + * Definitions of structs FlexcanRegs and FlexcanRegsMessageBuffer were + * originally written for the Linux kernel by: + * Andrey Volkov + * Sascha Hauer + * Marc Kleine-Budde + * David Jander + */ + +/* view of single message buffer registers */ +typedef struct FlexcanRegsMessageBuffer { + uint32_t can_ctrl; + uint32_t can_id; + uint32_t data[2]; +} FlexcanRegsMessageBuffer; + +/* RX FIFO view of message buffer registers */ +typedef struct FlexcanRegsRXFifo { + /* 6 message buffer deep queue, queue back first */ + FlexcanRegsMessageBuffer mb_back; + FlexcanRegsMessageBuffer mbs_queue[FLEXCAN_FIFO_DEPTH - 1]; + + /* number of filter elements active depends on ctrl2 | FLEXCAN_CTRL2_R= FFN */ + uint32_t filter_table_els[128]; +} FlexcanRegsRXFifo; + +/* FlexCAN register in hw layout */ +typedef struct FlexcanRegs { + uint32_t mcr; /* 0x00 */ + uint32_t ctrl; /* 0x04 - not affected by soft reset */ + uint32_t timer; /* 0x08 */ + uint32_t tcr; /* 0x0C */ + uint32_t rxmgmask; /* 0x10 - not affected by soft reset */ + uint32_t rx14mask; /* 0x14 - not affected by soft reset */ + uint32_t rx15mask; /* 0x18 - not affected by soft reset */ + uint32_t ecr; /* 0x1C */ + uint32_t esr; /* 0x20 */ + uint32_t imask2; /* 0x24 */ + uint32_t imask1; /* 0x28 */ + uint32_t iflag2; /* 0x2C */ + uint32_t iflag1; /* 0x30 */ + union { /* 0x34 */ + uint32_t gfwr_mx28; /* MX28, MX53 */ + uint32_t ctrl2; /* MX6, VF610 - not affected by soft rese= t */ + }; + uint32_t esr2; /* 0x38 */ + uint32_t imeur; /* 0x3C, unused */ + uint32_t lrfr; /* 0x40, unused */ + uint32_t crcr; /* 0x44 */ + uint32_t rxfgmask; /* 0x48 */ + uint32_t rxfir; /* 0x4C - not affected by soft reset */ + uint32_t cbt; /* 0x50, unused - not affected by soft re= set */ + uint32_t _reserved2; /* 0x54 */ + uint32_t dbg1; /* 0x58, unused */ + uint32_t dbg2; /* 0x5C, unused */ + uint32_t _reserved3[8]; /* 0x60 */ + union { /* 0x80 - not affected by soft reset */ + uint32_t mb[sizeof(FlexcanRegsMessageBuffer) * FLEXCAN_MAILBOX_COU= NT]; + FlexcanRegsMessageBuffer mbs[FLEXCAN_MAILBOX_COUNT]; + FlexcanRegsRXFifo fifo; + }; + uint32_t _reserved4[256]; /* 0x480 */ + uint32_t rximr[64]; /* 0x880 - not affected by soft reset */ + uint32_t _reserved5[24]; /* 0x980 */ + uint32_t gfwr_mx6; /* 0x9E0 - MX6 */ + + /* the rest is unused except for SMB */ + uint32_t _reserved6[39]; /* 0x9E4 */ + uint32_t _rxfir[6]; /* 0xA80 */ + uint32_t _reserved8[2]; /* 0xA98 */ + uint32_t _rxmgmask; /* 0xAA0 */ + uint32_t _rxfgmask; /* 0xAA4 */ + uint32_t _rx14mask; /* 0xAA8 */ + uint32_t _rx15mask; /* 0xAAC */ + uint32_t tx_smb[4]; /* 0xAB0 */ + union { /* 0xAC0, used for SMB emulation */ + uint32_t rx_smb0_raw[4]; + FlexcanRegsMessageBuffer rx_smb0; + }; + uint32_t rx_smb1[4]; /* 0xAD0 */ + uint32_t mecr; /* 0xAE0 */ + uint32_t erriar; /* 0xAE4 */ + uint32_t erridpr; /* 0xAE8 */ + uint32_t errippr; /* 0xAEC */ + uint32_t rerrar; /* 0xAF0 */ + uint32_t rerrdr; /* 0xAF4 */ + uint32_t rerrsynr; /* 0xAF8 */ + uint32_t errsr; /* 0xAFC */ + uint32_t _reserved7[64]; /* 0xB00 */ + uint32_t fdctrl; /* 0xC00 - not affected by soft reset */ + uint32_t fdcbt; /* 0xC04 - not affected by soft reset */ + uint32_t fdcrc; /* 0xC08 */ + uint32_t _reserved9[199]; /* 0xC0C */ + uint32_t tx_smb_fd[18]; /* 0xF28 */ + uint32_t rx_smb0_fd[18]; /* 0xF70 */ + uint32_t rx_smb1_fd[18]; /* 0xFB8 */ +} FlexcanRegs; + +typedef struct FlexcanState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + IMXCCMState *ccm; + qemu_irq irq; + + CanBusState *canbus; + CanBusClientState bus_client; + + union { + FlexcanRegs regs; + uint32_t regs_raw[sizeof(FlexcanRegs) / 4]; + }; + int64_t timer_start; + uint64_t last_rx_timer_cycles; + int32_t locked_mbidx; + int32_t smb_target_mbidx; + uint32_t timer_freq; +} FlexcanState; + +#define TYPE_CAN_FLEXCAN "flexcan" + +OBJECT_DECLARE_SIMPLE_TYPE(FlexcanState, CAN_FLEXCAN); + +#endif --=20 2.54.0 From nobody Sat May 30 17:31:18 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; 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=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1779988783; cv=none; d=zohomail.com; s=zohoarc; b=iDfPIBc3Oh+FDF0ANEo/lSne4ccGrW+F+uSlM3YhtENHfmTCQuMrEx9mbLDJel2SCiN1X3eVJz3sFUB+/UI2VL1cAtyGcLBN+FN2yfSQM1+IWeayr6dkzuJWeXpZQLY+id0ZQxVsVCewo7r0peDz3sfLm86a7JCc4RaaI5iIP8s= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779988783; h=Content-Type: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:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Rq11aXHJ23GUquXcGKqaH+GK8vzPjsmZcvK9Ayo3N+Y=; b=RdWXWbCim2YEYPVVrjQs1PPXNjKeN0OUieTOXU4ibOasSSUmul8LJOFvuGurOkK80BlAEitqAwXhc6MwIkm9iR55F3ajBoyUQtc0ugpKv3ji2UMqJn46pqQXKh/SHfWYiJUEFD9YtspgfQ76QKUMdF9ZNGHm6fZyttXtwEXJFKk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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 lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779988783631199.7854875560646; Thu, 28 May 2026 10:19:43 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wSeMn-0006f3-Vr; Thu, 28 May 2026 13:17:58 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wSeMR-0006UU-6w for qemu-devel@nongnu.org; Thu, 28 May 2026 13:17:36 -0400 Received: from mail-wm1-x32d.google.com ([2a00:1450:4864:20::32d]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wSeMO-00048f-6N for qemu-devel@nongnu.org; Thu, 28 May 2026 13:17:34 -0400 Received: by mail-wm1-x32d.google.com with SMTP id 5b1f17b1804b1-4891e86fabeso39035305e9.1 for ; Thu, 28 May 2026 10:17:31 -0700 (PDT) Received: from acidburn.pod.cvut.cz (acidburn.pod.cvut.cz. [147.32.90.2]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49092968066sm53774085e9.15.2026.05.28.10.17.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2026 10:17:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779988650; x=1780593450; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Rq11aXHJ23GUquXcGKqaH+GK8vzPjsmZcvK9Ayo3N+Y=; b=BrXGJnpLru87cLNESmJaZFCncMrX2LrZ/MhN8WY8FaDX8s+yBs+6z5+xcPefODAY5N 0mZSdeC73Faq1MLbDluv4q/g1mc8snnC2gMQq+xBoed9LAUX0Vj4rmV9+DfzfX+ZD42N WJIKQICBWkPzgAompKj70p1q7OoBDxBBncMKm49+2gUEZbEGAHW3GNusN0j8E4DgslIn jdpzJOcl5jv3gz5OkRPv3F6yq8XJWGZ+P/jaRDzsTrVCPd41ooFOzC5yb/bWGsEu9KKQ oo3SdNCdRLehAgW4xdcN+Peo2NTjp1HD9xcU19eV1Xwp5/lVXgLAtUnAt8dWYpIQh5aH VMcA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779988650; x=1780593450; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Rq11aXHJ23GUquXcGKqaH+GK8vzPjsmZcvK9Ayo3N+Y=; b=SKrjdgyZeDirfhSIlTA5C8Ot2d9y2c/VBX3qCPxIny4wURw419VD31YZoYRbExbn66 WcMk1I+R1dQ7MdGmdJ6/xr/RtUUh7aQ2VaWv7gbzCqngH1hj7rhDF5TuDCG5w9TaKsDl d7UYN7ViKuh2ZkcRbrqA1WhEtAxdJ06u3MprfYyKAAOvCpqnt7XuBN6K0AB8Htup7hHA 9kLOmwPjgXifN6xRvuH6eqrgjOa2QYMcErt9F/ISbXjX3eorH5Zu/TZe2mZ4yeMxSjdB AvMFTxUavVZrPMXX76rY23Kts7Kn9p8qPVqTk6d22cQwG+RJkM7jDhunG7nAYzKZovJq +wdA== X-Gm-Message-State: AOJu0Ywgn0YtvstkRaBO4y2VAyjc/+TZidDUSEsQ3Bs7LZiiM0orYsFH 3pLsLBKQSAHMhDTmqIiYJ2A9F6czVm2jWPV2bRlXhyFts7GAWDGS0gb41IET6012 X-Gm-Gg: Acq92OFuht4ZpvCzmAFX93irySCz4nC4ctbr4eY2zKRGx8D+Ij+Cn6bA62QPaft8r1G GNYjUdSvgsZUPVTHCZPzN8fpZ7c04rvzAFiakk8QjzEWhhIzX1lm4yp9EcANBHUyQv9+CJhJ1Gd 1I1w0DdjqEyeGrALv7zVXrtEYRbFNGuUN7zzA4U5KSsqCNHAqvJCPAsS3GGw3OZQBZTp04Ar9lM LaYeUppLD3GtM+RenvGinRaK9ubo9I0qXoMyABRBkT0f4e3NzC0RSs7BsmpXliDMq0r0BSE2yMK offwZoW64QN3Zl9+2gvwWnztnq15UW+WcySRe4ZRJdIFpSHP5U7Hq0ToJikkYFhddsOlXpFrM4R bAD/oy75bpua+FlZQLpQRwJqdCfelHwcYCenyNGQJ3oJ+uaHx3B+UkTI7E0/pLnmqFGeop00T7l tO9SMvilM62uWObEUJkCg3JKgqfnM1zw5m9oh543KI3GxUtopQ1DC4CI3V6TOJLUU6 X-Received: by 2002:a05:600c:1393:b0:489:c57:7836 with SMTP id 5b1f17b1804b1-490428e5b31mr464590265e9.27.1779988650266; Thu, 28 May 2026 10:17:30 -0700 (PDT) From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Bobek?= To: qemu-devel@nongnu.org, Matyas Bobek , Pavel Pisa , Bernhard Beschow Cc: qemu-arm@nongnu.org, Marc Kleine-Budde , Oliver Hartkopp , Nikita Ostrenkov , Peter Maydell , Andrey Volkov , =?UTF-8?q?Maty=C3=A1=C5=A1=20Bobek?= Subject: [PATCH v4 5/7] hw/arm: Plug FlexCAN into FSL_IMX6 and Sabrelite Date: Thu, 28 May 2026 19:17:15 +0200 Message-ID: <9b0a0ffeeeff5ca0ec9525659bb2296850a88c62.1779986496.git.matyas.bobek@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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=lists1p.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::32d; envelope-from=matyas.bobek@gmail.com; helo=mail-wm1-x32d.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, 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: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1779988784942158500 FlexcanState is added to the FslIMX6State struct like other peripherals. Add two new machine properties to Sabrelite machine for linking the embedded FlexCAN instances to QEMU CAN buses by name. No other machine uses FslIMX6State. Signed-off-by: Maty=C3=A1=C5=A1 Bobek Signed-off-by: Pavel Pisa Tested-by: Pavel Pisa Reviewed-by: Bernhard Beschow Reviewed-by: Pavel Pisa --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx6.c | 29 +++++++++++++++++++++++++++++ hw/arm/sabrelite.c | 24 ++++++++++++++++++++++++ include/hw/arm/fsl-imx6.h | 6 ++++++ 4 files changed, 60 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 5b198402d5..c44fc562e1 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -519,6 +519,7 @@ config FSL_IMX6 select IMX_FEC select IMX_I2C select IMX_USBPHY + select CAN_FLEXCAN select WDT_IMX2 select PL310 # cache controller select PCI_EXPRESS_DESIGNWARE diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index f663ddbf0a..337921d17d 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -90,6 +90,10 @@ static void fsl_imx6_init(Object *obj) snprintf(name, NAME_SIZE, "spi%d", i + 1); object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI); } + for (i =3D 0; i < FSL_IMX6_NUM_CANS; i++) { + snprintf(name, NAME_SIZE, "flexcan%d", i + 1); + object_initialize_child(obj, name, &s->can[i], TYPE_CAN_FLEXCAN); + } for (i =3D 0; i < FSL_IMX6_NUM_WDTS; i++) { snprintf(name, NAME_SIZE, "wdt%d", i); object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT); @@ -377,6 +381,27 @@ static void fsl_imx6_realize(DeviceState *dev, Error *= *errp) qdev_get_gpio_in(gic, spi_table[i].irq)); } =20 + /* Initialize all FLEXCANs */ + for (i =3D 0; i < FSL_IMX6_NUM_CANS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } flexcan_table[FSL_IMX6_NUM_CANS] =3D { + { FSL_IMX6_CAN1_ADDR, FSL_IMX6_FLEXCAN1_IRQ }, + { FSL_IMX6_CAN2_ADDR, FSL_IMX6_FLEXCAN2_IRQ }, + }; + + s->can[i].ccm =3D IMX_CCM(&s->ccm); + object_property_set_link(OBJECT(&s->can[i]), "canbus", + OBJECT(s->canbus[i]), &error_abort); + + sysbus_realize(SYS_BUS_DEVICE(&s->can[i]), &error_abort); + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->can[i]), 0, flexcan_table[i].ad= dr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->can[i]), 0, + qdev_get_gpio_in(gic, flexcan_table[i].irq)); + } + object_property_set_uint(OBJECT(&s->eth), "phy-num", s->phy_num, &error_abort); qemu_configure_nic_device(DEVICE(&s->eth), true, NULL); @@ -480,6 +505,10 @@ static void fsl_imx6_realize(DeviceState *dev, Error *= *errp) =20 static const Property fsl_imx6_properties[] =3D { DEFINE_PROP_UINT32("fec-phy-num", FslIMX6State, phy_num, 0), + DEFINE_PROP_LINK("canbus0", FslIMX6State, canbus[0], TYPE_CAN_BUS, + CanBusState *), + DEFINE_PROP_LINK("canbus1", FslIMX6State, canbus[1], TYPE_CAN_BUS, + CanBusState *), }; =20 static void fsl_imx6_class_init(ObjectClass *oc, const void *data) diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c index 7e036e6388..84bbc2f979 100644 --- a/hw/arm/sabrelite.c +++ b/hw/arm/sabrelite.c @@ -24,6 +24,7 @@ struct SabreliteMachineState { MachineState parent_obj; =20 FslIMX6State soc; + CanBusState *canbus[FSL_IMX6_NUM_CANS]; }; =20 #define TYPE_SABRELITE_MACHINE MACHINE_TYPE_NAME("sabrelite") @@ -64,6 +65,13 @@ static void sabrelite_init(MachineState *machine) /* Ethernet PHY address is 6 */ object_property_set_int(OBJECT(&s->soc), "fec-phy-num", 6, &error_fata= l); =20 + for (int i =3D 0; i < FSL_IMX6_NUM_CANS; i++) { + g_autofree char *bus_name =3D g_strdup_printf("canbus%d", i); + + object_property_set_link(OBJECT(&s->soc), bus_name, + OBJECT(s->canbus[i]), &error_fatal); + } + qdev_realize(DEVICE(&s->soc), NULL, &error_fatal); =20 memory_region_add_subregion(get_system_memory(), FSL_IMX6_MMDC_ADDR, @@ -112,6 +120,21 @@ static void sabrelite_init(MachineState *machine) } } =20 +static void sabrelite_machine_instance_init(Object *obj) +{ + SabreliteMachineState *s =3D SABRELITE_MACHINE(obj); + + 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 sabrelite_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc =3D MACHINE_CLASS(oc); @@ -128,6 +151,7 @@ static const TypeInfo sabrelite_machine_init_typeinfo = =3D { .name =3D TYPE_SABRELITE_MACHINE, .parent =3D TYPE_MACHINE, .class_init =3D sabrelite_machine_class_init, + .instance_init =3D sabrelite_machine_instance_init, .instance_size =3D sizeof(SabreliteMachineState), .abstract =3D false, .interfaces =3D arm_machine_interfaces, diff --git a/include/hw/arm/fsl-imx6.h b/include/hw/arm/fsl-imx6.h index cddd100dd6..8ea1677e86 100644 --- a/include/hw/arm/fsl-imx6.h +++ b/include/hw/arm/fsl-imx6.h @@ -30,12 +30,14 @@ #include "hw/sd/sdhci.h" #include "hw/ssi/imx_spi.h" #include "hw/net/imx_fec.h" +#include "hw/net/flexcan.h" #include "hw/usb/chipidea.h" #include "hw/usb/imx-usb-phy.h" #include "hw/pci-host/designware.h" #include "hw/core/or-irq.h" #include "system/memory.h" #include "target/arm/cpu.h" +#include "net/can_emu.h" #include "qom/object.h" =20 #define TYPE_FSL_IMX6 "fsl-imx6" @@ -51,6 +53,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(FslIMX6State, FSL_IMX6) #define FSL_IMX6_NUM_WDTS 2 #define FSL_IMX6_NUM_USB_PHYS 2 #define FSL_IMX6_NUM_USBS 4 +#define FSL_IMX6_NUM_CANS 2 =20 struct FslIMX6State { /*< private >*/ @@ -73,6 +76,7 @@ struct FslIMX6State { IMXUSBPHYState usbphy[FSL_IMX6_NUM_USB_PHYS]; ChipideaState usb[FSL_IMX6_NUM_USBS]; IMXFECState eth; + FlexcanState can[FSL_IMX6_NUM_CANS]; DesignwarePCIEHost pcie; OrIRQState pcie4_msi_irq; MemoryRegion rom; @@ -80,6 +84,8 @@ struct FslIMX6State { MemoryRegion ocram; MemoryRegion ocram_alias; uint32_t phy_num; + + CanBusState *canbus[FSL_IMX6_NUM_CANS]; }; =20 =20 --=20 2.54.0 From nobody Sat May 30 17:31:18 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; 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=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1779988809; cv=none; d=zohomail.com; s=zohoarc; b=L35yFEwvBq0AZpPNyhFpZkADxWeBg7pI1yyvarJGo4yprtxShvUPmuik32/uyJaMzjCjtqijpeX/ih3pZckXwoNkyQmZuAzY34KTbeCMk2YGG67tN+7nB0DKHdtxkcmyKcduFYFB9Z1EhpuX2WFNJTdZqcSHlmMf9YLaSg51m+E= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779988809; h=Content-Type: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:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=7XlZXXikjZPJNyVBb/rRAGZGRpHVkZDtSGlI/gZ7+vI=; b=N7WAoxCETBzN2lGnNzWzC/pYaI6usKmeJcx6+ovoLWU8SLjIW1QKIaiWtDbBhtVfkr4MYl9oItr6rEki3pTs0mEb0oD4+NUAMRmX7f/fOWJPNumXquEs+rqlB1Q9sOkGnDbPk0yGUfigcBDCAx+ihIiuL3x1Sj2YWELiaU/VFzg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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 lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779988809956949.9285693529955; Thu, 28 May 2026 10:20:09 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wSeMp-0006hX-NT; Thu, 28 May 2026 13:17:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wSeMS-0006VD-TA for qemu-devel@nongnu.org; Thu, 28 May 2026 13:17:38 -0400 Received: from mail-wm1-x32f.google.com ([2a00:1450:4864:20::32f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wSeMO-000496-RR for qemu-devel@nongnu.org; Thu, 28 May 2026 13:17:36 -0400 Received: by mail-wm1-x32f.google.com with SMTP id 5b1f17b1804b1-4905e190c71so56029685e9.3 for ; Thu, 28 May 2026 10:17:32 -0700 (PDT) Received: from acidburn.pod.cvut.cz (acidburn.pod.cvut.cz. [147.32.90.2]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49092968066sm53774085e9.15.2026.05.28.10.17.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2026 10:17:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779988651; x=1780593451; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=7XlZXXikjZPJNyVBb/rRAGZGRpHVkZDtSGlI/gZ7+vI=; b=Y80X80n+FZZVeZY6u62qP0P73ED1RaIOBbfdkmWOxx+hesZAUBUwT8ADjj22pxhzjI 1vB2BWmyjvDVQD2rxrRiRYDvaE93Fwhqd7t0b5elP5KGXSCGVup7Tex6/+k1ZK27qE7I ldjkU5T/5J0eA35LzsacUbC3QXh1qU75UQdGgOxWAGZHC85Ru3JmS/a+W2yfmOXU800o 6sDtBnZJxHqOar8uivsLCujglwPtgzunHUnNBpXdtHLePrb26txtOIbDevHgrSFN5sO9 rgjWwk4PS+Q9N0UM97wipoFJ02zrOOngUrhgTxFdmTQGwTNmypg/qD51LQ1SZEV7bRHe iFxQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779988651; x=1780593451; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=7XlZXXikjZPJNyVBb/rRAGZGRpHVkZDtSGlI/gZ7+vI=; b=CaSw4HKgzFGXyvdkA2LKiGSUuwmC1o4Cel8zax+kWuOUSnY0MBADJxe3gA73uVCiYt Z0cd3SEDYYlYmHDCuuRqSLn3S5Yx/8IGCBZ20QYP2txRjVx/Bn7CuOTHyR/KnoQ583Mw AplMnyKz/VNphOOEkRk3oDNNuRdCNwfi7saUrZ1ZfmrI4hkQ92hA7RKZsfkgdNE8rr1b q2AvODAUKBvHJJ53wDcdEYZHZHMuUayeSuCdiYzzixV9uDmubLzdxXBLiJwur+ipvUh0 c67R/3FNGURuI8hlJg9kFEJCN+tIQbNaACLjSlCtyQpsrnGNJYg9Islp5BZ2+yMm7NFg BAqQ== X-Gm-Message-State: AOJu0YzJfxahpTselRrt0TvWyMxkql3Hm/GZ/W3awsA6XmFEc+v7AG9B Rfx4s811WOIqKN8ABh3Sk1fMLxBRNvkVt8w4aaMhJOGzYNom+7pQoCy7ahI8nEYO X-Gm-Gg: Acq92OG+J+vwl5z3bml4lO0kYxecnI+c5XGQUePl892ATCZiYjecfhoDkmohN40TnK8 qUuR9IyHip6fvu2T75zCpHgADnVBguarXI0gjfup0bYFsmmaV4XmNe3NesK452JEVgy4A1oc+N1 JjN0a8313hj7iPmPIQ0TNd4Ddb5YcWlRrv+V1ffIN8V25F6NwZdiyVEsb1aU+S0jx3WkbEbLQs8 4SvN2WiQINJBX62CxwhPWCA7Uu0ZUiB3xY4J525bE2vpHntceCMjuswcz+NOOTEgnwj+pYv9Oqe jKvmsq+fUSz/KWg9cvgBsdiBKgsC971AcIDaNUdejAYU7TP6UuLXo+Z2tTV4dOn00pkiCCzlvG8 F8C4QTwquRvd8Cr9Sxkpaqbblj2/kIZUlGSFivtTtfUdhCxrw9mvP7GLbz/re/Jrjx+Vah9vdvU BdLyg9e0QP7l3Ufn7ykITyhyV5JEai38Avj8jh4kradGzQygodr2i23SLkVYc7KpS8 X-Received: by 2002:a05:600c:4ecc:b0:490:3c90:2cda with SMTP id 5b1f17b1804b1-490426cef73mr446648735e9.20.1779988651275; Thu, 28 May 2026 10:17:31 -0700 (PDT) From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Bobek?= To: qemu-devel@nongnu.org, Matyas Bobek , Pavel Pisa , Bernhard Beschow Cc: qemu-arm@nongnu.org, Marc Kleine-Budde , Oliver Hartkopp , Nikita Ostrenkov , Peter Maydell , Andrey Volkov , =?UTF-8?q?Maty=C3=A1=C5=A1=20Bobek?= Subject: [PATCH v4 6/7] tests: Add qtests for FlexCAN Date: Thu, 28 May 2026 19:17:16 +0200 Message-ID: <7363e06de3b8a8eac0e7878bc15a0b9238cce06d.1779986496.git.matyas.bobek@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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=lists1p.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::32f; envelope-from=matyas.bobek@gmail.com; helo=mail-wm1-x32f.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, 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: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1779988810844154100 The tests do not test all of the FlexCAN emulator functionality. Signed-off-by: Maty=C3=A1=C5=A1 Bobek Signed-off-by: Pavel Pisa Tested-by: Pavel Pisa Reviewed-by: Bernhard Beschow Reviewed-by: Pavel Pisa --- MAINTAINERS | 1 + tests/qtest/flexcan-test.c | 421 +++++++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 1 + 3 files changed, 423 insertions(+) create mode 100644 tests/qtest/flexcan-test.c diff --git a/MAINTAINERS b/MAINTAINERS index 36e056309b..45d5848da6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2108,6 +2108,7 @@ S: Maintained F: hw/net/can/flexcan.c F: hw/net/can/flexcan_regs.h F: include/hw/net/flexcan.h +F: tests/qtest/flexcan-test.c =20 EDU M: Jiri Slaby diff --git a/tests/qtest/flexcan-test.c b/tests/qtest/flexcan-test.c new file mode 100644 index 0000000000..87d947a806 --- /dev/null +++ b/tests/qtest/flexcan-test.c @@ -0,0 +1,421 @@ +/* + * QTests for FlexCAN CAN controller device model + * + * Copyright (c) 2025 Matyas Bobek + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "libqtest-single.h" + +#include "hw/net/flexcan.h" +#include "hw/net/can/flexcan_regs.h" + +#define FSL_IMX6_CAN2_ADDR 0x02094000 +#define FSL_IMX6_CAN2_SIZE 0x4000 +#define FSL_IMX6_CAN1_ADDR 0x02090000 +#define FSL_IMX6_CAN1_SIZE 0x4000 + +#define FC_QEMU_ARGS "-nographic -M sabrelite " \ + "-object can-bus,id=3Dqcan0 " \ + "-machine canbus0=3Dqcan0 -machine canbus1=3Dqcan0" + +/* used for masking out unused/reserved bits */ +#define FC_MB_CNT_USED_MASK (~0xF080FFFFu) + +#define FCREG(BASE_ADDR, REG) ((BASE_ADDR) + offsetof(FlexcanRegs, REG)) +#define FCMB(BASE_ADDR, MB_IDX, WORD_IDX) (FCREG(BASE_ADDR, mbs) + \ + 0x10 * (MB_IDX) + 4 * (WORD_IDX)) + +typedef struct FcTestFrame { + uint32_t id; + uint32_t data[2]; + uint8_t len; + bool ide; + bool rtr; + + /* rx only */ + bool expect_overrun; +} FcTestFrame; + +static const FcTestFrame fc_test_frame_1 =3D { + .id =3D 0x5AF, + .len =3D 8, + .data =3D { + 0x01020304, + 0x0A0B0C0D + }, + .ide =3D false +}; + +static const FcTestFrame fc_test_frame_1_ide =3D { + .id =3D 0x105AF5AF, + .len =3D 8, + .data =3D { + 0x01020304, + 0x0A0B0C0D + }, + .ide =3D true +}; + +static void fc_reset(hwaddr ba, uint32_t mcr_flags) +{ + /* disable */ + writel(FCREG(ba, mcr), 0xD890000F); + + /* enable in freeze mode */ + writel(FCREG(ba, mcr), 0x5980000F); + + /* soft reset */ + writel(FCREG(ba, mcr), 0x5980000F | FLEXCAN_MCR_SOFTRST); + + g_assert_cmpuint(readl(FCREG(ba, mcr)), =3D=3D, 0x5980000F); + g_assert_cmpuint(readl(FCREG(ba, ctrl)), =3D=3D, 0); + g_assert_cmpuint(readl(FCREG(ba, ctrl2)), =3D=3D, 0); + + writel(FCREG(ba, mcr), (0x5980000F & ~FLEXCAN_MCR_HALT) | mcr_flags); + writel(FCREG(ba, ctrl2), FLEXCAN_CTRL2_RRS); + + /* initialize all mailboxes as rx inactive */ + for (int i =3D 0; i < FLEXCAN_MAILBOX_COUNT; i++) { + writel(FCMB(ba, i, 0), FLEXCAN_MB_CODE_RX_INACTIVE); + writel(FCMB(ba, i, 1), 0); + writel(FCMB(ba, i, 2), 0); + writel(FCMB(ba, i, 3), 0); + } +} + +static uint64_t fc_get_irqs(hwaddr ba) +{ + return (uint64_t)readl(FCREG(ba, iflag1)) | + ((uint64_t)readl(FCREG(ba, iflag2)) << 32); +} + +static void fc_clear_irq(hwaddr ba, int idx) +{ + if (idx >=3D 32) { + writel(FCREG(ba, iflag2), (uint32_t)1 << (idx - 32)); + } else { + writel(FCREG(ba, iflag1), (uint32_t)1 << idx); + } + + g_assert_cmpuint(fc_get_irqs(ba) & ((uint64_t)1 << idx), =3D=3D, 0); +} + +static void fc_setup_rx_mb(hwaddr ba, int mbidx) +{ + writel(FCMB(ba, mbidx, 0), FLEXCAN_MB_CODE_RX_EMPTY); + writel(FCMB(ba, mbidx, 1), 0); + /* the data value should be ignored for RX mb */ + writel(FCMB(ba, mbidx, 2), 0); + writel(FCMB(ba, mbidx, 3), 0); + + g_assert_cmpuint(readl(FCMB(ba, mbidx, 0)), =3D=3D, FLEXCAN_MB_CODE_RX= _EMPTY); +} + +static void fc_tx(hwaddr ba, int mbidx, const FcTestFrame *frame) +{ + g_assert_cmpuint(frame->len, <=3D, 8); + + writel(FCMB(ba, mbidx, 0), FLEXCAN_MB_CODE_TX_INACTIVE); + uint32_t id =3D frame->ide ? frame->id : frame->id << 18; + writel(FCMB(ba, mbidx, 1), id); + writel(FCMB(ba, mbidx, 2), frame->data[0]); + writel(FCMB(ba, mbidx, 3), frame->data[1]); + + uint32_t ctrl =3D FLEXCAN_MB_CODE_TX_DATA | FLEXCAN_MB_CNT_LENGTH(fram= e->len); + if (frame->ide) { + ctrl |=3D FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR; + } + if (frame->rtr) { + ctrl |=3D FLEXCAN_MB_CNT_RTR; + } + writel(FCMB(ba, mbidx, 0), ctrl); + + /* check frame was transmitted */ + g_assert_cmpuint(fc_get_irqs(ba) & ((uint64_t)1 << mbidx), + !=3D, 0); + + uint32_t xpectd_ctrl =3D (ctrl & ~FLEXCAN_MB_CODE_MASK) | + FLEXCAN_MB_CODE_TX_INACTIVE; + g_assert_cmpuint(readl(FCMB(ba, mbidx, 0)) & FC_MB_CNT_USED_MASK, =3D= =3D, + xpectd_ctrl); + /* other fields should stay unchanged */ + g_assert_cmpuint(readl(FCMB(ba, mbidx, 1)), =3D=3D, id); + g_assert_cmpuint(readl(FCMB(ba, mbidx, 2)), =3D=3D, frame->data[0]); + g_assert_cmpuint(readl(FCMB(ba, mbidx, 3)), =3D=3D, frame->data[1]); +} + +static void fc_rx_check(hwaddr ba, int mbidx, const FcTestFrame *frame) +{ + uint32_t xpectd_ctrl =3D frame->expect_overrun ? FLEXCAN_MB_CODE_RX_OV= ERRUN + : FLEXCAN_MB_CODE_RX_FULL; + xpectd_ctrl |=3D FLEXCAN_MB_CNT_LENGTH(frame->len) | FLEXCAN_MB_CNT_SR= R; + if (frame->ide) { + xpectd_ctrl |=3D FLEXCAN_MB_CNT_IDE; + } + if (frame->rtr) { + xpectd_ctrl |=3D FLEXCAN_MB_CNT_RTR; + } + + uint32_t xpectd_id =3D frame->ide ? frame->id : frame->id << 18; + + uint32_t ctrl =3D readl(FCMB(ba, mbidx, 0)) & FC_MB_CNT_USED_MASK; + if ((ctrl & FLEXCAN_MB_CODE_MASK) =3D=3D FLEXCAN_MB_CODE_RX_EMPTY) { + fprintf(stderr, "expected frame (id=3D0x%X) not received\n", frame= ->id); + } + + g_assert_cmpuint(ctrl, =3D=3D, xpectd_ctrl); + g_assert_cmpuint(readl(FCMB(ba, mbidx, 1)), =3D=3D, xpectd_id); + g_assert_cmpuint(readl(FCMB(ba, mbidx, 2)), =3D=3D, frame->data[0]); + g_assert_cmpuint(readl(FCMB(ba, mbidx, 3)), =3D=3D, frame->data[1]); +} + +static void fc_check_empty_multi(hwaddr ba, int idx_count, int mbidxs[]) +{ + for (int i =3D 0; i < FLEXCAN_MAILBOX_COUNT; i++) { + bool check_empty =3D true; + int ctrl =3D readl(FCMB(ba, i, 0)); + + for (int j =3D 0; j < idx_count; j++) { + if (i =3D=3D mbidxs[j]) { + check_empty =3D false; + } + } + + if (check_empty) { + if (!(ctrl =3D=3D FLEXCAN_MB_CODE_RX_EMPTY || + ctrl =3D=3D FLEXCAN_MB_CODE_RX_INACTIVE)) { + g_assert_cmpuint(ctrl, =3D=3D, FLEXCAN_MB_CODE_RX_INACTIVE= ); + } + g_assert_cmpuint(readl(FCMB(ba, i, 1)), =3D=3D, 0); + g_assert_cmpuint(readl(FCMB(ba, i, 2)), =3D=3D, 0); + g_assert_cmpuint(readl(FCMB(ba, i, 3)), =3D=3D, 0); + } else { + g_assert_cmpuint( + ctrl & FLEXCAN_MB_CODE_MASK, !=3D, + FLEXCAN_MB_CODE_RX_INACTIVE + ); + } + } +} + +static void fc_check_empty(hwaddr ba, int mbidx) +{ + fc_check_empty_multi(ba, 1, &mbidx); +} + +static void flexcan_test_linux_probe_impl(hwaddr fba) +{ + /* -- test a Linux driver-like probe sequence -- */ + /* disable */ + writel(FCREG(fba, mcr), 0xD890000F); + g_assert_cmpuint(readl(FCREG(fba, mcr)), =3D=3D, 0xD890000F); + g_assert_cmpuint(readl(FCREG(fba, ctrl)), =3D=3D, 0); + + /* set bit in reserved field we do not implement (CTRL_CLK_SRC) */ + writel(FCREG(fba, ctrl), 0x00002000); + g_assert_cmpuint(readl(FCREG(fba, mcr)), =3D=3D, 0xD890000F); + + /* enable in freeze mode */ + writel(FCREG(fba, mcr), 0x5980000F); + g_assert_cmpuint(readl(FCREG(fba, mcr)), =3D=3D, 0x5980000F); + + /* enable Rx-FIFO */ + writel(FCREG(fba, mcr), 0x7980000F); + g_assert_cmpuint(readl(FCREG(fba, mcr)), =3D=3D, 0x7980000F); + g_assert_cmpuint(readl(FCREG(fba, ecr)), =3D=3D, 0); + + /* disable */ + writel(FCREG(fba, mcr), 0xF890000F); + g_assert_cmpuint(readl(FCREG(fba, mcr)), =3D=3D, 0xF890000F); +} + +static void flexcan_test_freeze_disable_interaction_impl(hwaddr fba) +{ + /* -- test normal <=3D> freeze <=3D> disable transitions -- */ + + /* leave freeze in disabled, FRZ_ACK should stay cleared */ + writel(FCREG(fba, mcr), 0xF890000F); /* disable */ + g_assert_cmpuint(readl(FCREG(fba, mcr)), =3D=3D, 0xF890000F); + writel(FCREG(fba, mcr), 0xB890000F); /* by clearing FRZ */ + g_assert_cmpuint(readl(FCREG(fba, mcr)), =3D=3D, 0xB890000F); + + writel(FCREG(fba, mcr), 0xF890000F); /* disable */ + g_assert_cmpuint(readl(FCREG(fba, mcr)), =3D=3D, 0xF890000F); + writel(FCREG(fba, mcr), 0xE890000F); /* by clearing HALT */ + g_assert_cmpuint(readl(FCREG(fba, mcr)), =3D=3D, 0xE890000F); + + writel(FCREG(fba, mcr), 0xF890000F); /* disable */ + g_assert_cmpuint(readl(FCREG(fba, mcr)), =3D=3D, 0xF890000F); + writel(FCREG(fba, mcr), 0xA890000F); /* by clearing both */ + g_assert_cmpuint(readl(FCREG(fba, mcr)), =3D=3D, 0xA890000F); + + /* enter and leave freeze */ + writel(FCREG(fba, mcr), 0x7980000F); /* enable in freeze mode */ + g_assert_cmpuint(readl(FCREG(fba, mcr)), =3D=3D, 0x7980000F); + writel(FCREG(fba, mcr), 0x3980000F); /* leave by clearing FRZ */ + g_assert_cmpuint(readl(FCREG(fba, mcr)), =3D=3D, 0x3080000F); + + writel(FCREG(fba, mcr), 0x7980000F); /* enable in freeze mode */ + g_assert_cmpuint(readl(FCREG(fba, mcr)), =3D=3D, 0x7980000F); + writel(FCREG(fba, mcr), 0x6980000F); /* leave by clearing HALT */ + g_assert_cmpuint(readl(FCREG(fba, mcr)), =3D=3D, 0x6080000F); +} + +static void flexcan_test_mailbox_io_impl(hwaddr ba_tx, hwaddr ba_rx) +{ + /* -- test correct handling of mailbox IO -- */ + const int test_1_mbidx =3D 0; + fc_reset(ba_tx, + FLEXCAN_MCR_SRX_DIS | FLEXCAN_MCR_MAXMB(FLEXCAN_MAILBOX_COUNT= )); + fc_reset(ba_rx, + FLEXCAN_MCR_SRX_DIS | FLEXCAN_MCR_MAXMB(FLEXCAN_MAILBOX_COUNT= )); + + fc_setup_rx_mb(ba_rx, test_1_mbidx); + fc_tx(ba_tx, test_1_mbidx, &fc_test_frame_1_ide); + g_assert_cmpuint(fc_get_irqs(ba_rx), =3D=3D, 1 << test_1_mbidx); + fc_rx_check(ba_rx, test_1_mbidx, &fc_test_frame_1_ide); + readl(FCREG(ba_rx, timer)); /* reset lock */ + + writel(FCMB(ba_rx, test_1_mbidx, 0), 0); + g_assert_cmpuint(readl(FCMB(ba_rx, test_1_mbidx, 0)), =3D=3D, 0); + writel(FCMB(ba_rx, test_1_mbidx, 1), 0x99AABBCC); + g_assert_cmpuint(readl(FCMB(ba_rx, test_1_mbidx, 1)), =3D=3D, 0x99AABB= CC); +} + +static void flexcan_test_dual_transmit_receive_impl(hwaddr ba_tx, hwaddr b= a_rx) +{ + /* -- test TX and RX between the two FlexCAN instances -- */ + const int test_1_mbidx =3D 50; + const int test_rounds =3D 50; + + /* self-receive enabled on tx FC */ + fc_reset(ba_tx, + FLEXCAN_MCR_MAXMB(FLEXCAN_MAILBOX_COUNT)); + fc_reset(ba_rx, + FLEXCAN_MCR_SRX_DIS | FLEXCAN_MCR_MAXMB(FLEXCAN_MAILBOX_COUNT= )); + + /* tests self-receive on tx and reception on rx */ + fc_setup_rx_mb(ba_rx, test_1_mbidx); + fc_check_empty(ba_rx, test_1_mbidx); + fc_setup_rx_mb(ba_tx, test_1_mbidx + 1); + fc_check_empty(ba_tx, test_1_mbidx + 1); + g_assert_cmpuint(fc_get_irqs(ba_rx), =3D=3D, 0); + g_assert_cmpuint(fc_get_irqs(ba_tx), =3D=3D, 0); + + fc_tx(ba_tx, test_1_mbidx, &fc_test_frame_1); + fc_clear_irq(ba_tx, test_1_mbidx); + + fc_rx_check(ba_rx, test_1_mbidx, &fc_test_frame_1); + fc_check_empty(ba_rx, test_1_mbidx); + fc_rx_check(ba_tx, test_1_mbidx + 1, &fc_test_frame_1); + int tx_non_empty_mbidxs[] =3D {test_1_mbidx, test_1_mbidx + 1}; + + fc_check_empty_multi(ba_tx, 2, tx_non_empty_mbidxs); + fc_clear_irq(ba_rx, test_1_mbidx); + fc_clear_irq(ba_tx, test_1_mbidx + 1); + readl(FCREG(ba_rx, timer)); /* reset lock */ + + for (int ridx =3D 0; ridx < test_rounds; ridx++) { + /* test extended IDs sent to all mailboxes */ + for (int i =3D 0; i < FLEXCAN_MAILBOX_COUNT; i++) { + fc_setup_rx_mb(ba_rx, i); + } + fc_check_empty_multi(ba_rx, 0, NULL); + g_assert_cmpuint(fc_get_irqs(ba_rx), =3D=3D, 0); + g_assert_cmpuint(fc_get_irqs(ba_tx), =3D=3D, 0); + + for (int i =3D 0; i < FLEXCAN_MAILBOX_COUNT; i++) { + fc_tx(ba_tx, i, &fc_test_frame_1_ide); + } + g_assert_cmpuint(fc_get_irqs(ba_rx), =3D=3D, UINT64_MAX); + g_assert_cmpuint(fc_get_irqs(ba_tx), =3D=3D, UINT64_MAX); + for (int i =3D 0; i < FLEXCAN_MAILBOX_COUNT; i++) { + fc_rx_check(ba_rx, i, &fc_test_frame_1_ide); + } + + /* reset interrupts */ + writel(FCREG(ba_rx, iflag1), UINT32_MAX); + writel(FCREG(ba_rx, iflag2), UINT32_MAX); + writel(FCREG(ba_tx, iflag1), UINT32_MAX); + writel(FCREG(ba_tx, iflag2), UINT32_MAX); + g_assert_cmpuint(fc_get_irqs(ba_rx), =3D=3D, 0); + g_assert_cmpuint(fc_get_irqs(ba_tx), =3D=3D, 0); + } +} + +static void flexcan_test_tx_abort_impl(hwaddr ba) +{ + /* -- test the TX abort feature -- */ + fc_reset(ba, + FLEXCAN_MCR_SRX_DIS | FLEXCAN_MCR_MAXMB(FLEXCAN_MAILBOX_COUNT= )); + + + for (int mbidx =3D 0; mbidx < FLEXCAN_MAILBOX_COUNT; mbidx++) { + fc_tx(ba, mbidx, &fc_test_frame_1); + + writel(FCMB(ba, mbidx, 0), FLEXCAN_MB_CODE_TX_ABORT); + g_assert_cmpuint(readl(FCMB(ba, mbidx, 0)), =3D=3D, + FLEXCAN_MB_CODE_TX_INACTIVE); + } +} + +static void flexcan_test_freeze_disable_interaction(void) +{ + qtest_start(FC_QEMU_ARGS); + flexcan_test_freeze_disable_interaction_impl(FSL_IMX6_CAN1_ADDR); + flexcan_test_freeze_disable_interaction_impl(FSL_IMX6_CAN2_ADDR); + qtest_end(); +} + +static void flexcan_test_linux_probe(void) +{ + qtest_start(FC_QEMU_ARGS); + flexcan_test_linux_probe_impl(FSL_IMX6_CAN1_ADDR); + flexcan_test_linux_probe_impl(FSL_IMX6_CAN2_ADDR); + qtest_end(); +} + +static void flexcan_test_dual_transmit_receive(void) +{ + qtest_start(FC_QEMU_ARGS); + flexcan_test_dual_transmit_receive_impl(FSL_IMX6_CAN1_ADDR, + FSL_IMX6_CAN2_ADDR); + flexcan_test_dual_transmit_receive_impl(FSL_IMX6_CAN2_ADDR, + FSL_IMX6_CAN1_ADDR); + qtest_end(); +} + +static void flexcan_test_tx_abort(void) +{ + qtest_start(FC_QEMU_ARGS); + flexcan_test_tx_abort_impl(FSL_IMX6_CAN1_ADDR); + flexcan_test_tx_abort_impl(FSL_IMX6_CAN2_ADDR); + qtest_end(); +} + +static void flexcan_test_mailbox_io(void) +{ + qtest_start(FC_QEMU_ARGS); + flexcan_test_mailbox_io_impl(FSL_IMX6_CAN1_ADDR, FSL_IMX6_CAN2_ADDR); + flexcan_test_mailbox_io_impl(FSL_IMX6_CAN2_ADDR, FSL_IMX6_CAN1_ADDR); + qtest_end(); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qtest_add_func("/net/flexcan/linux_probe", flexcan_test_linux_probe); + qtest_add_func("/net/flexcan/freeze_disable_interaction", + flexcan_test_freeze_disable_interaction); + qtest_add_func("/net/flexcan/dual_transmit_receive", + flexcan_test_dual_transmit_receive); + qtest_add_func("/net/flexcan/tx_abort", + flexcan_test_tx_abort); + qtest_add_func("/net/flexcan/mailbox_io", flexcan_test_mailbox_io); + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 728dde54b3..7bf1efcda5 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -249,6 +249,7 @@ qtests_arm =3D \ (config_all_devices.has_key('CONFIG_MICROBIT') ? ['microbit-test'] : [])= + \ (config_all_devices.has_key('CONFIG_STM32L4X5_SOC') ? qtests_stm32l4x5 := []) + \ (config_all_devices.has_key('CONFIG_FSI_APB2OPB_ASPEED') ? ['aspeed_fsi-= test'] : []) + \ + (config_all_devices.has_key('CONFIG_CAN_FLEXCAN') ? ['flexcan-test'] : [= ]) + \ (config_all_devices.has_key('CONFIG_STM32L4X5_SOC') and config_all_devices.has_key('CONFIG_DM163')? ['dm163-test'] : []) + \ ['arm-cpu-features', --=20 2.54.0 From nobody Sat May 30 17:31:18 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; 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=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1779988777; cv=none; d=zohomail.com; s=zohoarc; b=Emndn7/X4R/We2ew2u3lElXj7uOZT/K8/8Ri5F96Cn5pEl/ItTKqmUi8IRo3G05DekAPoz20T/uWAwcVEEyo6j5NJtFaUmBWnUvKzJ5jVcoMQF3RvSzwKzQIYtABFaJfs1ZeARIOyL4UT9BW8PJmquZ6p8WyT125ZQFEaUkQfWw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1779988777; h=Content-Type: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:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=iVoIwb+vhh8sM7msaYY87Ws0rtfErG1nVoKxO5ce55k=; b=QTSzQ+NrO1MAsnSEONT9lHtmzrySBUuUKWzGa2zC46klw/vlzqSMY/mzzWWkMJC1PhK+tj4LDuEMTIdenmBaD3yoxkG48iplfnZbxwYaJrbopx81glM4+Ju2sZxJvCyQSAms00a32fEt6TBrxIfknaCHo4mVvlxupuRsiHS9kZs= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; 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 lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1779988777820278.8572727524046; Thu, 28 May 2026 10:19:37 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wSeMg-0006ah-NL; Thu, 28 May 2026 13:17:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wSeMU-0006Vp-MC for qemu-devel@nongnu.org; Thu, 28 May 2026 13:17:40 -0400 Received: from mail-wm1-x32e.google.com ([2a00:1450:4864:20::32e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wSeMQ-0004A8-Oo for qemu-devel@nongnu.org; Thu, 28 May 2026 13:17:38 -0400 Received: by mail-wm1-x32e.google.com with SMTP id 5b1f17b1804b1-48d146705b4so137988995e9.3 for ; Thu, 28 May 2026 10:17:33 -0700 (PDT) Received: from acidburn.pod.cvut.cz (acidburn.pod.cvut.cz. [147.32.90.2]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49092968066sm53774085e9.15.2026.05.28.10.17.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2026 10:17:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779988652; x=1780593452; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=iVoIwb+vhh8sM7msaYY87Ws0rtfErG1nVoKxO5ce55k=; b=I6sGbx3QnzIB/J9qRcyxfivyYYRTiTlvArFN290aMyMBVV/Us4CNNkcNL805DJIXO6 GGZPC4VULJwbqnw8olY0MsoQFqBGUscloB5PvlONHV4A2OSP2A9SaV+0Jk/uSx23jzxh uvpw23Dqmei/z/Do4wQcC3C3Bt5dGrRPtJCMe95ZUFdnzNOGfxAoBfud0ARZuq3a8NtO CP645lLYLqtWthMorU4KxsNztE5vicLhHKxWGrtREMdDvXqwSHc6Yjrbri+6Rncvkwwa PnV1d9YhJSMoGgnRA8CraTl5S7/LTMu7S3DkPEakQMk2Ljpbf8PC0uiDW3T09/Iauwgr 8xMA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779988652; x=1780593452; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=iVoIwb+vhh8sM7msaYY87Ws0rtfErG1nVoKxO5ce55k=; b=ocAOwKj46AXdilhaQ+Hl5L2mOCrPPc79/aMiMvIch5/ddcUCeq1FzMSGnFwkQC4elZ iWXDpAPM1TxWHSuE1RZhPPVhkock69h5VpOMGzlaeW8vYjKXALoiOCStYIF3bAxWk1/D HYFyQeHvA0+Horv6e0NXUa4oeS7gJSIRjgMqc4DNQiqlAjwd+yB0RBCKEtdeanouae8X 0Y7fXIPxjL1gDG9ol5KCoTYyh8ZlGTTPVaF/44CJ5lxS3rg8hJeX/PfSmYgaMMtbkUhn RJREJqTOVAOrvuNFwkGvd28EyyWHq1qjgfEt4moRP6UkFWPfzkkcv5QIbp9rva2+wNdB cYyw== X-Gm-Message-State: AOJu0YyvnV2LjpeVoOVa+mt6wxCmwY74Q3J5cuewm9rBsm73O5ygK5OS PKOV9X7IK9Id6kurAY/YkOyNLVaFW4/vPJCKc0V2Qimzaciyb3VCwcGQwIxgX2pe X-Gm-Gg: Acq92OEfS/Ew0CG55jOPitVjx1Y0ezqkXqXbm4HbNA1PgG7Dzza+D6GMIPFlbZKf2fZ w8Xv9gcRZmycjpB5ck5zEfTgWtM561mAXRMdhwYS/E+94FIVPSR6aI86stbuDb/fhG5USfgKB2a qhbzjCHKtt8zscLl1E7mnvMjD7UnCzgRK4ULzmuP8DerC75BMFW5Z4t4nALq+aCEIg0pex1C1un vQ0YFFmBudUmA0guZfwhEbYgdLHUH+D0vZfgKjdXX8OXlVX6YCsPXpWiyMtVxnnd3CuNwtvBd9V ttKkQvQHEeTM/Lsw4dcDFh16iG393j9TKR3pX7BDLCgcCS4ncDBbXWU+/DlPI7QjDHYiJIg9Fe8 wz0DHkOxJqpWG2A5PyS63/9kMwhrw/YgHevgbDxWj9qqe1y6ke0gqsw/nbkOQV8x8C4tooz9299 uU+FEsi/smltYjswvdXR06lrEa41T2r0+IDvHYcBh4ws26hZHwGrbA9SG/yWFXgGTOZ+VydL9+J zs= X-Received: by 2002:a05:600c:a402:b0:488:9bf8:7f17 with SMTP id 5b1f17b1804b1-490425ad10cmr379774365e9.14.1779988652442; Thu, 28 May 2026 10:17:32 -0700 (PDT) From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Bobek?= To: qemu-devel@nongnu.org, Matyas Bobek , Pavel Pisa , Bernhard Beschow Cc: qemu-arm@nongnu.org, Marc Kleine-Budde , Oliver Hartkopp , Nikita Ostrenkov , Peter Maydell , Andrey Volkov , =?UTF-8?q?Maty=C3=A1=C5=A1=20Bobek?= Subject: [PATCH v4 7/7] docs/arm/sabrelite: Mention FlexCAN support Date: Thu, 28 May 2026 19:17:17 +0200 Message-ID: X-Mailer: git-send-email 2.54.0 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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=lists1p.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::32e; envelope-from=matyas.bobek@gmail.com; helo=mail-wm1-x32e.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1779988780523154100 Also added example command line usage of the Sabrelite board with FlexCAN controllers. Signed-off-by: Maty=C3=A1=C5=A1 Bobek Signed-off-by: Pavel Pisa Tested-by: Pavel Pisa Reviewed-by: Bernhard Beschow Reviewed-by: Pavel Pisa --- docs/system/arm/sabrelite.rst | 1 + docs/system/devices/can.rst | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/docs/system/arm/sabrelite.rst b/docs/system/arm/sabrelite.rst index 4ccb0560af..d3a3c01dd6 100644 --- a/docs/system/arm/sabrelite.rst +++ b/docs/system/arm/sabrelite.rst @@ -24,6 +24,7 @@ The SABRE Lite machine supports the following devices: * 4 SDHC storage controllers * 4 USB 2.0 host controllers * 5 ECSPI controllers + * 2 FlexCAN CAN controllers * 1 SST 25VF016B flash =20 Please note above list is a complete superset the QEMU SABRE Lite machine = can diff --git a/docs/system/devices/can.rst b/docs/system/devices/can.rst index 09121836fd..622f898952 100644 --- a/docs/system/devices/can.rst +++ b/docs/system/devices/can.rst @@ -173,6 +173,30 @@ The test can also be run the other way around, generat= ing messages in the guest system and capturing them in the host system. Other combinations are also possible. =20 +Examples on how to use CAN emulation for FlexCAN on SabreLite board +------------------------------------------------------------------- +FlexCANs are connected to QEMU CAN buses by passing the bus IDs as machine +properties: + +* property ``canbus0`` for connecting ``flexcan1`` +* property ``canbus1`` for connecting ``flexcan2`` + +Note that upstream Linux SabreLite DTs have only a single FlexCAN (``flexc= an1``) +enabled. + +An example command to run QEMU emulating a Sabrelite development board +with both FlexCANs connected to a single QEMU CAN bus (called ``qcan0``), +bridged to host system ``can0`` interface:: + + qemu-system-arm -M sabrelite -smp 4 -m 1G \ + -object can-bus,id=3Dqcan0 \ + -machine canbus0=3Dqcan0 -machine canbus1=3Dqcan0 \ + -object can-host-socketcan,if=3Dcan0,canbus=3Dqcan0,id=3Dqcan0-socketc= an \ + -kernel ... -dtb ... -initrd ... + +Note that in the Linux guest, bitrate for the FlexCAN device is ignored, +but needs to be set via the ``ip`` command. + Links to other resources ------------------------ =20 --=20 2.54.0