From patchwork Mon Aug 5 20:16:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754029 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 81D18C3DA4A for ; Mon, 5 Aug 2024 20:19:04 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb494-0001jj-Bi; Mon, 05 Aug 2024 16:17:30 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3UjOxZgUKCrksZuhofnnfkd.bnlpdlt-cdudkmnmfmt.nqf@flex--tavip.bounces.google.com>) id 1sb493-0001fu-Bf for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:29 -0400 Received: from mail-pj1-x104a.google.com ([2607:f8b0:4864:20::104a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3UjOxZgUKCrksZuhofnnfkd.bnlpdlt-cdudkmnmfmt.nqf@flex--tavip.bounces.google.com>) id 1sb490-0001Nu-Db for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:29 -0400 Received: by mail-pj1-x104a.google.com with SMTP id 98e67ed59e1d1-2cb576921b6so23235a91.1 for ; Mon, 05 Aug 2024 13:17:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889042; x=1723493842; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=v+XZ2Rl5k5if0oOWfRcW5SGcn2wm2BUtZIoAAUrM80c=; b=XvDD8jonemqGJ8R3hMqlTU3FSS8pzrMcSY9fZDzPPLiMqGHXkf+RRpUyKerPjqqBHj fh/uw9Xwh26MlYgdwby0DaKDtLpP84hBPzy4uYiDM67nl3G1SPhYodhBqHw9GswFKgNd iA5gwHSmxw82pRCIzLNw2w0AF4xsS/6WZ4mcATXtUCA5RViVfrg0cMu1o2JsTJgUalWx jRk99qaN3h1XRA6PioBEIlAJm/a6oTwZbRd3Apm3BHlXx4dyNQ8pyn3x77zTRqK4LWiV Z2d2eKQ/KROkPEOxRKUcjfDoVQSPiEajw3MQXm4z8y9eQccLx7UQTQ40EVPOhdAKmd6X uVkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889042; x=1723493842; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=v+XZ2Rl5k5if0oOWfRcW5SGcn2wm2BUtZIoAAUrM80c=; b=OEWUoxFlL1holtchCe0zW3LET23Rn1arh7jtU/9LLrduiwb4dB/0Q4OG03ezlVTPIj LYdUR4Ihd+DHbz5xbsJsaerhr8XpYBFyN9/8n4Nmpum263QTWhPt+OFZXzg/aVOIC1vJ IEXYrsKc48KMZnIfTpHoiRUSUya4uycSlpdx8pZJKuzI1rPV8WiebFWZwRnLMax6brE8 L9WXn5ncML4V4nZq/frlGRcJKY5QfTb/2uLpuUK1+YHSb85SIs8qjYPLlQlhANRwka2o F3+MVd1StaUXLfdP0IU1SP8ctbSwnLs+yalyywWGU5tPAUZL9bsgmE7CFyE3Gb6MLmOB FMzA== X-Gm-Message-State: AOJu0YzViGVWCb59B8XSlF4CBqK/wCYyV+/UhYGQiWSeHTqMwolMy/+q BC83Cmk3JLKnqjP4/zUDZSfKSnDkKHIt/kMttJ1vIG9RnF9y5enyof0Rp7rJuyEY8/3r6cfXvK1 t46jm76ibk9EnZTKMugxV38g4pYd1jGKEN9lHnhAGFWjU6jQa26YwPcw/Xi8Z4us+ZXGbQHLb2h ZIPPVe58aEvdHBNyUuiEyMy8I+gg== X-Google-Smtp-Source: AGHT+IGSw77EguaF6TzFUl9hSn+D85XT29tsuj2jEdezd7+A3i+GB6qt6WaOoxbln6W2tkN/LgpP3KwjKQ== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a17:90b:3cc7:b0:2c9:81c6:b0ee with SMTP id 98e67ed59e1d1-2cff9520a11mr181407a91.4.1722889042082; Mon, 05 Aug 2024 13:17:22 -0700 (PDT) Date: Mon, 5 Aug 2024 13:16:56 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-2-tavip@google.com> Subject: [RFC PATCH 01/23] fifo32: add peek function From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::104a; envelope-from=3UjOxZgUKCrksZuhofnnfkd.bnlpdlt-cdudkmnmfmt.nqf@flex--tavip.bounces.google.com; helo=mail-pj1-x104a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add fifo32_peek() that returns the first element from the queue without popping it. Signed-off-by: Octavian Purdila --- include/qemu/fifo32.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/include/qemu/fifo32.h b/include/qemu/fifo32.h index 4e9fd1b5ef..c9befc47c8 100644 --- a/include/qemu/fifo32.h +++ b/include/qemu/fifo32.h @@ -140,6 +140,35 @@ static inline uint32_t fifo32_pop(Fifo32 *fifo) return ret; } +/** + * fifo32_peek: + * @fifo: fifo to peek at + * + * Returns the value from the FIFO's head without poping it. Behaviour + * is undefined if the FIFO is empty. Clients are responsible for + * checking for emptiness using fifo32_is_empty(). + * + * Returns: the value from the FIFO's head + */ + +static inline uint32_t fifo32_peek(Fifo32 *fifo) +{ + uint32_t ret = 0, num; + const uint8_t *buf; + int i; + + buf = fifo8_peek_buf(&fifo->fifo, 4, &num); + if (num != 4) { + return ret; + } + + for (i = 0; i < sizeof(uint32_t); i++) { + ret |= buf[i] << (i * 8); + } + + return ret; +} + /** * There is no fifo32_pop_buf() because the data is not stored in the buffer * as a set of native-order words. From patchwork Mon Aug 5 20:16:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754031 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 307C8C3DA7F for ; Mon, 5 Aug 2024 20:19:22 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb495-0001nR-Dx; Mon, 05 Aug 2024 16:17:31 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3UzOxZgUKCroyf0nulttlqj.htrvjrz-ij0jqstslsz.twl@flex--tavip.bounces.google.com>) id 1sb493-0001h8-Kh for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:29 -0400 Received: from mail-pl1-x64a.google.com ([2607:f8b0:4864:20::64a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3UzOxZgUKCroyf0nulttlqj.htrvjrz-ij0jqstslsz.twl@flex--tavip.bounces.google.com>) id 1sb491-0001OU-6V for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:29 -0400 Received: by mail-pl1-x64a.google.com with SMTP id d9443c01a7336-1fc6db23c74so115137205ad.0 for ; Mon, 05 Aug 2024 13:17:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889044; x=1723493844; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=JASjBppiABUPjVgHvBEg2ThgRlH+bgfpU7wO5e+NaYE=; b=1226g7oegg9vUhLbTAtjLydrqssAY52KEi+t9PqFJ0cFVgWWFQZ9BB0BnpuPYSVC23 L9tJWAwuEgtwAgk5fyPfsdlniDX8Hlry0e3+NWDYmryvMqDgjOtgGCNkd3pmJjGKzfvV Is0XM5XwR7tsjIMF6w+4SNJHfFcRy7/GHG5trFSzUPwEufxwUhK2+Wo/Eo8eacb3wPNP 7ITxqbxd3YWf+eejO3x3WbxojC6s3+iuSyzm7St98SZWmHBJjBUVgx4xCRkwgcnixPNh akxMuOiHjMRrJa2wMQQSPzOnQsVgaqaeKJARNRvVekR9GufzU4FlYTty1ltNhjMeXneR ec1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889044; x=1723493844; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=JASjBppiABUPjVgHvBEg2ThgRlH+bgfpU7wO5e+NaYE=; b=snY0N364TfQrK43cE16fzJZZ9rvndp602vE5u/FpRirgjWZ0H9JNSpQ9QP6R3+Qb+w Wfio1iYsLTsvKTrXoDVHpxwtZUvBzKk7PPjSSzY0zmNOfhMvAyK72fzjM8iCni5jdyNd T6w0NLcmPtFCsdS5Flb/fGooGq+SIVTcaZTwB9nlMs0ISd44k8gOrgRDW/ahOVM+r0Ch JMS+KK+VYAdO70zdUUVWSvPJ7xayATpa0ZHLlCwRMPKU7fX8ErYnCkVun6NMemFLVtSv LYi4EOfiBU7HbW6KJQSBPkq192OZCCNMmFOCNEy9ntNd5S4giaNKC+12hUNsMLRoQZaI WHow== X-Gm-Message-State: AOJu0YyuYjfdXYH2/TZRgsS2yS7Oet80i+vurABNXVvEXJTYp6MdBRHO ToQRn4PO2U/OOucTGxSHub+7zaO04ULtPJLTtSlmosE2ca3N9igKZNEiIKEL3Z7/TtxTcrFjQ4E BW3lEaDBTMkgp2H1nYyiLmjiO7si9Yd2GAL2VBaq3uuBCMQDyf+oqMvdl4snSNng44OzxXH1Mhx B3SQJ7LW9eypd7CBYI5JNZFWmjxg== X-Google-Smtp-Source: AGHT+IGyyrIk3asawWetry+p/a5ZrU/dzfAfbZwm1JHiJ5mZUxhVOeR9NEDFuaROBsMRxBz+palCTk5KCA== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a17:902:c38c:b0:1fb:7f2c:5642 with SMTP id d9443c01a7336-1ff5730306cmr8797235ad.4.1722889043889; Mon, 05 Aug 2024 13:17:23 -0700 (PDT) Date: Mon, 5 Aug 2024 13:16:57 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-3-tavip@google.com> Subject: [RFC PATCH 02/23] tests/unit: add fifo test From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::64a; envelope-from=3UzOxZgUKCroyf0nulttlqj.htrvjrz-ij0jqstslsz.twl@flex--tavip.bounces.google.com; helo=mail-pl1-x64a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add a simple FIFO unit test that test wrap around and push, pop and peek for both fifo8 and fifo32. Signed-off-by: Octavian Purdila --- tests/unit/meson.build | 1 + tests/unit/test-fifo.c | 98 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 tests/unit/test-fifo.c diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 26c109c968..397f2503f8 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -47,6 +47,7 @@ tests = { 'test-logging': [], 'test-qapi-util': [], 'test-interval-tree': [], + 'test-fifo': [], } if have_system or have_tools diff --git a/tests/unit/test-fifo.c b/tests/unit/test-fifo.c new file mode 100644 index 0000000000..1686f8bd59 --- /dev/null +++ b/tests/unit/test-fifo.c @@ -0,0 +1,98 @@ +/* + * QEMU FIFO testing + * + * Copyright (C) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" + +#include "qemu/fifo8.h" +#include "qemu/fifo32.h" + +typedef struct { + Fifo8 fifo8; + Fifo32 fifo32; +} TestFixture; + +#define FIFO_SIZE 13 + +/* + * Test fixture initialization. + */ +static void set_up(TestFixture *f, gconstpointer data) +{ + int n = (uintptr_t) data; + + fifo8_create(&f->fifo8, n); + fifo32_create(&f->fifo32, n); +} + +static void tear_down(TestFixture *f, gconstpointer user_data) +{ + fifo8_destroy(&f->fifo8); + fifo32_destroy(&f->fifo32); +} + +static void test_push_pop_batch(TestFixture *f, int n) +{ + uint8_t i; + + /* push and check peek */ + for (i = 0; i < n; i++) { + uint8_t val8 = i; + uint32_t val32 = i | ((i + 1) << 8) | ((i + 2) << 16) | ((i + 3) << 24); + + fifo8_push(&f->fifo8, val8); + if (i == 0) { + g_assert(*fifo8_peek_buf(&f->fifo8, 1, NULL) == val8); + } + + fifo32_push(&f->fifo32, val32); + if (i == 0) { + g_assert(fifo32_peek(&f->fifo32) == val32); + } + } + + /* check peek and pop */ + for (i = 0; i < n; i++) { + uint8_t val8 = i; + uint32_t val32 = i | ((i + 1) << 8) | ((i + 2) << 16) | ((i + 3) << 24); + + g_assert(*fifo8_peek_buf(&f->fifo8, 1, NULL) == val8); + g_assert(fifo8_pop(&f->fifo8) == val8); + + g_assert(fifo32_peek(&f->fifo32) == val32); + g_assert(fifo32_pop(&f->fifo32) == val32); + } +} + +/* max n should be less then 256 - 3 */ +static void wrap_around_test(TestFixture *f, gconstpointer user_data) +{ + int n = (uintptr_t) user_data; + const int cycles = 3; + int i; + + for (i = 0; i < cycles; i++) { + test_push_pop_batch(f, n / 2 + 1); + } +} + +/* mock-ups */ +void *vmstate_info_buffer; +uint32_t vmstate_info_uint32; + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + g_test_add("/fifo/wrap-around", TestFixture, (gconstpointer)FIFO_SIZE, + set_up, wrap_around_test, tear_down); + + return g_test_run(); +} From patchwork Mon Aug 5 20:16:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754015 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id ECAD9C3DA4A for ; Mon, 5 Aug 2024 20:17:46 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb498-000229-Po; Mon, 05 Aug 2024 16:17:34 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3VTOxZgUKCrwvcxkriqqing.eqosgow-fgxgnpqpipw.qti@flex--tavip.bounces.google.com>) id 1sb497-0001vq-4S for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:33 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3VTOxZgUKCrwvcxkriqqing.eqosgow-fgxgnpqpipw.qti@flex--tavip.bounces.google.com>) id 1sb493-0001Op-Kd for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:32 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id 3f1490d57ef6-e0b3d35ccfbso14931894276.3 for ; Mon, 05 Aug 2024 13:17:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889047; x=1723493847; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=ZwJD/lgjO5kdqyhD8RpYuIvdatMPOMP/3LVoVmWvMSk=; b=hT7tLvCBrX28weZ43Gh3Vrt5LtM3k3GY0L6PUfG4xBpf/WMA3KA3C4TjRy1CFOtzBs n+TFcHbCu1vgguOSFvn/AqABMbZ7aGyRs9SmqFAgl1ZA2bUiyHtxE/6MFfzrHVO7iad/ Mn6WOnSGKkai/ltSNtYE1IvUovjiCYGm0P1wDNjX61UyaUDVQDZf+BY5rYxyDkmq+puj 3tShcmo01NoajcTa+kO2dBMtek2ePeMeon8iQKBxlby3rwy7wTRhD7q1mtkggoi6b3Jm lhJby44J26ad3dCvtu2I3oeCjNidRRmMy+Fji6Qbz7FDf48CSN0Mkpy+d6RpvhxtyQsJ psug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889047; x=1723493847; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=ZwJD/lgjO5kdqyhD8RpYuIvdatMPOMP/3LVoVmWvMSk=; b=UefI3HGcmG3bE412czofCKsYO373cKjfQEVnSD0mQX15DZE9i11bGo2DUlxWz/kTB/ XMqX7NQzYOXVvzBLvCAH4c1pc5Yhwrbx6m1OgwTaHIgiRz5I1yhlVJmYeNBfCoPxGfD2 Fxgs7en/g6IalZpyOEjK0cLtM7Bu4Tm4uylyQkLFPPZ6rgKOtfhQ29rnSo38ivS3/B9X bbYNXVGOiFlDUUYJa5KlLYX+k9jb0+wPcQIiQgUFoZrqYFUUmPhVaeQiJ5WnRSwm8ogx vdhKOjlz1BCq+HRLIXS4w871mcPzjFexmOs2w5RHcdIoe7/Mr1jcmfCPZIPZKEUylPX3 5NmA== X-Gm-Message-State: AOJu0YwdON3h762IL9H4Wcv1LsfvCcs+pEtuAa07l+Lmcbms4DwrVL7u gcL5LZcAKNRNVRz0uR8DO1VDjbjdB+Wy7LPFsEXnXeGZOJ3SscMYGORgd76Gu5gzp5DlpOw1FWD 50wUjmvZ56KYFM55Xik2jCUvbn1V2z6sb9i9ghoB/X4qD9VBk+rha+tMAb6kPnmMjtO1Xkswynl 3TEtRPUDrLDov1rwH69+T1GnhjUA== X-Google-Smtp-Source: AGHT+IHPWqYjn9MimH1P+Pyv+53F84pwYNK/yl/0rbjY4BL7b9DkAH4O74JY5ubkLMkSpdZVYH0QgxujeQ== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:6902:2b8a:b0:e03:2217:3c8f with SMTP id 3f1490d57ef6-e0bde21f848mr21913276.2.1722889045783; Mon, 05 Aug 2024 13:17:25 -0700 (PDT) Date: Mon, 5 Aug 2024 13:16:58 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-4-tavip@google.com> Subject: [RFC PATCH 03/23] scripts: add script to generate C header files from SVD XML files From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3VTOxZgUKCrwvcxkriqqing.eqosgow-fgxgnpqpipw.qti@flex--tavip.bounces.google.com; helo=mail-yb1-xb4a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Stefan Stanacar From: Stefan Stanacar The CMSIS System View Description format(CMSIS-SVD) is an XML based description of Arm Cortex-M microcontrollers provided and maintained by sillicon vendors. It includes details such as peripherals registers (down to bitfields), peripheral register block addresses, reset values, etc. This script uses this information to create header files that makes it easier to emulate peripherals. The script can be used to create either peripheral specific headers or board / system specific information. The script generated headers are similar to the SVDConv utility. Peripheral specific headers contains information such as register layout, register names and reset values for registers: typedef struct { ... union { uint32_t PSELID; /* 0x00000FF8 Peripheral Select and * Flexcomm module ID */ struct { uint32_t PERSEL : 3; /* [2..0] Peripheral Select */ uint32_t LOCK : 1; /* [3..3] Lock the peripheral select */ uint32_t USARTPRESENT : 1; /* [4..4] USART present indicator */ uint32_t SPIPRESENT : 1; /* [5..5] SPI present indicator */ uint32_t I2CPRESENT : 1; /* [6..6] I2C present indicator */ uint32_t I2SPRESENT : 1; /* [7..7] I2S Present */ uint32_t : 4; uint32_t ID : 20; /* [31..12] Flexcomm ID */ } PSELID_b; }; ... } FLEXCOMM_Type; /* Size = 4096 (0x1000) */ #define FLEXCOMM_PSELID_PERSEL_Pos (0UL) #define FLEXCOMM_PSELID_PERSEL_Msk (0x7UL) #define FLEXCOMM_PSELID_LOCK_Pos (3UL) #define FLEXCOMM_PSELID_LOCK_Msk (0x8UL) ... typedef enum { /* FLEXCOMM_PSELID_LOCK */ /* Peripheral select can be changed by software. */ FLEXCOMM_PSELID_LOCK_UNLOCKED = 0, /* Peripheral select is locked and cannot be changed until this * Flexcomm module or the entire device is reset. */ FLEXCOMM_PSELID_LOCK_LOCKED = 1, } FLEXCOMM_PSELID_LOCK_Enum; ... #define FLEXCOMM_REGISTER_NAMES_ARRAY(_name) \ const char *_name[sizeof(FLEXCOMM_Type)] = { \ [4088 ... 4091] = "PSELID", \ [4092 ... 4095] = "PID", \ } Board specific headers contains information about peripheral base register addresses. Signed-off-by: Stefan Stanacar Signed-off-by: Octavian Purdila --- configure | 2 +- meson.build | 4 + python/setup.cfg | 1 + python/tests/minreqs.txt | 3 + pythondeps.toml | 3 + scripts/svd-gen-header.py | 342 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 354 insertions(+), 1 deletion(-) create mode 100755 scripts/svd-gen-header.py diff --git a/configure b/configure index 5ad1674ca5..811bfa5d54 100755 --- a/configure +++ b/configure @@ -956,7 +956,7 @@ mkvenv="$python ${source_path}/python/scripts/mkvenv.py" # Finish preparing the virtual environment using vendored .whl files $mkvenv ensuregroup --dir "${source_path}/python/wheels" \ - ${source_path}/pythondeps.toml meson || exit 1 + ${source_path}/pythondeps.toml meson svd-gen-header || exit 1 # At this point, we expect Meson to be installed and available. # We expect mkvenv or pip to have created pyvenv/bin/meson for us. diff --git a/meson.build b/meson.build index ec59effca2..dee587483b 100644 --- a/meson.build +++ b/meson.build @@ -3235,6 +3235,10 @@ tracetool_depends = files( 'scripts/tracetool/vcpu.py' ) +svd_gen_header = [ + python, files('scripts/svd-gen-header.py') +] + qemu_version_cmd = [find_program('scripts/qemu-version.sh'), meson.current_source_dir(), get_option('pkgversion'), meson.project_version()] diff --git a/python/setup.cfg b/python/setup.cfg index 48668609d3..bc830c541a 100644 --- a/python/setup.cfg +++ b/python/setup.cfg @@ -45,6 +45,7 @@ devel = urwid >= 2.1.2 urwid-readline >= 0.13 Pygments >= 2.9.0 + pysvd >= 0.2.3 # Provides qom-fuse functionality fuse = diff --git a/python/tests/minreqs.txt b/python/tests/minreqs.txt index a3f423efd8..7993fcd23c 100644 --- a/python/tests/minreqs.txt +++ b/python/tests/minreqs.txt @@ -22,6 +22,9 @@ distlib==0.3.6 # Dependencies for FUSE support for qom-fuse fusepy==2.0.4 +# Dependencies for svd-gen-regs +pysvd==0.2.3 + # Test-runners, utilities, etc. avocado-framework==90.0 diff --git a/pythondeps.toml b/pythondeps.toml index 9c16602d30..8416b17650 100644 --- a/pythondeps.toml +++ b/pythondeps.toml @@ -32,3 +32,6 @@ sphinx_rtd_theme = { accepted = ">=0.5", installed = "1.1.1" } # avocado-framework, for example right now the limit is 92.x. avocado-framework = { accepted = "(>=88.1, <93.0)", installed = "88.1", canary = "avocado" } pycdlib = { accepted = ">=1.11.0" } + +[svd-gen-header] +pysvd = { accepted = ">=0.2.3.", installed = "0.2.3" } diff --git a/scripts/svd-gen-header.py b/scripts/svd-gen-header.py new file mode 100755 index 0000000000..ab8cb4b665 --- /dev/null +++ b/scripts/svd-gen-header.py @@ -0,0 +1,342 @@ +#!/usr/bin/env python3 + +# Copyright 2024 Google LLC +# +# This work is licensed under the terms of the GNU GPL, version 2 or later. +# See the COPYING file in the top-level directory. +# +# Use this script to generate a C header file from an SVD xml +# +# Two mode of operations are supported: peripheral and system. +# +# When running in peripheral mode a header for a specific peripheral +# is going to be generated. It will define a type and structure with +# all of the available registers at the bitfield level. An array that +# contains the reigster names indexed by address is also going to be +# generated as well as a function to initialize registers to their +# reset values. +# +# Invocation example: +# +# svd_gen_header -i MIMXRT595S_cm33.xml -o flexcomm.h -p FLEXCOMM0 -t FLEXCOMM +# +# When running in system mode a header for a specific system / +# platform will be generated. It will define register base addresses +# and interrupt numbers for selected peripherals. +# +# Invocation example: +# +# svd_gen_header -i MIMXRT595S_cm33.xml -o rt500.h -s RT500 -p FLEXCOMM0 \ +# -p CLKCTL0 -p CLKCTL1 +# + +import argparse +import datetime +import re +import os +import sys +import xml.etree.ElementTree +import pysvd + +data_type_by_bits = { + 8: "uint8_t", + 16: "uint16_t", + 32: "uint32_t", +} + + +def get_register_array_name_and_size(register): + """Return register name and register array size. + + The SVD can define register arrays and pysvd encodes the whole set + as as regular register with their name prepended by []. + + Returns a tuple with the register name and the size of the array or + zero if this is not a register set. + + """ + + split = re.split(r"[\[\]]", register.name) + return (split[0], int(split[1]) if len(split) > 1 else 0) + + +def generate_register(register): + """Generate register data. + + This include a field for accessing the full 32bits as we as + bitfield based register fields. + + """ + + data_type = data_type_by_bits[register.size] + + out = f" /* 0x{register.addressOffset:08X} {register.description} */\n" + out += " union {\n" + out += f" {data_type} {register.name};\n" + out += " struct {\n" + + fields = sorted(register.fields, key=lambda field: field.bitOffset) + last_msb = -1 + for field in fields: + reserve_bits = 0 + lsb = field.bitOffset + msb = field.bitWidth + lsb - 1 + + if last_msb == -1 and lsb > 0: + reserve_bits = lsb + + if last_msb != -1 and (lsb - last_msb) > 1: + reserve_bits = lsb - last_msb - 1 + + if reserve_bits > 0: + out += f" {data_type}:{reserve_bits};\n" + + out += f" /* [{msb}..{lsb}] {field.description} */\n" + out += f" {data_type} {field.name} : {field.bitWidth};\n" + + last_msb = msb + + if register.size - last_msb > 1: + out += f" {data_type}:{register.size - last_msb - 1};\n" + + reg_name, reg_array_size = get_register_array_name_and_size(register) + if reg_array_size > 0: + out += f" }} {reg_name}_b[{reg_array_size}];\n" + else: + out += f" }} {reg_name}_b;\n" + out += " };\n\n" + + return out + + +def generate_pos_and_msk_defines(name, periph): + """Generate Pos and Msk defines""" + + out = "\n" + for reg in periph.registers: + for field in reg.fields: + reg_name, _ = get_register_array_name_and_size(reg) + field_name = f"{name}_{reg_name}_{field.name}" + out += f"#define {field_name}_Pos ({field.bitOffset}UL)\n" + mask = ((1 << field.bitWidth) - 1) << field.bitOffset + out += f"#define {field_name}_Msk (0x{mask:x}UL)\n" + + return out + + +def generate_enum_values(name, periph): + """Generate enum values""" + + out = "\n" + for reg in periph.registers: + reg_name, _ = get_register_array_name_and_size(reg) + for field in reg.fields: + if hasattr(field, "enumeratedValues"): + out += "\n" + out += "typedef enum {\n" + for enum in field.enumeratedValues.enumeratedValues: + enum_name = f"{name}_{reg_name}_{field.name}_{enum.name}" + out += f" /* {enum.description} */\n" + out += f" {enum_name} = {enum.value},\n" + out += f"}} {name}_{reg_name}_{field.name}_Enum;\n" + + return out + + +def generate_register_names_array_macro(name, periph): + """Generate register names array macro""" + + out = f"#define {name}_REGISTER_NAMES_ARRAY(_name) \\\n" + out += f" const char *_name[sizeof({name}_Type)] = {{ \\\n" + for reg in periph.registers: + reg_name, reg_array_size = get_register_array_name_and_size(reg) + if reg_array_size > 0: + for i in range(0, reg_array_size): + start = reg.addressOffset + i * reg.size // 8 + stop = reg.addressOffset + (i + 1) * reg.size // 8 - 1 + out += f' [{start} ... {stop}] = "{reg_name}{i}", \\\n' + else: + start = reg.addressOffset + stop = reg.addressOffset + reg.size // 8 - 1 + out += f' [{start} ... {stop}] = "{reg.name}", \\\n' + out += " }\n" + + return out + + +def generate_reset_registers_function(name, periph): + """Generate reset registers function""" + + out = "\n" + fname = f"{name.lower()}_reset_registers" + out += f"static inline void {fname}({name}_Type *regs)\n" + out += "{\n" + for reg in periph.registers: + reg_name, reg_array_size = get_register_array_name_and_size(reg) + if reg_array_size > 0: + for i in range(0, int(reg_array_size)): + out += f" regs->{reg_name}[{i}] = {hex(reg.resetValue)};\n" + else: + out += f" regs->{reg_name} = {hex(reg.resetValue)};\n" + out += "}\n" + + return out + + +def generate_peripheral_header(periph, name): + """Generate peripheral header + + The following information is generated: + + * typedef with all of the available registers and register fields, + position and mask defines for register fields. + + * enum values that encode register fields options. + + * a macro that defines the register names indexed by the relative + address of the register. + + * a function that sets the registers to their reset values + + """ + + out = f"/* {name} - {periph.description} */\n\n" + out += "typedef struct {\n" + + last_reg_offset = 0 + cnt = 0 + for reg in periph.registers: + reserved_words = 0 + if (reg.addressOffset - last_reg_offset) > 0: + reserved_words = int((reg.addressOffset - last_reg_offset) // 4) + cnt += 1 + + if cnt: + show_count = cnt + else: + show_count = "" + + if reserved_words == 1: + out += f" uint32_t RESERVED{show_count};\n\n" + elif reserved_words > 1: + out += f" uint32_t RESERVED{show_count}[{reserved_words}];\n\n" + + out += generate_register(reg) + last_reg_offset = reg.addressOffset + reg.size // 8 + + size = periph.addressBlocks[0].size + out += f"}} {name}_Type; /* Size = {size} (0x{size:X}) */\n" + + out += "\n\n" + + out += generate_pos_and_msk_defines(name, periph) + + out += generate_enum_values(name, periph) + + out += generate_register_names_array_macro(name, periph) + + out += generate_reset_registers_function(name, periph) + + return out + + +def get_same_class_peripherals(svd, periph): + """Get a list of peripherals that are instances of the same class.""" + + return [periph] + [ + p + for p in svd.peripherals + if p.derivedFrom and p.derivedFrom.name == periph.name + ] + + +def generate_system_header(system, svd, periph): + """Generate base and irq defines for given list of peripherals""" + + out = "" + + for p in get_same_class_peripherals(svd, periph): + out += f"#define {system}_{p.name}_BASE 0x{p.baseAddress:X}UL\n" + out += "\n" + + for p in get_same_class_peripherals(svd, periph): + for irq in p.interrupts: + out += f"#define {system}_{irq.name}_IRQn 0x{irq.value}UL\n" + out += "\n" + + return out + + +def main(): + """Script to generate C header file from an SVD file""" + + parser = argparse.ArgumentParser() + parser.add_argument( + "-i", "--input", type=str, help="Input SVD file", required=True + ) + parser.add_argument( + "-o", "--output", type=str, help="Output .h file", required=True + ) + parser.add_argument( + "-p", + "--peripheral", + action="append", + help="peripheral name from the SVD file", + required=True, + ) + parser.add_argument( + "-t", + "--type-name", + type=str, + help="name to be used for peripheral definitions", + required=False, + ) + parser.add_argument( + "-s", + "--system", + type=str, + help="name to be used for the system definitions", + required=False, + ) + + args = parser.parse_args() + + node = xml.etree.ElementTree.parse(args.input).getroot() + svd = pysvd.element.Device(node) + + # Write license header + out = "/*\n" + license_text = svd.licenseText.split("\\n") + for line in license_text: + sline = f" * {line.strip()}" + out += f"{sline.rstrip()}\n" + + now = datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S") + out += f" * @note Automatically generated by {os.path.basename(__file__)}" + out += f" on {now} UTC from {os.path.basename(args.input)}.\n" + out += " *\n */\n\n" + + # Write some generic defines + out += "#pragma once\n\n" + + for name in args.peripheral: + periph = svd.find(name) + if periph: + if args.system: + out += generate_system_header(args.system, svd, periph) + else: + out += generate_peripheral_header( + periph, args.type_name if args.type_name else periph.name + ) + else: + print(f"No such peripheral: {name}") + return 1 + + with open(args.output, "w", encoding="ascii") as output: + output.write(out) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From patchwork Mon Aug 5 20:16:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754037 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D9CD0C3DA4A for ; Mon, 5 Aug 2024 20:19:34 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49F-0002Wo-8j; Mon, 05 Aug 2024 16:17:41 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3WDOxZgUKCr8yf0nulttlqj.htrvjrz-ij0jqstslsz.twl@flex--tavip.bounces.google.com>) id 1sb49A-00027p-6O for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:36 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3WDOxZgUKCr8yf0nulttlqj.htrvjrz-ij0jqstslsz.twl@flex--tavip.bounces.google.com>) id 1sb495-0001PB-Os for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:35 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id 3f1490d57ef6-e08bc29c584so16243575276.0 for ; Mon, 05 Aug 2024 13:17:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889048; x=1723493848; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=4wdCCjeNwO8Nd9IfMEbL3mdHNd1GL/ZDoT8770kOdC0=; b=WrqolcYQBHWy7OionzClsj44BhCmSQiASSBGyWqwgpymxsAzjdx2rsmBFi62Kfxlyw W/ma450owifF6OI1wfkPGodGqROI4J/w0sl7C9D6JIs0T6ZOqg5Vmi0gkpdtHby2CzgA 2oNbzQDbEWGKgep4znkRXuusLfdJcqcaLzBgEn8A2pm4aaBIX0QKnLmg0Q+Rru0cFv3r HmJ/z6+lefWX6pFri4bD9VrVOrGABdQDsdHsQoHoHV+DIa2wRwBjpg0MVcqv37jYv5/6 4LMqazq07GdYg4i/Fe452U03jWo+Q3fX8VQ9/VJsNdaucUk+3EhBJw4RSkugfVvjFp7Q Ab8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889048; x=1723493848; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=4wdCCjeNwO8Nd9IfMEbL3mdHNd1GL/ZDoT8770kOdC0=; b=TeJ2b/cE3YkLJgAUMkWi0HWUSutXvX1mWosgsn9bicpVIoVc2C0bbqw/ljkpSjGqIy kATiL2XCMsvdtBpNX573kvv1p4CQKriwE0GtfeDWLw9GGyQHbnavSemnrJm3Lh+V87Wq N8O/zQChsfawdF8jAEtqg7ifHBzaMp8X475EjeKd7eNKwH51CVQbrU7JNj/mAbBbFw4y krERLg50CBIU7MXKbsdD5mvKZ7uyh9PoTrUrukC7R4RLJYbFRs7AXaJp6o3X/gCCtIfO wGA5A2MsjeNK7aqg5/i95+41AOQzpRsgdcw+nHamUF+2X2jUmSJ9TpT9addm8JKJXJnV JOiA== X-Gm-Message-State: AOJu0YyJJzkB90N0bI1sRnlSpLgKsryc8Pbjtylv21nMNKLZ2qj2uz8I +edtqCJs+YXqgSbFwNa9vl+ZHt9sgDP+cOBUkPO7u8wbplmUztIZvEhDjn6vUOirSeM5TScE75T r5emEiFphUn8/MtCRJ/FGRAq5sI5Y1tLDznAccbUYWra5Z1/tT65XmwWseLelmhSRkVeG5CiUcT QaOqXyKxD+csONip/4O5BfxHq+Iw== X-Google-Smtp-Source: AGHT+IFc6T3TAxrL7s5Lv7ug2GUJd5MzzOoyezk2KKzPhvbVP98dIUt1LyxRK3Igl2effMsOknmdhYg5+A== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:6902:709:b0:e0b:9412:3295 with SMTP id 3f1490d57ef6-e0bde1eaf4bmr23833276.3.1722889048127; Mon, 05 Aug 2024 13:17:28 -0700 (PDT) Date: Mon, 5 Aug 2024 13:16:59 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-5-tavip@google.com> Subject: [RFC PATCH 04/23] hw/arm: add SVD file for NXP i.MX RT595 From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3WDOxZgUKCr8yf0nulttlqj.htrvjrz-ij0jqstslsz.twl@flex--tavip.bounces.google.com; helo=mail-yb1-xb4a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Picked from: https://github.com/nxp-mcuxpresso/mcux-soc-svd/blob/main/MIMXRT595S/MIMXRT595S_cm33.xml NOTE: the file is truncated to keep the email size reasonable. Please use the link above and download the full file if you want to try out the patch. Signed-off-by: Octavian Purdila --- hw/arm/svd/MIMXRT595S_cm33.xml | 224052 ++++++++++++++++++++++++++++++ 1 file changed, 224052 insertions(+) create mode 100644 hw/arm/svd/MIMXRT595S_cm33.xml diff --git a/hw/arm/svd/MIMXRT595S_cm33.xml b/hw/arm/svd/MIMXRT595S_cm33.xml new file mode 100644 index 0000000000..8943aa3555 --- /dev/null +++ b/hw/arm/svd/MIMXRT595S_cm33.xml @@ -0,0 +1,1725 @@ + + + nxp.com + MIMXRT595S_cm33 + 1.0 + MIMXRT595SFAWC,MIMXRT595SFFOC + +Copyright 2016-2023 NXP +SPDX-License-Identifier: BSD-3-Clause + + + CM33 + r2p0 + little + true + true + true + 3 + false + + 8 + 32 + + + RSTCTL0 + Reset Controller 0 + RSTCTL0 + 0x40000000 + + 0 + 0x7C + registers + + + + SYSRSTSTAT + System Reset Status Register + 0 + 32 + read-write + 0x1 + 0xFFFFFFFF + + + VDD_POR + VDD CORE Power-On Reset (POR) was detected + 0 + 1 + read-write + + + VDD_POR_EVENT_IS_NOT_DETECTED + No VDD CORE POR event is detected + 0 + + + VDD_POR_EVENT_WAS_DETECTED + VDD CORE POR event was detected + 0x1 + + + + + PAD_RESET + RESETN pin reset was detected + 4 + 1 + read-write + + + PAD_RESET_IS_NOT_DETECTED + No RESETN pin event is detected + 0 + + + PAD_RESET_WAS_DETECTED + RESETN pin event was detected. Write '1' to clear this bit + 0x1 + + + + + ARM_RESET + ARM reset was detected + 5 + 1 + read-write + + + ARM_RESET_IS_NOT_DETECTED + No ARM reset event is detected + 0 + + + ARM_RESET_WAS_DETECTED + ARM reset was detected. Write '1' to clear this bit + 0x1 + + + + + WDT0_RESET + WatchDog Timer 0 reset was detected + 6 + 1 + read-write + + + WDT0_RESET_IS_NOT_DETECTED + No WDT0 reset event detected + 0 + + + WDT0_RESET_WAS_DETECTED + WDT0 reset event detected. Write '1' to clear this bit + 0x1 + + + + + WDT1_RESET + WatchDog Timer 1 reset was detected + 7 + 1 + read-write + + + WDT1_RESET_IS_NOT_DETECTED + No WDT1 reset event detected + 0 + + + WDT1_RESET_WAS_DETECTED + WDT1 reset event detected. Write '1' to clear this bit + 0x1 + + + + + + + PRSTCTL0 + Peripheral Reset Control Register 0 + 0x10 + 32 + read-write + 0x7DF51F0A + 0xFFFFFFFF + + + DSP + Fusion F1 DSP reset control + 1 + 1 + read-write + + + DSP_CLR + Clear Reset + 0 + + + DSP_SET + Set Reset + 0x1 + + + + + AXI_SWITCH + AXI Switch reset control + 3 + 1 + read-write + + + AXI_SWITCH_CLR + Clear Reset + 0 + + + AXI_SWITCH_SET + Set Reset + 0x1 + + + + + POWERQUAD + POWERQUAD reset control + 8 + 1 + read-write + + + POWERQUAD_CLR + Clear Reset + 0 + + + POWERQUAD_SET + Set Reset + 0x1 + + + + + CASPER + CASPER reset control + 9 + 1 + read-write + + + CASPER_CLR + Clear Reset + 0 + + + CASPER_SET + Set Reset + 0x1 + + + + + HASHCRYPT + Hash-Crypt reset control + 10 + 1 + read-write + + + HASHCRYPT_CLR + Clear Reset + 0 + + + HASHCRYPT_SET + Set Reset + 0x1 + + + + + PUF + PUF reset control + 11 + 1 + read-write + + + PUF_CLR + Clear Reset + 0 + + + PUF_SET + Set Reset + 0x1 + + + + + RNG + RNG reset control + 12 + 1 + read-write + + + RNG_CLR + Clear Reset + 0 + + + RNG_SET + Set Reset + 0x1 + + + + + FLEXSPI0_OTFAD + FLEXSPI0 and OTFAD reset control + 16 + 1 + read-write + + + FLEXSPI0_OTFAD_CLR + Clear Reset + 0 + + + FLEXSPI0_OTFAD_SET + Set Reset + 0x1 + + + + + FLEXSPI1 + FLEXSPI1 reset control + 18 + 1 + read-write + + + FLEXSPI1_CLR + Clear Reset + 0 + + + FLEXSPI1_SET + Set Reset + 0x1 + + + + + USBHS_PHY + USB PHY reset control + 20 + 1 + read-write + + + USBHS_PHY_CLR + Clear Reset + 0 + + + USBHS_PHY_SET + Set Reset + 0x1 + + + + + USBHS_DEVICE + USB HS Device reset control + 21 + 1 + read-write + + + USBHS_DEVICE_CLR + Clear Reset + 0 + + + USBHS_DEVICE_SET + Set Reset + 0x1 + + + + + USBHS_HOST + USB HOST reset control + 22 + 1 + read-write + + + USBHS_HOST_CLR + Clear Reset + 0 + + + USBHS_HOST_SET + Set Reset + 0x1 + + + + + USBHS_SRAM + USB RAM reset control + 23 + 1 + read-write + + + USBHS_SRAM_CLR + Clear Reset + 0 + + + USBHS_SRAM_SET + Set Reset + 0x1 + + + + + SCT + SCTimer reset control + 24 + 1 + read-write + + + SCT_CLR + Clear Reset + 0 + + + SCT_SET + Set Reset + 0x1 + + + + + GPU + GPU reset control + 26 + 1 + read-write + + + GPU_CLR + Clear Reset + 0 + + + GPU_SET + Set Reset + 0x1 + + + + + DISPLAY_CONTROLLER + LCDIF Display Controller reset control + 27 + 1 + read-write + + + DISPLAY_CONTROLLER_CLR + Clear Reset + 0 + + + DISPLAY_CONTROLLER_SET + Set Reset + 0x1 + + + + + MIPI_DSI_CONTROLLER + MIPI Digital serial Interface controller reset control + 28 + 1 + read-write + + + MIPI_DSI_CONTROLLER_CLR + Clear Reset + 0 + + + MIPI_DSI_CONTROLLER_SET + Set Reset + 0x1 + + + + + MIPI_DSI_PHY + MIPI DSI PHY reset control + 29 + 1 + read-write + + + MIPI_DSI_PHY_CLR + Clear Reset + 0 + + + MIPI_DSI_PHY_SET + Set Reset + 0x1 + + + + + SMARTDMA + SMARTDMA Event/Algorithm handler reset control + 30 + 1 + read-write + + + SMARTDMA_CLR + Clear Reset + 0 + + + SMARTDMA_SET + Set Reset + 0x1 + + + + + + + PRSTCTL1 + Peripheral Reset Control Register 1 + 0x14 + 32 + read-write + 0x101800C + 0xFFFFFFFF + + + SDIO0 + SDIO0 reset control + 2 + 1 + read-write + + + SDIO0_CLR + Clear Reset + 0 + + + SDIO0_SET + Set Reset + 0x1 + + + + + SDIO1 + SDIO1 reset control + 3 + 1 + read-write + + + SDIO1_CLR + Clear Reset + 0 + + + SDIO1_SET + Set Reset + 0x1 + + + + + ACMP0 + Analog comparator reset control + 15 + 1 + read-write + + + ACMP0_CLR + Clear Reset + 0 + + + ACMP0_SET + Set Reset + 0x1 + + + + + ADC0 + Analog-to-Digital converter reset control + 16 + 1 + read-write + + + ADC0_CLR + Clear Reset + 0 + + + ADC0_SET + Set Reset + 0x1 + + + + + SHSGPIO0 + Secure GPIO 0 reset control + 24 + 1 + read-write + + + SHSGPIO0_CLR + Clear Reset + 0 + + + SHSGPIO0_SET + Set Reset + 0x1 + + + + + + + PRSTCTL2 + Peripheral Reset Control Register 2 + 0x18 + 32 + read-write + 0x1C000001 + 0xFFFFFFFF + + + UTICK0 + Micro-tick timer reset control + 0 + 1 + read-write + + + UTICK0_CLR + Clear Reset + 0 + + + UTICK0_SET + Set Reset + 0x1 + + + + + WWDT0 + Watchdog timer reset control + 1 + 1 + read-write + + + WWDT0_CLR + Clear Reset + 0 + + + WWDT0_SET + Set Reset + 0x1 + + + + + + + PRSTCTL0_SET + Peripheral Reset Control Register 0 SET + 0x40 + 32 + write-only + 0 + 0 + + + DSP + Fusion_ DSP reset set + 1 + 1 + write-only + + + DSP_CLR + No Effect + 0 + + + DSP_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + AXI_SWITCH + AXI SWITCH reset set + 3 + 1 + write-only + + + AXI_SWITCH_CLR + No Effect + 0 + + + AXI_SWITCH_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + POWERQUAD + POWERQUAD reset set + 8 + 1 + write-only + + + POWERQUAD_CLR + No Effect + 0 + + + POWERQUAD_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + CASPER + CASPER reset set + 9 + 1 + write-only + + + CASPER_CLR + No Effect + 0 + + + CASPER_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + HASHCRYPT + HASHCRYPT reset set + 10 + 1 + write-only + + + HASHCRYPT_CLR + No Effect + 0 + + + HASHCRYPT_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + PUF + PUF reset set + 11 + 1 + write-only + + + PUF_CLR + No Effect + 0 + + + PUF_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + RNG + RNG reset set + 12 + 1 + write-only + + + RNG_CLR + No Effect + 0 + + + RNG_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + FLEXSPI0_OTFAD + FLEXSPI0 and OTFAD reset set + 16 + 1 + write-only + + + FLEXSPI0_OTFAD_CLR + No Effect + 0 + + + FLEXSPI0_OTFAD_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + FLEXSPI1 + FLEXSPI1 reset set + 18 + 1 + write-only + + + FLEXSPI1_CLR + No Effect + 0 + + + FLEXSPI1_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + USBHS_PHY + USB PHY reset set + 20 + 1 + write-only + + + USBHS_PHY_CLR + No Effect + 0 + + + USBHS_PHY_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + USBHS_DEVICE + USB Device reset set + 21 + 1 + write-only + + + USBHS_DEVICE_CLR + No Effect + 0 + + + USBHS_DEVICE_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + USBHS_HOST + USB HOST reset set + 22 + 1 + write-only + + + USBHS_HOST_CLR + No Effect + 0 + + + USBHS_HOST_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + USBHS_SRAM + USBHS SRAM reset set + 23 + 1 + write-only + + + USBHS_SRAM_CLR + No Effect + 0 + + + USBHS_SRAM_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + SCT + SCTimer reset set + 24 + 1 + write-only + + + SCT_CLR + No Effect + 0 + + + SCT_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + GPU + GPU reset set + 26 + 1 + write-only + + + GPU_CLR + No Effect + 0 + + + GPU_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + DISPLAY_CONTROLLER + LCDIF DISPLAY CONTROLLER reset set + 27 + 1 + write-only + + + DISPLAY_CONTROLLER_CLR + No Effect + 0 + + + DISPLAY_CONTROLLER_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + MIPI_DSI_CONTROLLER + MIPI DSI controller reset set + 28 + 1 + write-only + + + MIPI_DSI_CONTROLLER_CLR + No Effect + 0 + + + MIPI_DSI_CONTROLLER_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + MIPI_DSI_PHY + MIPI DSI PHY reset set + 29 + 1 + write-only + + + MIPI_DSI_PHY_CLR + No Effect + 0 + + + MIPI_DSI_PHY_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + SMARTDMA + SMARTDMA Event/Algorithm handler reset set + 30 + 1 + write-only + + + SMARTDMA_CLR + No Effect + 0 + + + SMARTDMA_SET + Sets the PRSTCTL0 Bit + 0x1 + + + + + + + PRSTCTL1_SET + Peripheral Reset Control Register 1 SET + 0x44 + 32 + write-only + 0 + 0 + + + SDIO0 + SDIO0 reset set + 2 + 1 + write-only + + + SDIO0_CLR + No effect + 0 + + + SDIO0_SET + Sets the PRSTCTL1 Bit + 0x1 + + + + + SDIO1 + SDIO1 reset set + 3 + 1 + write-only + + + SDIO1_CLR + No effect + 0 + + + SDIO1_SET + Sets the PRSTCTL1 Bit + 0x1 + + + + + ACMP0 + ACMP0 reset set + 15 + 1 + write-only + + + ACMP0_CLR + No effect + 0 + + + ACMP0_SET + Sets the PRSTCTL1 Bit + 0x1 + + + + + ADC0 + ADC0 reset set + 16 + 1 + write-only + + + ADC0_CLR + No effect + 0 + + + ADC0_SET + Sets the PRSTCTL1 Bit + 0x1 + + + + + SHSGPIO0 + SHSGPIO0 reset set + 24 + 1 + write-only + + + SHSGPIO0_CLR + No effect + 0 + + + SHSGPIO0_SET + Sets the PRSTCTL1 Bit + 0x1 + + + + + + + PRSTCTL2_SET + Peripheral Reset Control Register 2 SET + 0x48 + 32 + write-only + 0 + 0 + + + UTICK0 + Micro-tick timer 0 reset set + 0 + 1 + write-only + + + UTICK0_CLR + No effect + 0 + + + UTICK0_SET + Sets the PRSTCTL2 Bit + 0x1 + + + + + WWDT0 + WWDT0 reset set + 1 + 1 + write-only + + + WWDT0_CLR + No effect + 0 + + + WWDT0_SET + Sets the PRSTCTL2 Bit + 0x1 + + + + + + + PRSTCTL0_CLR + Peripheral Reset Control Register 0 CLR + 0x70 + 32 + write-only + 0 + 0 + + + DSP + Fusion_ F1 DSP reset clear + 1 + 1 + write-only + + + DSP_CLR + No effect + 0 + + + DSP_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + AXI_SWITCH + AXI SWITCH reset clear + 3 + 1 + write-only + + + AXI_SWITCH_CLR + No effect + 0 + + + AXI_SWITCH_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + POWERQUAD + POWERQUAD reset clear + 8 + 1 + write-only + + + POWERQUAD_CLR + No effect + 0 + + + POWERQUAD_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + CASPER + CASPER reset clear + 9 + 1 + write-only + + + CASPER_CLR + No effect + 0 + + + CASPER_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + HASHCRYPT + HASHCRYPT reset clear + 10 + 1 + write-only + + + HASHCRYPT_CLR + No effect + 0 + + + HASHCRYPT_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + PUF + PUF reset clear + 11 + 1 + write-only + + + PUF_CLR + No effect + 0 + + + PUF_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + RNG + RNG reset clear + 12 + 1 + write-only + + + RNG_CLR + No effect + 0 + + + RNG_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + FLEXSPI0_OTFAD + FLEXSPI0 and OTFAD reset clear + 16 + 1 + write-only + + + FLEXSPI0_OTFAD_CLR + No effect + 0 + + + FLEXSPI0_OTFAD_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + FLEXSPI1 + FLEXSPI1 reset clear + 18 + 1 + write-only + + + FLEXSPI1_CLR + No effect + 0 + + + FLEXSPI1_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + USBHS_PHY + USB PHY reset clear + 20 + 1 + write-only + + + USBHS_PHY_CLR + No effect + 0 + + + USBHS_PHY_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + USBHS_DEVICE + USB DEVICE reset clear + 21 + 1 + write-only + + + USBHS_DEVICE_CLR + No effect + 0 + + + USBHS_DEVICE_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + USBHS_HOST + USB HOST reset clear + 22 + 1 + write-only + + + USBHS_HOST_CLR + No effect + 0 + + + USBHS_HOST_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + USBHS_SRAM + USBHS SRAM reset clear + 23 + 1 + write-only + + + USBHS_SRAM_CLR + No effect + 0 + + + USBHS_SRAM_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + SCT + SCT reset clear + 24 + 1 + write-only + + + SCT_CLR + No effect + 0 + + + SCT_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + GPU + GPU reset clear + 26 + 1 + write-only + + + GPU_CLR + No effect + 0 + + + GPU_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + DISPLAY_CONTROLLER + LCDIF DISPLAY CONTROLLER reset clear + 27 + 1 + write-only + + + DISPLAY_CONTROLLER_CLR + No effect + 0 + + + DISPLAY_CONTROLLER_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + MIPI_DSI_CONTROLLER + MIPI DSI controller reset clear + 28 + 1 + write-only + + + MIPI_DSI_CONTROLLER_CLR + No effect + 0 + + + MIPI_DSI_CONTROLLER_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + MIPI_DSI_PHY + MIPI DSI PHY reset clear + 29 + 1 + write-only + + + MIPI_DSI_PHY_CLR + No effect + 0 + + + MIPI_DSI_PHY_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + SMARTDMA + SMARTDMA Event/Algorithm handler reset clear + 30 + 1 + write-only + + + SMARTDMA_CLR + No effect + 0 + + + SMARTDMA_SET + Clears the PRSTCTL0 Bit + 0x1 + + + + + + + PRSTCTL1_CLR + Peripheral Reset Control Register 1 CLR + 0x74 + 32 + write-only + 0 + 0 + + + SDIO0 + SDIO0 reset clear + 2 + 1 + write-only + + + SDIO0_CLR + No effect + 0 + + + SDIO0_SET + Clears the PRSTCTL1 Bit + 0x1 + + + + + SDIO1 + SDIO1 reset clear + 3 + 1 + write-only + + + SDIO1_CLR + No effect + 0 + + + SDIO1_SET + Clears the PRSTCTL1 Bit + 0x1 + + + + + ACMP0 + ACMP0 reset clear + 15 + 1 + write-only + + + ACMP0_CLR + No effect + 0 + + + ACMP0_SET + Clears the PRSTCTL1 Bit + 0x1 + + + + + ADC0 + ADC0 reset clear + 16 + 1 + write-only + + + ADC0_CLR + No effect + 0 + + + ADC0_SET + Clears the PRSTCTL1 Bit + 0x1 + + + + + SHSGPIO0 + Secure HSGPIO0 reset clear + 24 + 1 + write-only + + + SHSGPIO0_CLR + No effect + 0 + + + SHSGPIO0_SET + Clears the PRSTCTL1 Bit + 0x1 + + + + + + + PRSTCTL2_CLR + Peripheral Reset Control Register 2 CLR + 0x78 + 32 + write-only + 0 + 0 + + + UTICK0 + Micro-tick timer 0 reset clear + 0 + 1 + write-only + + + UTICK0_CLR + No effect + 0 + + + UTICK0_SET + Clears the PRSTCTL2 Bit + 0x1 + + + + + WWDT0 + WWDT0 reset clear + 1 + 1 + write-only + + + WWDT0_CLR + No effect + 0 + + + WWDT0_SET + Clears the PRSTCTL2 Bit + 0x1 + + + + + + + + + \ No newline at end of file From patchwork Mon Aug 5 20:17:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754017 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 66BF2C3DA4A for ; Mon, 5 Aug 2024 20:18:07 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49C-0002Fs-AU; Mon, 05 Aug 2024 16:17:38 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3WTOxZgUKCsAzg1ovmuumrk.iuswks0-jk1krtutmt0.uxm@flex--tavip.bounces.google.com>) id 1sb499-00026I-S5 for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:35 -0400 Received: from mail-pg1-x54a.google.com ([2607:f8b0:4864:20::54a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3WTOxZgUKCsAzg1ovmuumrk.iuswks0-jk1krtutmt0.uxm@flex--tavip.bounces.google.com>) id 1sb497-0001Pu-Vn for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:35 -0400 Received: by mail-pg1-x54a.google.com with SMTP id 41be03b00d2f7-7b04199911bso5796187a12.1 for ; Mon, 05 Aug 2024 13:17:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889050; x=1723493850; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=SynE1NM0itYAW6y78a0dTYINIivdU1VNZIPOm/FZTSQ=; b=DCXqC7f9kTxmFQzSruXWMX/P2LgEAcImIH1X0H8wstda6iFSy2GAzeV7FOr0Pq8NiZ WpLXEUbDhNbCy/3cgK5BABCuY8WQsVfy82t/MSiOZiLp9PNuP31GU1yuKFsHeji0RFZJ 1oha8xuehJzM8MjjvKO42mpalPBvvP7SptPJJZaerMzFN0bTQM0nGOwqYxP6I+KTVzUl ogzccrMYVMcW0qcb4j0gMMQ6Z5vPa2yet9WGkUNNxLAPO83Gh4KWHoj9+umqohUXB7BW mgb/0uPbB3PL+FqRn0opu87fLkgmguSMAF2Otd6Deyd/pP3FrE9zZ3b9VS2FyvF9YqHu ThEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889050; x=1723493850; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=SynE1NM0itYAW6y78a0dTYINIivdU1VNZIPOm/FZTSQ=; b=YObONFlOHcK0ldqHklxeKKNBqVZbYTYi1wqOAEku6bpvXT4aVOAiIBr01UeZQDPQES V0+BimjgXXZjyEhBDqC4sbgV/D6vp3oCJ5F9+gH4g4DNuc8YiFQJtnpWsQVJRF+A6Ryf x4rgGZoWZzLVkUl34xf6jRG/BWjTVyuZz4CHobuVjbsogCh8I51iMfzIEYV+p9J/+Cw5 dUJ1nXlTw5ZlDj1+jMPpnbqeFT3mbZZzrSDW2vokZkxy9YooeDLbSZY3GWiyAHb2+9FQ HUeY2wO9qLtmtJ2qKylmHbh+hp714n9EAGn0F+mB1jRcHUzZCkwmfULj9b2tkKAuIJ0p AjZw== X-Gm-Message-State: AOJu0YxsPX5ottniQEDir0mfAwSLDqtPIz0U7MzuvdI31j1SlUKrZXab 4JwzAbnNnzs2zmgiLPBSCpXXfnYcaooyAUSucWZevSYAW6km+UkgOqQy/ClngAbULkw/qsFUyr9 wOXOjIAsRWKYUTk1LCjFrpRPTWWjzRgix38/2rko5hr6BHi4hR182NHva18SaFchpgSk/B6hwIH GnG8Auul2Y8S+bGkT9sK6dzP8uvg== X-Google-Smtp-Source: AGHT+IFfBSsEqahvMxIS6/LupdiNY3e6rJCtmeO4bkS0j6KTqHR7pmRUWlSDt8ZH4z2nOAzbSbhP6de15w== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a17:90a:1fc9:b0:2c8:632:7efe with SMTP id 98e67ed59e1d1-2cff0c5c916mr186752a91.4.1722889049713; Mon, 05 Aug 2024 13:17:29 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:00 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-6-tavip@google.com> Subject: [RFC PATCH 05/23] hw: add register access utility functions From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::54a; envelope-from=3WTOxZgUKCsAzg1ovmuumrk.iuswks0-jk1krtutmt0.uxm@flex--tavip.bounces.google.com; helo=mail-pg1-x54a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add register access utility functions for device models, like checking aligned access and reading and writing to a register backstore. Signed-off-by: Octavian Purdila --- include/hw/regs.h | 89 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 include/hw/regs.h diff --git a/include/hw/regs.h b/include/hw/regs.h new file mode 100644 index 0000000000..8d0da0629d --- /dev/null +++ b/include/hw/regs.h @@ -0,0 +1,89 @@ +/* + * Useful macros/functions for register handling. + * + * Copyright (c) 2021 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_REGS_H +#define HW_REGS_H + +#include "exec/hwaddr.h" +#include "exec/memattrs.h" + +#define BITS(hi, lo) (BIT(hi + 1) - BIT(lo)) +#define BIT_IS_SET(v, b) (((v) & BIT(b)) != 0) + +/* + * reg32_aligned_access + * @addr: address to check + * @size: size of access + * + * Check if access to a hardware address is 32bit aligned. + * + * Returns: true if access is 32bit aligned, false otherwise + */ +static inline bool reg32_aligned_access(hwaddr addr, unsigned size) +{ + if (size != 4 || addr % 4 != 0) { + return false; + } + return true; +} + +/* + * reg32_write + * @base: base address + * @addr: register offset in bytes + * @val: value to write + * @wr_bits_array: RW bitmask array + * + * Update the RW/WO bits of a 32bit register backstore with a given value + * (discarding updats to the RO bits). The RW/WO bits are encoded in the + * @wr_bits_array with bits set being RW and bits unset being RO. + * + * Usage example: + * + * wr_bits_array[] = { + * [REG1_ADDR/4] = 0xFF000000, // MSB byte writable + * [REG2_ADDR/4] = 0xFF, // LSB byte writable + * // all other registers are read-only + * }; + * + * // backstore is updated to 0x12000000 + * reg32_write(&backstore, REG1_ADDR, 0x12345678, wr_bits_array); + * // backstore is updated to 0x78 + * reg32_write(&backstore, REG2_ADDR, 0x12345678, wr_bits_array); + */ +static inline uint32_t reg32_write(void *base, uint32_t off, uint32_t val, + const uint32_t *rw_bits_array) +{ + uint32_t *ptr = base + addr; + uint32_t old_value = *ptr; + uint32_t mask = rw_bits_array ? rw_bits_array[addr / 4] : 0xFFFFFFFF; + + /* set WO/RW bits */ + *ptr |= val & mask; + /* clear RO bits */ + *ptr &= val | ~mask; + + return old_value; +} + +/* + * reg32_read + * @base: base address + * @addr: register offset in bytes + * + * Returns: 32bit value from register backstore + */ +static inline uint32_t reg32_read(void *base, uint32_t addr) +{ + return *(uint32_t *)(base + addr); +} + +#endif /* HW_REGS_H */ From patchwork Mon Aug 5 20:17:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754038 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C879EC52D70 for ; Mon, 5 Aug 2024 20:19:40 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49F-0002V0-0F; Mon, 05 Aug 2024 16:17:41 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3WzOxZgUKCsI1i3qxowwotm.kwuymu2-lm3mtvwvov2.wzo@flex--tavip.bounces.google.com>) id 1sb49C-0002GF-8q for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:38 -0400 Received: from mail-yw1-x1149.google.com ([2607:f8b0:4864:20::1149]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3WzOxZgUKCsI1i3qxowwotm.kwuymu2-lm3mtvwvov2.wzo@flex--tavip.bounces.google.com>) id 1sb498-0001QB-HT for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:37 -0400 Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-6688c44060fso240020527b3.2 for ; Mon, 05 Aug 2024 13:17:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889052; x=1723493852; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=wDO4e3UKSsj6tL7DUtVF1WgZwVGK3Elc+5u76pV26W8=; b=slLJnwGYysiyMaLCzRKWoFy2QbBP0GrniyRu4liyJ5tPEjDpna4eh29h3kDR4Qz0/M Ld5LTw0B3iwMOHZxb1bBg6oI8vD0HdtVLfjv5DbyeAJGpZzovtz/yfY4LzRDoQRMS0I8 dVSLL/StaxuBJUPPc4gXFes5mAGsks+QrFyJQbb7jOBHWY3VGWxQbdrg+gzUe0Do61j3 jb8HyhVgFs5TdChzY7TnROXW9gZsyO/WYJYJJIz+9HEFcCODGFSFFrqem5PSvW6OHPdL 6lb/J+wLJkwotkeEHML/FTNKvUVFMKqUqGYq/2Qbw75bvWY0l0wmi2upLybsQ6PUnqfO kRUw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889052; x=1723493852; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=wDO4e3UKSsj6tL7DUtVF1WgZwVGK3Elc+5u76pV26W8=; b=YfyMxY5MRWErUnoi7Za240wOnCvccIT73WaLfVaGZw7YEy69u7aB6WS3qHfnE9gvkz 9RV3va3oClW/bgsc7faLFf2Tr5UVqYu8sUOCfkoRy0LTtZf0YgsRKUT+TG50fzUAnlaS EyYd8YuaCQl4OppDr5TEqWfLoQ/JktRw3KfZXUW+CEGJqLqBN+CKICUwprNanurda4CB TYgZ6F98k8z2ePlZ/Rjv5tYM/2QvNk1KNnQZwiuFPHJyTM5mS+YVZvhjatyKfipAE/1M v9Fptyt5pKgW8S5b6RgRDwNERJroqOpQ/GJtVVsF9PwL/PJSkKACBSoZKqUwl8GINh/P KMXA== X-Gm-Message-State: AOJu0YyNXleavz1nX8an7NE6qfkfBVh2XpbAqdQMzdoi2WAiWobiRkQl IbLaoLbf62XwEGMB+SlLWqKHxSI4GlQ3bN/n8iLahjKRhcq8nuUISHqzEiDBDfWRWPBb+TAgcFX 9hut+jyd/0ua6XFnxaeSE4sVNnmx8WV8oqFlbKFcn6fIETPApUG1JjTLQatHukx2pZRs6LXTCbZ NoWeO5Z/fAOh6nD3FNOGOzSa94ow== X-Google-Smtp-Source: AGHT+IFhMaT7TM7CDKtYxkauXcy3SIIDxPG+x/C5CZqATVbeb3Vqn2DL3Vy0CU3eXiOiF2Rw4xAxnfEN6A== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:690c:f12:b0:648:3f93:68e0 with SMTP id 00721157ae682-6896313e32emr4155107b3.6.1722889051653; Mon, 05 Aug 2024 13:17:31 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:01 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-7-tavip@google.com> Subject: [RFC PATCH 06/23] hw/misc: add basic flexcomm device model From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::1149; envelope-from=3WzOxZgUKCsI1i3qxowwotm.kwuymu2-lm3mtvwvov2.wzo@flex--tavip.bounces.google.com; helo=mail-yw1-x1149.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add support for NXP's FLEXCOMM device model. It uses the NXP RT595 SVD file to generate the register structure. FLEXCOMM is a generic serial communication module which support multiple functions: UART, SPI and I2C. These are configurable at runtime. This patch adds the infrastructure to support adding the above mentioned hardware functions in a modular fashion in subsequent patches as well as switching between functions. Signed-off-by: Octavian Purdila --- hw/arm/meson.build | 2 + hw/arm/svd/meson.build | 4 + hw/misc/Kconfig | 3 + hw/misc/flexcomm.c | 283 +++++++++++++++++++++++++++++++++++++ hw/misc/meson.build | 2 + hw/misc/trace-events | 6 + include/hw/misc/flexcomm.h | 74 ++++++++++ 7 files changed, 374 insertions(+) create mode 100644 hw/arm/svd/meson.build create mode 100644 hw/misc/flexcomm.c create mode 100644 include/hw/misc/flexcomm.h diff --git a/hw/arm/meson.build b/hw/arm/meson.build index aefde0c69a..eb604d00cf 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -78,3 +78,5 @@ system_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c')) system_ss.add(when: 'CONFIG_Z2', if_true: files('z2.c')) hw_arch += {'arm': arm_ss} + +subdir('svd') diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build new file mode 100644 index 0000000000..9ce6c1d838 --- /dev/null +++ b/hw/arm/svd/meson.build @@ -0,0 +1,4 @@ +genh += custom_target('flexcomm.h', + output: 'flexcomm.h', + input: 'MIMXRT595S_cm33.xml', + command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'FLEXCOMM0', '-t', 'FLEXCOMM']) diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 1e08785b83..14167ae9e8 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -213,4 +213,7 @@ config IOSB config XLNX_VERSAL_TRNG bool +config FLEXCOMM + bool + source macio/Kconfig diff --git a/hw/misc/flexcomm.c b/hw/misc/flexcomm.c new file mode 100644 index 0000000000..6ec3773910 --- /dev/null +++ b/hw/misc/flexcomm.c @@ -0,0 +1,283 @@ +/* + * QEMU model for NXP's FLEXCOMM + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/mmap-alloc.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "migration/vmstate.h" +#include "exec/address-spaces.h" +#include "qapi/error.h" +#include "trace.h" +#include "hw/regs.h" +#include "hw/misc/flexcomm.h" + +#define reg(field) offsetof(FLEXCOMM_Type, field) +#define regi(x) (reg(x) / sizeof(uint32_t)) +#define REG_NO (sizeof(FLEXCOMM_Type) / sizeof(uint32_t)) + +static FLEXCOMM_REGISTER_NAMES_ARRAY(reg_names); + +#define modname "flexcomm: " + +static const FlexcommFunctionOps *flexcomm_fops[FLEXCOMM_FUNCTIONS]; +static void *flexcomm_farg[FLEXCOMM_FUNCTIONS]; + +static inline bool has_function(FlexcommState *s, int function) +{ + return s->functions & (1 << function); +} + +static inline int persel_to_function(FlexcommState *s) +{ + switch (s->regs.flex.PSELID_b.PERSEL) { + case FLEXCOMM_PERSEL_USART: + return FLEXCOMM_FUNC_USART; + case FLEXCOMM_PERSEL_SPI: + return FLEXCOMM_FUNC_SPI; + case FLEXCOMM_PERSEL_I2C: + return FLEXCOMM_FUNC_I2C; + case FLEXCOMM_PERSEL_I2S_TX: + case FLEXCOMM_PERSEL_I2S_RX: + return FLEXCOMM_FUNC_I2S; + default: + return -1; + } +} + +static void flexcomm_func_select(FlexcommState *s, bool selected) +{ + int f = persel_to_function(s); + + if (f < 0 || !flexcomm_fops[f] || !flexcomm_fops[f]->select) { + return; + } + + flexcomm_fops[f]->select(flexcomm_farg[f], s, f, selected); +} + +static MemTxResult flexcomm_func_reg_read(FlexcommState *s, hwaddr addr, + uint64_t *data, unsigned size) +{ + int f = persel_to_function(s); + + if (f < 0 || !flexcomm_fops[f] || !flexcomm_fops[f]->reg_read) { + return MEMTX_ERROR; + } + + return flexcomm_fops[f]->reg_read(flexcomm_farg[f], s, f, addr, data, size); +} + +static MemTxResult flexcomm_func_reg_write(FlexcommState *s, hwaddr addr, + uint64_t data, unsigned size) +{ + int f = persel_to_function(s); + + if (f < 0 || !flexcomm_fops[f] || !flexcomm_fops[f]->reg_write) { + return MEMTX_ERROR; + } + + return flexcomm_fops[f]->reg_write(flexcomm_farg[f], s, f, addr, data, + size); +} + +static void flexcomm_reset(DeviceState *dev) +{ + FlexcommState *s = FLEXCOMM(dev); + + trace_flexcomm_reset(); + + flexcomm_func_select(s, false); + + flexcomm_reset_registers(&s->regs.flex); + + s->regs.flex.PSELID_b.USARTPRESENT = has_function(s, FLEXCOMM_FUNC_USART); + s->regs.flex.PSELID_b.SPIPRESENT = has_function(s, FLEXCOMM_FUNC_SPI); + s->regs.flex.PSELID_b.I2CPRESENT = has_function(s, FLEXCOMM_FUNC_I2C); + s->regs.flex.PSELID_b.I2SPRESENT = has_function(s, FLEXCOMM_FUNC_I2S); + + s->irq_state = false; + qemu_set_irq(s->irq, s->irq_state); +} + +static MemTxResult flexcomm_reg_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + FlexcommState *s = opaque; + MemTxResult ret = MEMTX_OK; + + switch (addr) { + case reg(PSELID): + case reg(PID): + { + if (!reg32_aligned_access(addr, size)) { + ret = MEMTX_ERROR; + } else { + *data = reg32_read(&s->regs, addr); + } + break; + } + default: + return flexcomm_func_reg_read(s, addr, data, size); + } + + trace_flexcomm_reg_read(DEVICE(s)->id, reg_names[addr], addr, *data); + return ret; +} + +static int flexcomm_check_function(FlexcommState *s) +{ + int f = persel_to_function(s); + + if (f < 0 || !has_function(s, f)) { + return -1; + } + + return f; +} + +static MemTxResult flexcomm_reg_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + FlexcommState *s = opaque; + MemTxResult ret = MEMTX_OK; + static uint32_t mask[] = { + [regi(PSELID)] = BITS(3, 0), + }; + + trace_flexcomm_reg_write(DEVICE(s)->id, reg_names[addr], addr, value); + switch (addr) { + case reg(PID): + /* RO register, nothing do to */ + break; + case reg(PSELID): + { + if (!reg32_aligned_access(addr, size)) { + ret = MEMTX_ERROR; + break; + } + + if (s->regs.flex.PSELID_b.LOCK) { + break; + } + + flexcomm_func_select(s, false); + + reg32_write(&s->regs, addr, value, mask); + + if (flexcomm_check_function(s) < 0) { + s->regs.flex.PSELID_b.PERSEL = 0; + } + s->regs.flex.PID_b.ID = s->regs.flex.PSELID_b.PERSEL; + + flexcomm_func_select(s, true); + break; + } + default: + return flexcomm_func_reg_write(s, addr, value, size); + } + + return ret; +} + + +static const MemoryRegionOps flexcomm_ops = { + .read_with_attrs = flexcomm_reg_read, + .write_with_attrs = flexcomm_reg_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static Property flexcomm_properties[] = { + DEFINE_PROP_UINT32("functions", FlexcommState, functions, + FLEXCOMM_FULL), + DEFINE_PROP_END_OF_LIST(), +}; + +static void flexcomm_init(Object *obj) +{ + FlexcommState *s = FLEXCOMM(obj); + DeviceState *dev = DEVICE(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->mmio, obj, &flexcomm_ops, s, + TYPE_FLEXCOMM, sizeof(FLEXCOMM_Type)); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); + + sysbus_init_irq(sbd, &s->irq); +} + +static void flexcomm_realize(DeviceState *dev, Error **errp) +{ +} + +static void flexcomm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = flexcomm_reset; + device_class_set_props(dc, flexcomm_properties); + dc->realize = flexcomm_realize; +} + +static const TypeInfo flexcomm_info = { + .name = TYPE_FLEXCOMM, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(FlexcommState), + .instance_init = flexcomm_init, + .class_init = flexcomm_class_init, +}; + +static void flexcomm_register_types(void) +{ + type_register_static(&flexcomm_info); +} + +type_init(flexcomm_register_types) + +void flexcomm_irq(FlexcommState *s, bool irq) +{ + if (s->irq_state != irq) { + trace_flexcomm_irq(DEVICE(s)->id, irq); + qemu_set_irq(s->irq, irq); + s->irq_state = irq; + } +} + +bool flexcomm_register_ops(int f, void *arg, const FlexcommFunctionOps *ops, + Error **errp) +{ + if (f < 0 || f >= FLEXCOMM_FUNCTIONS) { + error_setg(errp, modname "invalid function %d", f); + return false; + } + + if (flexcomm_fops[f]) { + error_setg(errp, modname "function %d already registered", f); + return false; + } + + flexcomm_fops[f] = ops; + flexcomm_farg[f] = arg; + + return true; +} + +/* for unit tests */ +void flexcomm_unregister_ops(int f) +{ + flexcomm_fops[f] = NULL; + flexcomm_farg[f] = NULL; +} diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 86596a3888..8414767ae3 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -156,3 +156,5 @@ system_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) # HPPA devices system_ss.add(when: 'CONFIG_LASI', if_true: files('lasi.c')) + +system_ss.add(when: 'CONFIG_FLEXCOMM', if_true: files('flexcomm.c')) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 5d241cb40a..71ec77de29 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -351,3 +351,9 @@ djmemc_write(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRI # iosb.c iosb_read(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u" iosb_write(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u" + +# flexcomm +flexcomm_reset(void) "" +flexcomm_irq(const char *id, uint8_t irq) "%s %d" +flexcomm_reg_read(const char *devname, const char *regname, uint32_t addr, uint32_t val) "%s: %s[0x%04x] -> 0x%08x" +flexcomm_reg_write(const char *dename, const char *regname, uint32_t addr, uint32_t val) "%s: %s[0x%04x] <- 0x%08x" diff --git a/include/hw/misc/flexcomm.h b/include/hw/misc/flexcomm.h new file mode 100644 index 0000000000..422452bd96 --- /dev/null +++ b/include/hw/misc/flexcomm.h @@ -0,0 +1,74 @@ +/* + * QEMU model for NXP's FLEXCOMM + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_FLEXCOMM_H +#define HW_FLEXCOMM_H + +#include "hw/sysbus.h" +#include "hw/arm/svd/flexcomm.h" +#include "qemu/fifo32.h" + +#define TYPE_FLEXCOMM "flexcomm" +#define FLEXCOMM(obj) OBJECT_CHECK(FlexcommState, (obj), TYPE_FLEXCOMM) + +#define FLEXCOMM_FUNC_USART 0 +#define FLEXCOMM_FUNC_SPI 1 +#define FLEXCOMM_FUNC_I2C 2 +#define FLEXCOMM_FUNC_I2S 3 +#define FLEXCOMM_FUNCTIONS 4 + +#define FLEXCOMM_FULL 0xF +#define FLEXCOMM_HSSPI (1 << FLEXCOMM_FUNC_SPI) +#define FLEXCOMM_PMICI2C (1 << FLEXCOMM_FUNC_I2C) + +#define FLEXCOMM_PERSEL_USART 1 +#define FLEXCOMM_PERSEL_SPI 2 +#define FLEXCOMM_PERSEL_I2C 3 +#define FLEXCOMM_PERSEL_I2S_TX 4 +#define FLEXCOMM_PERSEL_I2S_RX 5 + +typedef struct { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion mmio; + union { + FLEXCOMM_Type flex; + } regs; + uint32_t functions; + qemu_irq irq; + bool irq_state; +} FlexcommState; + +typedef struct { + /* argument to pass to functions */ + void *arg; + + /* function / submodule has been selected / deselected. */ + void (*select)(void *o, FlexcommState *s, int f, bool selected); + + /* read register */ + MemTxResult (*reg_read)(void *o, FlexcommState *s, int f, hwaddr addr, + uint64_t *data, unsigned size); + + /* write register */ + MemTxResult (*reg_write)(void *o, FlexcommState *s, int f, hwaddr addr, + uint64_t data, unsigned size); +} FlexcommFunctionOps; + + +void flexcomm_irq(FlexcommState *s, bool irq); +bool flexcomm_register_ops(int f, void *arg, const FlexcommFunctionOps *ops, + Error **errp); +void flexcomm_unregister_ops(int f); + +#endif /* HW_FLEXCOMM_H */ From patchwork Mon Aug 5 20:17:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754041 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 22BECC3DA7F for ; Mon, 5 Aug 2024 20:20:28 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49H-0002lI-Rs; Mon, 05 Aug 2024 16:17:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3XTOxZgUKCsQ3k5szqyyqvo.myw0ow4-no5ovxyxqx4.y1q@flex--tavip.bounces.google.com>) id 1sb49E-0002R5-3C for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:40 -0400 Received: from mail-pl1-x649.google.com ([2607:f8b0:4864:20::649]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3XTOxZgUKCsQ3k5szqyyqvo.myw0ow4-no5ovxyxqx4.y1q@flex--tavip.bounces.google.com>) id 1sb499-0001QT-Et for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:39 -0400 Received: by mail-pl1-x649.google.com with SMTP id d9443c01a7336-1ff3dfaa090so56171235ad.3 for ; Mon, 05 Aug 2024 13:17:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889053; x=1723493853; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=fPOF8tPVCB5RUT1vLWhA1MQiOoDtDv85xjMES2IhNfM=; b=UO5C5yK+f9vyyGBWhg7P0Ag64aBxXhhP5ocfdrCHBj46zIXuqLs0E2QWRQnQXyxNup Z0HcRVD4bUW9JS6aQcC+y2/GDGeVAb0aQOwdjBhZw4MmBDfKEC0+YoU+PuHBcrQ1hT5l lUXRsKjesOIpoTloak8ZprhUpfKRCJtG3rKDiU0jfTNp0+nuT4BMFgIgXZqjHu/6eYEd yf6gpK1AZztUbgrVLA8CrzRmmaFGcjZ2ppIWUCiKoBwBdTR18YXazeVgvMi06+cOVLuH FgkNS4XEajsqAlYkndo4HbyDF6C/kk85cKO8ZbIYTAT7jIHnbmbdaQgS/AzQQvYw07Wr L8zg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889053; x=1723493853; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=fPOF8tPVCB5RUT1vLWhA1MQiOoDtDv85xjMES2IhNfM=; b=doqRgsVsPV+eQt1dYj0PIx5QfwfcoU2LrPTCkTHhgPZsvZNSgiWJefaNvw17siUgtP XDN8N2lqX3eKiJFPEhI8L4qQ4vr2V8yo7IFJXjB+xNZoW8dahYO1MTSNmJH//2Xfk0Pn qd27UurCeVPAia3aSkPv3t/YnGUVt8c6iq4NBPJOZ+Y55wqaIfMraT7VgHwgrBhlErqP 9CxXLz3Z1bgc1omzvOVgrqpZ+WESdIaWfoEQ3D6wnrmfAIjjsmrdn0+iTIzYjRtIxqJO RILhNY/HFJgyFCG9kLUG6gSYZLgTaiRcCAMZtBsHUTuMwKm6GyhNi6GTxNSHdmrqayq0 BnTw== X-Gm-Message-State: AOJu0YzkE+g05HLuiIQyQlEjWcl04Dki59dorI57KUtk9dYA9BUuYTrX V9QFwy6JarhXzgRR3PURQpnvRyQCeRJTkMqJE/dVun96ZoBgLyMxtEdJH6vP+OunYmVIPTqKdw2 1O8Zql0KYNgGQAcNf8rvd2mJlcXX0bHRGUEpis87GYOET/8050sic+6UPd7Olcl/KKlvM2mhLrN b4pxFHJGX5L0Guwn5N0oBJgOQECw== X-Google-Smtp-Source: AGHT+IGa+UzwdbIld7JsQhx6EPRnqA/aNMmojNYxLGBdvPzBROaZTGG7602qUJgCnMz1HGkefTTNEeUCUg== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a17:902:e742:b0:1f9:cbe5:e422 with SMTP id d9443c01a7336-1ff5748d438mr4976885ad.8.1722889053049; Mon, 05 Aug 2024 13:17:33 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:02 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-8-tavip@google.com> Subject: [RFC PATCH 07/23] tests/unit: add system bus mock From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::649; envelope-from=3XTOxZgUKCsQ3k5szqyyqvo.myw0ow4-no5ovxyxqx4.y1q@flex--tavip.bounces.google.com; helo=mail-pl1-x649.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Valentin Ghita From: Valentin Ghita Add a system bus mock and the necessary memory access functions to be able to create unit tests for device models. Signed-off-by: Valentin Ghita Signed-off-by: Octavian Purdila --- tests/unit/sysbus-mock.c | 314 +++++++++++++++++++++++++++++++++++++++ tests/unit/sysbus-mock.h | 82 ++++++++++ 2 files changed, 396 insertions(+) create mode 100644 tests/unit/sysbus-mock.c create mode 100644 tests/unit/sysbus-mock.h diff --git a/tests/unit/sysbus-mock.c b/tests/unit/sysbus-mock.c new file mode 100644 index 0000000000..c6c654eabc --- /dev/null +++ b/tests/unit/sysbus-mock.c @@ -0,0 +1,314 @@ +/* + * System Bus Mock + * + * Copyright (C) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/main-loop.h" +#include "exec/memory.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "hw/qdev-core.h" + +#include "sysbus-mock.h" + +AddressSpace address_space_memory; + +/* Simulates guest memory space. */ +static uint8_t *guest_mem; +static size_t guest_mem_size; + +static uint64_t memory_region_ram_device_read(void *opaque, + hwaddr addr, unsigned size) +{ + uint64_t data = (uint64_t)~0; + uint8_t *buf = opaque; + + switch (size) { + case 1: + data = *(uint8_t *)(buf + addr); + break; + case 2: + data = *(uint16_t *)(buf + addr); + break; + case 4: + data = *(uint32_t *)(buf + addr); + break; + case 8: + data = *(uint64_t *)(buf + addr); + break; + } + + return data; +} + +static void memory_region_ram_device_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + uint8_t *buf = opaque; + + switch (size) { + case 1: + *(uint8_t *)(buf + addr) = (uint8_t)data; + break; + case 2: + *(uint16_t *)(buf + addr) = (uint16_t)data; + break; + case 4: + *(uint32_t *)(buf + addr) = (uint32_t)data; + break; + case 8: + *(uint64_t *)(buf + addr) = data; + break; + } +} + +static const MemoryRegionOps ram_device_mem_ops = { + .read = memory_region_ram_device_read, + .write = memory_region_ram_device_write, + .endianness = DEVICE_HOST_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = true, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = true, + }, +}; + +void *cpu_physical_memory_map(hwaddr addr, hwaddr *plen, bool is_write) +{ + /* Mock implementation. Return a pointer inside the guest_mem buffer. */ + g_assert(guest_mem != NULL); + g_assert(guest_mem_size <= addr + (size_t)plen); + + return guest_mem + addr; +} + +void cpu_physical_memory_unmap(void *buffer, hwaddr len, + bool is_write, hwaddr access_len) +{ + /* Mock implementation. */ +} + +MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr, + MemTxAttrs attrs, void *buf, hwaddr len) +{ + /* Mock implementation */ + g_assert(guest_mem != NULL); + + if (guest_mem_size < addr + (size_t)len) { + return MEMTX_ERROR; + } + + memcpy(buf, guest_mem + addr, len); + + return MEMTX_OK; +} + +MemTxResult address_space_write(AddressSpace *as, hwaddr addr, + MemTxAttrs attrs, + const void *buf, hwaddr len) +{ + /* Mock implementation */ + g_assert(guest_mem != NULL); + + if (guest_mem_size < addr + (size_t)len) { + return MEMTX_ERROR; + } + + memcpy(guest_mem + addr, buf, len); + + return MEMTX_OK; +} + +MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, + void *buf, hwaddr len, bool is_write) +{ + if (is_write) { + return address_space_write(as, addr, attrs, buf, len); + } else { + return address_space_read_full(as, addr, attrs, buf, len); + } +} + +void cpu_physical_memory_rw(hwaddr addr, void *buf, + hwaddr len, bool is_write) +{ + address_space_rw(&address_space_memory, addr, MEMTXATTRS_UNSPECIFIED, + buf, len, is_write); +} + +void memory_region_init_io(MemoryRegion *mr, Object *owner, + const MemoryRegionOps *ops, void *opaque, + const char *name, uint64_t size) +{ + /* Mock implementation. */ + mr->size = size; + mr->ops = ops; + mr->opaque = opaque; +} + +void memory_region_init_ram_device_ptr(MemoryRegion *mr, Object *owner, + const char *name, uint64_t size, + void *ptr) +{ + mr->size = size; + mr->ops = &ram_device_mem_ops; + mr->opaque = ptr; +} + +void memory_region_set_readonly(MemoryRegion *mr, bool readonly) +{ + if (mr->readonly != readonly) { + mr->readonly = readonly; + } +} + +void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr) +{ + assert(n >= 0 && n < dev->num_mmio); + dev->mmio[n].addr = addr; + dev->mmio[n].memory->addr = addr; +} + +void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory) +{ + /* Mock implementation. */ + assert(dev->num_mmio < QDEV_MAX_MMIO); + int n = dev->num_mmio++; + dev->mmio[n].addr = -1; + dev->mmio[n].memory = memory; +} + +static void sysbus_device_class_init(ObjectClass *klass, void *data) +{ + /* Mock implementation. */ +} + +void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p) +{ + qdev_init_gpio_out_named(DEVICE(dev), p, SYSBUS_DEVICE_GPIO_IRQ, 1); +} + +/* + * Mock implementation of the sysbus device class. + * Including the sysbus source code is difficult because of the dependencies, + * so it is easier to define the type here. + */ +static const TypeInfo sysbus_device_type_info = { + .name = TYPE_SYS_BUS_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(SysBusDevice), + .abstract = true, + .class_size = sizeof(SysBusDeviceClass), + .class_init = sysbus_device_class_init, +}; + +void sysbus_mock_init(void) +{ + type_register_static(&sysbus_device_type_info); +} + +/* Find the mmio region containing an address. */ +static MemoryRegion *find_region(SysBusDevice *dev, hwaddr addr) +{ + int i; + + for (i = 0; i < dev->num_mmio; i++) { + if (dev->mmio[i].addr <= addr && + (addr - dev->mmio[i].addr) < dev->mmio[i].memory->size) { + + return dev->mmio[i].memory; + } + } + + return NULL; +} + +uint32_t sysbus_mmio_read_addr(DeviceState *dev, hwaddr addr, unsigned size) +{ + uint64_t value; + MemTxResult result; + MemoryRegion *mem = find_region(SYS_BUS_DEVICE(dev), addr); + + assert(mem != NULL); + assert(mem->ops->read_with_attrs != NULL || mem->ops->read != NULL); + + if (mem->ops->read_with_attrs != NULL) { + result = mem->ops->read_with_attrs(mem->opaque, addr - mem->addr, + &value, size, + MEMTXATTRS_UNSPECIFIED); + assert(result == MEMTX_OK); + } else { + value = mem->ops->read(mem->opaque, addr - mem->addr, size); + } + + return (uint32_t)value; +} + +void sysbus_mmio_write_addr(DeviceState *dev, hwaddr addr, uint64_t value, + unsigned size) +{ + MemTxResult result; + MemoryRegion *mem = find_region(SYS_BUS_DEVICE(dev), addr); + + assert(mem != NULL); + assert(mem->ops->write_with_attrs != NULL || mem->ops->write != NULL); + assert(!mem->readonly); + + if (mem->ops->write_with_attrs != NULL) { + result = mem->ops->write_with_attrs(mem->opaque, addr - mem->addr, + value, size, + MEMTXATTRS_UNSPECIFIED); + g_assert(result == MEMTX_OK); + } else { + mem->ops->write(mem->opaque, addr - mem->addr, value, size); + } +} + +void sysbus_dev_set_guest_mem(void *mem, size_t size) +{ + guest_mem = mem; + guest_mem_size = size; +} + +MemTxResult sysbus_mmio_read_addr_raw(DeviceState *dev, hwaddr addr, + uint64_t *value, unsigned size) +{ + uint64_t tmp; + MemTxResult result; + MemoryRegion *mem = find_region(SYS_BUS_DEVICE(dev), addr); + + assert(mem != NULL); + + result = mem->ops->read_with_attrs(dev, addr - mem->addr, &tmp, + size, + MEMTXATTRS_UNSPECIFIED); + *value = tmp; + return result; +} + +MemTxResult sysbus_mmio_write_addr_raw(DeviceState *dev, hwaddr addr, + uint64_t value, unsigned size) +{ + MemoryRegion *mem = find_region(SYS_BUS_DEVICE(dev), addr); + assert(mem != NULL); + assert(!mem->readonly); + + return mem->ops->write_with_attrs(dev, addr - mem->addr, value, + size, + MEMTXATTRS_UNSPECIFIED); +} diff --git a/tests/unit/sysbus-mock.h b/tests/unit/sysbus-mock.h new file mode 100644 index 0000000000..7a4c2e7b9a --- /dev/null +++ b/tests/unit/sysbus-mock.h @@ -0,0 +1,82 @@ +/* + * System Bus Mock + * + * Copyright (C) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef SYSBUS_MOCK_H +#define SYSBUS_MOCK_H + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/sysbus.h" + +/* + * sysbus_mock_init + * + * Initialize the sysbus mock implementation. + */ +void sysbus_mock_init(void); + +/* + * sysbus_mmio_read_addr + * @dev: device structure + * @addr: address to read from + * + * Read from an address in a mmio region and assert on errors. + */ +uint32_t sysbus_mmio_read_addr(DeviceState *dev, hwaddr addr, unsigned size); + +/* + * sysbus_mmio_write_addr + * @dev: device structure + * @addr: address to write to + * @value: value to write + * + * Write to an address in a mmio region and assert on errors. + */ +void sysbus_mmio_write_addr(DeviceState *dev, hwaddr addr, uint64_t value, + unsigned size); + +/* + * sysbus_dev_set_guest_mem + * + * Set guest generic memory space. + */ +void sysbus_dev_set_guest_mem(void *mem, size_t size); + + +/* + * sysbus_mmio_read_addr_raw + * @dev: device structure + * @addr: address to write to + * @size: access size + * + * Read from an address in a mmio region and return errors. + * + * Returns: MEMTX_OK if the access was successful, MEMTX_ERROR otherwise + */ +MemTxResult sysbus_mmio_read_addr_raw(DeviceState *dev, hwaddr addr, + uint64_t *value, unsigned size); + +/* + * sysbus_mmio_write_addr_raw + * @dev: device structure + * @addr: address to write to + * @value: value to write + * @size: access size + * + * Write to an address in a mmio region and return errors. + * + * Returns: MEMTX_OK if the access was successful, MEMTX_ERROR otherwise + */ +MemTxResult sysbus_mmio_write_addr_raw(DeviceState *dev, hwaddr addr, + uint64_t value, unsigned size); + +#endif /* SYSBUS_MOCK_H */ From patchwork Mon Aug 5 20:17:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754039 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C092EC3DA7F for ; Mon, 5 Aug 2024 20:19:49 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49H-0002hH-8z; Mon, 05 Aug 2024 16:17:43 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3XjOxZgUKCsU4l6t0rzzrwp.nzx1px5-op6pwyzyry5.z2r@flex--tavip.bounces.google.com>) id 1sb49E-0002Rj-3z for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:40 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3XjOxZgUKCsU4l6t0rzzrwp.nzx1px5-op6pwyzyry5.z2r@flex--tavip.bounces.google.com>) id 1sb49B-0001Qr-WD for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:39 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id 3f1490d57ef6-e0e3eb3fe93so3039972276.1 for ; Mon, 05 Aug 2024 13:17:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889055; x=1723493855; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=nk3wy3iOlV41EdYWg2ADHBcnClsgP1AAs+CwqJBw/xU=; b=jn3Hed2apC4MeGSWIyxVR+3UoRxESiaQARUo11hPk8A9U/howsPgtHtpRm8PxwuzPC PN0dU2JP5Z3yKx/gHxU4HA7SOHzNyX8Sn0Q/WTHbEx42oCzrxuKRLUAwcsqXHJasEcQE x7jmRIZ0PBKsXx93uHvMSAndAH0jqv8nFVYAcS73kJQqVKxXQZT4jKz5fAZAO0dZGasb oc6GHrtWVTsx3fnhV+E19V66Z8vMp+euVaGydzuZpNQ2pVQK2c6aaGXv19/eV+bLUsCT vhFjRkU85vUjUNVQvIbEXSy+WIbupiWLkwAmWZqMoo6rbgLfH2n7lylw93a0YBBZa1QB ORuw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889055; x=1723493855; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=nk3wy3iOlV41EdYWg2ADHBcnClsgP1AAs+CwqJBw/xU=; b=b2uLA/HyqQvrkDwiQruvvRbJ1sYc1zJUbMchxBpc0BNeuPq9p/CI5fNpPqGlrUc+xv M9InYmDs8UBDvSppM83J0VuDrAwfaPdunEuoGutdfp4R9ybe3PjfcVlWp15Lw4WyoOlv LGBt6UiIVfbnNRy+eURmE8ob1kPupqaXKhXeKkp01rHBLH0KVFYG8X8RmXPqUo8jg33e koppJNgh3ctZ2J6p01d6Q6MMy4MspW29E5todR6Rh1GsSmY9GTEgNRgmrQUQWdZBBXuJ OAhhShIFAF21ANdlhZDLzTAHQSKKXkw3XEyXMR7imloVGkjC3HhKCt2S4HSl7R+XRrD3 9qeQ== X-Gm-Message-State: AOJu0YxD14UKBg/DtbMuHycHj2Y/RjRNeO0NIfZNLjmx3lPYiaTHrWOL fW7wdLwkyhAkwesJzjV9jz/F2/7nU8bvXLemf1PQEV5epfCKDjeltp76vGoWqMrgzJMs/17wQ+8 oAB8/18KSh3Iu6KHC4gMb0oMTLTtYgeCVh/BD2agPgYp6vOC4+F1spdK+TcZp2bblfK1NzQx/WY xIukSo9ZhrmlIGaochSldjwQk4CA== X-Google-Smtp-Source: AGHT+IEii4/yzMfSp7LOsX7bSvtcsSwu3YPG0OH9OJP+3Z7rDF983ZAsDWCas7p00n2RRZm2FOn48nbu7Q== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a5b:404:0:b0:e0b:eb06:58b2 with SMTP id 3f1490d57ef6-e0beb068624mr15190276.8.1722889054883; Mon, 05 Aug 2024 13:17:34 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:03 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-9-tavip@google.com> Subject: [RFC PATCH 08/23] test/unit: add register access macros and functions From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3XjOxZgUKCsU4l6t0rzzrwp.nzx1px5-op6pwyzyry5.z2r@flex--tavip.bounces.google.com; helo=mail-yb1-xb4a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add register access macros for devices models that use SVD generated registers. This allows accessing register or register bit fields in unit tests, e.g.: REG32_WRITE(f->dev, FLEXCOMM, PSELID, persel); g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM, PSELID, PERSEL) == persel); Also add support for accessing 32bit registers with memory transaction state, e.g.: /* no register access until a function is selected */ g_assert(reg32_addr_read_raw(f->dev, FLEXCOMM_BASE, &tmp, 4) == MEMTX_ERROR); Signed-off-by: Octavian Purdila --- include/hw/regs.h | 2 +- tests/unit/reg-utils.h | 103 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 tests/unit/reg-utils.h diff --git a/include/hw/regs.h b/include/hw/regs.h index 8d0da0629d..fd6576ba2b 100644 --- a/include/hw/regs.h +++ b/include/hw/regs.h @@ -59,7 +59,7 @@ static inline bool reg32_aligned_access(hwaddr addr, unsigned size) * // backstore is updated to 0x78 * reg32_write(&backstore, REG2_ADDR, 0x12345678, wr_bits_array); */ -static inline uint32_t reg32_write(void *base, uint32_t off, uint32_t val, +static inline uint32_t reg32_write(void *base, uint32_t addr, uint32_t val, const uint32_t *rw_bits_array) { uint32_t *ptr = base + addr; diff --git a/tests/unit/reg-utils.h b/tests/unit/reg-utils.h new file mode 100644 index 0000000000..f18ee07d20 --- /dev/null +++ b/tests/unit/reg-utils.h @@ -0,0 +1,103 @@ +/* + * Register access utilities for peripheral device tests. + * + * Copyright (C) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef _REG_UTILS_H +#define _REG_UTILS_H + +#ifdef DEBUG_REG +#define debug(fmt, args...) fprintf(stderr, fmt, ## args) +#else +#define debug(fmt, args...) +#endif + +#define _REG_OFF(mod, field) (offsetof(mod##_Type, field)) + +#define REG32_READ(dev, mod, reg) \ + ({ \ + uint32_t value; \ + value = sysbus_mmio_read_addr(dev, mod##_BASE + _REG_OFF(mod, reg), \ + sizeof(uint32_t)); \ + debug("[%s] -> %08x\n", #reg, value); \ + value; \ + }) + +#define REG32_WRITE(dev, mod, reg, value) \ + do { \ + debug("[%s] <- %08x\n", #reg, value); \ + sysbus_mmio_write_addr(dev, mod##_BASE + _REG_OFF(mod, reg), value, \ + sizeof(uint32_t)); \ + } while (0) + +#define REG_FIELD_VAL(v, mod, reg, field) \ + ((v & mod##_##reg##_##field##_Msk) >> mod##_##reg##_##field##_Pos) + +#define REG32_READ_FIELD(dev, mod, reg, field) \ + REG_FIELD_VAL(REG32_READ(dev, mod, reg), mod, reg, field) + +#define REG32_WRITE_FIELD(dev, mod, reg, field, val) \ + do { \ + uint32_t _tmp = REG32_READ(dev, mod, reg); \ + \ + _tmp &= ~mod##_##reg##_##field##_Msk; \ + _tmp |= (val << mod##_##reg##_##field##_Pos) & \ + mod##_##reg##_##field##_Msk; \ + REG32_WRITE(dev, mod, reg, _tmp); \ + } while (0) + +#define REG32_WRITE_FIELD_NOUPDATE(dev, mod, reg, field, val) \ + do { \ + uint32_t _tmp; \ + \ + _tmp = (val << mod##_##reg##_##field##_Pos) & \ + mod##_##reg##_##field##_Msk; \ + REG32_WRITE(dev, mod, reg, _tmp); \ + } while (0) + +#define WAIT_REG32_FIELD(ms, dev, mod, reg, field, val) \ + { \ + int remaining = ms; \ + \ + while (remaining) { \ + if (REG32_READ_FIELD(dev, mod, reg, field) == val) { \ + break; \ + } \ + main_loop_wait(false); \ + usleep(1000); \ + remaining--; \ + } \ + \ + g_assert(remaining); \ + } + +static inline MemTxResult reg32_addr_read_raw(DeviceState *dev, uint32_t addr, + uint32_t *value, uint32_t size) +{ + MemTxResult res; + uint64_t tmp; + + res = sysbus_mmio_read_addr_raw(dev, addr, &tmp, size); + if (res == MEMTX_OK) { + *value = tmp; + } + debug("%d: [%x] -[%d]-> %08x\n", res, addr, size, *value); + return res; +} + +static inline MemTxResult reg32_addr_write_raw(DeviceState *dev, uint32_t addr, + uint32_t value, uint32_t size) +{ + MemTxResult res; + + res = sysbus_mmio_write_addr_raw(dev, addr, value, size); + debug("%d: [%x] <-[%d]- %08x\n", res, addr, size, value); + return res; +} + +#endif /* _REG_UTILS_H */ From patchwork Mon Aug 5 20:17:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754030 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 638F5C3DA7F for ; Mon, 5 Aug 2024 20:19:12 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49K-000335-PE; Mon, 05 Aug 2024 16:17:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3YDOxZgUKCsc6n8v2t11tyr.p1z3rz7-qr8ry010t07.14t@flex--tavip.bounces.google.com>) id 1sb49I-0002of-Cq for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:44 -0400 Received: from mail-pg1-x549.google.com ([2607:f8b0:4864:20::549]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3YDOxZgUKCsc6n8v2t11tyr.p1z3rz7-qr8ry010t07.14t@flex--tavip.bounces.google.com>) id 1sb49F-0001RE-9v for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:44 -0400 Received: by mail-pg1-x549.google.com with SMTP id 41be03b00d2f7-649731dd35bso8223203a12.0 for ; Mon, 05 Aug 2024 13:17:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889057; x=1723493857; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=xU5YoCp1yOlClenc+sMgGqOCDAj0a2iC6b3QkZBvnbA=; b=pdm/NZJFqMH1tWDotNl04VKDoHIWvrEJ83hniYdxmn9D16cynV0ETM7EHgV3ubrJND w4ljJza6vW8B0awYubUlwZSNOJM8slmLYxE2jjYtyiep3cjBs/1J4wooPmrfHjSIZ5+x 362gNKukqQ9W0A0GPKPA94YvAp5r62HVZ06ag3cm919WJib6UaHjskPNC7pAqDgvdAcy 0ozf6UIjaZW4477dV7yDexEz4IYc9Z9zifTi43ijoEJS+8i8c8i1dcM6SirV0IWqD4sB HM5an3Djsdeolu7u+MutEld2KuzzDALFR5dK5NZAZuzqbEZjOrmM2l6Sd6+Pvh6eFCxP 3MeA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889057; x=1723493857; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=xU5YoCp1yOlClenc+sMgGqOCDAj0a2iC6b3QkZBvnbA=; b=IqIXX7D2pYayq/AGHjWUi45VHvuVp4i5iellKEjbAtai4YS3l+wafD3AEXFafKsFqK ozA4e2oj+nQcO2UA/QYSwTMIZMCSFoPTichU7hMQM91qgixSjNJZOE/4XttbY6xd6djj ylo6zHBP0nx7alcva7uevrnHBEq+aXqRa1ICU+hKMMYX2UPDZ+Ko/jN1YL0oZ9+DwPaO mZamxJVaPyfTxxoDwR6jKmY/SpCPBebLtEORg8F+45dANpVPVzp6d3deLfsuhMMKikqR ST4JGSUhcr9eAX+JxJhYr1UPo923nTE1kI5JhR2jCQxxSAn3A/P7JsAXufFKg4t0fyjy Wy3Q== X-Gm-Message-State: AOJu0YyyQz0r/UCi/nFpXwTFlyDyf7aK5Y/q3rIkrwui0yALGV+tOare VDEFAXwbagZ5pvQpA8676OomZSilw7M98KGtke7e/Gr/Al83ADHt4tva7S/9Oi21rVdBJOtjaso O0+hAPNOwWmiRWmjnBqW8wG5EoAwhl60I09j8LQFE21YAQvmennYN7zQqQyTsPultMe72rYDc/7 GcYWeDTuMa8dnHeARFpsspk04kfg== X-Google-Smtp-Source: AGHT+IEtEwV3xypSgEnFhmUjU6qXW1j+oyQGdeQtD2Sw0m7UuLuMq4ZYQZwgA67eCesfEw+/BoRavLh1Bw== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a17:902:d4c5:b0:1fd:73e6:83c0 with SMTP id d9443c01a7336-1ff572a43eemr5414585ad.1.1722889056755; Mon, 05 Aug 2024 13:17:36 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:04 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-10-tavip@google.com> Subject: [RFC PATCH 09/23] test/unit: add flexcomm unit test From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::549; envelope-from=3YDOxZgUKCsc6n8v2t11tyr.p1z3rz7-qr8ry010t07.14t@flex--tavip.bounces.google.com; helo=mail-pg1-x549.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add flexcomm function selection unit tests. Signed-off-by: Octavian Purdila --- tests/unit/meson.build | 8 +- tests/unit/test-flexcomm.c | 215 +++++++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test-flexcomm.c diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 397f2503f8..4ccb15404d 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -141,7 +141,13 @@ if have_system 'test-bufferiszero': [], 'test-smp-parse': [qom, meson.project_source_root() / 'hw/core/machine-smp.c'], 'test-vmstate': [migration, io], - 'test-yank': ['socket-helpers.c', qom, io, chardev] + 'test-yank': ['socket-helpers.c', qom, io, chardev], + 'test-flexcomm': [ + hwcore, + meson.project_source_root() / 'hw/core/gpio.c', + meson.project_source_root() / 'tests/unit/sysbus-mock.c', + meson.project_source_root() / 'hw/misc/flexcomm.c', + ], } if config_host_data.get('CONFIG_INOTIFY1') tests += {'test-util-filemonitor': []} diff --git a/tests/unit/test-flexcomm.c b/tests/unit/test-flexcomm.c new file mode 100644 index 0000000000..f4efe2ac52 --- /dev/null +++ b/tests/unit/test-flexcomm.c @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/main-loop.h" +#include "exec/memory.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" + +#include "hw/misc/flexcomm.h" +#include "sysbus-mock.h" +#include "reg-utils.h" + +#define MAX_MSG_STACK 2 + +typedef struct { + DeviceState *dev; + char *msg[MAX_MSG_STACK]; + int msg_count; +} TestFixture; + +#define SELECT_MSG(f, selected) "f[%d]select(%d)", f, selected +#define REG_READ_MSG(f, addr, size) "f[%d]reg_read(%x, %d)", f, \ + (uint32_t)addr, size +#define REG_WRITE_MSG(f, addr, data, size) "f[%d]reg_write(%x, %x, %d)", \ + f, (uint32_t)addr, (uint32_t)data, size + +#define FLEXCOMM_BASE 0x40106000UL + + +static void f_ops_select(void *opaque, FlexcommState *s, int f, + bool selected) +{ + TestFixture *tf = (TestFixture *)opaque; + + tf->msg[tf->msg_count++] = g_strdup_printf(SELECT_MSG(f, selected)); +} + +static MemTxResult f_ops_reg_read(void *opaque, FlexcommState *s, int f, + hwaddr addr, uint64_t *data, unsigned size) +{ + TestFixture *tf = (TestFixture *)opaque; + + tf->msg[tf->msg_count++] = g_strdup_printf(REG_READ_MSG(f, addr, size)); + return MEMTX_OK; +} + +static MemTxResult f_ops_reg_write(void *opaque, FlexcommState *s, int f, + hwaddr addr, uint64_t data, unsigned size) +{ + TestFixture *tf = (TestFixture *)opaque; + + tf->msg[tf->msg_count++] = g_strdup_printf(REG_WRITE_MSG(f, addr, data, + size)); + return MEMTX_OK; +} + +static void assert_msg(TestFixture *f, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); + +static void assert_msg(TestFixture *f, const char *fmt, ...) +{ + va_list ap; + char *msg; + + va_start(ap, fmt); + msg = g_strdup_vprintf(fmt, ap); + va_end(ap); + + g_assert_cmpstr(msg, ==, f->msg[--f->msg_count]); +} + +static const FlexcommFunctionOps f_ops = { + .select = f_ops_select, + .reg_read = f_ops_reg_read, + .reg_write = f_ops_reg_write, +}; + +/* + * Test fixture initialization. + */ +static void set_up(TestFixture *f, gconstpointer data) +{ + int i; + + f->dev = qdev_new(TYPE_FLEXCOMM); + g_assert(f->dev); + + if (data != NULL) { + qdev_prop_set_int32(DEVICE(f->dev), "functions", (uintptr_t)data); + } + + qdev_realize_and_unref(f->dev, NULL, NULL); + sysbus_mmio_map(SYS_BUS_DEVICE(f->dev), 0, FLEXCOMM_BASE); + + for (i = 0; i < FLEXCOMM_FUNCTIONS; i++) { + /* replace functions ops */ + flexcomm_unregister_ops(i); + assert(flexcomm_register_ops(i, f, &f_ops, NULL)); + assert(!flexcomm_register_ops(i, f, &f_ops, NULL)); + } + + device_cold_reset(f->dev); +} + +static void tear_down(TestFixture *f, gconstpointer user_data) +{ + qdev_unrealize(f->dev); + g_free(f->dev); +} + +static void select_test(TestFixture *f, gconstpointer user_data) +{ + uint32_t tmp = 0; + struct { + int persel; + int func; + } persel_func_map[] = { + { FLEXCOMM_PERSEL_USART, FLEXCOMM_FUNC_USART }, + { FLEXCOMM_PERSEL_SPI, FLEXCOMM_FUNC_SPI }, + { FLEXCOMM_PERSEL_I2C, FLEXCOMM_FUNC_I2C }, + { FLEXCOMM_PERSEL_I2S_TX, FLEXCOMM_FUNC_I2S }, + { FLEXCOMM_PERSEL_I2S_RX, FLEXCOMM_FUNC_I2S }, + }; + int i; + + /* test that no function is selected */ + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM, PSELID, PERSEL) == 0); + + /* no register access until a function is selected */ + g_assert(reg32_addr_read_raw(f->dev, FLEXCOMM_BASE, &tmp, 4) + == MEMTX_ERROR); + g_assert(reg32_addr_write_raw(f->dev, FLEXCOMM_BASE, tmp, 4) + == MEMTX_ERROR); + + /* test that we can select all functions (including I2S RX) */ + for (i = 0; i < ARRAY_SIZE(persel_func_map); i++) { + int persel = persel_func_map[i].persel; + int func = persel_func_map[i].func; + + REG32_WRITE(f->dev, FLEXCOMM, PSELID, persel); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM, PSELID, PERSEL) == persel); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM, PID, ID) == persel); + + /* check that current function was selected */ + assert_msg(f, SELECT_MSG(func, 1)); + + /* check that previous function was de-selected */ + if (i > 0) { + int prev_func = persel_func_map[i - 1].func; + + assert_msg(f, SELECT_MSG(prev_func, 0)); + } + + /* test that we can access function registers */ + reg32_addr_write_raw(f->dev, FLEXCOMM_BASE + 0x100, 0xabcd, 4); + assert_msg(f, REG_WRITE_MSG(func, 0x100, 0xabcd, 4)); + + reg32_addr_read_raw(f->dev, FLEXCOMM_BASE + 0x100, &tmp, 4); + assert_msg(f, REG_READ_MSG(func, 0x100, 4)); + } + + /* try to select something invalid */ + REG32_WRITE(f->dev, FLEXCOMM, PSELID, 7); + /* check for no function selected */ + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM, PSELID, PERSEL) == 0); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM, PID, ID) == 0); + /* check that previous function was deselected */ + assert_msg(f, SELECT_MSG(FLEXCOMM_FUNC_I2S, 0)); + + /* now select and lock USART */ + tmp = FLEXCOMM_PSELID_LOCK_Msk | FLEXCOMM_PERSEL_USART; + REG32_WRITE(f->dev, FLEXCOMM, PSELID, tmp); + tmp = REG32_READ_FIELD(f->dev, FLEXCOMM, PSELID, PERSEL); + g_assert(tmp == FLEXCOMM_PERSEL_USART); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM, PSELID, LOCK) == 1); + tmp = REG32_READ_FIELD(f->dev, FLEXCOMM, PID, ID); + g_assert(tmp == FLEXCOMM_PERSEL_USART); + assert_msg(f, SELECT_MSG(FLEXCOMM_FUNC_USART, 1)); + + /* try to change the selection to spi */ + REG32_WRITE(f->dev, FLEXCOMM, PSELID, FLEXCOMM_PERSEL_SPI); + /* it should still be locked USART */ + tmp = REG32_READ_FIELD(f->dev, FLEXCOMM, PSELID, PERSEL); + g_assert(tmp == FLEXCOMM_PERSEL_USART); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM, PSELID, LOCK) == 1); + tmp = REG32_READ_FIELD(f->dev, FLEXCOMM, PID, ID); + g_assert(tmp == FLEXCOMM_PERSEL_USART); +} + +/* mock-up */ +const PropertyInfo qdev_prop_chr; + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + /* Initialize object types. */ + sysbus_mock_init(); + module_call_init(MODULE_INIT_QOM); + + g_test_add("/flexcomm/select_test", TestFixture, + (gconstpointer)FLEXCOMM_FULL, set_up, select_test, + tear_down); + + return g_test_run(); +} From patchwork Mon Aug 5 20:17:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754018 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 87A7AC52D70 for ; Mon, 5 Aug 2024 20:18:07 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49Q-0003Vy-Qd; Mon, 05 Aug 2024 16:17:52 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3YjOxZgUKCsk8pAx4v33v0t.r315t19-stAt0232v29.36v@flex--tavip.bounces.google.com>) id 1sb49L-00036o-7N for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:47 -0400 Received: from mail-pf1-x44a.google.com ([2607:f8b0:4864:20::44a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3YjOxZgUKCsk8pAx4v33v0t.r315t19-stAt0232v29.36v@flex--tavip.bounces.google.com>) id 1sb49G-0001TF-4f for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:46 -0400 Received: by mail-pf1-x44a.google.com with SMTP id d2e1a72fcca58-70d1df50db2so119812b3a.0 for ; Mon, 05 Aug 2024 13:17:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889059; x=1723493859; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=c49N6GGLSy9opjp4muaxH3Sb0XY//FAQu7ZNOX8Wu58=; b=vqSoI7DLM/cSp6I0LFfQiKIqAqtTP002ZrWTS9RaWynuJf5b5537cjjHfqOK4r6muH dNf4tKJpOtsrerBMBjIxiq8G8Sm1wINPTwn2nlfmKFL7M8oLYQtzGLWWm27KBDAxoCbj t/MO5P9prmHBwaS20V0q7LbRnnIDfuKTep1r6IGkxiMs/V7mURQq6L4F708dIQY+NSdv o3D+Ua0F4515uwddrY5lCKYQaKrefGgGMDV/OhY5cxTqPuHAT5HnSASODGDWlkYTglS9 Y14ZXH+TlGc2JX38rLffjVn3yEl6Ns/rC9LODH+yVPDNMQLMan+3vknMvCbt3n/Dk0w8 zhVw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889059; x=1723493859; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=c49N6GGLSy9opjp4muaxH3Sb0XY//FAQu7ZNOX8Wu58=; b=J4JqAmxyE2DUkhLcwZ41x+GeAvZGI/8dKdufpAuMtiv+bhhSzWMLG4o/i50lrvynBQ 1/AA9PNIno0VeV07nplTZicMsnMEz0fsaWRT0kbO7GspNoO7ltJDGS0Gc96F37dMaYhy fuefQuSY1OxNMdq2essoRxwuYq8cSWh149Be2ilbvGSI3+gK8bNATNsruaeDbI3TnI5v i10uFOOjyaM/iHwqMWx97lTzjYd0ui27zfGokbVTml0n2j1tTDXBWI7vYwhfZH/Duvul pQdj2SKTPWlcCQpWk0WhjZaTYjHBOvkmtrGny1N2MLmhJK3TvCY95zBnWxL7m1hdV6tM 1YKQ== X-Gm-Message-State: AOJu0Yy3oCrV4C6opW2toStU/7PeSir8L7Y/UXZg0VHO12DfmtSCDoGi 3TXdQAQ/mZvUf6+LBknBt2RGKIpIEWDnCyyogeHxPIFGG7t21DnfHfU9bxAiPPUpwMqOfO0Ngr1 pnBp5OmtMI/+n55qtq8/qvBWbyaWhHu8mEjZk6hJ8plDGEgxoCeHAo8f3Px8DTZ/EjYGrZTB+u7 8gwxUqFV1T464M/JbH4qqp3OVIQg== X-Google-Smtp-Source: AGHT+IHUhdCBb2qP/Rfk7DkSllCc8S8AqxUyTM4uvF8QUbFgLoRBTH1nTm66VqdJDI0OhIag0/X4LPzILQ== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:6a00:85a1:b0:70d:1b0d:a15d with SMTP id d2e1a72fcca58-71065f30ddfmr146221b3a.3.1722889058476; Mon, 05 Aug 2024 13:17:38 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:05 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-11-tavip@google.com> Subject: [RFC PATCH 10/23] hw/char: add support for flexcomm usart From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::44a; envelope-from=3YjOxZgUKCsk8pAx4v33v0t.r315t19-stAt0232v29.36v@flex--tavip.bounces.google.com; helo=mail-pf1-x44a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add support for NXP's flexcomm usart. It supports interupts and FIFO access but no DMA. Signed-off-by: Octavian Purdila --- hw/arm/svd/meson.build | 4 + hw/char/flexcomm_usart.c | 302 +++++++++++++++++++++++++++++++ hw/char/meson.build | 1 + hw/char/trace-events | 9 + hw/misc/flexcomm.c | 9 + include/hw/char/flexcomm_usart.h | 20 ++ include/hw/misc/flexcomm.h | 6 + tests/unit/meson.build | 3 +- 8 files changed, 353 insertions(+), 1 deletion(-) create mode 100644 hw/char/flexcomm_usart.c create mode 100644 include/hw/char/flexcomm_usart.h diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build index 9ce6c1d838..ed0f69f437 100644 --- a/hw/arm/svd/meson.build +++ b/hw/arm/svd/meson.build @@ -2,3 +2,7 @@ genh += custom_target('flexcomm.h', output: 'flexcomm.h', input: 'MIMXRT595S_cm33.xml', command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'FLEXCOMM0', '-t', 'FLEXCOMM']) +genh += custom_target('flexcomm_usart.h', + output: 'flexcomm_usart.h', + input: 'MIMXRT595S_cm33.xml', + command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'USART0', '-t', 'FLEXCOMM_USART']) diff --git a/hw/char/flexcomm_usart.c b/hw/char/flexcomm_usart.c new file mode 100644 index 0000000000..c00106eee6 --- /dev/null +++ b/hw/char/flexcomm_usart.c @@ -0,0 +1,302 @@ +/* + * QEMU model for NXP's FLEXCOMM USART + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "exec/address-spaces.h" +#include "qapi/error.h" +#include "trace.h" +#include "hw/regs.h" +#include "hw/char/flexcomm_usart.h" + +#define reg(field) offsetof(FLEXCOMM_USART_Type, field) +#define regi(x) (reg(x) / sizeof(uint32_t)) +#define REG_NO (sizeof(FLEXCOMM_USART_Type) / sizeof(uint32_t)) + +static FLEXCOMM_USART_REGISTER_NAMES_ARRAY(reg_names); + +static void flexcomm_usart_reset(FlexcommState *s) +{ + flexcomm_usart_reset_registers(&s->regs.usart); +} + +static void update_fifo_stat(FlexcommState *s) +{ + int rxlvl = fifo32_num_used(&s->rx_fifo); + int txlvl = fifo32_num_used(&s->tx_fifo); + + s->regs.usart.FIFOSTAT_b.RXLVL = fifo32_num_used(&s->rx_fifo); + s->regs.usart.FIFOSTAT_b.TXLVL = fifo32_num_used(&s->tx_fifo); + s->regs.usart.FIFOSTAT_b.RXFULL = fifo32_is_full(&s->rx_fifo) ? 1 : 0; + s->regs.usart.FIFOSTAT_b.RXNOTEMPTY = !fifo32_is_empty(&s->rx_fifo) ? 1 : 0; + s->regs.usart.FIFOSTAT_b.TXNOTFULL = !fifo32_is_full(&s->tx_fifo) ? 1 : 0; + s->regs.usart.FIFOSTAT_b.TXEMPTY = fifo32_is_empty(&s->tx_fifo) ? 1 : 0; + + if (s->regs.usart.FIFOTRIG_b.RXLVLENA && + (rxlvl > s->regs.usart.FIFOTRIG_b.RXLVL)) { + s->regs.usart.FIFOINTSTAT_b.RXLVL = 1; + } else { + s->regs.usart.FIFOINTSTAT_b.RXLVL = 0; + } + + if (s->regs.usart.FIFOTRIG_b.TXLVLENA && + (txlvl <= s->regs.usart.FIFOTRIG_b.TXLVL)) { + s->regs.usart.FIFOINTSTAT_b.TXLVL = 1; + } else { + s->regs.usart.FIFOINTSTAT_b.TXLVL = 0; + } + + trace_flexcomm_usart_fifostat(DEVICE(s)->id, s->regs.usart.FIFOSTAT, + s->regs.usart.FIFOINTSTAT); +} + +static void flexcomm_usart_irq_update(FlexcommState *s) +{ + bool irq, per_irqs, fifo_irqs, enabled = s->regs.usart.CFG_b.ENABLE; + + update_fifo_stat(s); + fifo_irqs = s->regs.usart.FIFOINTSTAT & s->regs.usart.FIFOINTENSET; + + s->regs.usart.INTSTAT = s->regs.usart.STAT & s->regs.usart.INTENSET; + per_irqs = s->regs.usart.INTSTAT != 0; + + irq = enabled && (fifo_irqs || per_irqs); + + trace_flexcomm_usart_irq(DEVICE(s)->id, irq, fifo_irqs, per_irqs, enabled); + flexcomm_irq(s, irq); +} + +static int flexcomm_usart_rx_space(void *opaque) +{ + FlexcommState *s = opaque; + uint32_t ret = fifo32_num_free(&s->rx_fifo); + + if (!s->regs.usart.CFG_b.ENABLE || !s->regs.usart.FIFOCFG_b.ENABLERX) { + ret = 0; + } + + trace_flexcomm_usart_rx_space(DEVICE(s)->id, ret); + + return ret; +} + +static void flexcomm_usart_rx(void *opaque, const uint8_t *buf, int size) +{ + FlexcommState *s = opaque; + + if (!s->regs.usart.CFG_b.ENABLE || !s->regs.usart.FIFOCFG_b.ENABLERX) { + return; + } + + trace_flexcomm_usart_rx(DEVICE(s)->id); + + while (!fifo32_is_full(&s->rx_fifo) && size) { + fifo32_push(&s->rx_fifo, *buf++); + size--; + } + + flexcomm_usart_irq_update(s); +} + +static MemTxResult flexcomm_usart_reg_read(void *opaque, FlexcommState *s, + int f, hwaddr addr, uint64_t *data, + unsigned size) +{ + MemTxResult ret = MEMTX_OK; + + if (!reg32_aligned_access(addr, size)) { + ret = MEMTX_ERROR; + goto out; + } + + switch (addr) { + case reg(FIFORD): + { + if (!fifo32_is_empty(&s->rx_fifo)) { + *data = fifo32_pop(&s->rx_fifo); + qemu_chr_fe_accept_input(&s->chr); + } + break; + } + case reg(FIFORDNOPOP): + { + if (!fifo32_is_empty(&s->rx_fifo)) { + *data = fifo32_peek(&s->rx_fifo); + } + break; + } + default: + *data = reg32_read(&s->regs, addr); + break; + } + + flexcomm_usart_irq_update(s); + +out: + trace_flexcomm_usart_reg_read(DEVICE(s)->id, reg_names[addr], addr, *data); + return ret; +} + +static MemTxResult flexcomm_usart_reg_write(void *opaque, FlexcommState *s, + int f, hwaddr addr, uint64_t value, + unsigned size) +{ + MemTxResult ret = MEMTX_OK; + static uint32_t mask[REG_NO] = { + [regi(CFG)] = BITS(23, 18) | BITS(15, 14) | BITS(12, 11) | BITS(9, 2) | + BIT(0), + [regi(CTL)] = BIT(16) | BITS(9, 8) | BIT(6) | BITS(2, 1), + [regi(STAT)] = BITS(16, 11) | BIT(5), + [regi(INTENSET)] = BITS(16, 11) | BITS(6, 5) | BIT(3), + [regi(INTENCLR)] = BITS(16, 11) | BITS(6, 5) | BIT(3), + [regi(BRG)] = BITS(15, 0), + [regi(OSR)] = BITS(3, 0), + [regi(ADDR)] = BITS(7, 0), + [regi(FIFOCFG)] = BITS(16, 12) | BITS(5, 4) | BITS(1, 0), + [regi(FIFOSTAT)] = BITS(1, 0), + [regi(FIFOTRIG)] = BITS(19, 16) | BITS(11, 8) | BITS(1, 0), + [regi(FIFOINTENSET)] = BITS(3, 0), + [regi(FIFOINTENCLR)] = BITS(3, 0), + [regi(FIFOWR)] = BITS(8, 0), + }; + + if (!reg32_aligned_access(addr, size)) { + ret = MEMTX_ERROR; + goto out; + } + + switch (addr) { + case reg(INTENCLR): + { + reg32_write(&s->regs, addr, value, mask); + s->regs.usart.INTENSET &= ~s->regs.usart.INTENCLR; + break; + } + case reg(FIFOCFG): + { + reg32_write(&s->regs, addr, value, mask); + if (s->regs.usart.FIFOCFG_b.EMPTYRX) { + s->regs.usart.FIFOCFG_b.EMPTYRX = 0; + fifo32_reset(&s->rx_fifo); + } + if (s->regs.usart.FIFOCFG_b.EMPTYTX) { + s->regs.usart.FIFOCFG_b.EMPTYTX = 0; + fifo32_reset(&s->tx_fifo); + } + break; + } + case reg(FIFOSTAT): + { + bool rxerr = s->regs.usart.FIFOSTAT_b.RXERR; + bool txerr = s->regs.usart.FIFOSTAT_b.TXERR; + + reg32_write(&s->regs, addr, value, mask); + + if (rxerr && s->regs.usart.FIFOSTAT_b.RXERR) { + rxerr = false; + } + if (txerr && s->regs.usart.FIFOSTAT_b.TXERR) { + txerr = false; + } + + s->regs.usart.FIFOSTAT_b.RXERR = rxerr; + s->regs.usart.FIFOSTAT_b.TXERR = txerr; + break; + } + case reg(FIFOINTENSET): + { + s->regs.usart.FIFOINTENSET |= value & mask[addr / 4]; + break; + } + case reg(FIFOINTENCLR): + { + reg32_write(&s->regs, addr, value, mask); + s->regs.usart.FIFOINTENSET &= ~s->regs.usart.FIFOINTENCLR; + break; + } + case reg(FIFOWR): + { + reg32_write(&s->regs, addr, value, mask); + if (!fifo32_is_full(&s->tx_fifo)) { + fifo32_push(&s->tx_fifo, s->regs.usart.FIFOWR); + } + + if (!s->regs.usart.CFG_b.ENABLE || !s->regs.usart.FIFOCFG_b.ENABLETX) { + break; + } + + while (!fifo32_is_empty(&s->tx_fifo)) { + uint32_t val32 = fifo32_pop(&s->tx_fifo); + uint8_t val8 = val32 & 0xff; + + trace_flexcomm_usart_tx(DEVICE(s)->id); + qemu_chr_fe_write_all(&s->chr, &val8, sizeof(val8)); + } + break; + } + case reg(CFG): + { + reg32_write(&s->regs, addr, value, mask); + break; + } + default: + reg32_write(&s->regs, addr, value, mask); + break; + } + + flexcomm_usart_irq_update(s); + +out: + trace_flexcomm_usart_reg_write(DEVICE(s)->id, reg_names[addr], addr, value); + return ret; +} + +static void flexcomm_usart_select(void *opaque, FlexcommState *s, int f, + bool set) +{ + if (set) { + qemu_chr_fe_set_handlers(&s->chr, flexcomm_usart_rx_space, + flexcomm_usart_rx, NULL, NULL, + s, NULL, true); + flexcomm_usart_reset(s); + fifo32_create(&s->rx_fifo, s->regs.usart.FIFOSIZE_b.FIFOSIZE); + fifo32_create(&s->tx_fifo, s->regs.usart.FIFOSIZE_b.FIFOSIZE); + } else { + qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL, NULL, NULL, + false); + fifo32_destroy(&s->rx_fifo); + fifo32_destroy(&s->tx_fifo); + } +} + +static const FlexcommFunctionOps flexcomm_usart_ops = { + .select = flexcomm_usart_select, + .reg_read = flexcomm_usart_reg_read, + .reg_write = flexcomm_usart_reg_write, +}; + +void flexcomm_usart_init(FlexcommState *s) +{ +} + +void flexcomm_usart_register(void) +{ + Error *err = NULL; + + if (!flexcomm_register_ops(FLEXCOMM_FUNC_USART, NULL, + &flexcomm_usart_ops, &err)) { + error_report_err(err); + } +} diff --git a/hw/char/meson.build b/hw/char/meson.build index e5b13b6958..8f8c17ae66 100644 --- a/hw/char/meson.build +++ b/hw/char/meson.build @@ -39,3 +39,4 @@ system_ss.add(when: 'CONFIG_GOLDFISH_TTY', if_true: files('goldfish_tty.c')) specific_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('terminal3270.c')) specific_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-serial-bus.c')) specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_vty.c')) +system_ss.add(when: 'CONFIG_FLEXCOMM', if_true: files('flexcomm_usart.c')) diff --git a/hw/char/trace-events b/hw/char/trace-events index 8875758076..19fcf1f832 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -125,3 +125,12 @@ xen_console_unrealize(unsigned int idx) "idx %u" xen_console_realize(unsigned int idx, const char *chrdev) "idx %u chrdev %s" xen_console_device_create(unsigned int idx) "idx %u" xen_console_device_destroy(unsigned int idx) "idx %u" + +# flexcomm_usart.c +flexcomm_usart_reg_read(const char *id, const char *reg_name, uint32_t addr, uint32_t val) " %s: %s[0x%04x] -> 0x%08x" +flexcomm_usart_reg_write(const char *id, const char *reg_name, uint32_t addr, uint32_t val) "%s: %s[0x%04x] <- 0x%08x" +flexcomm_usart_rx_space(const char *id, uint32_t rx) "%s: %d" +flexcomm_usart_rx(const char *id) "%s" +flexcomm_usart_tx(const char *id) "%s" +flexcomm_usart_fifostat(const char *id, uint32_t fifostat, uint32_t fifoinstat) "%s: %08x %08x" +flexcomm_usart_irq(const char *id, bool irq, bool fifoirqs, bool perirqs, bool enabled) "%s: %d %d %d %d" diff --git a/hw/misc/flexcomm.c b/hw/misc/flexcomm.c index 6ec3773910..0c94928aa2 100644 --- a/hw/misc/flexcomm.c +++ b/hw/misc/flexcomm.c @@ -22,6 +22,7 @@ #include "trace.h" #include "hw/regs.h" #include "hw/misc/flexcomm.h" +#include "hw/char/flexcomm_usart.h" #define reg(field) offsetof(FLEXCOMM_Type, field) #define regi(x) (reg(x) / sizeof(uint32_t)) @@ -203,6 +204,7 @@ static const MemoryRegionOps flexcomm_ops = { static Property flexcomm_properties[] = { DEFINE_PROP_UINT32("functions", FlexcommState, functions, FLEXCOMM_FULL), + DEFINE_PROP_CHR("chardev", FlexcommState, chr), DEFINE_PROP_END_OF_LIST(), }; @@ -221,6 +223,11 @@ static void flexcomm_init(Object *obj) static void flexcomm_realize(DeviceState *dev, Error **errp) { + FlexcommState *s = FLEXCOMM(dev); + + if (has_function(s, FLEXCOMM_FUNC_USART)) { + flexcomm_usart_init(s); + } } static void flexcomm_class_init(ObjectClass *klass, void *data) @@ -230,6 +237,8 @@ static void flexcomm_class_init(ObjectClass *klass, void *data) dc->reset = flexcomm_reset; device_class_set_props(dc, flexcomm_properties); dc->realize = flexcomm_realize; + + flexcomm_usart_register(); } static const TypeInfo flexcomm_info = { diff --git a/include/hw/char/flexcomm_usart.h b/include/hw/char/flexcomm_usart.h new file mode 100644 index 0000000000..07d14cb330 --- /dev/null +++ b/include/hw/char/flexcomm_usart.h @@ -0,0 +1,20 @@ +/* + * QEMU model for NXP's FLEXCOMM USART + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_CHAR_FLEXCOMM_USART_H +#define HW_CHAR_FLEXCOMM_USART_H + +#include "hw/misc/flexcomm.h" + +void flexcomm_usart_init(FlexcommState *s); +void flexcomm_usart_register(void); + +#endif /* HW_CHAR_RT500_FLEXCOMM_USART_H */ diff --git a/include/hw/misc/flexcomm.h b/include/hw/misc/flexcomm.h index 422452bd96..db76e32c6d 100644 --- a/include/hw/misc/flexcomm.h +++ b/include/hw/misc/flexcomm.h @@ -13,7 +13,9 @@ #define HW_FLEXCOMM_H #include "hw/sysbus.h" +#include "chardev/char-fe.h" #include "hw/arm/svd/flexcomm.h" +#include "hw/arm/svd/flexcomm_usart.h" #include "qemu/fifo32.h" #define TYPE_FLEXCOMM "flexcomm" @@ -43,10 +45,14 @@ typedef struct { MemoryRegion mmio; union { FLEXCOMM_Type flex; + FLEXCOMM_USART_Type usart; } regs; uint32_t functions; qemu_irq irq; bool irq_state; + CharBackend chr; + Fifo32 tx_fifo; + Fifo32 rx_fifo; } FlexcommState; typedef struct { diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 4ccb15404d..70e816c034 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -143,10 +143,11 @@ if have_system 'test-vmstate': [migration, io], 'test-yank': ['socket-helpers.c', qom, io, chardev], 'test-flexcomm': [ - hwcore, + hwcore, chardev, qom, migration, meson.project_source_root() / 'hw/core/gpio.c', meson.project_source_root() / 'tests/unit/sysbus-mock.c', meson.project_source_root() / 'hw/misc/flexcomm.c', + meson.project_source_root() / 'hw/char/flexcomm_usart.c', ], } if config_host_data.get('CONFIG_INOTIFY1') From patchwork Mon Aug 5 20:17:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754022 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1C115C3DA4A for ; Mon, 5 Aug 2024 20:18:30 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49Q-0003RA-23; Mon, 05 Aug 2024 16:17:52 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3ZDOxZgUKCssArCz6x55x2v.t537v3B-uvCv2454x4B.58x@flex--tavip.bounces.google.com>) id 1sb49L-00036l-6P for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:47 -0400 Received: from mail-yw1-x114a.google.com ([2607:f8b0:4864:20::114a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3ZDOxZgUKCssArCz6x55x2v.t537v3B-uvCv2454x4B.58x@flex--tavip.bounces.google.com>) id 1sb49H-0001Td-84 for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:46 -0400 Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-664916e5b40so2092217b3.1 for ; Mon, 05 Aug 2024 13:17:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889060; x=1723493860; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=4nDAaRYoPQUybXMrCeQ4yM0etvHUlZuu5xJy/FcdLbg=; b=VjJbhMzZZvfUmILjLUPhDyy594hs6XjOdfWPM3GnzoDbDjemVaNqYgEkmz/5R1M7GS Z9kJnQhP01Crp/H2Ekl82mH9cJXpwNXVnB83yp15vf0kwNtP8BlQhFoXqtyyawnUmnNm lxBR82csc51d9rZIYr4jZHtytVQ4Jfy32IasdgBRr0WKFstMTpW8R+ToWJfeVbkCykEt S0GtxUuMQr0wWTMHz+FUv155Go4uwFZd+wHC+Pn0tJF+TbajSdJUlvXTo1okLFKBz2jn dgBzdYJpk7gcAkWjIcZtN6+eL5RzO1RQNGpBbWS4N6f1rG3emaUs73glG1cU4xydzrbf KESw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889060; x=1723493860; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=4nDAaRYoPQUybXMrCeQ4yM0etvHUlZuu5xJy/FcdLbg=; b=EF3aG5WuOVhf0rtAwG+MZ8GBeIZ6rk1vkPZkWCX7OVvlTLTCtGaBg9L0ENU9mhzGBO jpJbGEgL7mYbsSlZv4kvJh0LN2/P8D/qyulGr9xveYUUlc6+uUcxMlDvEwY2qQns6igL Lj5uS52sxvfhQ8wUb/OeYZENDsJDAkuExCEDz7vmhshWHhmBApsa1nNFFY1IluIOJn4J Mlkw5FMxM6qGOoi6rbxXDNvGh+DpPpBLZHZgo+Ou7OCFSOk6LmNgIZtBoGgZhRjyFt5t hWJqBZlwry5ALlN25FE9EM7Qstn+vDJmK4WkXJVHZ3NFOINpprTHQjxD/FJUEgbO4fgO 6xzA== X-Gm-Message-State: AOJu0Yz8QNx4GCelUZlArcTpKuh50xOQFx/8elefxhaQqczS4TP2Gr13 LdwseFNfQm3XKPq32jxFOaqmJdgm881qcDIhEwy8im94XJr4NBoZPT4ceGIib8JZI676U1S3oXS 5WaVY45pPvMVB+GRe5iDYLpfg4bnzenoTk42IASi5iz4qf4ygtKW/nomjthmMZ9RMe06rBTY062 xR/rvXOgPxTd5AnLgkIItqGG+irg== X-Google-Smtp-Source: AGHT+IEbUnH+6fvsnahVEKUA+AUBoPinsmnz1TNDh7dXnwnN24dOVdyWczd/BAVBFAEQ1m9fDZI+fItK6w== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a0d:c843:0:b0:665:7b0d:ed27 with SMTP id 00721157ae682-688b7457a53mr986987b3.2.1722889060159; Mon, 05 Aug 2024 13:17:40 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:06 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-12-tavip@google.com> Subject: [RFC PATCH 11/23] test/unit: add flexcomm usart unit test From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::114a; envelope-from=3ZDOxZgUKCssArCz6x55x2v.t537v3B-uvCv2454x4B.58x@flex--tavip.bounces.google.com; helo=mail-yw1-x114a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add polling and irq unit tests for the flexcomm usart device model. Signed-off-by: Octavian Purdila --- tests/unit/meson.build | 7 + tests/unit/test-flexcomm-usart.c | 321 +++++++++++++++++++++++++++++++ 2 files changed, 328 insertions(+) create mode 100644 tests/unit/test-flexcomm-usart.c diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 70e816c034..dcfd2e661c 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -149,6 +149,13 @@ if have_system meson.project_source_root() / 'hw/misc/flexcomm.c', meson.project_source_root() / 'hw/char/flexcomm_usart.c', ], + 'test-flexcomm-usart': [ + hwcore, chardev, qom, migration, + meson.project_source_root() / 'hw/core/gpio.c', + meson.project_source_root() / 'tests/unit/sysbus-mock.c', + meson.project_source_root() / 'hw/misc/flexcomm.c', + meson.project_source_root() / 'hw/char/flexcomm_usart.c', + ], } if config_host_data.get('CONFIG_INOTIFY1') tests += {'test-util-filemonitor': []} diff --git a/tests/unit/test-flexcomm-usart.c b/tests/unit/test-flexcomm-usart.c new file mode 100644 index 0000000000..645f3b4c26 --- /dev/null +++ b/tests/unit/test-flexcomm-usart.c @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" + +#include "qemu/config-file.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qapi/error.h" +#include "qemu/sockets.h" +#include "sysemu/sysemu.h" +#include "qemu/main-loop.h" +#include "qemu/option.h" +#include "exec/memory.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" + +#include "hw/misc/flexcomm.h" +#include "sysbus-mock.h" +#include "reg-utils.h" + +typedef struct { + DeviceState *dev; + int sock; + Chardev *chr; + bool irq; +} TestFixture; + +#define FLEXCOMM_BASE 0x40106000UL +#define FLEXCOMM_USART_BASE FLEXCOMM_BASE + +/* Callback for the interrupt line. */ +static void usart_irq_set(void *opaque, int line, int level) +{ + TestFixture *f = (TestFixture *)opaque; + + f->irq = level; +} + +/* + * Test fixture initialization. + */ +static void set_up(TestFixture *f, gconstpointer data) +{ + struct sockaddr_in sockaddr = { + .sin_family = AF_INET, + }; + socklen_t sockaddr_len = sizeof(sockaddr); + char chr_opts[] = "udp:127.0.0.1:xxxxx"; + FlexcommState *s; + char buf[] = "xxx"; + int port; + + /* create "server" socket and bind to a random port */ + f->sock = socket(AF_INET, SOCK_DGRAM, 0); + g_assert(f->sock >= 0); + g_assert(bind(f->sock, &sockaddr, sizeof(sockaddr)) == 0); + g_assert(getsockname(f->sock, &sockaddr, &sockaddr_len) == 0); + + /* create the an UDP char device and connect it to the sever */ + port = ntohs(sockaddr.sin_port); + g_assert(port != 0); + snprintf(chr_opts, sizeof(chr_opts), "udp:127.0.0.1:%d", port); + f->chr = qemu_chr_new("udp", chr_opts, NULL); + g_assert_nonnull(f->chr); + + /* test connectivity and connect server to UDP char device */ + qemu_chr_write_all(f->chr, (const uint8_t *)"210", sizeof("210")); + recvfrom(f->sock, buf, sizeof(buf), 0, &sockaddr, &sockaddr_len); + g_assert(strcmp(buf, "210") == 0); + g_assert(sockaddr_len == sizeof(sockaddr)); + g_assert(connect(f->sock, &sockaddr, sockaddr_len) == 0); + + f->dev = qdev_new(TYPE_FLEXCOMM); + g_assert(f->dev); + + s = FLEXCOMM(f->dev); + s->irq = qemu_allocate_irq(usart_irq_set, f, 0); + g_assert(qemu_chr_fe_init(&s->chr, f->chr, &error_abort)); + + if (data != NULL) { + qdev_prop_set_int32(DEVICE(f->dev), "functions", (uintptr_t)data); + } + + qdev_realize_and_unref(f->dev, NULL, &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(f->dev), 0, FLEXCOMM_BASE); + + qemu_chr_be_update_read_handlers(f->chr, NULL); + + device_cold_reset(f->dev); +} + +static void tear_down(TestFixture *f, gconstpointer user_data) +{ + qdev_unrealize(f->dev); + object_unparent(OBJECT(f->chr)); + close(f->sock); + g_free(f->dev); +} + +static void polling_test(TestFixture *f, gconstpointer user_data) +{ + int i; + uint32_t tmp; + unsigned char byte; + int fifo_size; + + /* select and lock USART */ + tmp = FLEXCOMM_PSELID_LOCK_Msk | FLEXCOMM_PERSEL_USART; + REG32_WRITE(f->dev, FLEXCOMM, PSELID, tmp); + + fifo_size = REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSIZE, FIFOSIZE); + + /* enable USART */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_USART, CFG, ENABLE, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, CFG, ENABLE) == 1); + + /* enable TX and RX FIFO */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_USART, FIFOCFG, ENABLETX, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOCFG, ENABLETX) == 1); + REG32_WRITE_FIELD(f->dev, FLEXCOMM_USART, FIFOCFG, ENABLERX, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOCFG, ENABLERX) == 1); + + /* test writes and fifo counters wrap */ + for (i = 0; i < fifo_size / 2; i++) { + /* check fifostat */ + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, RXFULL) == + 0); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, RXNOTEMPTY) + == 0); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, TXNOTFULL) + == 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, TXEMPTY) == + 1); + + REG32_WRITE(f->dev, FLEXCOMM_USART, FIFOWR, 'a' + i); + recv(f->sock, &byte, 1, 0); + g_assert_cmpuint(byte, ==, 'a' + i); + } + + /* test reads and fifo level */ + + for (i = 0; i < fifo_size / 2; i++) { + byte = 'A' + i; + g_assert(send(f->sock, &byte, 1, 0) == 1); + } + + /* wait for the RXLVL to update */ + WAIT_REG32_FIELD(1000, f->dev, FLEXCOMM_USART, FIFOSTAT, RXLVL, + fifo_size / 2); + + /* check fifo stat */ + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, RXFULL) == 0); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, RXNOTEMPTY) + == 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, TXNOTFULL) + == 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, TXEMPTY) + == 1); + + /* send until FIFO is full */ + for (i = fifo_size / 2; i < fifo_size; i++) { + byte = 'A' + i; + g_assert(send(f->sock, &byte, 1, 0) == 1); + } + + /* wait for the RXLVL to update */ + WAIT_REG32_FIELD(1000, f->dev, FLEXCOMM_USART, FIFOSTAT, RXLVL, fifo_size); + + /* check fifo stat */ + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, RXFULL) == 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, RXNOTEMPTY) == + 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, TXNOTFULL) == + 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, TXEMPTY) == + 1); + + /* check read no pop */ + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFORDNOPOP, RXDATA) == + 'A'); + + /* now read from the fifo */ + for (i = 0; i < fifo_size; i++) { + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFORD, RXDATA) == + 'A' + i); + } + + /* check fifostat */ + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, RXFULL) == 0); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, RXNOTEMPTY) == + 0); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, TXNOTFULL) == + 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, TXEMPTY) == 1); +} + +static void irq_test(TestFixture *f, gconstpointer user_data) +{ + char buf[256] = { 0, }; + uint32_t tmp; + + /* select and lock FLEXCOMM_USART */ + tmp = FLEXCOMM_PSELID_LOCK_Msk | FLEXCOMM_PERSEL_USART; + REG32_WRITE(f->dev, FLEXCOMM, PSELID, tmp); + + /* + * set RX IRQ/DMA trigger level to 4 bytes - value 3 in FIFOTRIG + * + * 0000 - Trigger when the RX FIFO has received 1 entry (is no longer empty) + * 0001 - Trigger when the RX FIFO has received 2 entries + * 1111 - Trigger when the RX FIFO has received 16 entries (has become full) + */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_USART, FIFOTRIG, RXLVL, 3); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOTRIG, RXLVL) == 3); + + /* enable RX trigger for IRQ/DMA */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_USART, FIFOTRIG, RXLVLENA, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOTRIG, RXLVLENA) == 1); + + /* enable RXLVL interrupt */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_USART, FIFOINTENSET, RXLVL, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOINTENSET, RXLVL) + == 1); + + /* enable FLEXCOMM_USART */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_USART, CFG, ENABLE, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, CFG, ENABLE) == 1); + + /* enable TX and RX FIFO */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_USART, FIFOCFG, ENABLETX, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOCFG, ENABLETX) == 1); + REG32_WRITE_FIELD(f->dev, FLEXCOMM_USART, FIFOCFG, ENABLERX, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOCFG, ENABLERX) == 1); + + /* check interrupt status */ + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOINTSTAT, RXLVL) == 0); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOINTSTAT, TXLVL) == 0); + g_assert(f->irq == false); + + /* enable TX trigger for IRQ/DMA */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_USART, FIFOTRIG, TXLVLENA, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOTRIG, TXLVLENA) == 1); + + /* enable irq for TX */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_USART, FIFOINTENSET, TXLVL, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOINTENSET, TXLVL) == + 1); + + /* check TX irq */ + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOINTSTAT, TXLVL) == 1); + g_assert(f->irq == true); + + /* disable irq for TX */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_USART, FIFOTRIG, TXLVLENA, 0); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOTRIG, TXLVLENA) == 0); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOINTSTAT, TXLVL) == 0); + g_assert(f->irq == false); + + /* send 3 bytes */ + g_assert(send(f->sock, buf, 3, 0) == 3); + + /* check that we have 3 bytes in the fifo */ + WAIT_REG32_FIELD(1000, f->dev, FLEXCOMM_USART, FIFOSTAT, RXLVL, 3); + + /* and no interrupt has been triggered yet */ + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOINTSTAT, RXLVL) == 0); + g_assert(f->irq == false); + + /* push it over the edge */ + g_assert(send(f->sock, buf, 1, 0) == 1); + + /* check that we have 4 bytes in the fifo */ + WAIT_REG32_FIELD(1000, f->dev, FLEXCOMM_USART, FIFOSTAT, RXLVL, 4); + + /* and the interrupt has been triggered */ + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOINTSTAT, RXLVL) == 1); + g_assert(f->irq == true); + + /* read one byte from the fifo */ + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFORD, RXDATA) == 0); + + /* we should have 3 bytes in the FIFO */ + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOSTAT, RXLVL) == 3); + + /* and no interrupts active */ + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_USART, FIFOINTSTAT, RXLVL) == 0); + g_assert(f->irq == false); +} + +/* mock-up */ +const PropertyInfo qdev_prop_chr; + +int main(int argc, char **argv) +{ + qemu_init_main_loop(&error_abort); + socket_init(); + + g_test_init(&argc, &argv, NULL); + + /* Initialize object types. */ + sysbus_mock_init(); + module_call_init(MODULE_INIT_QOM); + qemu_add_opts(&qemu_chardev_opts); + + g_test_add("/flexcomm-usart/polling", TestFixture, + (gconstpointer)(1 << FLEXCOMM_FUNC_USART), + set_up, polling_test, tear_down); + + g_test_add("/flexcomm-usart/irq", TestFixture, + (gconstpointer)(1 << FLEXCOMM_FUNC_USART), + set_up, irq_test, tear_down); + + return g_test_run(); +} From patchwork Mon Aug 5 20:17:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754032 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 088ADC3DA4A for ; Mon, 5 Aug 2024 20:19:23 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49S-0003cc-2V; Mon, 05 Aug 2024 16:17:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3ZTOxZgUKCswBsD07y66y3w.u648w4C-vwDw3565y5C.69y@flex--tavip.bounces.google.com>) id 1sb49O-0003L9-GY for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:51 -0400 Received: from mail-pj1-x104a.google.com ([2607:f8b0:4864:20::104a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3ZTOxZgUKCswBsD07y66y3w.u648w4C-vwDw3565y5C.69y@flex--tavip.bounces.google.com>) id 1sb49L-0001Tr-Gg for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:49 -0400 Received: by mail-pj1-x104a.google.com with SMTP id 98e67ed59e1d1-2cb4d02f34cso10950096a91.3 for ; Mon, 05 Aug 2024 13:17:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889063; x=1723493863; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=JJx2zYTysuPPGq4jl/CUtBvGg4dYG4R93ytcuWg1fhs=; b=eFeDg+4ImBxloSjupfPH3XHn743nG7QTAZpYTG5QEt2aUMeLAwZJWTwVbZxQJIXRw1 yqB+f4GFKP8FxMCt7VNC31bz8qCgF0AbR1N3NC/mR7z1VaCxWwnO8Sa2PCsATfDUJsIr IWIgLLZZ88C9j1Ju56JVABv1YF4kFna8cR+2vNPs/JLYbhl1YWt8El6rI1nJ3kE/jwBw pnKnYQjSHxI4CWZSEjsFUyXkILViD0ttHF4YcnHuLGM6Sq8SbAdwjCkN6N0fO6zubt/i 9j2imVM35EI5cjt8c/lmTP4qnRfv9+a5JrHEP1DcXJIos5LmS63try320nFsuiHxprMq sehA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889063; x=1723493863; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=JJx2zYTysuPPGq4jl/CUtBvGg4dYG4R93ytcuWg1fhs=; b=liEvEp8wY2CEQQbg7kDancJLogpSktcplHG3QwFokPN1vMV9HkDsmS4WAPleYT82uB 9meUuZnBUWMOjCKcGDNeWSrSyN7Lx/eKGDGm55bmxjmUJh0SPnAyDtSuKEHf8GMCxgz1 69Is21NqbRcjtBstjcmuxTsicbJEsIrO+T/PJJWnequKVpoLZqKew4NyQCk1xgrmWa0+ +qRI+ubtS1jEOjkiqVwD4v/7QxDj8FXrQPUUMD8nYcAPVHd9iW735OBbVHOQTr+pBSb4 sRfXkdKOQbwt4kPo++o5g+7Xy6gSQGgoWl1fduH4ILLeHDGtflctPVFkRIswFDRMTttg nS0Q== X-Gm-Message-State: AOJu0YzLSyR4IQKMeVh7ziyNNNSVM8Pi4x1uCXdmY30HbVaQ55elL3Jo o6PoT3+OsT71z6wftNFSaHjGcEXgjr0h+7/tmjoCz7aIFluHtXYocEEvJ32pZPglqAt4e9bC2Q3 MzCXQbWuGzhulgejxFwWlzzetNqUD5UY0S+zVogSquuRsXI/H6Rh0ke86G2PMm33cQz+hZsRAWg wvFXf/UwVN8pKz2wSs12QtC7LRyA== X-Google-Smtp-Source: AGHT+IFJ6HmLYx+llIq607FEkRA2hqMCqRAGPVf+vAAKgX7jthaVgxS/Ia/9f+16jdToHqdzT0ceAn1c4g== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a17:90b:3e8c:b0:2c9:9208:ee66 with SMTP id 98e67ed59e1d1-2cff956d6f7mr34756a91.7.1722889061818; Mon, 05 Aug 2024 13:17:41 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:07 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-13-tavip@google.com> Subject: [RFC PATCH 12/23] hw/i2c: add support for flexcomm i2c From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::104a; envelope-from=3ZTOxZgUKCswBsD07y66y3w.u648w4C-vwDw3565y5C.69y@flex--tavip.bounces.google.com; helo=mail-pj1-x104a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add support for NXP's flexcomm i2c. It does not support slave mode or DMA. Signed-off-by: Octavian Purdila --- hw/arm/svd/meson.build | 4 + hw/i2c/flexcomm_i2c.c | 224 ++++++++++++++++++++++++++++++++++ hw/i2c/meson.build | 1 + hw/i2c/trace-events | 10 ++ hw/misc/flexcomm.c | 6 + include/hw/i2c/flexcomm_i2c.h | 27 ++++ include/hw/misc/flexcomm.h | 4 + tests/unit/meson.build | 4 + 8 files changed, 280 insertions(+) create mode 100644 hw/i2c/flexcomm_i2c.c create mode 100644 include/hw/i2c/flexcomm_i2c.h diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build index ed0f69f437..fa0d3da829 100644 --- a/hw/arm/svd/meson.build +++ b/hw/arm/svd/meson.build @@ -6,3 +6,7 @@ genh += custom_target('flexcomm_usart.h', output: 'flexcomm_usart.h', input: 'MIMXRT595S_cm33.xml', command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'USART0', '-t', 'FLEXCOMM_USART']) +genh += custom_target('flexcomm_i2c_regs.h', + output: 'flexcomm_i2c.h', + input: 'MIMXRT595S_cm33.xml', + command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'I2C0', '-t', 'FLEXCOMM_I2C']) diff --git a/hw/i2c/flexcomm_i2c.c b/hw/i2c/flexcomm_i2c.c new file mode 100644 index 0000000000..7e74f858ce --- /dev/null +++ b/hw/i2c/flexcomm_i2c.c @@ -0,0 +1,224 @@ +/* + * QEMU model for NXP's FLEXCOMM I2C + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "exec/address-spaces.h" +#include "qapi/error.h" +#include "trace.h" +#include "hw/regs.h" +#include "hw/i2c/flexcomm_i2c.h" + +#define reg(field) offsetof(FLEXCOMM_I2C_Type, field) +#define regi(x) (reg(x) / sizeof(uint32_t)) +#define REG_NO (sizeof(FLEXCOMM_I2C_Type) / sizeof(uint32_t)) + +static FLEXCOMM_I2C_REGISTER_NAMES_ARRAY(reg_names); + +static void flexcomm_i2c_reset(FlexcommState *s) +{ + flexcomm_i2c_reset_registers(&s->regs.i2c); +} + +static void flexcomm_i2c_irq_update(FlexcommState *s) +{ + bool enabled = s->regs.i2c.CFG_b.MSTEN; + bool irq, per_irqs; + + s->regs.i2c.INTSTAT = s->regs.i2c.STAT & s->regs.i2c.INTENSET; + per_irqs = s->regs.i2c.INTSTAT != 0; + + irq = enabled && per_irqs; + + trace_flexcomm_i2c_irq(DEVICE(s)->id, irq, per_irqs, enabled); + flexcomm_irq(s, irq); +} + +static MemTxResult flexcomm_i2c_reg_read(void *opaque, FlexcommState *s, + int f, hwaddr addr, uint64_t *data, + unsigned size) +{ + MemTxResult ret = MEMTX_OK; + + if (!reg32_aligned_access(addr, size)) { + ret = MEMTX_ERROR; + goto out; + } + + *data = reg32_read(&s->regs, addr); + + flexcomm_i2c_irq_update(s); + +out: + trace_flexcomm_i2c_reg_read(DEVICE(s)->id, reg_names[addr], addr, *data); + return ret; +} + +static MemTxResult flexcomm_i2c_reg_write(void *opaque, FlexcommState *s, + int f, hwaddr addr, uint64_t value, + unsigned size) +{ + MemTxResult ret = MEMTX_OK; + static uint32_t mask[REG_NO] = { + [regi(CFG)] = BITS(5, 0), + [regi(STAT)] = BITS(25, 24) | BIT(19) | BIT(17) | BIT(15) | BIT(6), + [regi(INTENSET)] = BITS(25, 24) | BIT(19) | BITS(17, 15) | BIT(11) | + BIT(8) | BIT(6) | BIT(4) | BIT(0), + [regi(INTENCLR)] = BITS(25, 24) | BIT(19) | BITS(17, 15) | BIT(11) | + BIT(8) | BIT(6) | BIT(4) | BIT(0), + [regi(TIMEOUT)] = BITS(15, 0), + [regi(CLKDIV)] = BITS(15, 0), + [regi(MSTCTL)] = BITS(3, 0), + [regi(MSTTIME)] = BITS(6, 4) | BITS(2, 0), + [regi(MSTDAT)] = BITS(7, 0), + [regi(SLVCTL)] = BITS(9, 8) | BIT(3) | BITS(1, 0), + [regi(SLVDAT)] = BITS(7, 0), + [regi(SLVADR0)] = BIT(15) | BITS(7, 0), + [regi(SLVADR1)] = BIT(15) | BITS(7, 0), + [regi(SLVADR2)] = BIT(15) | BITS(7, 0), + [regi(SLVADR3)] = BIT(15) | BITS(7, 0), + [regi(SLVQUAL0)] = BITS(7, 0), + }; + + if (!reg32_aligned_access(addr, size)) { + ret = MEMTX_ERROR; + goto out; + } + + switch (addr) { + case reg(CFG): + { + reg32_write(&s->regs, addr, value, mask); + if (s->regs.i2c.CFG_b.SLVEN) { + qemu_log_mask(LOG_GUEST_ERROR, "I2C slave not supported"); + } + if (s->regs.i2c.CFG_b.MONEN) { + qemu_log_mask(LOG_GUEST_ERROR, "I2C monitoring not supported"); + } + break; + } + case reg(INTENCLR): + { + s->regs.i2c.INTENSET &= ~(value & mask[addr / 4]); + break; + } + case reg(TIMEOUT): + { + reg32_write(&s->regs, addr, value, mask); + /* The bottom 4 bits are hard-wired to 0xF */ + s->regs.i2c.TIMEOUT_b.TOMIN = 0xf; + break; + } + case reg(MSTCTL): + { + reg32_write(&s->regs, addr, value, mask); + if (s->regs.i2c.MSTCTL_b.MSTSTART) { + uint8_t i2c_addr = s->regs.i2c.MSTDAT_b.DATA; + bool recv = i2c_addr & 1; + + trace_flexcomm_i2c_start(DEVICE(s)->id, i2c_addr, recv); + if (i2c_start_transfer(s->i2c, i2c_addr, recv)) { + s->regs.i2c.STAT_b.MSTSTATE = MSTSTATE_NAKADR; + trace_flexcomm_i2c_nak(DEVICE(s)->id); + } else { + if (recv) { + uint8_t data = i2c_recv(s->i2c); + + s->regs.i2c.MSTDAT_b.DATA = data; + trace_flexcomm_i2c_rx(DEVICE(s)->id, data); + s->regs.i2c.STAT_b.MSTSTATE = MSTSTATE_RXRDY; + } else { + s->regs.i2c.STAT_b.MSTSTATE = MSTSTATE_TXRDY; + } + } + } + if (s->regs.i2c.MSTCTL_b.MSTSTOP) { + s->regs.i2c.STAT_b.MSTSTATE = MSTSTATE_IDLE; + i2c_end_transfer(s->i2c); + } + if (s->regs.i2c.MSTCTL_b.MSTCONTINUE) { + if (s->regs.i2c.STAT_b.MSTSTATE == MSTSTATE_TXRDY) { + uint8_t data = s->regs.i2c.MSTDAT_b.DATA; + + trace_flexcomm_i2c_tx(DEVICE(s)->id, data); + if (i2c_send(s->i2c, data)) { + s->regs.i2c.STAT_b.MSTSTATE = MSTSTATE_NAKDAT; + } + } else if (s->regs.i2c.STAT_b.MSTSTATE == MSTSTATE_RXRDY) { + uint8_t data = i2c_recv(s->i2c); + + s->regs.i2c.MSTDAT_b.DATA = data; + trace_flexcomm_i2c_rx(DEVICE(s)->id, data); + } + } + break; + } + case reg(STAT): + { + /* write 1 to clear bits */ + s->regs.i2c.STAT &= ~(value & mask[addr / 4]); + break; + } + case reg(SLVCTL): + case reg(SLVDAT): + case reg(SLVADR0): + case reg(SLVADR1): + case reg(SLVADR2): + case reg(SLVADR3): + case reg(SLVQUAL0): + { + qemu_log_mask(LOG_GUEST_ERROR, "I2C slave not supported\n"); + break; + } + default: + reg32_write(&s->regs, addr, value, mask); + break; + } + + flexcomm_i2c_irq_update(s); + +out: + trace_flexcomm_i2c_reg_write(DEVICE(s)->id, reg_names[addr], addr, value); + return ret; +} + +static void flexcomm_i2c_select(void *opaque, FlexcommState *s, int f, + bool set) +{ + if (set) { + flexcomm_i2c_reset(s); + } +} + +static const FlexcommFunctionOps flexcomm_i2c_ops = { + .select = flexcomm_i2c_select, + .reg_read = flexcomm_i2c_reg_read, + .reg_write = flexcomm_i2c_reg_write, +}; + +void flexcomm_i2c_init(FlexcommState *s) +{ + s->i2c = i2c_init_bus(DEVICE(s), "i2c"); +} + +void flexcomm_i2c_register(void) +{ + Error *err = NULL; + + if (!flexcomm_register_ops(FLEXCOMM_FUNC_I2C, NULL, + &flexcomm_i2c_ops, &err)) { + error_report_err(err); + } +} diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build index c459adcb59..e7d79e6938 100644 --- a/hw/i2c/meson.build +++ b/hw/i2c/meson.build @@ -18,4 +18,5 @@ i2c_ss.add(when: 'CONFIG_PPC4XX', if_true: files('ppc4xx_i2c.c')) i2c_ss.add(when: 'CONFIG_PCA954X', if_true: files('i2c_mux_pca954x.c')) i2c_ss.add(when: 'CONFIG_PMBUS', if_true: files('pmbus_device.c')) i2c_ss.add(when: 'CONFIG_BCM2835_I2C', if_true: files('bcm2835_i2c.c')) +i2c_ss.add(when: 'CONFIG_FLEXCOMM', if_true: files('flexcomm_i2c.c')) system_ss.add_all(when: 'CONFIG_I2C', if_true: i2c_ss) diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events index 6900e06eda..9f0175fab7 100644 --- a/hw/i2c/trace-events +++ b/hw/i2c/trace-events @@ -51,3 +51,13 @@ npcm7xx_smbus_recv_fifo(const char *id, uint8_t received, uint8_t expected) "%s pca954x_write_bytes(uint8_t value) "PCA954X write data: 0x%02x" pca954x_read_data(uint8_t value) "PCA954X read data: 0x%02x" + +# flexcomm_i2c.c + +flexcomm_i2c_reg_read(const char *id, const char *reg_name, uint32_t addr, uint32_t val) " %s: %s[0x%04x] -> 0x%08x" +flexcomm_i2c_reg_write(const char *id, const char *reg_name, uint32_t addr, uint32_t val) "%s: %s[0x%04x] <- 0x%08x" +flexcomm_i2c_start(const char *id, uint8_t addr, uint8_t recv) "%s: 0x%02x %d" +flexcomm_i2c_rx(const char *id, uint8_t data) "%s: <- 0x%02x" +flexcomm_i2c_tx(const char *id, uint8_t data) "%s: -> 0x%02x" +flexcomm_i2c_nak(const char *id) "%s: <- nak" +flexcomm_i2c_irq(const char *id, bool irq, bool perirqs, bool enabled) "%s: %d %d %d" diff --git a/hw/misc/flexcomm.c b/hw/misc/flexcomm.c index 0c94928aa2..2722c1d6a9 100644 --- a/hw/misc/flexcomm.c +++ b/hw/misc/flexcomm.c @@ -23,6 +23,7 @@ #include "hw/regs.h" #include "hw/misc/flexcomm.h" #include "hw/char/flexcomm_usart.h" +#include "hw/i2c/flexcomm_i2c.h" #define reg(field) offsetof(FLEXCOMM_Type, field) #define regi(x) (reg(x) / sizeof(uint32_t)) @@ -228,6 +229,10 @@ static void flexcomm_realize(DeviceState *dev, Error **errp) if (has_function(s, FLEXCOMM_FUNC_USART)) { flexcomm_usart_init(s); } + + if (has_function(s, FLEXCOMM_FUNC_I2C)) { + flexcomm_i2c_init(s); + } } static void flexcomm_class_init(ObjectClass *klass, void *data) @@ -239,6 +244,7 @@ static void flexcomm_class_init(ObjectClass *klass, void *data) dc->realize = flexcomm_realize; flexcomm_usart_register(); + flexcomm_i2c_register(); } static const TypeInfo flexcomm_info = { diff --git a/include/hw/i2c/flexcomm_i2c.h b/include/hw/i2c/flexcomm_i2c.h new file mode 100644 index 0000000000..aea01f13bd --- /dev/null +++ b/include/hw/i2c/flexcomm_i2c.h @@ -0,0 +1,27 @@ +/* + * QEMU model for NXP's FLEXCOMM I2C + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_CHAR_FLEXCOMM_I2C_H +#define HW_CHAR_FLEXCOMM_I2C_H + +#include "hw/misc/flexcomm.h" + +void flexcomm_i2c_init(FlexcommState *s); +void flexcomm_i2c_register(void); + +#define MSTSTATE_IDLE 0 +#define MSTSTATE_RXRDY 1 +#define MSTSTATE_TXRDY 2 +#define MSTSTATE_NAKADR 3 +#define MSTSTATE_NAKDAT 4 + + +#endif /* HW_CHAR_FLEXCOMM_I2C_H */ diff --git a/include/hw/misc/flexcomm.h b/include/hw/misc/flexcomm.h index db76e32c6d..3d042a3511 100644 --- a/include/hw/misc/flexcomm.h +++ b/include/hw/misc/flexcomm.h @@ -14,8 +14,10 @@ #include "hw/sysbus.h" #include "chardev/char-fe.h" +#include "hw/i2c/i2c.h" #include "hw/arm/svd/flexcomm.h" #include "hw/arm/svd/flexcomm_usart.h" +#include "hw/arm/svd/flexcomm_i2c.h" #include "qemu/fifo32.h" #define TYPE_FLEXCOMM "flexcomm" @@ -46,6 +48,7 @@ typedef struct { union { FLEXCOMM_Type flex; FLEXCOMM_USART_Type usart; + FLEXCOMM_I2C_Type i2c; } regs; uint32_t functions; qemu_irq irq; @@ -53,6 +56,7 @@ typedef struct { CharBackend chr; Fifo32 tx_fifo; Fifo32 rx_fifo; + I2CBus *i2c; } FlexcommState; typedef struct { diff --git a/tests/unit/meson.build b/tests/unit/meson.build index dcfd2e661c..4c22cb3ccc 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -148,6 +148,8 @@ if have_system meson.project_source_root() / 'tests/unit/sysbus-mock.c', meson.project_source_root() / 'hw/misc/flexcomm.c', meson.project_source_root() / 'hw/char/flexcomm_usart.c', + meson.project_source_root() / 'hw/i2c/flexcomm_i2c.c', + meson.project_source_root() / 'hw/i2c/core.c', ], 'test-flexcomm-usart': [ hwcore, chardev, qom, migration, @@ -155,6 +157,8 @@ if have_system meson.project_source_root() / 'tests/unit/sysbus-mock.c', meson.project_source_root() / 'hw/misc/flexcomm.c', meson.project_source_root() / 'hw/char/flexcomm_usart.c', + meson.project_source_root() / 'hw/i2c/flexcomm_i2c.c', + meson.project_source_root() / 'hw/i2c/core.c', ], } if config_host_data.get('CONFIG_INOTIFY1') From patchwork Mon Aug 5 20:17:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754016 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D47DAC3DA7F for ; Mon, 5 Aug 2024 20:18:03 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49R-0003bh-SH; Mon, 05 Aug 2024 16:17:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3aDOxZgUKCs8EvG3A19916z.x97Bz7F-yzGz689818F.9C1@flex--tavip.bounces.google.com>) id 1sb49P-0003P6-DZ for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:51 -0400 Received: from mail-pj1-x1049.google.com ([2607:f8b0:4864:20::1049]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3aDOxZgUKCs8EvG3A19916z.x97Bz7F-yzGz689818F.9C1@flex--tavip.bounces.google.com>) id 1sb49M-0001UI-DX for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:50 -0400 Received: by mail-pj1-x1049.google.com with SMTP id 98e67ed59e1d1-2cff79ae0f3so4096152a91.0 for ; Mon, 05 Aug 2024 13:17:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889066; x=1723493866; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=yKViGbBXbgsf40jDlea1Rbu9Pc/wgyZ+coz/6jiEdWo=; b=TTFrgSvOk16Gwg0E4EM49VxC+sCASYSVRwsmx0NJw8dssUcWd6G5sV+UZRZalSF4LK aKKl+Xi0cZiE9A7JgFgR1/Gy2VGI5WTY5vCzenhmcM098lgt+FSMFQHXThgViK4+7GTI VrYkIbdrG5y506LW5/fPZGYXOsAl8I3zGA7Rk8vN58xyIoZCnk5MHpPMV3/TZcPmd3ts TydypEll3hXLJbTM8UfJPhZLbJTTZmv8P2tf8q09TGIIHyom2SCsH8dY00w0EvS2jt1X bLKe5WU3st0BOj+MmZpQs+dlvK1M83hBuh6a/et1u7kjeiLqtFGWR2P2mp1UzgHOWaim QVcw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889066; x=1723493866; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=yKViGbBXbgsf40jDlea1Rbu9Pc/wgyZ+coz/6jiEdWo=; b=avkh5edue9TcOe4FIaNdyfpuNaQc8IwTLC6S7dm5mSU7D4bUlVnHLzSXuOGzmJGEHl gn/LvHfGTtnIPOv0o3UJtkShgf22Cub5rgqyKw1ar7tt2+r82mw33uMZfOFjrQSd2pgv nNLXXiL83/Ki7/UCRHmneZ3ysHgOMxo7Iuzeth6Nn0PLVhyo6wl6HMg3GQDEigwMihAe 8CWs+62NepgfLm2BK+gOpFgav+6uttQdFRvnTOP8GoCzfqizOLmWc57Dk20QxFItj7Y3 p2OBuRqB3X7edbItL4TYQDxWKwRhbXYgwjUv5RvKjXV/jmqMKQCJxKgrxueKOkb3mztm wrwQ== X-Gm-Message-State: AOJu0YyEeLbKFFVHBlB4TvcyU1U0TZFbQq4XsJFridhVEA9/5pXZOf03 ls36nuJjkQ68HxAeeuPJub82P4eOz4L7s76SF31xXMpWfpCY8RPGtbW+KyOFfJA5jHF/0cOfNHL NCIsKPEqkYfEhjPDYf2/D6haeLQVyAC1TfqhUguSQgq5Lbf/vYCoYuAGYotgIY8wJUlmBkQunSx lbjXB803jre9rZkaSoCqq3rZ16DA== X-Google-Smtp-Source: AGHT+IEru86bm/+1q+FLmL7wwlYksXRv1IHzcU3JoLAoRcdP6I9MQ8+1J/BYTCPAlqTiOGFbzd7E25IUmA== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a17:90a:c982:b0:2c9:63d6:a183 with SMTP id 98e67ed59e1d1-2cff955376dmr29109a91.7.1722889064153; Mon, 05 Aug 2024 13:17:44 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:08 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-14-tavip@google.com> Subject: [RFC PATCH 13/23] test/unit: add i2c-tester From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::1049; envelope-from=3aDOxZgUKCs8EvG3A19916z.x97Bz7F-yzGz689818F.9C1@flex--tavip.bounces.google.com; helo=mail-pj1-x1049.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add a simple i2c peripheral to be used for testing I2C device models. The peripheral has a fixed number of registers that can be read and written. Signed-off-by: Octavian Purdila --- tests/unit/i2c_tester.c | 111 ++++++++++++++++++++++++++++++++++++++++ tests/unit/i2c_tester.h | 34 ++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 tests/unit/i2c_tester.c create mode 100644 tests/unit/i2c_tester.h diff --git a/tests/unit/i2c_tester.c b/tests/unit/i2c_tester.c new file mode 100644 index 0000000000..ea36a17f1f --- /dev/null +++ b/tests/unit/i2c_tester.c @@ -0,0 +1,111 @@ +/* + * Simple I2C peripheral for testing I2C device models. + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "i2c_tester.h" +#include "qemu/log.h" +#include "qemu/module.h" + +static void i2c_tester_reset(DeviceState *ds) +{ + I2cTesterState *s = I2C_TESTER(ds); + + s->set_reg_idx = false; + s->reg_idx = 0; + memset(s->regs, 0, I2C_TESTER_NUM_REGS); +} + +static int i2c_tester_event(I2CSlave *i2c, enum i2c_event event) +{ + I2cTesterState *s = I2C_TESTER(i2c); + + if (event == I2C_START_SEND) { + s->set_reg_idx = true; + } + + return 0; +} + +static uint8_t i2c_tester_rx(I2CSlave *i2c) +{ + I2cTesterState *s = I2C_TESTER(i2c); + + if (s->reg_idx >= I2C_TESTER_NUM_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid reg 0x%02x\n", __func__, + s->reg_idx); + return I2C_NACK; + } + + return s->regs[s->reg_idx]; +} + +static int i2c_tester_tx(I2CSlave *i2c, uint8_t data) +{ + I2cTesterState *s = I2C_TESTER(i2c); + + if (s->set_reg_idx) { + /* Setting the register in which the operation will be done. */ + s->reg_idx = data; + s->set_reg_idx = false; + return 0; + } + + if (s->reg_idx >= I2C_TESTER_NUM_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid reg 0x%02x\n", __func__, + s->reg_idx); + return I2C_NACK; + } + + /* Write reg data. */ + s->regs[s->reg_idx] = data; + + return 0; +} + +static void i2c_tester_init(Object *obj) +{ +} + +static void i2c_tester_realize(DeviceState *ds, Error **errp) +{ +} + +static void i2c_tester_unrealize(DeviceState *dev) +{ +} + +static void i2c_tester_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc); + + dc->reset = i2c_tester_reset; + dc->realize = i2c_tester_realize; + dc->unrealize = i2c_tester_unrealize; + + isc->event = i2c_tester_event; + isc->recv = i2c_tester_rx; + isc->send = i2c_tester_tx; +} + +static const TypeInfo i2c_tester_info = { + .name = TYPE_I2C_TESTER, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(I2cTesterState), + .instance_init = i2c_tester_init, + .class_init = i2c_tester_class_init +}; + +static void i2c_tester_register_type(void) +{ + type_register_static(&i2c_tester_info); +} + +type_init(i2c_tester_register_type); diff --git a/tests/unit/i2c_tester.h b/tests/unit/i2c_tester.h new file mode 100644 index 0000000000..9eebe1b6e3 --- /dev/null +++ b/tests/unit/i2c_tester.h @@ -0,0 +1,34 @@ +/* + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef TESTS_UNIT_I2C_TESTER_H +#define TESTS_UNIT_I2C_TESTER_H + +#include "qemu/osdep.h" +#include "hw/i2c/i2c.h" +#include "hw/irq.h" + +#define I2C_TESTER_NUM_REGS 0x31 + +#define TYPE_I2C_TESTER "i2c_tester" +#define I2C_TESTER(obj) OBJECT_CHECK(I2cTesterState, (obj), TYPE_I2C_TESTER) + +typedef struct { + /* */ + I2CSlave i2c; + + /* */ + bool set_reg_idx; + + uint8_t reg_idx; + uint8_t regs[I2C_TESTER_NUM_REGS]; +} I2cTesterState; + +#endif /* TESTS_UNIT_I2C_TESTER_H */ From patchwork Mon Aug 5 20:17:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754033 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 4D4A0C3DA7F for ; Mon, 5 Aug 2024 20:19:26 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49U-0003lZ-7k; Mon, 05 Aug 2024 16:17:56 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3aTOxZgUKCtAFwH4B2AA270.yA8C08G-z0H079A929G.AD2@flex--tavip.bounces.google.com>) id 1sb49R-0003YK-6p for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:53 -0400 Received: from mail-yb1-xb49.google.com ([2607:f8b0:4864:20::b49]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3aTOxZgUKCtAFwH4B2AA270.yA8C08G-z0H079A929G.AD2@flex--tavip.bounces.google.com>) id 1sb49M-0001Ua-QM for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:52 -0400 Received: by mail-yb1-xb49.google.com with SMTP id 3f1490d57ef6-e0ba4d19585so12221910276.0 for ; Mon, 05 Aug 2024 13:17:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889066; x=1723493866; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=ZCjJ5sPbPGT4/PTAX3XbZdjutmIYVAwZmRenYV+abhM=; b=nN6T+zNebGkR+9/2SR8+ARnk98GB+/+d+nP312ksC/Bn/FijEizrVu+pW1fMsrIib2 BkcuyUbh/qMO99cuxg2WSf91IJU2yovUjiz5UKrB08pGvzdKKhV4hvgH1R9rD7puNLK7 XkLldWV/Cdlw8EK/kU3Morwl+rxvPoAiO9F9yybQGCBzkvjh+/rTt41DRukeRJPSWlZ0 jJWZjlGEcR3s2EILTVJG6wNgFgD886NxNUwiJa3C7loeQvJxqJT8mH/cfhhz/IH+JZLN uD2iXzdwFzJsO3VymKwSTNrWrTyZJEelRcU4e9nkus93DIWL5A6DgR3j7U8PV6GO1f3/ hsEA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889066; x=1723493866; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=ZCjJ5sPbPGT4/PTAX3XbZdjutmIYVAwZmRenYV+abhM=; b=PST0zBMibx1eRk2PzF550GUYvm7xGrWkULr82EzD/MhLsboBnY25RY2VhjE9FlWwYE MXvRDVz/xqhIGvlLKSuN0B39/18qUXdSutSODyqCF0qEAndRXfE5D2RLrw81uBJM8go1 tRrW5TLTRTbiKMsDqILziG2iJLc4YoWZ3O7IwOrr0jcAm0T/AJl7+6MSyZs8bN7hFFhb 6eMju0n8tFOhpq1OTRkYgWgfAmm9HeOE26GXx07ZdaqrKblUU6hOGk2A0YmdB+LkyRRr 2dt3rmtkigDrFJd3Lnbz8pvRirhLaurS6scSLpHh1Zq/d4fpzbwseqArss7lsaVy2UXp f4Ug== X-Gm-Message-State: AOJu0YwXSsOEbvRSfqJ45TlFZTFwH8ezIXpRlO/qwV0PG4Gk9o9KcsoR 5cGpfDAFeNtKA7mwy83c7d1xbtFhYX9uWpJoAWhz1pkWWFJPTYRrrehBjOOLxtiKirZNySibIU3 032nA5ygle/1b6/ePa/1ad9r/xNQv9A7gXPzzinarpd7y6LYv95lcvpQsEB/uOVTuc8yekZckPH KuQEKd+eaqseMrHboToD7FjGl4Vw== X-Google-Smtp-Source: AGHT+IG1Pt6E3mwx56V6QB58tAS/P9w8eY0tLuEvmxKONHteSzlgUW4zheNvXzY2wiJgw8FsY0r8S0yjHw== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:6902:154e:b0:e02:c06f:1db8 with SMTP id 3f1490d57ef6-e0bde2612ebmr23616276.4.1722889065783; Mon, 05 Aug 2024 13:17:45 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:09 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-15-tavip@google.com> Subject: [RFC PATCH 14/23] test/unit: add unit tests for flexcomm i2c From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::b49; envelope-from=3aTOxZgUKCtAFwH4B2AA270.yA8C08G-z0H079A929G.AD2@flex--tavip.bounces.google.com; helo=mail-yb1-xb49.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add master mode tests for flexcomm i2c. Signed-off-by: Octavian Purdila --- tests/unit/meson.build | 10 ++ tests/unit/test-flexcomm-i2c.c | 209 +++++++++++++++++++++++++++++++++ 2 files changed, 219 insertions(+) create mode 100644 tests/unit/test-flexcomm-i2c.c diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 4c22cb3ccc..3491e2003b 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -160,6 +160,16 @@ if have_system meson.project_source_root() / 'hw/i2c/flexcomm_i2c.c', meson.project_source_root() / 'hw/i2c/core.c', ], + 'test-flexcomm-i2c': [ + hwcore, chardev, qom, migration, + meson.project_source_root() / 'hw/core/gpio.c', + meson.project_source_root() / 'tests/unit/sysbus-mock.c', + meson.project_source_root() / 'hw/misc/flexcomm.c', + meson.project_source_root() / 'hw/char/flexcomm_usart.c', + meson.project_source_root() / 'hw/i2c/flexcomm_i2c.c', + meson.project_source_root() / 'hw/i2c/core.c', + 'i2c_tester.c', + ], } if config_host_data.get('CONFIG_INOTIFY1') tests += {'test-util-filemonitor': []} diff --git a/tests/unit/test-flexcomm-i2c.c b/tests/unit/test-flexcomm-i2c.c new file mode 100644 index 0000000000..9d02c94101 --- /dev/null +++ b/tests/unit/test-flexcomm-i2c.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2024 Google LLC. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" + +#include "qemu/config-file.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qapi/error.h" +#include "qemu/sockets.h" +#include "sysemu/sysemu.h" +#include "qemu/main-loop.h" +#include "qemu/option.h" +#include "exec/memory.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-core.h" + +#include "hw/i2c/flexcomm_i2c.h" +#include "i2c_tester.h" +#include "sysbus-mock.h" +#include "reg-utils.h" + +#define PERIPH_ADDR (0x20) +#define INVALID_ADDR (0x10) + +#define REG_ADDR 0x11 +#define REG_VALUE 0xAA + +#define FLEXCOMM_BASE 0x40106000UL +#define FLEXCOMM_I2C_BASE FLEXCOMM_BASE + +typedef struct { + DeviceState *dev; + I2CSlave *periph; + bool irq; +} TestFixture; + +/* Callback for the interrupt line. */ +static void spi_irq_set(void *opaque, int line, int level) +{ + TestFixture *f = (TestFixture *)opaque; + + f->irq = level; +} + +/* + * Test fixture initialization. + */ +static void set_up(TestFixture *f, gconstpointer data) +{ + FlexcommState *s; + + f->dev = qdev_new(TYPE_FLEXCOMM); + g_assert(f->dev); + + s = FLEXCOMM(f->dev); + s->irq = qemu_allocate_irq(spi_irq_set, f, 0); + + if (data != NULL) { + qdev_prop_set_int32(DEVICE(f->dev), "functions", (uintptr_t)data); + } + + qdev_realize_and_unref(f->dev, NULL, &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(f->dev), 0, FLEXCOMM_BASE); + + device_cold_reset(f->dev); + + f->periph = i2c_slave_create_simple(s->i2c, TYPE_I2C_TESTER, PERIPH_ADDR); +} + +static void tear_down(TestFixture *f, gconstpointer user_data) +{ + qdev_unrealize(f->dev); + qdev_unrealize(DEVICE(f->periph)); +} + +static void master_test(TestFixture *f, gconstpointer user_data) +{ + uint32_t tmp; + + /* Select and lock I2C */ + tmp = FLEXCOMM_PSELID_LOCK_Msk | FLEXCOMM_PERSEL_I2C; + REG32_WRITE(f->dev, FLEXCOMM, PSELID, tmp); + + /* Enable master mode */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_I2C, CFG, MSTEN, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, CFG, MSTEN) == 1); + + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, STAT, MSTPENDING) == 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_IDLE); + + /* Enable interrupts */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_I2C, INTENSET, MSTPENDINGEN, 1); + g_assert(f->irq == true); + + /* start for invalid address */ + REG32_WRITE(f->dev, FLEXCOMM_I2C, MSTDAT, INVALID_ADDR); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTSTART, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_NAKADR); + g_assert(f->irq == true); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTSTOP, 1); + + /* write past the last register */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_I2C, MSTDAT, DATA, PERIPH_ADDR); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTSTART, 1); + g_assert(f->irq == true); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_TXRDY); + REG32_WRITE_FIELD(f->dev, FLEXCOMM_I2C, MSTDAT, DATA, + (I2C_TESTER_NUM_REGS + 10)); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTCONTINUE, 1); + g_assert(f->irq == true); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_TXRDY); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTCONTINUE, 1); + g_assert(f->irq == true); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_NAKDAT); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTSTOP, 1); + + /* write value to register */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_I2C, MSTDAT, DATA, PERIPH_ADDR); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTSTART, 1); + g_assert(f->irq == true); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_TXRDY); + REG32_WRITE_FIELD(f->dev, FLEXCOMM_I2C, MSTDAT, DATA, REG_ADDR); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTCONTINUE, 1); + g_assert(f->irq == true); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_TXRDY); + REG32_WRITE_FIELD(f->dev, FLEXCOMM_I2C, MSTDAT, DATA, REG_VALUE); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTCONTINUE, 1); + g_assert(f->irq == true); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_TXRDY); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTSTOP, 1); + g_assert(f->irq == true); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_IDLE); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTSTOP, 1); + + /* read value back from register */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_I2C, MSTDAT, DATA, PERIPH_ADDR); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTSTART, 1); + g_assert(f->irq == true); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_TXRDY); + REG32_WRITE_FIELD(f->dev, FLEXCOMM_I2C, MSTDAT, DATA, REG_ADDR); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTCONTINUE, 1); + g_assert(f->irq == true); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_TXRDY); + REG32_WRITE_FIELD(f->dev, FLEXCOMM_I2C, MSTDAT, DATA, (PERIPH_ADDR + 1)); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTSTART, 1); + g_assert(f->irq == true); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_RXRDY); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTCONTINUE, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, MSTDAT, DATA) == REG_VALUE); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTSTOP, 1); + + /* + * Check that the master ended the transaction (i.e. i2c_end_transfer was + * called). If the master does not properly end the transaction this would + * be seen as a restart and it would not be NACKed. + */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_I2C, MSTDAT, DATA, INVALID_ADDR); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTSTART, 1); + + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_NAKADR); + g_assert(f->irq == true); + REG32_WRITE_FIELD_NOUPDATE(f->dev, FLEXCOMM_I2C, MSTCTL, MSTSTOP, 1); + + /* Disable interrupts */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_I2C, INTENCLR, MSTPENDINGCLR, 1); + g_assert(f->irq == false); +} + +/* mock-up */ +const PropertyInfo qdev_prop_chr; + +int main(int argc, char **argv) +{ + qemu_init_main_loop(&error_abort); + + g_test_init(&argc, &argv, NULL); + + /* Initialize object types. */ + sysbus_mock_init(); + module_call_init(MODULE_INIT_QOM); + qemu_add_opts(&qemu_chardev_opts); + + g_test_add("/flexcomm-i2c/master", TestFixture, + (gconstpointer)(1 << FLEXCOMM_FUNC_I2C), + set_up, master_test, tear_down); + + return g_test_run(); +} From patchwork Mon Aug 5 20:17:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754019 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 658CAC3DA4A for ; Mon, 5 Aug 2024 20:18:22 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49X-0003sW-UU; Mon, 05 Aug 2024 16:18:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3azOxZgUKCtIHyJ6D4CC492.0CAE2AI-12J29BCB4BI.CF4@flex--tavip.bounces.google.com>) id 1sb49S-0003ed-BS for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:54 -0400 Received: from mail-pl1-x64a.google.com ([2607:f8b0:4864:20::64a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3azOxZgUKCtIHyJ6D4CC492.0CAE2AI-12J29BCB4BI.CF4@flex--tavip.bounces.google.com>) id 1sb49O-0001Uy-Kh for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:54 -0400 Received: by mail-pl1-x64a.google.com with SMTP id d9443c01a7336-1fc5e651bcdso117281125ad.3 for ; Mon, 05 Aug 2024 13:17:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889068; x=1723493868; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=tlHjF4vRKeBL3TO5oBeur+r2v3G8z+HC6VUlJGVX4fk=; b=j1IHkbTe50+42nRoCH2pHjE+8E0rSy9qA+2lk6GLgqRIbDKrX2C/sWi055+/vmUe85 +HW5RteRc1Ba37sDGGKb7vJgcApCpDz2AAzoMUk5G8RCnblfp5U0FKCTxcMy4ApD7gsP ZB1p4dhDAFXwdHzgKHnEWzD3pZ6CnDJbGRFa2MoBiVkxfBO3UhfDragVm9q1M6TR4S/0 QvrtDeQENTi40UqUjis9+U45yFHHsAyLgszF4VcdMw/MLf/TmhndIpsIvn5N6hea/DEQ WQD7aXW57tJ82DW2zpe+VLnpJbIHJItMxYT8W5WqnCdmnwJL2XWFCPpvASLO+Vtk0mG8 glhg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889068; x=1723493868; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=tlHjF4vRKeBL3TO5oBeur+r2v3G8z+HC6VUlJGVX4fk=; b=QBVLgZFG5IB3HnjGONQGue/p6DnCf8YFLa7JqRUSzSmEhneDIwG1JnQ9xzmnkViiQs MFhq2F0/W4Xabju4asS2igscsJK6pvGCOnJP183nQsoAI/a3YbHOwo15Rycr+3DJrTXb K8T0dlQuDftmJ6zmC/oqUrqCBZTJn281BR3boLC1kCP3cNHlRTqOSI8TK/iZovejeWbB 7jCrQuKzkzXYGYbKIrS3mdkjgCRdYYAd5YdRBjTUGKy1xadvR49NhLrqbdoG8HLgHUra U5zDNoRktWv/08fm9AVtTry3H0ydenTjD3KoK9nIZCCqAS5DofGhwag306k0w4INivnT L9IA== X-Gm-Message-State: AOJu0Yzu3HOFgsPJKK6MAtv+3FhCz7L64LqS71rbL8MZPLyghBfoYZdQ 6r2gl7lGjILziUcb9QZzNrfIWyRnhaS9+8zkZT0GaV8O5GzHl3yx1Af6A3GA22z7TIkQrl+R+QW 2mNt/Ysu+6teoOp2Va45041MnhIZuIDv2O9BVu63531ldSzu9ic55HPIM8PAwniCQqoz7ErPuJN 4ttCNLyk5BBQc15e3XFo78XEp6vA== X-Google-Smtp-Source: AGHT+IFPemp2sc6tjT2XKanRsS0vFFuKY6C/1QzGpCElqtmWwxiPKcpufHzMF5kfVgvwLX0f1fXpqgpNLw== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a17:902:dac4:b0:1fd:d6d8:134e with SMTP id d9443c01a7336-1ff573a358bmr8377605ad.8.1722889067793; Mon, 05 Aug 2024 13:17:47 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:10 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-16-tavip@google.com> Subject: [RFC PATCH 15/23] hw/ssi: add support for flexcomm spi From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::64a; envelope-from=3azOxZgUKCtIHyJ6D4CC492.0CAE2AI-12J29BCB4BI.CF4@flex--tavip.bounces.google.com; helo=mail-pl1-x64a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Sebastian Ene From: Sebastian Ene Add support for NXP's flexcomm spi. It supports FIFO access, interrupts and master mode only. It does not support DMA. Signed-off-by: Sebastian Ene Signed-off-by: Octavian Purdila --- hw/arm/svd/meson.build | 4 + hw/misc/flexcomm.c | 6 + hw/ssi/flexcomm_spi.c | 443 ++++++++++++++++++++++++++++++++++ hw/ssi/meson.build | 1 + hw/ssi/trace-events | 8 + include/hw/misc/flexcomm.h | 8 + include/hw/ssi/flexcomm_spi.h | 20 ++ tests/unit/meson.build | 7 + 8 files changed, 497 insertions(+) create mode 100644 hw/ssi/flexcomm_spi.c create mode 100644 include/hw/ssi/flexcomm_spi.h diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build index fa0d3da829..8b3b045137 100644 --- a/hw/arm/svd/meson.build +++ b/hw/arm/svd/meson.build @@ -10,3 +10,7 @@ genh += custom_target('flexcomm_i2c_regs.h', output: 'flexcomm_i2c.h', input: 'MIMXRT595S_cm33.xml', command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'I2C0', '-t', 'FLEXCOMM_I2C']) +genh += custom_target('flexcomm_spi.h', + output: 'flexcomm_spi.h', + input: 'MIMXRT595S_cm33.xml', + command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'SPI0', '-t', 'FLEXCOMM_SPI']) diff --git a/hw/misc/flexcomm.c b/hw/misc/flexcomm.c index 2722c1d6a9..6f3ce62448 100644 --- a/hw/misc/flexcomm.c +++ b/hw/misc/flexcomm.c @@ -24,6 +24,7 @@ #include "hw/misc/flexcomm.h" #include "hw/char/flexcomm_usart.h" #include "hw/i2c/flexcomm_i2c.h" +#include "hw/ssi/flexcomm_spi.h" #define reg(field) offsetof(FLEXCOMM_Type, field) #define regi(x) (reg(x) / sizeof(uint32_t)) @@ -233,6 +234,10 @@ static void flexcomm_realize(DeviceState *dev, Error **errp) if (has_function(s, FLEXCOMM_FUNC_I2C)) { flexcomm_i2c_init(s); } + + if (has_function(s, FLEXCOMM_FUNC_SPI)) { + flexcomm_spi_init(s); + } } static void flexcomm_class_init(ObjectClass *klass, void *data) @@ -245,6 +250,7 @@ static void flexcomm_class_init(ObjectClass *klass, void *data) flexcomm_usart_register(); flexcomm_i2c_register(); + flexcomm_spi_register(); } static const TypeInfo flexcomm_info = { diff --git a/hw/ssi/flexcomm_spi.c b/hw/ssi/flexcomm_spi.c new file mode 100644 index 0000000000..7b649ba17e --- /dev/null +++ b/hw/ssi/flexcomm_spi.c @@ -0,0 +1,443 @@ +/* + * QEMU model for NXP's FLEXCOMM SPI + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "qemu/cutils.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "exec/address-spaces.h" +#include "qapi/error.h" +#include "trace.h" +#include "hw/regs.h" +#include "hw/ssi/flexcomm_spi.h" + +#define reg(field) offsetof(FLEXCOMM_SPI_Type, field) +#define regi(x) (reg(x) / sizeof(uint32_t)) +#define REG_NO (sizeof(FLEXCOMM_SPI_Type) / sizeof(uint32_t)) + +#define FLEXCOMM_SSEL_ASSERTED (0) +#define FLEXCOMM_SSEL_DEASSERTED (1) + +#define FLEXCOMM_SPI_FIFOWR_LEN_MIN (3) +#define FLEXCOMM_SPI_FIFOWR_LEN_MAX (15) + +static FLEXCOMM_SPI_REGISTER_NAMES_ARRAY(reg_names); + +static void flexcomm_spi_reset(FlexcommState *s) +{ + flexcomm_spi_reset_registers(&s->regs.spi); + s->regs.spi.FIFOSIZE_b.FIFOSIZE = 0x8; +} + +static void update_fifo_stat(FlexcommState *s) +{ + int rxlvl = fifo32_num_used(&s->rx_fifo); + int txlvl = fifo32_num_used(&s->tx_fifo); + + s->regs.spi.FIFOSTAT_b.RXLVL = fifo32_num_used(&s->rx_fifo); + s->regs.spi.FIFOSTAT_b.TXLVL = fifo32_num_used(&s->tx_fifo); + s->regs.spi.FIFOSTAT_b.RXFULL = fifo32_is_full(&s->rx_fifo) ? 1 : 0; + s->regs.spi.FIFOSTAT_b.RXNOTEMPTY = !fifo32_is_empty(&s->rx_fifo) ? 1 : 0; + s->regs.spi.FIFOSTAT_b.TXNOTFULL = !fifo32_is_full(&s->tx_fifo) ? 1 : 0; + s->regs.spi.FIFOSTAT_b.TXEMPTY = fifo32_is_empty(&s->tx_fifo) ? 1 : 0; + + if (s->regs.spi.FIFOTRIG_b.RXLVLENA && + (rxlvl > s->regs.spi.FIFOTRIG_b.RXLVL)) { + s->regs.spi.FIFOINTSTAT_b.RXLVL = 1; + } else { + s->regs.spi.FIFOINTSTAT_b.RXLVL = 0; + } + + if (s->regs.spi.FIFOTRIG_b.TXLVLENA && + (txlvl <= s->regs.spi.FIFOTRIG_b.TXLVL)) { + s->regs.spi.FIFOINTSTAT_b.TXLVL = 1; + } else { + s->regs.spi.FIFOINTSTAT_b.TXLVL = 0; + } + + trace_flexcomm_spi_fifostat(DEVICE(s)->id, s->regs.spi.FIFOSTAT, + s->regs.spi.FIFOINTSTAT); +} + +static void flexcomm_spi_irq_update(FlexcommState *s) +{ + bool irq, per_irqs, fifo_irqs, enabled = s->regs.spi.CFG_b.ENABLE; + + update_fifo_stat(s); + fifo_irqs = s->regs.spi.FIFOINTSTAT & s->regs.spi.FIFOINTENSET; + + s->regs.spi.INTSTAT = s->regs.spi.STAT & s->regs.spi.INTENSET; + per_irqs = s->regs.spi.INTSTAT != 0; + + irq = enabled && (fifo_irqs || per_irqs); + + trace_flexcomm_spi_irq(DEVICE(s)->id, irq, fifo_irqs, per_irqs, enabled); + flexcomm_irq(s, irq); +} + +static void flexcomm_spi_select(void *opaque, FlexcommState *s, int f, + bool set) +{ + if (set) { + int i; + + flexcomm_spi_reset(s); + fifo32_create(&s->rx_fifo, s->regs.spi.FIFOSIZE_b.FIFOSIZE); + fifo32_create(&s->tx_fifo, s->regs.spi.FIFOSIZE_b.FIFOSIZE); + for (i = 0; i < ARRAY_SIZE(s->cs); i++) { + bool spol = s->regs.spi.CFG & (FLEXCOMM_SPI_CFG_SPOL0_Msk << i); + + s->cs_asserted[i] = false; + qemu_set_irq(s->cs[i], !spol); + } + } else { + fifo32_destroy(&s->rx_fifo); + fifo32_destroy(&s->tx_fifo); + } +} + +static MemTxResult flexcomm_spi_reg_read(void *opaque, FlexcommState *s, + int f, hwaddr addr, uint64_t *data, + unsigned size) +{ + MemTxResult ret = MEMTX_OK; + + /* + * Allow 8/16 bits access to the FIFORD LSB half-word. This is supported by + * hardware and required for 1/2 byte(s) width DMA transfers. + */ + if (!reg32_aligned_access(addr, size) && addr != reg(FIFORD)) { + ret = MEMTX_ERROR; + goto out; + } + + switch (addr) { + case reg(FIFORD): + { + /* If we are running in loopback mode get the data from TX FIFO */ + if (s->regs.spi.CFG_b.LOOP && + s->regs.spi.CFG_b.MASTER) + { + if (!fifo32_is_empty(&s->tx_fifo)) { + *data = fifo32_pop(&s->tx_fifo); + } + break; + } + + if (!fifo32_is_empty(&s->rx_fifo)) { + *data = fifo32_pop(&s->rx_fifo); + qemu_chr_fe_accept_input(&s->chr); + } + break; + } + case reg(FIFORDNOPOP): + { + if (!fifo32_is_empty(&s->rx_fifo)) { + *data = fifo32_peek(&s->rx_fifo); + } + break; + } + default: + *data = reg32_read(&s->regs, addr); + break; + } + + flexcomm_spi_irq_update(s); + +out: + trace_flexcomm_spi_reg_read(DEVICE(s)->id, reg_names[addr], addr, *data); + return ret; +} + +static uint32_t fifowr_len_bits(uint32_t val) +{ + int len = (val & FLEXCOMM_SPI_FIFOWR_LEN_Msk) >> + FLEXCOMM_SPI_FIFOWR_LEN_Pos; + + if (len < FLEXCOMM_SPI_FIFOWR_LEN_MIN || + len > FLEXCOMM_SPI_FIFOWR_LEN_MAX) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid spi xfer len %d\n", + __func__, val); + return 0; + } + + return len + 1; +} + +static inline uint32_t fifowr_len_mask(uint32_t val) +{ + return (1 << fifowr_len_bits(val)) - 1; +} + +static inline uint32_t fifowr_len_bytes(uint32_t val) +{ + return fifowr_len_bits(val) > 8 ? 2 : 1; +} + +static uint32_t flexcomm_spi_xfer_word(FlexcommState *s, + uint32_t out_data, + int bytes, + bool be) +{ + uint32_t word = 0; + int i; + int out = 0; + + for (i = 0; i < bytes; i++) { + if (be) { + int byte_offset = bytes - i - 1; + out = (out_data & (0xFF << byte_offset * 8)) >> byte_offset * 8; + word |= ssi_transfer(s->spi, out) << byte_offset * 8; + } else { + out = (out_data & (0xFF << i * 8)) >> i * 8; + word |= ssi_transfer(s->spi, out) << i * 8; + } + } + + return word; +} + +static uint32_t flexcomm_spi_get_ss_mask(FlexcommState *s, + uint32_t txfifo_val) +{ + uint32_t slave_select_mask = 0; + for (int i = 0; i < ARRAY_SIZE(s->cs); i++) { + int tx_ss_pos = FLEXCOMM_SPI_FIFOWR_TXSSEL0_N_Pos + i; + uint32_t state = (txfifo_val & (1 << tx_ss_pos)) >> tx_ss_pos; + bool spol = s->regs.spi.CFG & (FLEXCOMM_SPI_CFG_SPOL0_Msk << i); + int irq_level = state ? spol : !spol; + + slave_select_mask |= (state << i); + s->cs_asserted[i] = state; + qemu_set_irq(s->cs[i], irq_level); + } + + return slave_select_mask; +} + +static MemTxResult flexcomm_spi_reg_write(void *opaque, FlexcommState *s, + int f, hwaddr addr, uint64_t value, + unsigned size) +{ + MemTxResult ret = MEMTX_OK; + static uint32_t mask[REG_NO] = { + [regi(CFG)] = BITS(11, 7) | BITS(5, 2) | BIT(0), + [regi(DLY)] = BITS(15, 0), + [regi(STAT)] = BIT(7) | BIT(5) | BIT(4), + [regi(INTENSET)] = BIT(8) | BITS(5, 4), + [regi(INTENCLR)] = BIT(8) | BITS(5, 4), + [regi(DIV)] = BITS(15, 0), + [regi(FIFOCFG)] = BITS(18, 12) | BITS(1, 0), + [regi(FIFOSTAT)] = BITS(1, 0), + [regi(FIFOTRIG)] = BITS(19, 16) | BITS(11, 8) | BITS(1, 0), + [regi(FIFOINTENSET)] = BITS(3, 0), + [regi(FIFOINTENCLR)] = BITS(3, 0), + [regi(FIFOWR)] = BITS(27, 0), + }; + + /* + * Allow 8/16 bits access to both the FIFOWR MSB and LSB half-words. The + * former is required for updating the control bits while the latter for DMA + * transfers of 1/2 byte(s) width. + */ + if (!reg32_aligned_access(addr, size) && (addr / 4 * 4 != reg(FIFOWR))) { + ret = MEMTX_ERROR; + goto out; + } + + switch (addr) { + case reg(CFG): + { + reg32_write(&s->regs, addr, value, mask); + + if (s->regs.spi.CFG_b.ENABLE) { + qemu_chr_fe_accept_input(&s->chr); + } + + break; + } + case reg(INTENCLR): + { + reg32_write(&s->regs, addr, value, mask); + s->regs.spi.INTENSET &= ~s->regs.spi.INTENCLR; + break; + } + case reg(FIFOCFG): + { + reg32_write(&s->regs, addr, value, mask); + if (s->regs.spi.FIFOCFG_b.EMPTYRX) { + s->regs.spi.FIFOCFG_b.EMPTYRX = 0; + fifo32_reset(&s->rx_fifo); + } + if (s->regs.spi.FIFOCFG_b.EMPTYTX) { + s->regs.spi.FIFOCFG_b.EMPTYTX = 0; + fifo32_reset(&s->tx_fifo); + } + if (s->regs.spi.FIFOCFG_b.ENABLERX) { + qemu_chr_fe_accept_input(&s->chr); + } + break; + } + case reg(FIFOSTAT): + { + bool rxerr = s->regs.spi.FIFOSTAT_b.RXERR; + bool txerr = s->regs.spi.FIFOSTAT_b.TXERR; + + reg32_write(&s->regs, addr, value, mask); + + if (rxerr && s->regs.spi.FIFOSTAT_b.RXERR) { + rxerr = false; + } + if (txerr && s->regs.spi.FIFOSTAT_b.TXERR) { + txerr = false; + } + + s->regs.spi.FIFOSTAT_b.RXERR = rxerr; + s->regs.spi.FIFOSTAT_b.TXERR = txerr; + break; + } + case reg(FIFOINTENSET): + { + s->regs.spi.FIFOINTENSET |= value & mask[addr / 4]; + break; + } + case reg(FIFOINTENCLR): + { + reg32_write(&s->regs, addr, value, mask); + s->regs.spi.FIFOINTENSET &= ~s->regs.spi.FIFOINTENCLR; + break; + } + /* update control bits but don't push into the FIFO */ + case reg(FIFOWR) + 2: + { + if (size > 2) { + ret = MEMTX_ERROR; + break; + } + if (value != 0) { + s->spi_tx_ctrl = value << 16; + } + break; + } + /* update control bits but don't push into the FIFO */ + case reg(FIFOWR) + 3: + { + if (size > 1) { + ret = MEMTX_ERROR; + break; + } + if (value != 0) { + s->spi_tx_ctrl = value << 24; + } + break; + } + case reg(FIFOWR): + { + /* fifo value contains both data and control bits */ + uint32_t txfifo_val; + + if (size > 2 && (value & ~FLEXCOMM_SPI_FIFOWR_TXDATA_Msk) != 0) { + /* non-zero writes to control bits updates them */ + s->spi_tx_ctrl = value & ~FLEXCOMM_SPI_FIFOWR_TXDATA_Msk; + txfifo_val = value; + } else { + /* otherwise reuse previous control bits */ + txfifo_val = value | s->spi_tx_ctrl; + } + + if (!fifo32_is_full(&s->tx_fifo)) { + fifo32_push(&s->tx_fifo, txfifo_val); + } + + if (!s->regs.spi.CFG_b.ENABLE || !s->regs.spi.FIFOCFG_b.ENABLETX) { + break; + } + + /* + * On loopback mode we just insert the values in the TX FIFO. On slave + * mode master needs to initiate the SPI transfer. + */ + if (s->regs.spi.CFG_b.LOOP || !s->regs.spi.CFG_b.MASTER) { + break; + } + + while (!fifo32_is_empty(&s->tx_fifo)) { + txfifo_val = fifo32_pop(&s->tx_fifo); + + uint32_t ss_mask = flexcomm_spi_get_ss_mask(s, txfifo_val); + uint32_t data = txfifo_val & fifowr_len_mask(txfifo_val); + uint8_t bytes = fifowr_len_bytes(txfifo_val); + bool msb = !s->regs.spi.CFG_b.LSBF; + uint32_t val32; + + val32 = flexcomm_spi_xfer_word(s, data, bytes, msb); + + if (!fifo32_is_full(&s->rx_fifo)) { + /* Append the mask that informs which client is active */ + val32 |= (ss_mask << FLEXCOMM_SPI_FIFORD_RXSSEL0_N_Pos); + fifo32_push(&s->rx_fifo, val32); + } + + /* If this is the end of the transfer raise the CS line */ + if (txfifo_val & FLEXCOMM_SPI_FIFOWR_EOT_Msk) { + bool spol[ARRAY_SIZE(s->cs)] = { + s->regs.spi.CFG_b.SPOL0, + s->regs.spi.CFG_b.SPOL1, + s->regs.spi.CFG_b.SPOL2, + s->regs.spi.CFG_b.SPOL3, + }; + + for (int i = 0; i < ARRAY_SIZE(s->cs); i++) { + if (s->cs_asserted[i]) { + s->cs_asserted[i] = false; + qemu_set_irq(s->cs[i], !spol[i]); + } + } + } + } + break; + } + default: + reg32_write(&s->regs, addr, value, mask); + break; + } + + flexcomm_spi_irq_update(s); + +out: + trace_flexcomm_spi_reg_write(DEVICE(s)->id, reg_names[addr], addr, value); + return ret; +} + +static const FlexcommFunctionOps flexcomm_spi_ops = { + .select = flexcomm_spi_select, + .reg_read = flexcomm_spi_reg_read, + .reg_write = flexcomm_spi_reg_write, +}; + +void flexcomm_spi_init(FlexcommState *s) +{ + s->spi = ssi_create_bus(DEVICE(s), "spi"); + qdev_init_gpio_out_named(DEVICE(s), &s->cs[0], "cs", ARRAY_SIZE(s->cs)); +} + +/* Register the SPI operations with the flexcomm upper layer */ +void flexcomm_spi_register(void) +{ + Error *err = NULL; + + if (!flexcomm_register_ops(FLEXCOMM_FUNC_SPI, NULL, + &flexcomm_spi_ops, &err)) { + error_report_err(err); + } +} diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build index b999aeb027..57d3e14727 100644 --- a/hw/ssi/meson.build +++ b/hw/ssi/meson.build @@ -12,3 +12,4 @@ system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_spi.c')) system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_spi.c')) system_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_spi_host.c')) system_ss.add(when: 'CONFIG_BCM2835_SPI', if_true: files('bcm2835_spi.c')) +system_ss.add(when: 'CONFIG_FLEXCOMM', if_true: files('flexcomm_spi.c')) diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events index 2d5bd2b83d..5caa1c17ac 100644 --- a/hw/ssi/trace-events +++ b/hw/ssi/trace-events @@ -32,3 +32,11 @@ ibex_spi_host_reset(const char *msg) "%s" ibex_spi_host_transfer(uint32_t tx_data, uint32_t rx_data) "tx_data: 0x%" PRIx32 " rx_data: @0x%" PRIx32 ibex_spi_host_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size %u: 0x%" PRIx64 ibex_spi_host_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size %u:" + +# flexcomm_spi.c +flexcomm_spi_reg_read(const char *id, const char *reg_name, uint32_t addr, uint32_t val) " %s: %s[0x%04x] -> 0x%08x" +flexcomm_spi_reg_write(const char *id, const char *reg_name, uint32_t addr, uint32_t val) "%s: %s[0x%04x] <- 0x%08x" +flexcomm_spi_fifostat(const char *id, uint32_t fifostat, uint32_t fifoinstat) "%s: %08x %08x" +flexcomm_spi_irq(const char *id, bool irq, bool fifoirqs, bool perirqs, bool enabled) "%s: %d %d %d %d" +flexcomm_spi_chr_rx_space(const char *id, uint32_t rx) "%s: %d" +flexcomm_spi_chr_rx(const char *id) "%s" diff --git a/include/hw/misc/flexcomm.h b/include/hw/misc/flexcomm.h index 3d042a3511..62f327925d 100644 --- a/include/hw/misc/flexcomm.h +++ b/include/hw/misc/flexcomm.h @@ -15,9 +15,12 @@ #include "hw/sysbus.h" #include "chardev/char-fe.h" #include "hw/i2c/i2c.h" +#include "hw/ssi/ssi.h" #include "hw/arm/svd/flexcomm.h" #include "hw/arm/svd/flexcomm_usart.h" #include "hw/arm/svd/flexcomm_i2c.h" +#undef EOF +#include "hw/arm/svd/flexcomm_spi.h" #include "qemu/fifo32.h" #define TYPE_FLEXCOMM "flexcomm" @@ -49,6 +52,7 @@ typedef struct { FLEXCOMM_Type flex; FLEXCOMM_USART_Type usart; FLEXCOMM_I2C_Type i2c; + FLEXCOMM_SPI_Type spi; } regs; uint32_t functions; qemu_irq irq; @@ -57,6 +61,10 @@ typedef struct { Fifo32 tx_fifo; Fifo32 rx_fifo; I2CBus *i2c; + SSIBus *spi; + qemu_irq cs[4]; + bool cs_asserted[4]; + uint32_t spi_tx_ctrl; } FlexcommState; typedef struct { diff --git a/include/hw/ssi/flexcomm_spi.h b/include/hw/ssi/flexcomm_spi.h new file mode 100644 index 0000000000..d5567aa1e6 --- /dev/null +++ b/include/hw/ssi/flexcomm_spi.h @@ -0,0 +1,20 @@ +/* + * QEMU model for NXP's FLEXCOMM SPI + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_CHAR_FLEXCOMM_SPI_H +#define HW_CHAR_FLEXCOMM_SPI_H + +#include "hw/misc/flexcomm.h" + +void flexcomm_spi_init(FlexcommState *s); +void flexcomm_spi_register(void); + +#endif /* HW_CHAR_FLEXCOMM_SPI_H */ diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 3491e2003b..1ddd174576 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -150,6 +150,8 @@ if have_system meson.project_source_root() / 'hw/char/flexcomm_usart.c', meson.project_source_root() / 'hw/i2c/flexcomm_i2c.c', meson.project_source_root() / 'hw/i2c/core.c', + meson.project_source_root() / 'hw/ssi/flexcomm_spi.c', + meson.project_source_root() / 'hw/ssi/ssi.c', ], 'test-flexcomm-usart': [ hwcore, chardev, qom, migration, @@ -159,6 +161,8 @@ if have_system meson.project_source_root() / 'hw/char/flexcomm_usart.c', meson.project_source_root() / 'hw/i2c/flexcomm_i2c.c', meson.project_source_root() / 'hw/i2c/core.c', + meson.project_source_root() / 'hw/ssi/flexcomm_spi.c', + meson.project_source_root() / 'hw/ssi/ssi.c', ], 'test-flexcomm-i2c': [ hwcore, chardev, qom, migration, @@ -169,6 +173,9 @@ if have_system meson.project_source_root() / 'hw/i2c/flexcomm_i2c.c', meson.project_source_root() / 'hw/i2c/core.c', 'i2c_tester.c', + meson.project_source_root() / 'hw/ssi/flexcomm_spi.c', + meson.project_source_root() / 'hw/ssi/ssi.c', + ], ], } if config_host_data.get('CONFIG_INOTIFY1') From patchwork Mon Aug 5 20:17:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754035 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id EE677C52D70 for ; Mon, 5 Aug 2024 20:19:30 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49b-0004MD-Ao; Mon, 05 Aug 2024 16:18:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3bTOxZgUKCtQJ0L8F6EE6B4.2ECG4CK-34L4BDED6DK.EH6@flex--tavip.bounces.google.com>) id 1sb49T-0003iq-A8 for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:55 -0400 Received: from mail-yb1-xb49.google.com ([2607:f8b0:4864:20::b49]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3bTOxZgUKCtQJ0L8F6EE6B4.2ECG4CK-34L4BDED6DK.EH6@flex--tavip.bounces.google.com>) id 1sb49Q-0001VG-GR for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:54 -0400 Received: by mail-yb1-xb49.google.com with SMTP id 3f1490d57ef6-e0be470f76bso7577021276.3 for ; Mon, 05 Aug 2024 13:17:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889069; x=1723493869; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=HolQ6M2QNUE2ejhU+N0utPdQeOsLaCbhpFMvlfrSt68=; b=uZDRhc+KQTimayIm6PWtaVrkHvy1YUccUMWvqGAQxpu1is+QVmPkKBMK0xG5G4mACq mtguNMcC75TQxAz7WWJBFIcGYgSqM4/Qx/mB7lzrWmepmc5E60JsNMlxZS5oMd++eFHm R9AF/iiaSF1xt+xOLkSry6NlEYrb4amUI0iUrVcipoSzz7Sw08B4KAuKCI85rTNOTXbw 4NLax8QhpPUlq22Co2yujk/qqrkX6dweMYO6uz7aIaKniquZr7mvPxM0XUtFTtTkaW1p k6Haq6uUpOhya6aMgpTqgdBSZNeMLdZ164SZuTxxwMKUR0JlbT5nWG7RzV19kiI+uruv 8pNw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889069; x=1723493869; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=HolQ6M2QNUE2ejhU+N0utPdQeOsLaCbhpFMvlfrSt68=; b=OZOvy98Q8jQg5IrXtQ9qvYkhRH8yHmeLlroTPPaaK8Pxq2qWWN9KmXhzQU8Cl8Ra/n vGbnyUioTMwqAaYCXP082kjARbzHS+1POAEWYh3CXOQq2g3bZM6fEU4Aod4sgrY5KRcC MnRgPDDvVQrdmgc/VZJ6HNUZpEQu7GUTpc2LBBb3LLe0kpAyU/GalmHeFUXyFUFunsb3 rxfdiNXMyDe6c5ZqVHXdmmdGiEfgtc1JcOK7ypy9I9i4uvyr8NZDJptYcyt/wkoHcuCB lFD15NfQq7Z4lIyZe5JYcoYhztGaIaBFtjtIW2jOwr0EU3Gw8S2D8BmOXpwn6fiImXbf BrJA== X-Gm-Message-State: AOJu0YyGugkJ+6r3cqRzw7G3ps92/tOE3Haya4LcIGP6TSrurgUMultJ +POlmVQfXGG6YaLSvdS+trVJHyG1u272JXm8m8Oes97tqZ045l04a/A2AP7XthdNPllW62WBmVe nCgkhBxJVBvzComL+Xzo3jsItC88Fn88piM4xLQFAb9Ui6l8xequjqZJOa0JGBPEA4wjV0qWXmX d3tijCNqTikxT5H6jj5CrQhhRqQA== X-Google-Smtp-Source: AGHT+IHJ2yivBPbFmiyhK3hrpQuvMsngp9pP9WhL1UClne9zJKqUNbF4+KVclnzUr+aIx/QWIhVmtv/sfw== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:6902:100c:b0:e0b:c18c:ebfb with SMTP id 3f1490d57ef6-e0bde1eca27mr94734276.2.1722889069374; Mon, 05 Aug 2024 13:17:49 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:11 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-17-tavip@google.com> Subject: [RFC PATCH 16/23] test/unit: add spi-tester From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::b49; envelope-from=3bTOxZgUKCtQJ0L8F6EE6B4.2ECG4CK-34L4BDED6DK.EH6@flex--tavip.bounces.google.com; helo=mail-yb1-xb49.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add a simple SPI peripheral that echoes back received data. Useful for testing SPI controllers. Signed-off-by: Octavian Purdila --- tests/unit/spi_tester.c | 60 +++++++++++++++++++++++++++++++++++++++++ tests/unit/spi_tester.h | 32 ++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 tests/unit/spi_tester.c create mode 100644 tests/unit/spi_tester.h diff --git a/tests/unit/spi_tester.c b/tests/unit/spi_tester.c new file mode 100644 index 0000000000..7bccc680cc --- /dev/null +++ b/tests/unit/spi_tester.c @@ -0,0 +1,60 @@ +/* + * Simple SPI peripheral echo device used for SPI controller testing. + * + * Copyright (c) 2024 Google LLC. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "spi_tester.h" + +static uint32_t spi_tester_transfer(SSIPeripheral *dev, uint32_t value) +{ + SpiTesterState *s = SPI_TESTER(dev); + + if (s->cs) { + return 0; + } + + return value; +} + +static void spi_tester_realize(SSIPeripheral *d, Error **errp) +{ +} + +static int spi_tester_set_cs(SSIPeripheral *dev, bool select) +{ + SpiTesterState *s = SPI_TESTER(dev); + + s->cs = select; + + return 0; +} + +static void spi_tester_class_init(ObjectClass *klass, void *data) +{ + SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); + + k->realize = spi_tester_realize; + k->transfer = spi_tester_transfer; + k->set_cs = spi_tester_set_cs; + k->cs_polarity = SSI_CS_LOW; +} + +static const TypeInfo spi_tester_info = { + .name = TYPE_SPI_TESTER, + .parent = TYPE_SSI_PERIPHERAL, + .instance_size = sizeof(SpiTesterState), + .class_init = spi_tester_class_init, +}; + +static void spi_tester_register_types(void) +{ + type_register_static(&spi_tester_info); +} + +type_init(spi_tester_register_types) diff --git a/tests/unit/spi_tester.h b/tests/unit/spi_tester.h new file mode 100644 index 0000000000..16e08d2b5c --- /dev/null +++ b/tests/unit/spi_tester.h @@ -0,0 +1,32 @@ +/* + * Simple SPI peripheral device used for SPI controller testing. + * + * Copyright (c) 2024 Google LLC. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef TESTS_UNIT_SPI_TESTER_H +#define TESTS_UNIT_SPI_TESTER_H + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/bswap.h" +#include "hw/irq.h" +#include "hw/ssi/ssi.h" +#include "qemu/timer.h" +#include "hw/qdev-properties.h" + +#define TYPE_SPI_TESTER "spi-tester" +#define SPI_TESTER(obj) OBJECT_CHECK(SpiTesterState, (obj), TYPE_SPI_TESTER) + +typedef struct { + SSIPeripheral ssidev; + bool cs; +} SpiTesterState; + +#endif /* TESTS_UNIT_SPI_TESTER_H */ From patchwork Mon Aug 5 20:17:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754021 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 4ABF0C3DA7F for ; Mon, 5 Aug 2024 20:18:30 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49f-0004Rq-Hy; Mon, 05 Aug 2024 16:18:09 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3bzOxZgUKCtYL2NAH8GG8D6.4GEI6EM-56N6DFGF8FM.GJ8@flex--tavip.bounces.google.com>) id 1sb49V-0003t9-Vg for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:58 -0400 Received: from mail-pl1-x64a.google.com ([2607:f8b0:4864:20::64a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3bzOxZgUKCtYL2NAH8GG8D6.4GEI6EM-56N6DFGF8FM.GJ8@flex--tavip.bounces.google.com>) id 1sb49T-0001Vp-45 for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:57 -0400 Received: by mail-pl1-x64a.google.com with SMTP id d9443c01a7336-1ff3dfaa090so56173155ad.3 for ; Mon, 05 Aug 2024 13:17:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889071; x=1723493871; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=wzBmDOceMrnHqMQIWuQIRSZOR9yk0Yvpmsomz+UG+gg=; b=O3PgGvJq0KeHXh/UXMpemJC46Dp/bohzJ8pJdeBz8zkAVHh00+KxRhlNPael4tibPs SCT916P9BE11j++9g/WyWc3LzOVRwg0N7dqsdNxTDCQBeDaSiDunnKYVtb0oH8uj3to7 ZC/aTkGUQllEiXgJmh68hW4IiD9mep6hB4HoS6Z0Ywe61a5lf38KAX8BDjq6I9E4y6yO oH4FH00VlXBU/bIottUWf/iYKU0SRbRGMMhphf4Xc5RUQyfveRdkMWaPf3iNULK7gB2z KAPQt5TGAWGFydnWxMSFebUKoPSv6NcwfISoAAmqRvLCdSzS2q2ZVXanMPbg25wpW6tU jMlg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889071; x=1723493871; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=wzBmDOceMrnHqMQIWuQIRSZOR9yk0Yvpmsomz+UG+gg=; b=Hug4BOmX92WNsDgLFuMYTWlpnpmjCy3fcxheXK4q26yJ6b5XW2+izHgJE//XAlbDsy VKAjC+V3RDWOZj6q9urQ8Za5lGVXd6dBE7K1pAdkvb9782c76CoEb8xu5IYwn5FH8Qxc VgNcso/5b268HonZijqW/t6ff87ITwgcN9jrOMVtEztoZ7YddxgYPOxhcKIaFyjATOIE EjIRirrF0AWz/nBN9LKZEIuhUPrg9YYJbpQn5SMeIcSWVI3HcQ/LrmJBQVyjRHJs6n8p Gc3xFW1ZGTfH7a9IWjoOP4rsG+6W7b5I8RZuEIa7yfMgGQxrUWVuhr0CzxWq8HBxT5tr 4xXQ== X-Gm-Message-State: AOJu0YwVdMTDwidKOM/t2FpA0op3OZk4LVcq08DGaIgxM1RKttGTJ86g SUG/4t2LHTHk3f/uU8FdGaNLyUcUp04YgGROlRxaY+CSc76PO+9xECREz5CGjNEW2OVqZiedcI4 xYsyLRcl83A474YbWONlAajfdD18e4tx4cBCc0xiyg8KI4k6eAqdqXTB5cIoo39jaA0H23RAB0e Dgk6eBkays2TgX1ydQfNhUgU9Pqw== X-Google-Smtp-Source: AGHT+IHVi7BSDYYhjOka8/Q/qJLSQwS1b7zusawaDngOT+BQcrbPW5yMM/adD7GWmfTork0iu8CQc2L59Q== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a17:902:ec85:b0:1fb:1ae6:6ab9 with SMTP id d9443c01a7336-1ff570db092mr4983795ad.0.1722889071130; Mon, 05 Aug 2024 13:17:51 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:12 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-18-tavip@google.com> Subject: [RFC PATCH 17/23] test/unit: add unit tests for flexcomm spi From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::64a; envelope-from=3bzOxZgUKCtYL2NAH8GG8D6.4GEI6EM-56N6DFGF8FM.GJ8@flex--tavip.bounces.google.com; helo=mail-pl1-x64a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Sebastian Ene From: Sebastian Ene Add master and loopback tests for flexcomm spi. Signed-off-by: Sebastian Ene Signed-off-by: Octavian Purdila --- tests/unit/meson.build | 11 ++ tests/unit/test-flexcomm-spi.c | 204 +++++++++++++++++++++++++++++++++ 2 files changed, 215 insertions(+) create mode 100644 tests/unit/test-flexcomm-spi.c diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 1ddd174576..7a28e7b521 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -176,6 +176,17 @@ if have_system meson.project_source_root() / 'hw/ssi/flexcomm_spi.c', meson.project_source_root() / 'hw/ssi/ssi.c', ], + 'test-flexcomm-spi': [ + qom, hwcore, migration, chardev, + meson.project_source_root() / 'hw/core/gpio.c', + meson.project_source_root() / 'tests/unit/sysbus-mock.c', + meson.project_source_root() / 'hw/misc/flexcomm.c', + meson.project_source_root() / 'hw/char/flexcomm_usart.c', + meson.project_source_root() / 'hw/i2c/flexcomm_i2c.c', + meson.project_source_root() / 'hw/i2c/core.c', + meson.project_source_root() / 'hw/ssi/flexcomm_spi.c', + meson.project_source_root() / 'hw/ssi/ssi.c', + 'spi_tester.c', ], } if config_host_data.get('CONFIG_INOTIFY1') diff --git a/tests/unit/test-flexcomm-spi.c b/tests/unit/test-flexcomm-spi.c new file mode 100644 index 0000000000..4aaf511d70 --- /dev/null +++ b/tests/unit/test-flexcomm-spi.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2024 Google LLC. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" + +#include "qemu/config-file.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qapi/error.h" +#include "qemu/sockets.h" +#include "sysemu/sysemu.h" +#include "qemu/main-loop.h" +#include "qemu/option.h" +#include "exec/memory.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-core.h" + +#include "hw/misc/flexcomm.h" +#include "spi_tester.h" +#include "sysbus-mock.h" +#include "reg-utils.h" + +/* The number of words sent on the SPI in loopback mode. */ +#define SEQ_LOOPBACK_MODE (8) + +/* This value is used to set the cycle counter for the spi tester */ +#define SPI_TESTER_CONFIG (0x10) + +#define FLEXCOMM_BASE 0x40106000UL +#define FLEXCOMM_SPI_BASE FLEXCOMM_BASE + +typedef struct { + DeviceState *dev; + DeviceState *periph; + bool irq; +} TestFixture; + +/* Callback for the interrupt line. */ +static void spi_irq_set(void *opaque, int line, int level) +{ + TestFixture *f = (TestFixture *)opaque; + + f->irq = level; +} + +/* + * Test fixture initialization. + */ +static void set_up(TestFixture *f, gconstpointer data) +{ + FlexcommState *s; + + f->dev = qdev_new(TYPE_FLEXCOMM); + g_assert(f->dev); + + s = FLEXCOMM(f->dev); + s->irq = qemu_allocate_irq(spi_irq_set, f, 0); + + if (data != NULL) { + qdev_prop_set_int32(DEVICE(f->dev), "functions", (uintptr_t)data); + } + + qdev_realize_and_unref(f->dev, NULL, &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(f->dev), 0, FLEXCOMM_BASE); + + device_cold_reset(f->dev); + + f->periph = ssi_create_peripheral(s->spi, TYPE_SPI_TESTER); + s->cs[0] = qdev_get_gpio_in_named(f->periph, SSI_GPIO_CS, 0); +} + +static void tear_down(TestFixture *f, gconstpointer user_data) +{ + qdev_unrealize(f->dev); + qdev_unrealize(DEVICE(f->periph)); + g_free(f->dev); +} + +static void configure_spi(TestFixture *f, bool master, bool is_loopback_mode) +{ + uint32_t tmp; + + /* Select and lock SPI */ + tmp = FLEXCOMM_PSELID_LOCK_Msk | FLEXCOMM_PERSEL_SPI; + REG32_WRITE(f->dev, FLEXCOMM, PSELID, tmp); + + /* Disable the FIFO */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_SPI, CFG, ENABLE, 0); + REG32_WRITE_FIELD(f->dev, FLEXCOMM_SPI, FIFOCFG, ENABLETX, 0); + REG32_WRITE_FIELD(f->dev, FLEXCOMM_SPI, FIFOCFG, ENABLERX, 0); + + if (is_loopback_mode) { + /* Set up SPI interface - loop mode, master mode */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_SPI, CFG, LOOP, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_SPI, CFG, LOOP) == 1); + } + + if (master) { + REG32_WRITE_FIELD(f->dev, FLEXCOMM_SPI, CFG, MASTER, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_SPI, CFG, MASTER) == 1); + } else { + REG32_WRITE_FIELD(f->dev, FLEXCOMM_SPI, CFG, MASTER, 0); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_SPI, CFG, MASTER) == 0); + } + + /* Enable the FIFO */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_SPI, FIFOCFG, ENABLETX, 1); + REG32_WRITE_FIELD(f->dev, FLEXCOMM_SPI, FIFOCFG, ENABLERX, 1); + + /* Enable the SPI */ + REG32_WRITE_FIELD(f->dev, FLEXCOMM_SPI, CFG, ENABLE, 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_SPI, CFG, ENABLE) == 1); +} + +/* The SPI controller running in master mode can run in loopback mode for */ +/* internal testing. Transmit and receive lines are connected together. */ +static void loopback_test(TestFixture *f, gconstpointer user_data) +{ + int i; + + configure_spi(f, true, true); + + /* Write a sequence */ + for (i = 0; i < SEQ_LOOPBACK_MODE; i++) { + REG32_WRITE(f->dev, FLEXCOMM_SPI, FIFOWR, i); + } + + /* Read the sequence back */ + for (i = 0; i < SEQ_LOOPBACK_MODE; i++) { + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_SPI, FIFORD, RXDATA) == i); + } +} + +static void spi_master_test(TestFixture *f, gconstpointer user_data) +{ + uint32_t tmp; + + configure_spi(f, true, false); + + REG32_WRITE_FIELD(f->dev, FLEXCOMM_SPI, CFG, LSBF, 1); + + /* single 16bit word transfer */ + + tmp = 0x1122; + tmp |= FLEXCOMM_SPI_FIFOWR_EOT_Msk; + tmp |= FLEXCOMM_SPI_FIFOWR_TXSSEL0_N_Msk; + tmp |= (0xF << FLEXCOMM_SPI_FIFOWR_LEN_Pos); + REG32_WRITE(f->dev, FLEXCOMM_SPI, FIFOWR, tmp); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_SPI, FIFOSTAT, RXNOTEMPTY) == 1); + g_assert_cmpuint(REG32_READ_FIELD(f->dev, FLEXCOMM_SPI, FIFORD, RXDATA), + ==, 0x1122); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_SPI, FIFOSTAT, RXNOTEMPTY) == 0); + + /* multi word 8 bits transfer */ + + tmp = 0x11; + tmp |= FLEXCOMM_SPI_FIFOWR_TXSSEL0_N_Msk; + tmp |= (0x7 << FLEXCOMM_SPI_FIFOWR_LEN_Pos); + REG32_WRITE(f->dev, FLEXCOMM_SPI, FIFOWR, tmp); + tmp = 0x22; + tmp |= FLEXCOMM_SPI_FIFOWR_EOT_Msk; + tmp |= FLEXCOMM_SPI_FIFOWR_TXSSEL0_N_Msk; + tmp |= (0x7 << FLEXCOMM_SPI_FIFOWR_LEN_Pos); + REG32_WRITE(f->dev, FLEXCOMM_SPI, FIFOWR, tmp); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_SPI, FIFOSTAT, RXNOTEMPTY) == 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_SPI, FIFORD, RXDATA) == 0x11); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_SPI, FIFOSTAT, RXNOTEMPTY) == 1); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_SPI, FIFORD, RXDATA) == 0x22); + g_assert(REG32_READ_FIELD(f->dev, FLEXCOMM_SPI, FIFOSTAT, RXNOTEMPTY) == 0); +} + + +/* mock-up */ +const PropertyInfo qdev_prop_chr; + +int main(int argc, char **argv) +{ + qemu_init_main_loop(&error_abort); + socket_init(); + + g_test_init(&argc, &argv, NULL); + + /* Initialize object types. */ + sysbus_mock_init(); + module_call_init(MODULE_INIT_QOM); + qemu_add_opts(&qemu_chardev_opts); + + g_test_add("/flexcomm-spi/loopback", TestFixture, + (gconstpointer)(1 << FLEXCOMM_FUNC_SPI), + set_up, loopback_test, tear_down); + + g_test_add("/flexcomm-spi/master", TestFixture, + (gconstpointer)(1 << FLEXCOMM_FUNC_SPI), + set_up, spi_master_test, tear_down); + + return g_test_run(); +} From patchwork Mon Aug 5 20:17:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754040 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 28E96C52D70 for ; Mon, 5 Aug 2024 20:20:28 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49i-00059A-BE; Mon, 05 Aug 2024 16:18:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3cTOxZgUKCtgN4PCJAIIAF8.6IGK8GO-78P8FHIHAHO.ILA@flex--tavip.bounces.google.com>) id 1sb49X-00040G-Lt for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:59 -0400 Received: from mail-pl1-x649.google.com ([2607:f8b0:4864:20::649]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3cTOxZgUKCtgN4PCJAIIAF8.6IGK8GO-78P8FHIHAHO.ILA@flex--tavip.bounces.google.com>) id 1sb49T-0001WB-MA for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:17:59 -0400 Received: by mail-pl1-x649.google.com with SMTP id d9443c01a7336-1fd9a0efe4eso89516645ad.0 for ; Mon, 05 Aug 2024 13:17:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889073; x=1723493873; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=v2jh5tjCtlI1RmgfNYjqVuuv8CQQZbs99DRkNkD9UB4=; b=QZkkMQ56ebcCn4zst7AmsNZ77oAl1z1JaooJ37+EmqH8ExhJF9zDJ3rRFkPfFPxYxv EAh+C4vDnVjh5c5syvwb6hKV90dFO9GIPPydG9vcj75c6Y5mKDYbHQGOLsKd5RfVyM5f Csyrf/JPzKO6JMPYQ0wgrDYZOnD8fz60b86Oe9laZxOLeKrphZIPMH71mpg/BqKV0VZ7 2p5SSG8wHDebTugmJ2P2MZVSga5d2TJdWEJUF0/kh48A4s6ygkYPGV1ZmgD45ENKF8rJ 680Op7TPurtFvXgxG4F63AJjdjl6RLNldOzd23GTN6mIdF9GMwHM9v3S3+yxcXPH4mj4 LjWg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889073; x=1723493873; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=v2jh5tjCtlI1RmgfNYjqVuuv8CQQZbs99DRkNkD9UB4=; b=AoD5YAosmksTdEzOwW+JuGtJOFR7IA55jMoA+dtQV3cCqL9I+wTBHlQSm40LpBN/YT YU44lSijjCCWjYsl6yP7s3mSIjHkGGTGo04IApWxWiej0fo9N5xcJ37VgBUBl1jXOHNu wpRjMncX0U7hN/wh/hTQziufzEO4ggIzpJozVUoCWoqSn3+dX0wiN7TPaZgoMlG7fONT 3uvapk+WSKrGzAnohvHpIrb1R6UekogFbeBHSorQRtT9U6sfNRls+bo/xkfGD9KiRThh cWYLx8rGbBiuLAfkcuUdSQEAkAdk8ZFbmhz7PodmAeJ7h3QjPvCQElF9nhhTcccJ/pqn XOAg== X-Gm-Message-State: AOJu0YzHJHarB0tsu08EfxcUsiu0qqmjF4iaGSrROXzhshF9QIECke4j pZhiLP7q+nBoaJQbpI+w6wRQCeZdikX9vsZ6z0PZi4mYkOM68PrCnm3bOp2E7MfnJNx3KdNgf8X DAqjnEtd3OfXsR9jhAIGr/XVO/ShOsFAiaF3drSi2pdTkycRaKJur7W8efInklYlmHY9UaC38ar o7S3osFMSb2XkVAAUh0vKqnBnzuA== X-Google-Smtp-Source: AGHT+IEZdX2+oV28BPB0L7VYVGqFiktD6Oe29pv7sN7eBnPkvt3mVBy2Us8eoLe88yTqNmo0HP3uxSkHfQ== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a17:902:dac4:b0:1fc:57b7:9959 with SMTP id d9443c01a7336-1ff5732e3b0mr3746995ad.6.1722889073028; Mon, 05 Aug 2024 13:17:53 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:13 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-19-tavip@google.com> Subject: [RFC PATCH 18/23] hw/misc: add support for RT500's clock controller From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::649; envelope-from=3cTOxZgUKCtgN4PCJAIIAF8.6IGK8GO-78P8FHIHAHO.ILA@flex--tavip.bounces.google.com; helo=mail-pl1-x649.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org It supports system and audio PLL initialization and SYSTICK and OSTIMER clock source selection. Signed-off-by: Octavian Purdila --- hw/arm/svd/meson.build | 8 + hw/misc/Kconfig | 6 + hw/misc/meson.build | 2 + hw/misc/rt500_clkctl0.c | 243 ++++++++++++++++++++++++++++++ hw/misc/rt500_clkctl1.c | 224 +++++++++++++++++++++++++++ hw/misc/trace-events | 8 + include/hw/misc/rt500_clk_freqs.h | 18 +++ include/hw/misc/rt500_clkctl0.h | 37 +++++ include/hw/misc/rt500_clkctl1.h | 38 +++++ 9 files changed, 584 insertions(+) create mode 100644 hw/misc/rt500_clkctl0.c create mode 100644 hw/misc/rt500_clkctl1.c create mode 100644 include/hw/misc/rt500_clk_freqs.h create mode 100644 include/hw/misc/rt500_clkctl0.h create mode 100644 include/hw/misc/rt500_clkctl1.h diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build index 8b3b045137..6ab13f8757 100644 --- a/hw/arm/svd/meson.build +++ b/hw/arm/svd/meson.build @@ -14,3 +14,11 @@ genh += custom_target('flexcomm_spi.h', output: 'flexcomm_spi.h', input: 'MIMXRT595S_cm33.xml', command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'SPI0', '-t', 'FLEXCOMM_SPI']) +genh += custom_target('rt500_clkctl0.h', + output: 'rt500_clkctl0.h', + input: 'MIMXRT595S_cm33.xml', + command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'CLKCTL0', '-t', 'RT500_CLKCTL0']) +genh += custom_target('rt500_clkctl1.h', + output: 'rt500_clkctl1.h', + input: 'MIMXRT595S_cm33.xml', + command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'CLKCTL1', '-t', 'RT500_CLKCTL1']) diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 14167ae9e8..392ae9e84f 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -216,4 +216,10 @@ config XLNX_VERSAL_TRNG config FLEXCOMM bool +config RT500_CLKCTL0 + bool + +config RT500_CLKCTL1 + bool + source macio/Kconfig diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 8414767ae3..68929949a6 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -158,3 +158,5 @@ system_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) system_ss.add(when: 'CONFIG_LASI', if_true: files('lasi.c')) system_ss.add(when: 'CONFIG_FLEXCOMM', if_true: files('flexcomm.c')) +system_ss.add(when: 'CONFIG_RT500_CLKCTL0', if_true: files('rt500_clkctl0.c')) +system_ss.add(when: 'CONFIG_RT500_CLKCTL1', if_true: files('rt500_clkctl1.c')) diff --git a/hw/misc/rt500_clkctl0.c b/hw/misc/rt500_clkctl0.c new file mode 100644 index 0000000000..84b5631924 --- /dev/null +++ b/hw/misc/rt500_clkctl0.c @@ -0,0 +1,243 @@ +/* + * QEMU model for RT500 Clock Controller + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/clock.h" +#include "hw/irq.h" +#include "hw/qdev-clock.h" +#include "hw/qdev-properties.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "exec/address-spaces.h" +#include "hw/regs.h" +#include "hw/misc/rt500_clkctl0.h" +#include "hw/misc/rt500_clk_freqs.h" + +#include "trace.h" + +#define reg(field) offsetof(RT500_CLKCTL0_Type, field) +#define REG_NO (sizeof(RT500_CLKCTL0_Type) / sizeof(uint32_t)) +#define regi(x) (reg(x) / sizeof(uint32_t)) + +static RT500_CLKCTL0_REGISTER_NAMES_ARRAY(reg_names); + +static MemTxResult rt500_clkctl0_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + RT500ClkCtl0State *s = opaque; + MemTxResult ret = MEMTX_OK; + + if (!reg32_aligned_access(addr, size)) { + ret = MEMTX_ERROR; + goto out; + } + + switch (addr) { + case reg(PSCCTL0_SET): + case reg(PSCCTL1_SET): + case reg(PSCCTL2_SET): + case reg(PSCCTL0_CLR): + case reg(PSCCTL1_CLR): + case reg(PSCCTL2_CLR): + /* write only registers */ + ret = MEMTX_ERROR; + break; + default: + *data = reg32_read(&s->regs, addr); + break; + } + +out: + trace_rt500_clkctl0_reg_read(reg_names[addr], addr, *data); + return ret; +} + +static inline void set_systick_clk_from_div(RT500ClkCtl0State *s) +{ + uint32_t div = s->regs.SYSTICKFCLKDIV_b.DIV + 1; + uint32_t rate = clock_get_hz(s->sysclk); + + clock_set_hz(s->systick_clk, rate / div); +} + +static MemTxResult rt500_clkctl0_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + RT500ClkCtl0State *s = opaque; + MemTxResult ret = MEMTX_OK; + static uint32_t wr_mask[REG_NO] = { + [0 ... REG_NO - 1] = BITS(31, 0), + [regi(FRO_CAPVAL)] = 0, + [regi(FROCLKSTATUS)] = 0, + }; + + if (!reg32_aligned_access(addr, size)) { + ret = MEMTX_ERROR; + goto out; + } + + switch (addr) { + case reg(PSCCTL0): + case reg(PSCCTL1): + case reg(PSCCTL2): + { + reg32_write(&s->regs, addr, value, wr_mask); + break; + } + case reg(PSCCTL0_SET): + case reg(PSCCTL1_SET): + case reg(PSCCTL2_SET): + { + uint32_t update_addr = reg(PSCCTL0) + (addr - reg(PSCCTL0_SET)); + reg32_write(&s->regs, update_addr, + reg32_read(&s->regs, update_addr) | value, wr_mask); + break; + } + case reg(PSCCTL0_CLR): + case reg(PSCCTL1_CLR): + case reg(PSCCTL2_CLR): + { + uint32_t update_addr = reg(PSCCTL0) + (addr - reg(PSCCTL0_CLR)); + reg32_write(&s->regs, update_addr, + reg32_read(&s->regs, update_addr) & ~value, wr_mask); + break; + } + default: + reg32_write(&s->regs, addr, value, wr_mask); + } + + switch (addr) { + case reg(SYSPLL0PFD): + { + if (!s->regs.SYSPLL0PFD_b.PFD0_CLKGATE) { + s->regs.SYSPLL0PFD_b.PFD0_CLKRDY = 1; + } else { + s->regs.SYSPLL0PFD_b.PFD0_CLKRDY = 0; + } + if (!s->regs.SYSPLL0PFD_b.PFD1_CLKGATE) { + s->regs.SYSPLL0PFD_b.PFD1_CLKRDY = 1; + } else { + s->regs.SYSPLL0PFD_b.PFD1_CLKRDY = 0; + } + if (!s->regs.SYSPLL0PFD_b.PFD2_CLKGATE) { + s->regs.SYSPLL0PFD_b.PFD2_CLKRDY = 1; + } else { + s->regs.SYSPLL0PFD_b.PFD2_CLKRDY = 0; + } + if (!s->regs.SYSPLL0PFD_b.PFD3_CLKGATE) { + s->regs.SYSPLL0PFD_b.PFD3_CLKRDY = 1; + } else { + s->regs.SYSPLL0PFD_b.PFD3_CLKRDY = 0; + } + break; + } + case reg(SYSTICKFCLKSEL): + { + switch (s->regs.SYSTICKFCLKSEL_b.SEL) { + case SYSTICKFCLKSEL_DIVOUT: + { + set_systick_clk_from_div(s); + break; + } + case SYSTICKFCLKSEL_LPOSC: + { + clock_set_hz(s->systick_clk, LPOSC_CLK_HZ); + break; + } + case SYSTICKFCLKSEL_32KHZRTC: + { + clock_set_hz(s->systick_clk, RTC32KHZ_CLK_HZ); + break; + } + case SYSTICKFCLKSEL_NONE: + { + clock_set_hz(s->systick_clk, 0); + break; + } + } + clock_propagate(s->systick_clk); + break; + } + case reg(SYSTICKFCLKDIV): + { + if (s->regs.SYSTICKFCLKSEL_b.SEL == SYSTICKFCLKSEL_DIVOUT) { + set_systick_clk_from_div(s); + clock_propagate(s->systick_clk); + } + break; + } + } + +out: + trace_rt500_clkctl0_reg_write(reg_names[addr], addr, value); + return ret; + + return MEMTX_OK; +} + +static const MemoryRegionOps rt500_clkctl0_ops = { + .read_with_attrs = rt500_clkctl0_read, + .write_with_attrs = rt500_clkctl0_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void rt500_clkctl0_reset(DeviceState *dev) +{ + RT500ClkCtl0State *s = RT500_CLKCTL0(dev); + + memset(&s->regs, 0, sizeof(s->regs)); + + rt500_clkctl0_reset_registers(&s->regs); + + /* clock OK immediately after reset */ + s->regs.FROCLKSTATUS = 0x00000001; +} + +static void rt500_clkctl0_init(Object *obj) +{ + RT500ClkCtl0State *s = RT500_CLKCTL0(obj); + + memory_region_init_io(&s->mmio, obj, &rt500_clkctl0_ops, s, + TYPE_RT500_CLKCTL0, sizeof(s->regs)); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); + s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0); + s->systick_clk = qdev_init_clock_out(DEVICE(s), "systick_clk"); +} + +static void rt500_clkctl0_realize(DeviceState *dev, Error **errp) +{ +} + +static void rt500_clkctl0_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = rt500_clkctl0_reset; + dc->realize = rt500_clkctl0_realize; +} + +static const TypeInfo rt500_clkctl0_info = { + .name = TYPE_RT500_CLKCTL0, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RT500ClkCtl0State), + .instance_init = rt500_clkctl0_init, + .class_init = rt500_clkctl0_class_init, +}; + +static void rt500_clkctl0_register_types(void) +{ + type_register_static(&rt500_clkctl0_info); +} + +type_init(rt500_clkctl0_register_types) + diff --git a/hw/misc/rt500_clkctl1.c b/hw/misc/rt500_clkctl1.c new file mode 100644 index 0000000000..a5a8cf6564 --- /dev/null +++ b/hw/misc/rt500_clkctl1.c @@ -0,0 +1,224 @@ +/* + * QEMU model for RT500 Clock Controller + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/clock.h" +#include "hw/irq.h" +#include "hw/qdev-clock.h" +#include "hw/qdev-properties.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "exec/address-spaces.h" +#include "hw/regs.h" +#include "hw/misc/rt500_clkctl1.h" +#include "hw/misc/rt500_clk_freqs.h" + +#include "trace.h" + +#define reg(field) offsetof(RT500_CLKCTL1_Type, field) +#define REG_NO (sizeof(RT500_CLKCTL1_Type) / sizeof(uint32_t)) +#define regi(x) (reg(x) / sizeof(uint32_t)) + +static RT500_CLKCTL1_REGISTER_NAMES_ARRAY(reg_names); + +static MemTxResult rt500_clkctl1_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + RT500ClkCtl1State *s = opaque; + MemTxResult ret = MEMTX_OK; + + if (!reg32_aligned_access(addr, size)) { + ret = MEMTX_ERROR; + goto out; + } + + switch (addr) { + case reg(PSCCTL0_SET): + case reg(PSCCTL1_SET): + case reg(PSCCTL2_SET): + case reg(PSCCTL0_CLR): + case reg(PSCCTL1_CLR): + case reg(PSCCTL2_CLR): + /* write only registers */ + ret = MEMTX_ERROR; + break; + default: + *data = reg32_read(&s->regs, addr); + break; + } + +out: + trace_rt500_clkctl1_reg_read(reg_names[addr], addr, *data); + return ret; +} + +static MemTxResult rt500_clkctl1_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + RT500ClkCtl1State *s = opaque; + MemTxResult ret = MEMTX_OK; + static uint32_t wr_mask[REG_NO] = { + [0 ... REG_NO - 1] = BITS(31, 0), + }; + + if (!reg32_aligned_access(addr, size)) { + ret = MEMTX_ERROR; + goto out; + } + + switch (addr) { + case reg(PSCCTL0): + case reg(PSCCTL1): + case reg(PSCCTL2): + { + reg32_write(&s->regs, addr, value, wr_mask); + break; + } + case reg(PSCCTL0_SET): + case reg(PSCCTL1_SET): + case reg(PSCCTL2_SET): + { + uint32_t update_addr = reg(PSCCTL0) + (addr - reg(PSCCTL0_SET)); + reg32_write(&s->regs, update_addr, + reg32_read(&s->regs, update_addr) | value, wr_mask); + break; + } + case reg(PSCCTL0_CLR): + case reg(PSCCTL1_CLR): + case reg(PSCCTL2_CLR): + { + uint32_t update_addr = reg(PSCCTL0) + (addr - reg(PSCCTL0_CLR)); + reg32_write(&s->regs, update_addr, + reg32_read(&s->regs, update_addr) & ~value, wr_mask); + break; + } + default: + reg32_write(&s->regs, addr, value, wr_mask); + } + + switch (addr) { + case reg(AUDIOPLL0PFD): + { + if (!s->regs.AUDIOPLL0PFD_b.PFD0_CLKGATE) { + s->regs.AUDIOPLL0PFD_b.PFD0_CLKRDY = 1; + } else { + s->regs.AUDIOPLL0PFD_b.PFD0_CLKRDY = 0; + } + if (!s->regs.AUDIOPLL0PFD_b.PFD1_CLKGATE) { + s->regs.AUDIOPLL0PFD_b.PFD1_CLKRDY = 1; + } else { + s->regs.AUDIOPLL0PFD_b.PFD1_CLKRDY = 0; + } + if (!s->regs.AUDIOPLL0PFD_b.PFD2_CLKGATE) { + s->regs.AUDIOPLL0PFD_b.PFD2_CLKRDY = 1; + } else { + s->regs.AUDIOPLL0PFD_b.PFD2_CLKRDY = 0; + } + if (!s->regs.AUDIOPLL0PFD_b.PFD3_CLKGATE) { + s->regs.AUDIOPLL0PFD_b.PFD3_CLKRDY = 1; + } else { + s->regs.AUDIOPLL0PFD_b.PFD3_CLKRDY = 0; + } + break; + } + case reg(OSEVENTTFCLKSEL): + { + switch (s->regs.OSEVENTTFCLKSEL_b.SEL) { + case OSEVENTTFCLKSEL_LPOSC: + { + clock_set_hz(s->ostimer_clk, LPOSC_CLK_HZ); + break; + } + case OSEVENTTFCLKSEL_32KHZRTC: + { + clock_set_hz(s->ostimer_clk, RTC32KHZ_CLK_HZ); + break; + } + case OSEVENTTFCLKSEL_HCLK: + { + clock_set_hz(s->ostimer_clk, clock_get_hz(s->sysclk)); + break; + } + case OSEVENTTFCLKSEL_NONE: + { + clock_set_hz(s->ostimer_clk, 0); + break; + } + } + + clock_propagate(s->ostimer_clk); + break; + } + } + +out: + trace_rt500_clkctl1_reg_write(reg_names[addr], addr, value); + return ret; + + return MEMTX_OK; +} + + +static const MemoryRegionOps rt500_clkctl1_ops = { + .read_with_attrs = rt500_clkctl1_read, + .write_with_attrs = rt500_clkctl1_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void rt500_clkctl1_reset(DeviceState *dev) +{ + RT500ClkCtl1State *s = RT500_CLKCTL1(dev); + + memset(&s->regs, 0, sizeof(s->regs)); + + rt500_clkctl1_reset_registers(&s->regs); +} + +static void rt500_clkctl1_init(Object *obj) +{ + RT500ClkCtl1State *s = RT500_CLKCTL1(obj); + + memory_region_init_io(&s->mmio, obj, &rt500_clkctl1_ops, s, + TYPE_RT500_CLKCTL1, sizeof(s->regs)); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); + s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0); + s->ostimer_clk = qdev_init_clock_out(DEVICE(s), "ostimer_clk"); +} + +static void rt500_clkctl1_realize(DeviceState *dev, Error **errp) +{ +} + +static void rt500_clkctl1_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = rt500_clkctl1_reset; + dc->realize = rt500_clkctl1_realize; +} + +static const TypeInfo rt500_clkctl1_info = { + .name = TYPE_RT500_CLKCTL1, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RT500ClkCtl1State), + .instance_init = rt500_clkctl1_init, + .class_init = rt500_clkctl1_class_init, +}; + +static void rt500_clkctl1_register_types(void) +{ + type_register_static(&rt500_clkctl1_info); +} + +type_init(rt500_clkctl1_register_types) + diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 71ec77de29..e65fcfa613 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -357,3 +357,11 @@ flexcomm_reset(void) "" flexcomm_irq(const char *id, uint8_t irq) "%s %d" flexcomm_reg_read(const char *devname, const char *regname, uint32_t addr, uint32_t val) "%s: %s[0x%04x] -> 0x%08x" flexcomm_reg_write(const char *dename, const char *regname, uint32_t addr, uint32_t val) "%s: %s[0x%04x] <- 0x%08x" + +# rt500_clkctl0.c +rt500_clkctl0_reg_read(const char *regname, uint32_t addr, uint32_t val) "%s[0x%04x] -> 0x%08x" +rt500_clkctl0_reg_write(const char *regname, uint32_t addr, uint32_t val) "%s[0x%04x] <- 0x%08x" + +# rt500_clkctl1.c +rt500_clkctl1_reg_read(const char *regname, uint32_t addr, uint32_t val) "%s[0x%04x] -> 0x%08x" +rt500_clkctl1_reg_write(const char *regname, uint32_t addr, uint32_t val) "%s[0x%04x] <- 0x%08x" diff --git a/include/hw/misc/rt500_clk_freqs.h b/include/hw/misc/rt500_clk_freqs.h new file mode 100644 index 0000000000..1e366d4967 --- /dev/null +++ b/include/hw/misc/rt500_clk_freqs.h @@ -0,0 +1,18 @@ +/* + * QEMU model for RT500 Clock Controller + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_MISC_RT500_CLK_FREQS_H +#define HW_MISC_RT500_CLK_FREQS_H + +#define RTC32KHZ_CLK_HZ 32000 +#define LPOSC_CLK_HZ 1000000 + +#endif /* HW_MISC_RT500_CLK_FREQS_H */ diff --git a/include/hw/misc/rt500_clkctl0.h b/include/hw/misc/rt500_clkctl0.h new file mode 100644 index 0000000000..798ded96e3 --- /dev/null +++ b/include/hw/misc/rt500_clkctl0.h @@ -0,0 +1,37 @@ +/* + * QEMU model for RT500 Clock Controller + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_MISC_RT500_CLKCTL0_H +#define HW_MISC_RT500_CLKCTL0_H + +#include "hw/arm/svd/rt500_clkctl0.h" +#include "hw/sysbus.h" + +#define TYPE_RT500_CLKCTL0 "rt500-clkctl0" +#define RT500_CLKCTL0(o) OBJECT_CHECK(RT500ClkCtl0State, o, TYPE_RT500_CLKCTL0) + +#define SYSTICKFCLKSEL_DIVOUT 0 +#define SYSTICKFCLKSEL_LPOSC 1 +#define SYSTICKFCLKSEL_32KHZRTC 2 +#define SYSTICKFCLKSEL_NONE 7 + +typedef struct { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion mmio; + RT500_CLKCTL0_Type regs; + Clock *systick_clk; + Clock *sysclk; +} RT500ClkCtl0State; + +#endif /* HW_MISC_RT500_CLKCTL0_H */ diff --git a/include/hw/misc/rt500_clkctl1.h b/include/hw/misc/rt500_clkctl1.h new file mode 100644 index 0000000000..7b6e56e294 --- /dev/null +++ b/include/hw/misc/rt500_clkctl1.h @@ -0,0 +1,38 @@ +/* + * QEMU model for RT500 Clock Controller + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + + +#ifndef HW_MISC_RT500_CLKCTL1_H +#define HW_MISC_RT500_CLKCTL1_H + +#include "hw/arm/svd/rt500_clkctl1.h" +#include "hw/sysbus.h" + +#define TYPE_RT500_CLKCTL1 "rt500-clkctl1" +#define RT500_CLKCTL1(o) OBJECT_CHECK(RT500ClkCtl1State, o, TYPE_RT500_CLKCTL1) + +#define OSEVENTTFCLKSEL_LPOSC 0 +#define OSEVENTTFCLKSEL_32KHZRTC 1 +#define OSEVENTTFCLKSEL_HCLK 2 +#define OSEVENTTFCLKSEL_NONE 7 + +typedef struct { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion mmio; + RT500_CLKCTL1_Type regs; + Clock *sysclk; + Clock *ostimer_clk; +} RT500ClkCtl1State; + +#endif /* HW_MISC_RT500_CLKCTL1_H */ From patchwork Mon Aug 5 20:17:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754034 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1C7E0C3DA7F for ; Mon, 5 Aug 2024 20:19:30 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49j-0005QD-PK; Mon, 05 Aug 2024 16:18:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3cjOxZgUKCtkO5QDKBJJBG9.7JHL9HP-89Q9GIJIBIP.JMB@flex--tavip.bounces.google.com>) id 1sb49c-0004XO-So for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:18:05 -0400 Received: from mail-pg1-x549.google.com ([2607:f8b0:4864:20::549]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3cjOxZgUKCtkO5QDKBJJBG9.7JHL9HP-89Q9GIJIBIP.JMB@flex--tavip.bounces.google.com>) id 1sb49X-0001Wt-Rr for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:18:04 -0400 Received: by mail-pg1-x549.google.com with SMTP id 41be03b00d2f7-7a267d9e7b0so8383193a12.2 for ; Mon, 05 Aug 2024 13:17:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889076; x=1723493876; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=TDXUM/DnNUUyn6pHbVPdEoD8ZybpFrPwu+WD1vFxHS8=; b=P0jeBNKe9VJyfd1tjbon6jVJ51NGTCE0bMyIsbeVWloxuS+i+nn3m2x6yUfNzXI+q7 iD4UPUytwT/nzlNKXFPbk/Mi+QQzUBsUQ4HvE1qXPK2ZLTSN7apz4BSPDl1YNl5vu1LD 4oMOgu2OsV+IxdC2NjVuRTlsBo1EWvIXjQDhuf+o6mX8lLZ6bMKnJF3VBVniicBXdR1w ZrbETAwTRbhNR0b91BaNWcf59vI9RvGKYDH8AKeHwRWtVhISCKgvcrVKIhPujT4KE1On ZZUd3KGnh2Q1mgsBduQR2AQlEr3pyX5jDrFwYMlth+0x6U+Dmmp0pOlS1jGvVvWD5KTC szcg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889076; x=1723493876; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=TDXUM/DnNUUyn6pHbVPdEoD8ZybpFrPwu+WD1vFxHS8=; b=PQJV//NG4jrYcFG0fjhyy1Ma4uLWkf4UiQUUYaLVLlHInM6aSoRuM3wLTrQKHt+hQR Dp/FjQaZQAQZNq/IHSXcYxBeezCisTu9vG5JNOjo1d1Ss7vaCtlnNh6++sGHj1UYHKIU KHtVkDt1ei3EtuwOBVeqdOnvGcwNrdYXwzOaaFLN2QVzMYfGuc+KsoRSei+t308kI3i4 EIlh2taL3U+Jlf6F8X8XsYgzOK09JMgoYjA2NDakqQrGXLrsVSRyFEpDstzAOJhbmDD4 FlJppJbF8tM86zgDVUJoU5RaD+hjXEXOe3rEfV+acO2YMVBfK7CplfbjNW8ERApAM/+0 XB3g== X-Gm-Message-State: AOJu0Yza65vlPuew7f9Acgd8sxOjZkC9y4xTzyuOaBRvIX62zBTOWmZT VecGjRbvBhFw22GM2zMuYCPgLahC4rD3gTBFsdFh5e24zpT8QVZb402L08MMktuTDq7sh+2W0W5 HXcn4wISeNg58bJ4UakpxpYaVzkxi3udXIc7OhgM0bKJLnWGzZUR6POF0behZlhWdoIXf8X6NSy 8r2MZLH6wJzA6/SLTJGqXo0/N82w== X-Google-Smtp-Source: AGHT+IFnbKW0982idR2ThGvBGZQLmLXkxC9szOhbfZs08+ppAvucuotVSSXrQPXEto+7IAj1EGypCgRzBg== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a17:90b:1b05:b0:2ca:7e66:2d90 with SMTP id 98e67ed59e1d1-2cff955f924mr72168a91.7.1722889074724; Mon, 05 Aug 2024 13:17:54 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:14 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-20-tavip@google.com> Subject: [RFC PATCH 19/23] test/unit: add unit tests for RT500's clock controller From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::549; envelope-from=3cjOxZgUKCtkO5QDKBJJBG9.7JHL9HP-89Q9GIJIBIP.JMB@flex--tavip.bounces.google.com; helo=mail-pg1-x549.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add test to exercise clocks set and clear, system PLL initialization, audio PLL initialization, systick and ostimer clock source selection. Signed-off-by: Octavian Purdila --- tests/unit/meson.build | 7 + tests/unit/test-rt500-clkctl.c | 270 +++++++++++++++++++++++++++++++++ 2 files changed, 277 insertions(+) create mode 100644 tests/unit/test-rt500-clkctl.c diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 7a28e7b521..be3062acbf 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -188,6 +188,13 @@ if have_system meson.project_source_root() / 'hw/ssi/ssi.c', 'spi_tester.c', ], + 'test-rt500-clkctl': [ + hwcore, + meson.project_source_root() / 'hw/core/gpio.c', + meson.project_source_root() / 'hw/misc/rt500_clkctl0.c', + meson.project_source_root() / 'hw/misc/rt500_clkctl1.c', + meson.project_source_root() / 'tests/unit/sysbus-mock.c', + ], } if config_host_data.get('CONFIG_INOTIFY1') tests += {'test-util-filemonitor': []} diff --git a/tests/unit/test-rt500-clkctl.c b/tests/unit/test-rt500-clkctl.c new file mode 100644 index 0000000000..9312091c46 --- /dev/null +++ b/tests/unit/test-rt500-clkctl.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/main-loop.h" +#include "exec/memory.h" +#include "hw/clock.h" +#include "hw/irq.h" +#include "hw/qdev-clock.h" +#include "hw/qdev-properties.h" + +#include "hw/misc/rt500_clkctl0.h" +#include "hw/misc/rt500_clkctl1.h" +#include "hw/misc/rt500_clk_freqs.h" +#include "sysbus-mock.h" +#include "reg-utils.h" + +typedef struct { + DeviceState *clk0; + DeviceState *clk1; + Clock *sysclk; + Clock *systick_clk; + Clock *ostimer_clk; +} TestFixture; + +#define SYSCLK_HZ 100000000 + +#define RT500_CLKCTL0_BASE 0x40001000UL +#define RT500_CLKCTL1_BASE 0x40021000UL + +/* + * Test fixture initialization. + */ +static void set_up(TestFixture *f, gconstpointer data) +{ + f->clk0 = qdev_new(TYPE_RT500_CLKCTL0); + g_assert(f->clk0); + + f->clk1 = qdev_new(TYPE_RT500_CLKCTL1); + g_assert(f->clk1); + + f->sysclk = clock_new(OBJECT(&f->clk0->parent_obj), "SYSCLK"); + clock_set_hz(f->sysclk, SYSCLK_HZ); + + qdev_connect_clock_in(f->clk0, "sysclk", f->sysclk); + f->systick_clk = RT500_CLKCTL0(f->clk0)->systick_clk; + + qdev_connect_clock_in(f->clk1, "sysclk", f->sysclk); + f->ostimer_clk = RT500_CLKCTL1(f->clk1)->ostimer_clk; + + qdev_realize_and_unref(f->clk0, NULL, NULL); + sysbus_mmio_map(SYS_BUS_DEVICE(f->clk0), 0, RT500_CLKCTL0_BASE); + + qdev_realize_and_unref(f->clk1, NULL, NULL); + sysbus_mmio_map(SYS_BUS_DEVICE(f->clk1), 0, RT500_CLKCTL1_BASE); + + device_cold_reset(f->clk0); + device_cold_reset(f->clk1); +} + +static void tear_down(TestFixture *f, gconstpointer user_data) +{ + qdev_unrealize(f->clk0); + qdev_unrealize(f->clk1); + g_free(f->clk0); + g_free(f->clk1); +} + +#undef CLKCTL0 +#undef CLKCTL1 + +static void pscctl_test(TestFixture *f, gconstpointer user_data) +{ + /* rom controller clock should be enabled at reset */ + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, PSCCTL0, ROM_CTRLR_CLK) + == 1); + + /* DSP clk is disabled at reset */ + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, PSCCTL0, DSP_CLK) == 0); + + /* check PSCTL_SET functionality */ + REG32_WRITE(f->clk0, RT500_CLKCTL0, PSCCTL0_SET, + RT500_CLKCTL0_PSCCTL0_DSP_CLK_Msk); + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, PSCCTL0, DSP_CLK) == 1); + + /* check PSCTL_CLR functionality */ + REG32_WRITE(f->clk0, RT500_CLKCTL0, PSCCTL0_CLR, + RT500_CLKCTL0_PSCCTL0_DSP_CLK_Msk); + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, PSCCTL0, DSP_CLK) == 0); + + /* FLEXIO clk is disabled at reset */ + g_assert(REG32_READ_FIELD(f->clk1, RT500_CLKCTL1, PSCCTL0, FlexIO) == 0); + + /* check PSCTL_SET functionality */ + REG32_WRITE(f->clk1, RT500_CLKCTL1, PSCCTL0_SET, + RT500_CLKCTL1_PSCCTL0_FlexIO_Msk); + g_assert(REG32_READ_FIELD(f->clk1, RT500_CLKCTL1, PSCCTL0, FlexIO) == 1); + + /* check PSCTL_CLR functionality */ + REG32_WRITE(f->clk1, RT500_CLKCTL1, PSCCTL0_CLR, + RT500_CLKCTL1_PSCCTL0_FlexIO_Msk); + g_assert(REG32_READ_FIELD(f->clk1, RT500_CLKCTL1, PSCCTL0, FlexIO) == 0); +} + +static void audiopll0pfd_test(TestFixture *f, gconstpointer user_data) +{ + /* audio plls are gated at boot */ + g_assert(REG32_READ_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, + PFD3_CLKGATE) == 1); + g_assert(REG32_READ_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, + PFD2_CLKGATE) == 1); + g_assert(REG32_READ_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, + PFD1_CLKGATE) == 1); + g_assert(REG32_READ_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, + PFD0_CLKGATE) == 1); + + /* ,,, and clocks are not ready */ + g_assert(REG32_READ_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, PFD3_CLKRDY) + == 0); + g_assert(REG32_READ_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, PFD2_CLKRDY) + == 0); + g_assert(REG32_READ_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, PFD1_CLKRDY) + == 0); + g_assert(REG32_READ_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, PFD0_CLKRDY) + == 0); + + /* ungate all plls and check that clocks are ready */ + REG32_WRITE_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, PFD3_CLKGATE, 0); + REG32_WRITE_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, PFD2_CLKGATE, 0); + REG32_WRITE_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, PFD1_CLKGATE, 0); + REG32_WRITE_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, PFD0_CLKGATE, 0); + + g_assert(REG32_READ_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, PFD3_CLKRDY) + == 1); + g_assert(REG32_READ_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, PFD2_CLKRDY) + == 1); + g_assert(REG32_READ_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, PFD1_CLKRDY) + == 1); + g_assert(REG32_READ_FIELD(f->clk1, RT500_CLKCTL1, AUDIOPLL0PFD, PFD0_CLKRDY) + == 1); +} + +static void syspll0pfd_test(TestFixture *f, gconstpointer user_data) +{ + /* system plls are gated at boot */ + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD3_CLKGATE) + == 1); + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD2_CLKGATE) + == 1); + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD1_CLKGATE) + == 1); + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD0_CLKGATE) + == 1); + + /* ,,, and clocks are not ready */ + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD3_CLKRDY) + == 0); + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD2_CLKRDY) + == 0); + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD1_CLKRDY) + == 0); + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD0_CLKRDY) + == 0); + + /* ungate all plls and check that clocks are ready */ + REG32_WRITE_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD3_CLKGATE, 0); + REG32_WRITE_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD2_CLKGATE, 0); + REG32_WRITE_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD1_CLKGATE, 0); + REG32_WRITE_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD0_CLKGATE, 0); + + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD3_CLKRDY) + == 1); + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD2_CLKRDY) + == 1); + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD1_CLKRDY) + == 1); + g_assert(REG32_READ_FIELD(f->clk0, RT500_CLKCTL0, SYSPLL0PFD, PFD0_CLKRDY) + == 1); +} + +static void systick_clk_test(TestFixture *f, gconstpointer user_data) +{ + /* systick is not running at reset */ + g_assert(clock_get_hz(f->systick_clk) == 0); + + /* select divout no divisor */ + REG32_WRITE_FIELD(f->clk0, RT500_CLKCTL0, SYSTICKFCLKSEL, SEL, + SYSTICKFCLKSEL_DIVOUT); + g_assert(clock_get_hz(f->systick_clk) == SYSCLK_HZ); + + /* change divisor to 2 */ + REG32_WRITE_FIELD(f->clk0, RT500_CLKCTL0, SYSTICKFCLKDIV, DIV, 1); + g_assert(clock_get_hz(f->systick_clk) == SYSCLK_HZ / 2); + + /* select lpsoc */ + REG32_WRITE_FIELD(f->clk0, RT500_CLKCTL0, SYSTICKFCLKSEL, SEL, + SYSTICKFCLKSEL_LPOSC); + g_assert(clock_get_hz(f->systick_clk) == LPOSC_CLK_HZ); + + /* select lpsoc */ + REG32_WRITE_FIELD(f->clk0, RT500_CLKCTL0, SYSTICKFCLKSEL, SEL, + SYSTICKFCLKSEL_32KHZRTC); + g_assert(clock_get_hz(f->systick_clk) == RTC32KHZ_CLK_HZ); + + /* disable clock */ + REG32_WRITE_FIELD(f->clk0, RT500_CLKCTL0, SYSTICKFCLKSEL, SEL, + SYSTICKFCLKSEL_NONE); + g_assert(clock_get_hz(f->systick_clk) == 0); +} + +static void ostimer_clk_test(TestFixture *f, gconstpointer user_data) +{ + /* systick is not running at reset */ + g_assert(clock_get_hz(f->ostimer_clk) == 0); + + /* select lpsoc */ + REG32_WRITE_FIELD(f->clk1, RT500_CLKCTL1, OSEVENTTFCLKSEL, SEL, + OSEVENTTFCLKSEL_LPOSC); + g_assert(clock_get_hz(f->ostimer_clk) == LPOSC_CLK_HZ); + + + /* select 32khz RTC */ + REG32_WRITE_FIELD(f->clk1, RT500_CLKCTL1, OSEVENTTFCLKSEL, SEL, + OSEVENTTFCLKSEL_32KHZRTC); + g_assert(clock_get_hz(f->ostimer_clk) == RTC32KHZ_CLK_HZ); + + /* select hclk */ + REG32_WRITE_FIELD(f->clk1, RT500_CLKCTL1, OSEVENTTFCLKSEL, SEL, + OSEVENTTFCLKSEL_HCLK); + g_assert(clock_get_hz(f->ostimer_clk) == SYSCLK_HZ); + + /* disable clock */ + REG32_WRITE_FIELD(f->clk1, RT500_CLKCTL1, OSEVENTTFCLKSEL, SEL, + OSEVENTTFCLKSEL_NONE); + g_assert(clock_get_hz(f->ostimer_clk) == 0); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + /* Initialize object types. */ + sysbus_mock_init(); + module_call_init(MODULE_INIT_QOM); + + g_test_add("/rt500-clkctl/pscctl-test", TestFixture, NULL, + set_up, pscctl_test, tear_down); + + g_test_add("/rt500-clkctl/syspll0pfd-test", TestFixture, NULL, + set_up, syspll0pfd_test, tear_down); + + g_test_add("/rt500-clkctl/audiopll0pfd-test", TestFixture, NULL, + set_up, audiopll0pfd_test, tear_down); + + g_test_add("/rt500-clkctl/systick-test", TestFixture, NULL, + set_up, systick_clk_test, tear_down); + + g_test_add("/rt500-clkctl/ostimer-clk-test", TestFixture, NULL, + set_up, ostimer_clk_test, tear_down); + + return g_test_run(); +} From patchwork Mon Aug 5 20:17:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754036 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 15B3DC52D71 for ; Mon, 5 Aug 2024 20:19:31 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49j-0005Mp-EP; Mon, 05 Aug 2024 16:18:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3dDOxZgUKCtsQ7SFMDLLDIB.9LJNBJR-ABSBIKLKDKR.LOD@flex--tavip.bounces.google.com>) id 1sb49c-0004XP-TA for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:18:05 -0400 Received: from mail-yb1-xb49.google.com ([2607:f8b0:4864:20::b49]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3dDOxZgUKCtsQ7SFMDLLDIB.9LJNBJR-ABSBIKLKDKR.LOD@flex--tavip.bounces.google.com>) id 1sb49Y-0001X1-6h for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:18:04 -0400 Received: by mail-yb1-xb49.google.com with SMTP id 3f1490d57ef6-e0bfd36cda0so4034171276.0 for ; Mon, 05 Aug 2024 13:17:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889077; x=1723493877; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=uWXVZOdEqjXdKO04u4G3py2UIxHgdgvpM9yktaFqR4s=; b=TyNyglI0Wm0hq600I5vrTma3NUxb3X1E4DY3LNGV01r3WzvnQBheevL9RhYLvwEcr6 S4xbu7NjEd+C6HyifnD8dJTyzElbqZaULqpD+pAIq8HCDMnAlfSe5RcysVyKkBM4Aezl 9spGypb/XTkSRmgQIRc4izUWmf+qFRFNW+75UXbo7FHuEV7X5cuYshUTOLud6H8uDIRP kZX4an4GZRzR7LcftLnrAfKPWsGHAjf3ZWW+jazzfoAgOFA0PPUzlCHy2BeI2dp5o9C2 G4sD7qN7klwdvNV0mBMVTWZXGyP3OLPS2O87GzYwrBZ9aFjKm+OucZlP2dznv7iszOw3 eYuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889077; x=1723493877; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=uWXVZOdEqjXdKO04u4G3py2UIxHgdgvpM9yktaFqR4s=; b=mVV8l4kst3bBR9IxuX7Iwr+ZPn69NReUnB/eu/m1s3aJPPiQFrAoG0Pn9/iX9j4yRQ ESulF6RkYjRGh5c1LfidsUkQcWWz57TyqIgbCFNozDdaOw4PM9b2k8tJZkwQmPDnN7LK 9Pv+O3olGX5oKQ5D6xxtbnMcveoXlPqUgctYHMDOX5dA4Il1cil4LzL3QNVyyd48a1kW UprIBKHOacHDqWPiTWi/Pz9zqTN/usJ3WR1wwvqJB88mi/LOGp/2KIE1WoLyH2QZwjW8 uabuYgCeaPXgtQrZDLCAgoX2VPKoH+0pGCFfMRXFWIjwGINTXcAhaufRcV3tsMqTTPcs ghJw== X-Gm-Message-State: AOJu0YxIKL1hFOtV8wR+eZ7Yj/9mYQfqZkoGaYVEyG9DIdIypD/T/Iq7 Hr+Q9QgWqXbUgIBfES1J3JQbBURHka5g7XDPmTJRBd6W2gV337mG85pm+G0u2fppHWgg1IhqOr3 h9ElrUiI1v6IqMB1QZYtIo29Rrg0zrHWsY4Tm7icalwenuh98u4qCifQZl6Lo8owAh+drmx4lIj wJzuK3qz5KmpgsXQrDQRJiCASOkQ== X-Google-Smtp-Source: AGHT+IF6ad53oY6Byn5ycWISeZ4CH5DfNX2AzNIngdoOEtPty6mxbdGKKGCvTPgplaEx4QLHEjhsPUrOdQ== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a25:ce54:0:b0:e0b:e23a:9713 with SMTP id 3f1490d57ef6-e0be23a97a3mr31090276.1.1722889076722; Mon, 05 Aug 2024 13:17:56 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:15 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-21-tavip@google.com> Subject: [RFC PATCH 20/23] hw/ssi: add support for flexspi From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::b49; envelope-from=3dDOxZgUKCtsQ7SFMDLLDIB.9LJNBJR-ABSBIKLKDKR.LOD@flex--tavip.bounces.google.com; helo=mail-yb1-xb49.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This is mostly a stub which completes SPI transactions as noops by masking out the error interrupts and never clearing the IPCMDDONE interrupt. Although incomplete, this allows software that uses NXP's mcuxpresso SDK to run the SDK board initialization functions. It also supports AHB memory access, aka XIP, for now as simple RAM memory regions. Signed-off-by: Octavian Purdila --- hw/arm/svd/meson.build | 4 + hw/ssi/Kconfig | 4 + hw/ssi/flexspi.c | 216 +++++++++++++++++++++++++++++++++++++++ hw/ssi/meson.build | 1 + hw/ssi/trace-events | 4 + include/hw/ssi/flexspi.h | 34 ++++++ 6 files changed, 263 insertions(+) create mode 100644 hw/ssi/flexspi.c create mode 100644 include/hw/ssi/flexspi.h diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build index 6ab13f8757..22f75880f5 100644 --- a/hw/arm/svd/meson.build +++ b/hw/arm/svd/meson.build @@ -22,3 +22,7 @@ genh += custom_target('rt500_clkctl1.h', output: 'rt500_clkctl1.h', input: 'MIMXRT595S_cm33.xml', command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'CLKCTL1', '-t', 'RT500_CLKCTL1']) +genh += custom_target('flexspi.h', + output: 'flexspi.h', + input: 'MIMXRT595S_cm33.xml', + command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'FLEXSPI0', '-t', 'FLEXSPI']) diff --git a/hw/ssi/Kconfig b/hw/ssi/Kconfig index 83ee53c1d0..fb8feeb024 100644 --- a/hw/ssi/Kconfig +++ b/hw/ssi/Kconfig @@ -24,3 +24,7 @@ config STM32F2XX_SPI config BCM2835_SPI bool select SSI + +config FLEXSPI + bool + select SSI diff --git a/hw/ssi/flexspi.c b/hw/ssi/flexspi.c new file mode 100644 index 0000000000..305d1a5bac --- /dev/null +++ b/hw/ssi/flexspi.c @@ -0,0 +1,216 @@ +/* + * QEMU model for FLEXSPI + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/mmap-alloc.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/units.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "migration/vmstate.h" +#include "exec/address-spaces.h" +#include "hw/regs.h" +#include "hw/ssi/flexspi.h" +#include "hw/arm/svd/flexspi.h" + +#include "trace.h" + +#define reg(field) offsetof(FLEXSPI_Type, field) +#define regi(x) (reg(x) / sizeof(uint32_t)) +#define REG_NO (sizeof(FLEXSPI_Type) / sizeof(uint32_t)) + +static FLEXSPI_REGISTER_NAMES_ARRAY(reg_names); + +static void flexspi_reset(DeviceState *dev) +{ + FlexSpiState *s = FLEXSPI(dev); + + memset(&s->regs, 0, sizeof(s->regs)); + + flexspi_reset_registers(&s->regs); + + /* idle immediately after reset */ + s->regs.STS0_b.SEQIDLE = 1; +} + +static MemTxResult flexspi_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + FlexSpiState *s = opaque; + MemTxResult ret = MEMTX_OK; + + if (!reg32_aligned_access(addr, size)) { + ret = MEMTX_ERROR; + goto out; + } + + switch (addr) { + default: + *data = reg32_read(&s->regs, addr); + break; + } + +out: + trace_flexspi_reg_read(DEVICE(s)->id, reg_names[addr], addr, *data); + return ret; +} + +static uint32_t wr_mask[REG_NO] = { + [regi(MCR0)] = BITS(31, 14) | BITS(12, 8) | BITS(5, 4) | BITS(1, 0), + [regi(MCR1)] = BITS(31, 0), + [regi(MCR2)] = BITS(31, 24) | BIT(11), + [regi(AHBCR)] = BIT(10) | BITS(7, 2) | BIT(0), + [regi(INTEN)] = BITS(13, 0), + /* + * TODO: once SPI transfers are implemented restore mask to: + * + * [regi(INTR)] = BIT(16) | BITS(12, 0). + * + * In the meantime this INTR mask allows for fake SPI transfers. + */ + [regi(INTR)] = BIT(0), + [regi(LUTKEY)] = BITS(31, 0), + [regi(LUTCR)] = BITS(1, 0), + [regi(AHBRXBUF0CR0)] = BIT(31) | BITS(26, 24) | BITS(19, 16) | BITS(7, 0), + [regi(AHBRXBUF1CR0)] = BIT(31) | BITS(26, 24) | BITS(19, 16) | BITS(7, 0), + [regi(AHBRXBUF2CR0)] = BIT(31) | BITS(26, 24) | BITS(19, 16) | BITS(7, 0), + [regi(AHBRXBUF3CR0)] = BIT(31) | BITS(26, 24) | BITS(19, 16) | BITS(7, 0), + [regi(AHBRXBUF4CR0)] = BIT(31) | BITS(26, 24) | BITS(19, 16) | BITS(7, 0), + [regi(AHBRXBUF5CR0)] = BIT(31) | BITS(26, 24) | BITS(19, 16) | BITS(7, 0), + [regi(AHBRXBUF6CR0)] = BIT(31) | BITS(26, 24) | BITS(19, 16) | BITS(7, 0), + [regi(AHBRXBUF7CR0)] = BIT(31) | BITS(26, 24) | BITS(19, 16) | BITS(7, 0), + [regi(FLSHA1CR0)] = BITS(22, 0), + [regi(FLSHA2CR0)] = BITS(22, 0), + [regi(FLSHB1CR0)] = BITS(22, 0), + [regi(FLSHB2CR0)] = BITS(22, 0), + [regi(FLSHCR1A1)] = BITS(31, 0), + [regi(FLSHCR1A2)] = BITS(31, 0), + [regi(FLSHCR1B1)] = BITS(31, 0), + [regi(FLSHCR1B2)] = BITS(31, 0), + [regi(FLSHCR2A1)] = BITS(30, 13) | BITS(11, 5) | BITS(3, 0), + [regi(FLSHCR2A2)] = BITS(30, 13) | BITS(11, 5) | BITS(3, 0), + [regi(FLSHCR2B1)] = BITS(30, 13) | BITS(11, 5) | BITS(3, 0), + [regi(FLSHCR2B2)] = BITS(30, 13) | BITS(11, 5) | BITS(3, 0), + [regi(FLSHCR4)] = BITS(3, 2) | BIT(0), + [regi(IPCR0)] = BITS(31, 0), + [regi(IPCR1)] = BIT(31) | BITS(26, 24) | BITS(19, 0), + [regi(IPCMD)] = BIT(1), + [regi(DLPR)] = BITS(31, 0), + [regi(IPRXFCR)] = BITS(8, 0), + [regi(IPTXFCR)] = BITS(8, 0), + [regi(DLLCRA)] = BITS(14, 8) | BITS(6, 3) | BITS(1, 0), + [regi(DLLCRB)] = BITS(14, 8) | BITS(6, 3) | BITS(1, 0), + [regi(HADDRSTART)] = BITS(31, 12) | BIT(0), + [regi(HADDREND)] = BITS(31, 12), + [regi(HADDROFFSET)] = BITS(31, 12), +}; + +static MemTxResult flexspi_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + FlexSpiState *s = opaque; + MemTxResult ret = MEMTX_OK; + + trace_flexspi_reg_write(DEVICE(s)->id, reg_names[addr], addr, value); + + if (!reg32_aligned_access(addr, size)) { + ret = MEMTX_ERROR; + goto out; + } + + switch (addr) { + case reg(MCR0): + { + reg32_write(&s->regs, addr, value, wr_mask); + + if (s->regs.MCR0_b.SWRESET) { + s->regs.MCR0_b.SWRESET = 0; + } + break; + } + + default: + reg32_write(&s->regs, addr, value, wr_mask); + break; + } + +out: + return ret; +} + +static const MemoryRegionOps flexspi_ops = { + .read_with_attrs = flexspi_read, + .write_with_attrs = flexspi_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static Property flexspi_properties[] = { + DEFINE_PROP_UINT32("mmap_base", FlexSpiState, mmap_base, 0), + DEFINE_PROP_UINT32("mmap_size", FlexSpiState, mmap_size, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void flexspi_init(Object *obj) +{ + FlexSpiState *s = FLEXSPI(obj); + + memory_region_init_io(&s->mmio, obj, &flexspi_ops, s, TYPE_FLEXSPI, + sizeof(FLEXSPI_Type)); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); +} + +static void flexspi_realize(DeviceState *dev, Error **errp) +{ + FlexSpiState *s = FLEXSPI(dev); + + if (s->mmap_size) { + memory_region_init_ram(&s->mem, OBJECT(s), DEVICE(s)->id, s->mmap_size, + NULL); + memory_region_add_subregion(get_system_memory(), s->mmap_base, &s->mem); + } +} + +static void flexspi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = flexspi_reset; + dc->realize = flexspi_realize; + device_class_set_props(dc, flexspi_properties); +} + +static const TypeInfo flexspi_info = { + .name = TYPE_FLEXSPI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(FlexSpiState), + .instance_init = flexspi_init, + .class_init = flexspi_class_init, +}; + +static void flexspi_register_types(void) +{ + int i; + + for (i = 0; i < 32; i++) { + wr_mask[regi(TFDR[i])] = BITS(31, 0); + } + for (i = 0; i < 64; i++) { + wr_mask[regi(LUT[i])] = BITS(31, 0); + } + + type_register_static(&flexspi_info); +} + +type_init(flexspi_register_types) diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build index 57d3e14727..c5b7e0a6e2 100644 --- a/hw/ssi/meson.build +++ b/hw/ssi/meson.build @@ -13,3 +13,4 @@ system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_spi.c')) system_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_spi_host.c')) system_ss.add(when: 'CONFIG_BCM2835_SPI', if_true: files('bcm2835_spi.c')) system_ss.add(when: 'CONFIG_FLEXCOMM', if_true: files('flexcomm_spi.c')) +system_ss.add(when: 'CONFIG_FLEXSPI', if_true: files('flexspi.c')) diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events index 5caa1c17ac..d623022a79 100644 --- a/hw/ssi/trace-events +++ b/hw/ssi/trace-events @@ -40,3 +40,7 @@ flexcomm_spi_fifostat(const char *id, uint32_t fifostat, uint32_t fifoinstat) "% flexcomm_spi_irq(const char *id, bool irq, bool fifoirqs, bool perirqs, bool enabled) "%s: %d %d %d %d" flexcomm_spi_chr_rx_space(const char *id, uint32_t rx) "%s: %d" flexcomm_spi_chr_rx(const char *id) "%s" + +# flexspi.c +flexspi_reg_read(const char *id, const char *reg_name, uint32_t addr, uint32_t val) " %s: %s[0x%04x] -> 0x%08x" +flexspi_reg_write(const char *id, const char *reg_name, uint32_t addr, uint32_t val) "%s: %s[0x%04x] <- 0x%08x" diff --git a/include/hw/ssi/flexspi.h b/include/hw/ssi/flexspi.h new file mode 100644 index 0000000000..f5fea9dee9 --- /dev/null +++ b/include/hw/ssi/flexspi.h @@ -0,0 +1,34 @@ +/* + * QEMU model for FLEXSPI + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_RT500_FLEXSPI_H +#define HW_RT500_FLEXSPI_H + +#include "hw/sysbus.h" +#include "hw/ssi/ssi.h" +#include "hw/arm/svd/flexspi.h" + +#define TYPE_FLEXSPI "flexspi" +#define FLEXSPI(obj) OBJECT_CHECK(FlexSpiState, (obj), TYPE_FLEXSPI) + +typedef struct { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion mmio; + FLEXSPI_Type regs; + MemoryRegion mem; + uint32_t mmap_base; + uint32_t mmap_size; +} FlexSpiState; + +#endif /* HW_RT500_FLEXSPI_H */ From patchwork Mon Aug 5 20:17:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754028 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D730EC3DA7F for ; Mon, 5 Aug 2024 20:18:59 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49k-0005co-NW; Mon, 05 Aug 2024 16:18:12 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3djOxZgUKCt0S9UHOFNNFKD.BNLPDLT-CDUDKMNMFMT.NQF@flex--tavip.bounces.google.com>) id 1sb49e-0004kR-FJ for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:18:07 -0400 Received: from mail-pj1-x104a.google.com ([2607:f8b0:4864:20::104a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3djOxZgUKCt0S9UHOFNNFKD.BNLPDLT-CDUDKMNMFMT.NQF@flex--tavip.bounces.google.com>) id 1sb49a-0001Xd-Ue for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:18:06 -0400 Received: by mail-pj1-x104a.google.com with SMTP id 98e67ed59e1d1-2cd2c7904dcso10970947a91.0 for ; Mon, 05 Aug 2024 13:18:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889080; x=1723493880; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=u4G3+QfEQuPGYkcQf8AOgE2UDxpBxkJrxB1kWGdX9cU=; b=ez+dIN6o0yfY+RQX3vua/ge+lTOQ3I095HhrufQmI3cW1wXip0gLTiH65Vs3XbQ67H YirHe/M8H9eEfekVjtsI9DlNws6DWBdkgaShHvhd4sC6pPV7rkARZ+mmh/g8X7ZWYC7T gsiKmttveQOFb67G+6jdvwG1ao9JagpRI2s1RwpA4A/qYNSHbDtRT8G4YJcH8uJbBrz0 0OLXqhEpNEd0E8Fm3lEWUrfgGthYMKNKZSess28958ZCwNGr16ldiTOQBL/YmaLbY7a6 hjxADkP+Wnu8iY/yLcH/B4ZyPczPMBYBKqAjMbwQxtkH4xGIubKmy2AGYSJpcpjeM6sI 8r7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889080; x=1723493880; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=u4G3+QfEQuPGYkcQf8AOgE2UDxpBxkJrxB1kWGdX9cU=; b=N+NdQj+y67MzWenynRKjtimHAxleZq8TYp5ycw2Pa/SE7zolY/TlwH0D55LWoX1r7n 0T5Clm0NO3RSYF21ZOVOkrfvLg6AXNw644112P9l0p+SI1RHWjK0EPFa58WEZx9XV1+H ByWYntBI8J90wL6+WauaJdLiPXcnbcVqNGxz8+b0RBDai7mStAjlVp6W95lM2biFGlPn X9CWvA2E5JL2Jm9IfigVDfJm7VJBMAi81npZ9TdsUu2pnsJFuOpsmti8uu433cR4VTCj a9jLuCusyr43Nl1zNzMzkjWqnNbQ4igpH89zszY7hE+DATWTGIL2KcjvaGFkc02KegN8 taUA== X-Gm-Message-State: AOJu0YxRPov8UUJ/0QAcwEWpR44GMJ7kEYS8Fi12RdwXKnG1sltvPu3J pJfucrzQ3xpHHPVEzdQ/kRrUMYxLgVAnnn2fuBC4vjQng+pjlD0r/CPRYyy50wZYgNoqBVEuFHN hUT1sqLd0MPvSMDe58SA9Cr9lmaZWCrVxvTRzNCznxXWKmXQCXsfr+El7DNji2dSlozHJrAUXXy wkAVbkdbnJFDdYAAVzcjRrIve47g== X-Google-Smtp-Source: AGHT+IFou9H80QB90t2SGEHQlrSm6cRFXg4Q/BYZGtoq36SYjaPwpS566HoPuRH/kcQrZnxxlae98b/Ryw== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a17:90a:6042:b0:2c3:1985:e9c3 with SMTP id 98e67ed59e1d1-2cff95243c6mr34825a91.3.1722889078446; Mon, 05 Aug 2024 13:17:58 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:16 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-22-tavip@google.com> Subject: [RFC PATCH 21/23] hw/misc: add support for RT500 reset controller From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::104a; envelope-from=3djOxZgUKCt0S9UHOFNNFKD.BNLPDLT-CDUDKMNMFMT.NQF@flex--tavip.bounces.google.com; helo=mail-pj1-x104a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org The RT500 reset controller has two instances that have the same register layout but with different fields for some registers. The model only provides set and clear functionality for the various reset lines which is common for both instances. Because of that only one type is implemented for both controllers. Signed-off-by: Octavian Purdila --- hw/arm/svd/meson.build | 8 ++ hw/misc/Kconfig | 3 + hw/misc/meson.build | 1 + hw/misc/rt500_rstctl.c | 219 +++++++++++++++++++++++++++++++++ hw/misc/trace-events | 4 + include/hw/misc/rt500_rstctl.h | 38 ++++++ 6 files changed, 273 insertions(+) create mode 100644 hw/misc/rt500_rstctl.c create mode 100644 include/hw/misc/rt500_rstctl.h diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build index 22f75880f5..72a7421c6f 100644 --- a/hw/arm/svd/meson.build +++ b/hw/arm/svd/meson.build @@ -26,3 +26,11 @@ genh += custom_target('flexspi.h', output: 'flexspi.h', input: 'MIMXRT595S_cm33.xml', command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'FLEXSPI0', '-t', 'FLEXSPI']) +genh += custom_target('rt500_rstctl0.h', + output: 'rt500_rstctl0.h', + input: 'MIMXRT595S_cm33.xml', + command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'RSTCTL0', '-t', 'RT500_RSTCTL0']) +genh += custom_target('rt500_rstctl1.h', + output: 'rt500_rstctl1.h', + input: 'MIMXRT595S_cm33.xml', + command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'RSTCTL1', '-t', 'RT500_RSTCTL1']) diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 392ae9e84f..70a2a269ac 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -222,4 +222,7 @@ config RT500_CLKCTL0 config RT500_CLKCTL1 bool +config RT500_RSTCTL + bool + source macio/Kconfig diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 68929949a6..5e2728e982 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -160,3 +160,4 @@ system_ss.add(when: 'CONFIG_LASI', if_true: files('lasi.c')) system_ss.add(when: 'CONFIG_FLEXCOMM', if_true: files('flexcomm.c')) system_ss.add(when: 'CONFIG_RT500_CLKCTL0', if_true: files('rt500_clkctl0.c')) system_ss.add(when: 'CONFIG_RT500_CLKCTL1', if_true: files('rt500_clkctl1.c')) +system_ss.add(when: 'CONFIG_RT500_RSTCTL', if_true: files('rt500_rstctl.c')) diff --git a/hw/misc/rt500_rstctl.c b/hw/misc/rt500_rstctl.c new file mode 100644 index 0000000000..2806a94150 --- /dev/null +++ b/hw/misc/rt500_rstctl.c @@ -0,0 +1,219 @@ +/* + * QEMU model for RT500 Reset Controller + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "exec/address-spaces.h" +#include "hw/regs.h" +#include "hw/misc/rt500_rstctl.h" + +#include "trace.h" + +/* + * There are two intances for RSTCTL with the same register names but + * with different fields. + */ +#define reg(field) offsetof(RT500_RSTCTL0_Type, field) +#define regi(x) (reg(x) / sizeof(uint32_t)) +#define REG_NO (sizeof(RT500_RSTCTL0_Type) / sizeof(uint32_t)) + +#define RSTCTL_SYSRSTSTAT_WMASK (BITS(7, 4) | BIT(0)) +#define RSTCL0_PRSCTL0_WMASK (BITS(30, 26) | BITS(24, 20) | BIT(18) | \ + BIT(16) | BITS(12, 8) | BIT(3) | BIT(1)) +#define RSTCL0_PRSCTL1_WMASK (BIT(24) | BITS(16, 15) | BITS(3, 2)) +#define RSTCL0_PRSCTL2_WMASK (BITS(1, 0)) +#define RSTCL1_PRSCTL0_WMASK (BIT(29) | BIT(27) | BITS(25, 8)) +#define RSTCL1_PRSCTL1_WMASK (BIT(31) | BITS(29, 28) | BITS(24, 23) | \ + BIT(16) | BITS(7, 0)) +#define RSTCL1_PRSCTL2_WMASK (BITS(31, 30) | BITS(17, 16) | BIT(10) | \ + BIT(8) | BITS(4, 0)) + +static RT500_RSTCTL0_REGISTER_NAMES_ARRAY(reg_names); + +static MemTxResult rt500_rstctl_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + RT500RstCtlState *s = opaque; + MemTxResult ret = MEMTX_OK; + + if (s->num > 1 || !reg32_aligned_access(addr, size)) { + ret = MEMTX_ERROR; + goto out; + } + + switch (addr) { + case reg(SYSRSTSTAT): + case reg(PRSTCTL0): + case reg(PRSTCTL1): + case reg(PRSTCTL2): + *data = reg32_read(&s->regs.ctl0, addr); + break; + default: + ret = MEMTX_ERROR; + } + +out: + trace_rt500_rstctl_reg_read(DEVICE(s)->id, reg_names[addr], addr, *data); + return ret; +} + +static MemTxResult rt500_rstctl_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + RT500RstCtlState *s = opaque; + static uint32_t mask0[REG_NO] = { + [regi(SYSRSTSTAT)] = RSTCTL_SYSRSTSTAT_WMASK, + [regi(PRSTCTL0)] = RSTCL0_PRSCTL0_WMASK, + [regi(PRSTCTL1)] = RSTCL0_PRSCTL1_WMASK, + [regi(PRSTCTL2)] = RSTCL0_PRSCTL2_WMASK, + [regi(PRSTCTL0_SET)] = RSTCL0_PRSCTL0_WMASK, + [regi(PRSTCTL1_SET)] = RSTCL0_PRSCTL1_WMASK, + [regi(PRSTCTL2_SET)] = RSTCL0_PRSCTL2_WMASK, + [regi(PRSTCTL0_CLR)] = RSTCL0_PRSCTL0_WMASK, + [regi(PRSTCTL1_CLR)] = RSTCL0_PRSCTL1_WMASK, + [regi(PRSTCTL2_CLR)] = RSTCL0_PRSCTL2_WMASK, + }; + static uint32_t mask1[REG_NO] = { + [regi(SYSRSTSTAT)] = RSTCTL_SYSRSTSTAT_WMASK, + [regi(PRSTCTL0)] = RSTCL1_PRSCTL0_WMASK, + [regi(PRSTCTL1)] = RSTCL1_PRSCTL1_WMASK, + [regi(PRSTCTL2)] = RSTCL1_PRSCTL2_WMASK, + [regi(PRSTCTL0_SET)] = RSTCL1_PRSCTL0_WMASK, + [regi(PRSTCTL1_SET)] = RSTCL1_PRSCTL1_WMASK, + [regi(PRSTCTL2_SET)] = RSTCL1_PRSCTL2_WMASK, + [regi(PRSTCTL0_CLR)] = RSTCL1_PRSCTL0_WMASK, + [regi(PRSTCTL1_CLR)] = RSTCL1_PRSCTL1_WMASK, + [regi(PRSTCTL2_CLR)] = RSTCL1_PRSCTL2_WMASK, + }; + uint32_t mask; + + trace_rt500_rstctl_reg_write(DEVICE(s)->id, reg_names[addr], addr, value); + + if (s->num > 1 || !reg32_aligned_access(addr, size)) { + return MEMTX_ERROR; + } + + if (s->num == 0) { + mask = mask0[addr / sizeof(uint32_t)]; + } else { + mask = mask1[addr / sizeof(uint32_t)]; + } + + switch (addr) { + case reg(SYSRSTSTAT): + { + /* write 1 to clear bits */ + s->regs.ctl0.SYSRSTSTAT &= ~(value & mask); + break; + } + case reg(PRSTCTL0): + case reg(PRSTCTL1): + case reg(PRSTCTL2): + { + uint32_t idx = addr / sizeof(uint32_t); + + s->regs.raw[idx] = (value & mask); + break; + } + case reg(PRSTCTL0_SET): + case reg(PRSTCTL1_SET): + case reg(PRSTCTL2_SET): + { + uint32_t idx; + + idx = (reg(PRSTCTL0) + (addr - reg(PRSTCTL0_SET))) / sizeof(uint32_t); + s->regs.raw[idx] |= (value & mask); + break; + } + case reg(PRSTCTL0_CLR): + case reg(PRSTCTL1_CLR): + case reg(PRSTCTL2_CLR): + { + uint32_t idx; + + idx = (reg(PRSTCTL0) + (addr - reg(PRSTCTL0_CLR))) / sizeof(uint32_t); + s->regs.raw[idx] &= ~(value & mask); + break; + } + } + + return MEMTX_OK; +} + + +static const MemoryRegionOps rt500_rstctl_ops = { + .read_with_attrs = rt500_rstctl_read, + .write_with_attrs = rt500_rstctl_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static Property rt500_rstctl_properties[] = { + DEFINE_PROP_UINT32("num", RT500RstCtlState, num, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void rt500_rstctl_reset(DeviceState *dev) +{ + RT500RstCtlState *s = RT500_RSTCTL(dev); + + memset(&s->regs, 0, sizeof(s->regs)); + + switch (s->num) { + case 0: + rt500_rstctl0_reset_registers(&s->regs.ctl0); + break; + case 1: + rt500_rstctl1_reset_registers(&s->regs.ctl1); + break; + } +} + +static void rt500_rstctl_init(Object *obj) +{ + RT500RstCtlState *s = RT500_RSTCTL(obj); + + memory_region_init_io(&s->mmio, obj, &rt500_rstctl_ops, s, + TYPE_RT500_RSTCTL, sizeof(s->regs)); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); +} + +static void rt500_rstctl_realize(DeviceState *dev, Error **errp) +{ +} + +static void rt500_rstctl_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = rt500_rstctl_reset; + device_class_set_props(dc, rt500_rstctl_properties); + dc->realize = rt500_rstctl_realize; +} + +static const TypeInfo rt500_rstctl_info = { + .name = TYPE_RT500_RSTCTL, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RT500RstCtlState), + .instance_init = rt500_rstctl_init, + .class_init = rt500_rstctl_class_init, +}; + +static void rt500_rstctl_register_types(void) +{ + type_register_static(&rt500_rstctl_info); +} + +type_init(rt500_rstctl_register_types) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index e65fcfa613..41a94d5ef6 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -365,3 +365,7 @@ rt500_clkctl0_reg_write(const char *regname, uint32_t addr, uint32_t val) "%s[0x # rt500_clkctl1.c rt500_clkctl1_reg_read(const char *regname, uint32_t addr, uint32_t val) "%s[0x%04x] -> 0x%08x" rt500_clkctl1_reg_write(const char *regname, uint32_t addr, uint32_t val) "%s[0x%04x] <- 0x%08x" + +# rt500_rstctl.c +rt500_rstctl_reg_read(const char *id, const char *regname, uint32_t addr, uint32_t val) "%s: %s[0x%04x] -> 0x%08x" +rt500_rstctl_reg_write(const char *id, const char *regname, uint32_t addr, uint32_t val) "%s: %s[0x%04x] <- 0x%08x" diff --git a/include/hw/misc/rt500_rstctl.h b/include/hw/misc/rt500_rstctl.h new file mode 100644 index 0000000000..d9726df5f6 --- /dev/null +++ b/include/hw/misc/rt500_rstctl.h @@ -0,0 +1,38 @@ +/* + * QEMU model for RT500 Reset Controller + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_MISC_RT500_RSTCTL_H +#define HW_MISC_RT500_RSTCTL_H + +#include "hw/arm/svd/rt500_rstctl0.h" +#include "hw/arm/svd/rt500_rstctl1.h" +#include "hw/sysbus.h" + +#define RSTCTL_Type RSTCTL0_Type + +#define TYPE_RT500_RSTCTL "rt500-rstctl" +#define RT500_RSTCTL(o) OBJECT_CHECK(RT500RstCtlState, o, TYPE_RT500_RSTCTL) + +typedef struct { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion mmio; + uint32_t num; + union { + RT500_RSTCTL0_Type ctl0; + RT500_RSTCTL1_Type ctl1; + uint32_t raw[sizeof(RT500_RSTCTL0_Type) / sizeof(uint32_t)]; + } regs; +} RT500RstCtlState; + +#endif /* HW_MISC_RT500_RSTCTL_H */ From patchwork Mon Aug 5 20:17:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754020 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0BDC8C3DA4A for ; Mon, 5 Aug 2024 20:18:26 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49k-0005Xz-EH; Mon, 05 Aug 2024 16:18:12 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3eDOxZgUKCt8UBWJQHPPHMF.DPNRFNV-EFWFMOPOHOV.PSH@flex--tavip.bounces.google.com>) id 1sb49f-0004pH-2u for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:18:07 -0400 Received: from mail-yw1-x114a.google.com ([2607:f8b0:4864:20::114a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3eDOxZgUKCt8UBWJQHPPHMF.DPNRFNV-EFWFMOPOHOV.PSH@flex--tavip.bounces.google.com>) id 1sb49a-0001Xg-NC for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:18:06 -0400 Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-68dcbd6135dso64352827b3.3 for ; Mon, 05 Aug 2024 13:18:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889080; x=1723493880; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=4u1P5SIla3BTMDBQNng926h7zNREK6etGIfsOHcMKR0=; b=W+xt1ui9C6SahVsxDgI27zBE7YqWEYkpfFj86gqECR5HYzPT7azq4OWpIdNglB2YMP kMhr2itAneQh2CK+A+31gHSQp7G0JrihO7SrJGa8gXBn00+3vGofgf8dtdgITXOkI/Wi Hqs1cb6tBFkUUlOu8H02tSY0w93TZIvV6nYv5lCSZodmSjDiKtijxaRoRBfKRTaTzICF D9NEmivVV9xKr9EFaFke56qulBi2leOv//RMwe8IIiuQeZMBgcSu8mApkanTTnnkMAUQ bnm/hXOS7R0Lu7TOqdEqaFVXb+xIHCB7V1QWh78oiDnCs5Hd1MYAXLKKFcCBTgtHKEIi VmXg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889080; x=1723493880; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=4u1P5SIla3BTMDBQNng926h7zNREK6etGIfsOHcMKR0=; b=dN914UHnS8+emjSLvBA7HKV0vu2qDqt9OLGXHWauE+WIJaxR/ORCkzzFjwuEIigH+s d4XMMY1iWHx9CJiSFoe30h9R+E/6ympTqEadhRHM6S8C80y2aM2fVJ8ZAKYoeFxzYC4w ktVaPWZBgPw5lVkC34HJql6gmxx8OYqqEV/7h0gPEBfmUoU5IUQ5tYmSbdyN7a+xpjPw Hi37Yxj6PUhBZZ+oisB9U5/PJACTnTOiLm15ycODBCUmdCOaz2jwvgurdh0Xjbvr8KQV i3AgNMUn3G+qQuXwq+wRB36FXYBKeSde8crOPxK0LAnEVhEPcppjb5vdKTJzTnXcDzgv 6Zsw== X-Gm-Message-State: AOJu0YyVHHVFwYzJsq0zz+hyvWNftnKg4wNNo0YDJRYYBrxlIGpQNonm vv0IVfnquiraY3mZXipcVvwYKmQtdN10JoBxEUuKtzK+1NmnwgU/FUe5qMAPiOBRY6X88Sz21Xr xOyrzkPpVCAm+5KP+y+YEGP82iXca+k4203jG4aY80w1NyTVr9IWzD3nT3x42PR9jm9hr+t1yio YAeNAQy4kN6/EmSyp5DMKuCIEQ0Q== X-Google-Smtp-Source: AGHT+IETKmxMUfzjPk4qDciUlfp9GgJp/XDZSs4LIyahMhe5QVAt6LybinSSK4kDNRuQBJAnL26S8NRD1Q== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:690c:660d:b0:691:2f66:4af9 with SMTP id 00721157ae682-6912f664f8amr3358477b3.4.1722889080107; Mon, 05 Aug 2024 13:18:00 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:17 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-23-tavip@google.com> Subject: [RFC PATCH 22/23] hw/arm: add basic support for the RT500 SoC From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::114a; envelope-from=3eDOxZgUKCt8UBWJQHPPHMF.DPNRFNV-EFWFMOPOHOV.PSH@flex--tavip.bounces.google.com; helo=mail-yw1-x114a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add basic support for the RT500 SoC. It supports enough peripherals to run the NXP's microXpresso SDK hello world example. Signed-off-by: Octavian Purdila --- hw/arm/Kconfig | 8 + hw/arm/meson.build | 1 + hw/arm/rt500.c | 348 +++++++++++++++++++++++++++++++++++++++++ hw/arm/svd/meson.build | 6 + include/hw/arm/rt500.h | 49 ++++++ 5 files changed, 412 insertions(+) create mode 100644 hw/arm/rt500.c create mode 100644 include/hw/arm/rt500.h diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 1ad60da7aa..7ffece3dec 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -712,3 +712,11 @@ config ARMSSE select UNIMP select SSE_COUNTER select SSE_TIMER + +config RT500 + bool + select FLEXCOMM + select RT500_CLKCTL0 + select RT500_CLKCTL1 + select FLEXSPI + select RT500_RSTCTL diff --git a/hw/arm/meson.build b/hw/arm/meson.build index eb604d00cf..7d827d512c 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -59,6 +59,7 @@ arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) arm_ss.add(when: 'CONFIG_XEN', if_true: files('xen_arm.c')) +arm_ss.add(when: 'CONFIG_RT500', if_true: files('rt500.c')) system_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c')) system_ss.add(when: 'CONFIG_CHEETAH', if_true: files('palm.c')) diff --git a/hw/arm/rt500.c b/hw/arm/rt500.c new file mode 100644 index 0000000000..0866ef3ef6 --- /dev/null +++ b/hw/arm/rt500.c @@ -0,0 +1,348 @@ +/* + * i.MX RT500 platforms. + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/sysbus.h" +#include "hw/arm/boot.h" +#include "hw/boards.h" +#include "hw/irq.h" +#include "qemu/log.h" +#include "qemu/datadir.h" +#include "exec/address-spaces.h" +#include "sysemu/reset.h" +#include "sysemu/runstate.h" +#include "sysemu/sysemu.h" +#include "hw/arm/armv7m.h" +#include "hw/loader.h" +#include "hw/qdev-clock.h" +#include "hw/misc/unimp.h" +#include "hw/arm/rt500.h" +#include "hw/arm/svd/rt500.h" + +#define MMAP_SRAM_CODE_BASE (0x0) +#define MMAP_SRAM_DATA_BASE (0x20000000) +#define MMAP_SRAM_SIZE (5 * MiB) +#define MMAP_BOOT_ROM_BASE (0x03000000) +#define MMAP_BOOT_ROM_SIZE (192 * KiB) +#define MMAP_SDMA_RAM_BASE (0x24100000) +#define MMAP_SDMA_RAM_SIZE (32 * KiB) +#define MMAP_FLEXSPI0_BASE (0x08000000) +#define MMAP_FLEXSPI0_SIZE (128 * MiB) +#define MMAP_FLEXSPI1_BASE (0x28000000) +#define MMAP_FLEXSPI1_SIZE (128 * MiB) + +#define SECURE_OFFSET (0x10000000) + +typedef enum MemInfoType { + MEM_RAM, + MEM_ROM, + MEM_ALIAS +} MemInfoType; + +static void do_sys_reset(void *opaque, int n, int level) +{ + if (level) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + } +} + +static void rt500_init(Object *obj) +{ + RT500State *s = RT500(obj); + int i; + + /* Add ARMv7-M device */ + object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M); + + for (i = 0; i < RT500_FLEXCOMM_NUM; i++) { + char id[] = "flexcommXX"; + + snprintf(id, sizeof(id), "flexcomm%d", i); + object_initialize_child(obj, id, &s->flexcomm[i], TYPE_FLEXCOMM); + DEVICE(&s->flexcomm[i])->id = g_strdup(id); + } + + object_initialize_child(obj, "clkctl0", &s->clkctl0, TYPE_RT500_CLKCTL0); + object_initialize_child(obj, "clkctl1", &s->clkctl1, TYPE_RT500_CLKCTL1); + + /* Initialize clocks */ + s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0); + s->refclk = qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0); + + for (i = 0; i < RT500_FLEXSPI_NUM; i++) { + char id[] = "flexspiXX"; + + snprintf(id, sizeof(id), "flexspi%d", i); + object_initialize_child(obj, id, &s->flexspi[i], TYPE_FLEXSPI); + DEVICE(&s->flexspi[i])->id = g_strdup(id); + } + + for (i = 0; i < RT500_RSTCTL_NUM; i++) { + char id[] = "rstctlX"; + + snprintf(id, sizeof(id), "rstctl%d", i); + object_initialize_child(obj, id, &s->rstctl[i], + TYPE_RT500_RSTCTL); + DEVICE(&s->rstctl[i])->id = g_strdup(id); + } +} + +static void rt500_realize_memory(RT500State *s, Error **errp) +{ + const struct { + const char *name; + hwaddr base; + size_t size; + MemInfoType type; + int alias_for; + } mem_info[] = { + { + .name = "SRAM (code bus)", + .base = MMAP_SRAM_CODE_BASE, + .size = MMAP_SRAM_SIZE, + .type = MEM_RAM, + }, + { + .name = "BOOT-ROM", + .base = MMAP_BOOT_ROM_BASE, + .size = MMAP_BOOT_ROM_SIZE, + .type = MEM_ROM, + }, + { + .name = "Smart DMA RAM", + .base = MMAP_SDMA_RAM_BASE, + .size = MMAP_SDMA_RAM_SIZE, + .type = MEM_RAM, + }, + { + .name = "SRAM (data bus)", + .base = MMAP_SRAM_DATA_BASE, + .size = MMAP_SRAM_SIZE, + .type = MEM_ALIAS, + .alias_for = 0 + }, + }; + int i; + + s->mem = g_malloc_n(2 * ARRAY_SIZE(mem_info), sizeof(MemoryRegion)); + for (i = 0; i < ARRAY_SIZE(mem_info); i++) { + const char *name = mem_info[i].name; + int size = mem_info[i].size; + int type = mem_info[i].type; + int alias_for = mem_info[i].alias_for; + MemoryRegion *mem = &s->mem[i]; + uint32_t base = mem_info[i].base; + MemoryRegion *sec_mem; + char sec_name[256]; + + switch (type) { + case MEM_RAM: + memory_region_init_ram(mem, OBJECT(s), name, size, errp); + break; + case MEM_ROM: + memory_region_init_rom(mem, OBJECT(s), name, size, errp); + break; + case MEM_ALIAS: + { + MemoryRegion *orig = &s->mem[alias_for]; + + memory_region_init_alias(mem, OBJECT(s), name, orig, 0, size); + break; + } + default: + g_assert_not_reached(); + } + + memory_region_add_subregion(get_system_memory(), base, mem); + + /* create secure alias */ + snprintf(sec_name, sizeof(sec_name), "SECURE %s", name); + sec_mem = &s->mem[ARRAY_SIZE(mem_info) + i]; + if (type == MEM_ALIAS) { + mem = &s->mem[alias_for]; + } + memory_region_init_alias(sec_mem, OBJECT(s), sec_name, mem, 0, size); + memory_region_add_subregion(get_system_memory(), base + SECURE_OFFSET, + sec_mem); + + if (mem_info[i].type == MEM_ROM) { + char *fname = qemu_find_file(QEMU_FILE_TYPE_BIOS, "rt500.rom"); + + if (fname) { + int fsize = get_image_size(fname); + int ret; + + if (fsize > size) { + error_setg(errp, "rom file too big: %d > %d", fsize, size); + } else { + ret = load_image_targphys(fname, base, size); + if (ret < 0) { + error_setg(errp, "could not load rom: %s", fname); + } + } + } + g_free(fname); + } + } +} + +static void rt500_realize(DeviceState *dev, Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + RT500State *s = RT500(dev); + int i; + + rt500_realize_memory(s, errp); + + /* Setup ARMv7M CPU */ + qdev_prop_set_uint32(DEVICE(&s->armv7m), "num-irq", + RT500_FLEXCOMM16_IRQn + 1); + qdev_prop_set_uint8(DEVICE(&s->armv7m), "num-prio-bits", 3); + qdev_prop_set_string(DEVICE(&s->armv7m), "cpu-type", ms->cpu_type); + object_property_set_link(OBJECT(&s->armv7m), "memory", + OBJECT(get_system_memory()), &error_abort); + if (!ms->kernel_filename) { + qdev_prop_set_uint32(DEVICE(&s->armv7m), "init-nsvtor", + MMAP_BOOT_ROM_BASE); + qdev_prop_set_uint32(DEVICE(&s->armv7m), "init-svtor", + MMAP_BOOT_ROM_BASE + SECURE_OFFSET); + } + + qdev_connect_clock_in(DEVICE(&s->armv7m), "cpuclk", s->sysclk); + qdev_connect_clock_in(DEVICE(&s->armv7m), "refclk", + qdev_get_clock_out(DEVICE(&s->clkctl0), "systick_clk")); + + sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->armv7m), errp); + qdev_connect_gpio_out_named(DEVICE(&s->armv7m), "SYSRESETREQ", 0, + qemu_allocate_irq(&do_sys_reset, NULL, 0)); + + /* Setup FLEXCOMM */ + for (i = 0; i < RT500_FLEXCOMM_NUM; i++) { + const uint32_t addr[] = { + RT500_FLEXCOMM0_BASE, RT500_FLEXCOMM1_BASE, RT500_FLEXCOMM2_BASE, + RT500_FLEXCOMM3_BASE, RT500_FLEXCOMM4_BASE, RT500_FLEXCOMM5_BASE, + RT500_FLEXCOMM6_BASE, RT500_FLEXCOMM7_BASE, RT500_FLEXCOMM8_BASE, + RT500_FLEXCOMM8_BASE, RT500_FLEXCOMM10_BASE, RT500_FLEXCOMM11_BASE, + RT500_FLEXCOMM12_BASE, RT500_FLEXCOMM13_BASE, RT500_FLEXCOMM14_BASE, + RT500_FLEXCOMM15_BASE, RT500_FLEXCOMM16_BASE + }; + const int irq[] = { + RT500_FLEXCOMM0_IRQn, RT500_FLEXCOMM1_IRQn, RT500_FLEXCOMM2_IRQn, + RT500_FLEXCOMM3_IRQn, RT500_FLEXCOMM4_IRQn, RT500_FLEXCOMM5_IRQn, + RT500_FLEXCOMM6_IRQn, RT500_FLEXCOMM7_IRQn, RT500_FLEXCOMM8_IRQn, + RT500_FLEXCOMM9_IRQn, RT500_FLEXCOMM10_IRQn, RT500_FLEXCOMM11_IRQn, + RT500_FLEXCOMM12_IRQn, RT500_FLEXCOMM13_IRQn, RT500_FLEXCOMM14_IRQn, + RT500_FLEXCOMM15_IRQn, RT500_FLEXCOMM16_IRQn + }; + const int functions[] = { + FLEXCOMM_FULL, FLEXCOMM_FULL, FLEXCOMM_FULL, + FLEXCOMM_FULL, FLEXCOMM_FULL, FLEXCOMM_FULL, + FLEXCOMM_FULL, FLEXCOMM_FULL, FLEXCOMM_FULL, + FLEXCOMM_FULL, FLEXCOMM_FULL, FLEXCOMM_FULL, + FLEXCOMM_FULL, FLEXCOMM_FULL, FLEXCOMM_HSSPI, + FLEXCOMM_PMICI2C, FLEXCOMM_HSSPI + }; + DeviceState *ds = DEVICE(&s->flexcomm[i]); + char id[] = "flexcommXX"; + + snprintf(id, sizeof(id), "flexcomm%d", i); + qdev_prop_set_uint32(ds, "functions", functions[i]); + qdev_prop_set_chr(ds, "chardev", qemu_chr_find(id)); + sysbus_realize_and_unref(SYS_BUS_DEVICE(ds), errp); + sysbus_mmio_map(SYS_BUS_DEVICE(ds), 0, addr[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(ds), 0, + qdev_get_gpio_in(DEVICE(&s->armv7m), irq[i])); + } + + /* Setup CTLCTL0 */ + qdev_connect_clock_in(DEVICE(&s->clkctl0), "sysclk", s->sysclk); + sysbus_realize_and_unref(SYS_BUS_DEVICE(DEVICE(&s->clkctl0)), errp); + sysbus_mmio_map(SYS_BUS_DEVICE(DEVICE(&s->clkctl0)), 0, RT500_CLKCTL0_BASE); + + /* Setup CTLCTL1 */ + qdev_connect_clock_in(DEVICE(&s->clkctl1), "sysclk", s->sysclk); + sysbus_realize_and_unref(SYS_BUS_DEVICE(DEVICE(&s->clkctl1)), errp); + sysbus_mmio_map(SYS_BUS_DEVICE(DEVICE(&s->clkctl1)), 0, RT500_CLKCTL1_BASE); + + /* Setup FlexSPI */ + for (i = 0; i < RT500_FLEXSPI_NUM; i++) { + const uint32_t addr[] = { + RT500_FLEXSPI0_BASE, RT500_FLEXSPI1_BASE + }; + const uint32_t mmap_base[] = { + MMAP_FLEXSPI0_BASE, MMAP_FLEXSPI1_BASE + }; + const uint32_t mmap_size[] = { + MMAP_FLEXSPI0_SIZE, MMAP_FLEXSPI1_SIZE, + }; + DeviceState *ds = DEVICE(&s->flexspi[i]); + + qdev_prop_set_uint32(ds, "mmap_base", mmap_base[i]); + qdev_prop_set_uint32(ds, "mmap_size", mmap_size[i]); + sysbus_realize_and_unref(SYS_BUS_DEVICE(ds), errp); + sysbus_mmio_map(SYS_BUS_DEVICE(ds), 0, addr[i]); + } + + /* Setup reset controllers */ + for (i = 0; i < RT500_RSTCTL_NUM; i++) { + DeviceState *ds = DEVICE(&s->rstctl[i]); + + const uint32_t addr[] = { + RT500_RSTCTL0_BASE, RT500_RSTCTL1_BASE + }; + + qdev_prop_set_uint32(ds, "num", i); + sysbus_realize_and_unref(SYS_BUS_DEVICE(ds), errp); + sysbus_mmio_map(SYS_BUS_DEVICE(ds), 0, addr[i]); + } +} + +static void rt500_finalize(Object *obj) +{ + RT500State *s = RT500(obj); + + g_free(s->mem); +} + +static void rt500_reset(DeviceState *ds) +{ +} + +static Property rt500_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static void rt500_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + device_class_set_props(dc, rt500_properties); + dc->realize = rt500_realize; + dc->desc = "RT500 (ARM Cortex-M33)"; + dc->reset = rt500_reset; +} + +static const TypeInfo rt500_type_info = { + .name = TYPE_RT500, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RT500State), + .instance_init = rt500_init, + .instance_finalize = rt500_finalize, + .class_init = rt500_class_init, +}; + +static void rt500_register_types(void) +{ + type_register_static(&rt500_type_info); +} + +type_init(rt500_register_types) diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build index 72a7421c6f..930a8b7343 100644 --- a/hw/arm/svd/meson.build +++ b/hw/arm/svd/meson.build @@ -34,3 +34,9 @@ genh += custom_target('rt500_rstctl1.h', output: 'rt500_rstctl1.h', input: 'MIMXRT595S_cm33.xml', command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'RSTCTL1', '-t', 'RT500_RSTCTL1']) +genh += custom_target('rt500.h', + output: 'rt500.h', + input: 'MIMXRT595S_cm33.xml', + command: [ svd_gen_header,'-i', '@INPUT@', '-o', '@OUTPUT@', '-s', 'RT500', + '-p', 'FLEXCOMM0', '-p', 'CLKCTL0', '-p', 'CLKCTL1', + '-p', 'FLEXSPI0', '-p', 'FLEXSPI1', '-p', 'RSTCTL0', '-p', 'RSTCTL1']) diff --git a/include/hw/arm/rt500.h b/include/hw/arm/rt500.h new file mode 100644 index 0000000000..8ca7972f8a --- /dev/null +++ b/include/hw/arm/rt500.h @@ -0,0 +1,49 @@ +/* + * i.MX RT500 platforms. + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#ifndef HW_ARM_RT500_H +#define HW_ARM_RT500_H + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "hw/arm/boot.h" +#include "hw/arm/armv7m.h" +#include "hw/misc/flexcomm.h" +#include "hw/misc/rt500_clkctl0.h" +#include "hw/misc/rt500_clkctl1.h" +#include "hw/ssi/flexspi.h" +#include "hw/misc/rt500_rstctl.h" + +#define TYPE_RT500 "rt500" +#define RT500(obj) OBJECT_CHECK(RT500State, (obj), TYPE_RT500) + +#define RT500_FLEXCOMM_NUM (17) +#define RT500_FLEXSPI_NUM (2) +#define RT500_RSTCTL_NUM (2) + +typedef struct RT500State { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + ARMv7MState armv7m; + MemoryRegion *mem; + FlexcommState flexcomm[RT500_FLEXCOMM_NUM]; + RT500ClkCtl0State clkctl0; + RT500ClkCtl1State clkctl1; + FlexSpiState flexspi[RT500_FLEXSPI_NUM]; + RT500RstCtlState rstctl[RT500_RSTCTL_NUM]; + + Clock *sysclk; + Clock *refclk; +} RT500State; + +#endif /* HW_ARM_RT500_H */ From patchwork Mon Aug 5 20:17:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 13754042 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2761FC3DA7F for ; Mon, 5 Aug 2024 20:20:49 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sb49l-0005n4-Ft; Mon, 05 Aug 2024 16:18:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3ejOxZgUKCuEWDYLSJRRJOH.FRPTHPX-GHYHOQRQJQX.RUJ@flex--tavip.bounces.google.com>) id 1sb49g-0004wE-Iu for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:18:09 -0400 Received: from mail-pf1-x44a.google.com ([2607:f8b0:4864:20::44a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3ejOxZgUKCuEWDYLSJRRJOH.FRPTHPX-GHYHOQRQJQX.RUJ@flex--tavip.bounces.google.com>) id 1sb49e-0001YG-Pr for qemu-devel@nongnu.org; Mon, 05 Aug 2024 16:18:08 -0400 Received: by mail-pf1-x44a.google.com with SMTP id d2e1a72fcca58-71065f49b10so4642372b3a.0 for ; Mon, 05 Aug 2024 13:18:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1722889084; x=1723493884; darn=nongnu.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=3GjBap7FxZdPpDdgQeaY7XNjHE33uQ9g7r73DwU0Kyw=; b=pWxmf9Aoupp/srEsQyrS2UCJIHAwT1L7Ou3GOx9mAdhznqSok6OPw1BGzskOSLfALr XJwzaoQ6WjKvdpC7Q5YabiT7J+kkLVc7hzc1kfL7UMhGe9UinqZMhHjW0gVQYZkVCFAi wtBS7Uac0vlf9IosOJN/0ZIoEa0iE6gDiTW4XsDHZjHGOmZIcWrh/65JczlR2BL0Gb6S njaItpeoQL7DyDtqrZgnJppnvkbj/ocJ8ABek+foXLpKQUKgeEQu+eNaPS3StwGJo1rP rqYXD2mLsQpTWlMC5kkj4YfY0HhBqqt9XUrNaavBk48qOqJohVDGFgQ7PyrjNjOT6Zg3 wBiw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722889084; x=1723493884; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=3GjBap7FxZdPpDdgQeaY7XNjHE33uQ9g7r73DwU0Kyw=; b=HKxdznFdD6EP0IAeh88mW3cv/KfxCq1lB9yF66GZc1IeZ7kFvQd4KbiBnS7i6TaKKW pxNAHBxgVVgRA+QW/QuV6oSQC2y5VsTosDw9PxQFuOgh4sMgpkvF3VF5UPnuLHSrswOd zsqJhvnTxcRGqm+vquYd+zM5/kAbl3Ustc4pyAYErsSHYPHZFDUL1E75Tye984xGzEh8 zmaUVMiY2pSemdGnlYoK0V0zbMdZIDoa4RtseSjecz9/2eGJReYn5jkqX/Jpht0EWt89 7O5jtMaBCsfQhdV+oFdr5G+xCq3212xQxsGS3F8R1NAAChs4ouEdnyautfoI5RAF/l78 tgJQ== X-Gm-Message-State: AOJu0YxpC6HDHkYvBmwMGK2iGfc3g6z6uRZOAvKAQi6ECeuwP1vqRnyJ Mq5pvXnfbc6tg84olYelupJ2b31UaBmQpGxcukE3BSBHBCDDcmfRGtcHqkFHrt4AgXhLDOR3WrN bZ5qMKJrwGZSqCBCGJdXnQo8O7ddNPoG/vb87yAWNvlkx0eGVg0hfDA+NQikUdqS3Op2XrZS/ze 5V87v8vljl5IYtXzVIbUI2p4I3cw== X-Google-Smtp-Source: AGHT+IEXkrqOE/XzNbGuVKsM0VKvpvoMdnNt3Ub2rtyWCRwYu7a+ohGR2cw4S360MRHtx60w8KRKA+NVSw== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:6a00:9153:b0:710:5798:44de with SMTP id d2e1a72fcca58-7106cf97a92mr55487b3a.2.1722889082012; Mon, 05 Aug 2024 13:18:02 -0700 (PDT) Date: Mon, 5 Aug 2024 13:17:18 -0700 In-Reply-To: <20240805201719.2345596-1-tavip@google.com> Mime-Version: 1.0 References: <20240805201719.2345596-1-tavip@google.com> X-Mailer: git-send-email 2.46.0.rc2.264.g509ed76dc8-goog Message-ID: <20240805201719.2345596-24-tavip@google.com> Subject: [RFC PATCH 23/23] hw/arm: add RT595-EVK board From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, alex.bennee@linaro.org, thuth@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, alistair@alistair23.me, berrange@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, bleal@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::44a; envelope-from=3ejOxZgUKCuEWDYLSJRRJOH.FRPTHPX-GHYHOQRQJQX.RUJ@flex--tavip.bounces.google.com; helo=mail-pf1-x44a.google.com X-Spam_score_int: -95 X-Spam_score: -9.6 X-Spam_bar: --------- X-Spam_report: (-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add basic support for the RT595-EVK board, enough to be able to run the NXP's microXpresso SDK hello world example. Signed-off-by: Octavian Purdila --- hw/arm/Kconfig | 5 ++++ hw/arm/meson.build | 1 + hw/arm/rt595-evk.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 hw/arm/rt595-evk.c diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 7ffece3dec..26ec3d391a 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -720,3 +720,8 @@ config RT500 select RT500_CLKCTL1 select FLEXSPI select RT500_RSTCTL + +config RT595_EVK + bool + default y + select RT500 diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 7d827d512c..9792c93142 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -60,6 +60,7 @@ arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-e arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) arm_ss.add(when: 'CONFIG_XEN', if_true: files('xen_arm.c')) arm_ss.add(when: 'CONFIG_RT500', if_true: files('rt500.c')) +arm_ss.add(when: 'CONFIG_RT595_EVK', if_true: files('rt595-evk.c')) system_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c')) system_ss.add(when: 'CONFIG_CHEETAH', if_true: files('palm.c')) diff --git a/hw/arm/rt595-evk.c b/hw/arm/rt595-evk.c new file mode 100644 index 0000000000..fff3004195 --- /dev/null +++ b/hw/arm/rt595-evk.c @@ -0,0 +1,64 @@ +/* + * i.MX RT595 EVK + * + * Copyright (c) 2024 Google LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "elf.h" +#include "exec/address-spaces.h" +#include "hw/loader.h" +#include "hw/sysbus.h" +#include "hw/boards.h" +#include "qemu/log.h" +#include "hw/arm/armv7m.h" +#include "hw/misc/unimp.h" +#include "hw/arm/rt500.h" +#include "hw/qdev-clock.h" +#include "sysemu/reset.h" + +static void rt595_evk_reset(MachineState *ms, ShutdownCause reason) +{ + /* + * CPU reset is not done by default, we need to do it manually when the + * machine is reset. + */ + cpu_reset(first_cpu); + + qemu_devices_reset(reason); +} + +static void rt595_evk_init(MachineState *ms) +{ + RT500State *s; + Clock *sysclk; + + sysclk = clock_new(OBJECT(ms), "SYSCLK"); + clock_set_hz(sysclk, 200000000); + + s = RT500(object_new(TYPE_RT500)); + qdev_connect_clock_in(DEVICE(s), "sysclk", sysclk); + object_property_add_child(OBJECT(ms), "soc", OBJECT(s)); + sysbus_realize_and_unref(SYS_BUS_DEVICE(s), &error_fatal); + + if (ms->kernel_filename) { + armv7m_load_kernel(ARM_CPU(first_cpu), ms->kernel_filename, 0, 0); + } +} + +static void rt595_evk_machine_init(MachineClass *mc) +{ + mc->desc = "RT595 EVK Machine (ARM Cortex-M33)"; + mc->init = rt595_evk_init; + mc->reset = rt595_evk_reset; + + mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33"); + mc->ignore_memory_transaction_failures = true; +} + +DEFINE_MACHINE("rt595-evk", rt595_evk_machine_init);