From patchwork Tue Oct 8 01:18:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993896 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=dbmY/ZCj; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMyqR5tjCz1xsn for ; Tue, 8 Oct 2024 12:19:47 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxysn-0007tC-Ru; Mon, 07 Oct 2024 21:19:29 -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 <3f4gEZwUKCuAVCXKRIQQING.EQOSGOW-FGXGNPQPIPW.QTI@flex--tavip.bounces.google.com>) id 1sxysQ-0007cD-FO for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:03 -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 <3f4gEZwUKCuAVCXKRIQQING.EQOSGOW-FGXGNPQPIPW.QTI@flex--tavip.bounces.google.com>) id 1sxysO-00006p-NB for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:02 -0400 Received: by mail-pf1-x44a.google.com with SMTP id d2e1a72fcca58-71dfa361499so2100210b3a.0 for ; Mon, 07 Oct 2024 18:18:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350337; x=1728955137; 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=tX+6Z1PHnYxk320Y4l1d37qXLvaekBWmUkrZNyFnhQ0=; b=dbmY/ZCjpBKcnfie7FHk5Q4XREW4d0AptJVY+ZUQHuTYy8ax5kwtpdbdpBrfT/dPto gCfL4xLURjBI/XGpHdnv3uEX5IwoEzycP1/LqTI6U26Igs36HmvpOnDjpaf9JHN2jooj 4aNs2TswgWE/VnRHisRqPUxe2hKhV7q/0SaE7DBPV3SuzwyvHjlN4u8awvcosoz3ANSx 9uk9ARuHIvWSMKb0HBUZfmQQb03EqyY8o+0McglPlOk9LbWwwuhFSg8hswt12VdSXUGw TVt293mW22HU4nMSxC7jDDR11CGZ/5Qi0teN1rXk5Bx1PwmdODtYsUQhqP9UFxUFp98D QD5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350337; x=1728955137; 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=tX+6Z1PHnYxk320Y4l1d37qXLvaekBWmUkrZNyFnhQ0=; b=iDnRWt0/rvv/2mJvpxDCDzkD4gRmX8jHeuHUWJsv0Oj75bAQV2fBAWkUjwCxddlA1d uvlvH37QjR5tbqlrKRLxPgMr8c7TU9x9W1O0tjhtNJNte+k8tvortSItOJGyTTOmIbmE nNDB2ok3laoFtzC1Mffjnr2JVEqxsd/hh54IM9sciwSwXyvI/BNAvXgGETo+CRsuN4cX o8QjYr4a8lmo/BWH1T2qiWOJ+JGyuso9myFgzIiCC4yeyHKuqBMMYyYtlnjbXH2mS8SF zqmKPQxTIC/hLoNBbQilbU4CdwLo/0aCfTxlBJ4vIRCw9o4SXYOLa9b4Gt+dU8v4d6+O vk5w== X-Gm-Message-State: AOJu0Yzg3BkTAWy3Sejd495u5jVKR/GNeHLcfVNir9uCVtl/MeoG/VHX tdFqMjEU76U5BxGJFN64Hxz47KLvmbZGquEONES9BqtTAg1tBWT2GHS2pDDNO0sl6q5kM8xPJ6V 86bkCB9QEBz4wlp43PNSK5zx6ISH6MLknVc5SS9A7zEQK0VhXKWzJV8eq1xwHgfQe0r7D3gsV7r zKJ83JcqbRoy24wBWgiYtjh2CyrQ== X-Google-Smtp-Source: AGHT+IFcS0b2L6CwNcAuaaxIJ0yPVF1XIP3tgzQU+rGCAQO+Un5l5gv5AKJ7m2pQ1hJxX6pAHEEMx7pv1Q== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:6a00:8c0b:b0:71d:ef26:2c6f with SMTP id d2e1a72fcca58-71def262d76mr15806b3a.1.1728350335998; Mon, 07 Oct 2024 18:18:55 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:27 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-2-tavip@google.com> Subject: [PATCH v2 01/25] fifo32: add peek function From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::44a; envelope-from=3f4gEZwUKCuAVCXKRIQQING.EQOSGOW-FGXGNPQPIPW.QTI@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.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 | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/include/qemu/fifo32.h b/include/qemu/fifo32.h index 4e9fd1b5ef..9de1807375 100644 --- a/include/qemu/fifo32.h +++ b/include/qemu/fifo32.h @@ -140,6 +140,34 @@ 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; + + buf = fifo8_peek_bufptr(&fifo->fifo, 4, &num); + if (num != 4) { + return ret; + } + + for (int 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 Tue Oct 8 01:18:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993909 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=sUmZs6x5; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMywD2QdSz1xth for ; Tue, 8 Oct 2024 12:23:56 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxysy-0008Cd-Kj; Mon, 07 Oct 2024 21:19:36 -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 <3gYgEZwUKCuIXEZMTKSSKPI.GSQUIQY-HIZIPRSRKRY.SVK@flex--tavip.bounces.google.com>) id 1sxysQ-0007br-5l for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:03 -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 <3gYgEZwUKCuIXEZMTKSSKPI.GSQUIQY-HIZIPRSRKRY.SVK@flex--tavip.bounces.google.com>) id 1sxysO-00006w-FD for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:01 -0400 Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-6e30cf0cf1bso16065357b3.0 for ; Mon, 07 Oct 2024 18:18:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350338; x=1728955138; 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=wyZg7kxpkNCds2EZflCHxHMwXfcdXxrO/ZcaHcLL39s=; b=sUmZs6x50LQ/pe4Gez4ZK7t8kjzZvn/cx2qAoJC/7Y4F68dzQ2xvg5k45/wjdGXgo3 hFQf/wA/gJMDCEmbwjZvVkLT1pCF9CcYNQz50G99FM2uXCZx57Db8ZQLDjWvdLu9qFQT ovBzXs1neqv3tzxBZce9oLOY7tmfUHv2RgCc3RbJlZH4rsWqQLF/aT7ccrIFGNrnYufX jIMQ9zzLKMsc57TWkNSR/qvyorhy+F9gQ3Jj93KlQJzgiVw2qwdwNDlQzNIpd1ps0MaM ZfsQsRSiBCoTu1ogZkiFizMVw9hIB36Ew55tHEq013wHhq03py+2Mj/uno8nxwVXKBIa ueKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350338; x=1728955138; 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=wyZg7kxpkNCds2EZflCHxHMwXfcdXxrO/ZcaHcLL39s=; b=oiE3LkJ3p75jGNwaF01xmFwjh718Hq5GsvpSZnLxLlwlLE0xCEt/7nbKSJSAA1IiiV EArxJDTWfmJKQ76KHEXLGw4awBb62z0T+94EYgwyQKhOR8IIEVMUIlkKjmcYSKeH4U9M gc9M30CMyq+HrPVAATxUw/hp8cIZ7Alqo51EjjW++W6jKy7BKzUKAUCwylfZlspmGEBZ JbI6XtKkXZJgi2CGR+BcvuimcswVN40kHl8pRtwMxU5PD3fHFVaoEs7P6OfSVigj/EP9 nYUgCB7W/1TG1cCJSKO0qD2ILJFN6TkE0IpCoCuoquNRaYkUVjKCPWeYPXzCBVk/m4EG gOTw== X-Gm-Message-State: AOJu0YymgggF4pwxu9UxSNvjHATwKkv4aLitwurhwsJ3lQluZN1sZrDd 8RjrgHoiWQ/LUmNnwiAWr70n4jx/VODidx0RG+iprZCM+GQnsn3Skfbx9rjfleLKVlk9RBZ/jbI vlMzmxV+xkRBItm+BxTJ4ITe/bb4X8liu5qsGB+cDgcsku26pGwK3Qav+55vnLT8ZgEQs1xwbNI T3tBHS28fJpxNz9cX8PL7cjwuIKw== X-Google-Smtp-Source: AGHT+IE3/W9CgSMU393ZW56+VU+vEEAMQd6ttBYHzgtNP0gr2mWHRr9OJi2xXWSJjWwG7FxSWygOJf1nyg== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a81:b513:0:b0:6e3:eab:18b1 with SMTP id 00721157ae682-6e30eab1934mr52557b3.1.1728350337999; Mon, 07 Oct 2024 18:18:57 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:28 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-3-tavip@google.com> Subject: [PATCH v2 02/25] tests/unit: add fifo32 tests From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::114a; envelope-from=3gYgEZwUKCuIXEZMTKSSKPI.GSQUIQY-HIZIPRSRKRY.SVK@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add push/pop and peek tests for fifo32. Signed-off-by: Octavian Purdila --- tests/unit/test-fifo.c | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/unit/test-fifo.c b/tests/unit/test-fifo.c index 14153c41fa..d0e05ba95c 100644 --- a/tests/unit/test-fifo.c +++ b/tests/unit/test-fifo.c @@ -13,6 +13,7 @@ #include "qemu/osdep.h" #include "migration/vmstate.h" #include "qemu/fifo8.h" +#include "qemu/fifo32.h" const VMStateInfo vmstate_info_uint32; const VMStateInfo vmstate_info_buffer; @@ -432,6 +433,53 @@ static void test_fifo8_pushpop(void) fifo8_destroy(&fifo); } +static void test_fifo32_pushpop(void) +{ + Fifo32 fifo; + uint32_t e; + + fifo32_create(&fifo, 2); + fifo32_push(&fifo, 0x11121314); + fifo32_push(&fifo, 0x21222324); + g_assert(fifo32_num_used(&fifo) == 2); + + e = fifo32_pop(&fifo); + g_assert(e == 0x11121314); + g_assert(fifo32_num_used(&fifo) == 1); + + e = fifo32_peek(&fifo); + g_assert(e == 0x21222324); + + g_assert(fifo32_num_used(&fifo) == 1); + fifo32_destroy(&fifo); +} + +static void test_fifo32_peek(void) +{ + Fifo32 fifo; + uint32_t e; + + fifo32_create(&fifo, 2); + fifo32_push(&fifo, 0x11121314); + fifo32_push(&fifo, 0x21222324); + g_assert(fifo32_num_used(&fifo) == 2); + + e = fifo32_peek(&fifo); + g_assert(e == 0x11121314); + g_assert(fifo32_num_used(&fifo) == 2); + + e = fifo32_pop(&fifo); + g_assert(e == 0x11121314); + g_assert(fifo32_num_used(&fifo) == 1); + + e = fifo32_peek(&fifo); + g_assert(e == 0x21222324); + g_assert(fifo32_num_used(&fifo) == 1); + + fifo32_destroy(&fifo); +} + + int main(int argc, char *argv[]) { g_test_init(&argc, &argv, NULL); @@ -445,5 +493,7 @@ int main(int argc, char *argv[]) g_test_add_func("/fifo8/peek_bufptr_wrap", test_fifo8_peek_bufptr_wrap); g_test_add_func("/fifo8/pop_bufptr", test_fifo8_pop_bufptr); g_test_add_func("/fifo8/pop_bufptr_wrap", test_fifo8_pop_bufptr_wrap); + g_test_add_func("/fifo32/pushpop", test_fifo32_pushpop); + g_test_add_func("/fifo32/peek", test_fifo32_peek); return g_test_run(); } From patchwork Tue Oct 8 01:18:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993911 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=sGyscZBv; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMywG1kgMz1xth for ; Tue, 8 Oct 2024 12:23:58 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxyt0-0008PT-Ui; Mon, 07 Oct 2024 21:19:39 -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 <3g4gEZwUKCuQZGbOVMUUMRK.IUSWKSa-JKbKRTUTMTa.UXM@flex--tavip.bounces.google.com>) id 1sxysT-0007ho-MG for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:06 -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 <3g4gEZwUKCuQZGbOVMUUMRK.IUSWKSa-JKbKRTUTMTa.UXM@flex--tavip.bounces.google.com>) id 1sxysR-00007M-8F for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:05 -0400 Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-690404fd230so29853237b3.3 for ; Mon, 07 Oct 2024 18:19:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350340; x=1728955140; 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=mOjYfJjVDbekrSS0dJ0e0WrdZI53XB9lrt52zwVXgdE=; b=sGyscZBvjMn8mHYUvroZ7MhL/wGAbDcDA8xQP0KsuzCzGssc8MWlpeZuqCyR68uh4r R3S0cJ8GYlzqbXdMFuNTtvOhUIwfFEZrYxV2yiNhHTG62qBdDCwspzAczEpotJPYjh7/ 0N7Bmss8EDN4AO9sdWPgVWFd52g+LQsZkMIGhoWvjYnddexxcfMit2A/jzdzrQ1+XW5M W86TRatIO5v3B97PpGLn8Ah85vb53O8+//MCYIGr7iRSvLQsIx8HWG7QGFusvS6b9C5j 8o1fxuiGAyvcHreJuhBpk3ePcPAwxpDbmNm5sWMWzzZUfTCUU3YmclQp5L5PzIiJmYms X2VQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350340; x=1728955140; 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=mOjYfJjVDbekrSS0dJ0e0WrdZI53XB9lrt52zwVXgdE=; b=TWF8zr2/Xq2SrYMYOPoXYoXiqqKWfKrX14BZaKvqu0i3IE3GE7cLHY6iBnzSuNkK1O EIIPRlNw1gYrFB5iuLPsKnWzrdPNCUKW3abB0YH8ijRpO+jRmLRjtVUTMK9z7v87ekCv oW1GIvP1+Au6GtbzwiBMt3HlGtZ7xMBEJU2iLuN7MOviNsUtkjTJg2H0EMmw/rk5w7bp sP0yxO7mwnY70BYlDFQVU5HXX1husETpnRq5mXlWcqCHzP6qERfgUekwVrk0hnjX2nrM cP+N9AV46amOP5CBeI1DBfgIYJ70Ey8Ry3im3xjuwT1aKJe3eXRIAvZKkQ16f/xEPt7p 0/sQ== X-Gm-Message-State: AOJu0YwitT7ibLwZyJB6kgVDfrg99W3SWSb110ChW2gw4MtGP3MEQvIG Usoil5FpyFmG7A2fYqLWn+wIIF6vvpVuxcZ9yc+Kld8NfjnMNdW6tauqmRZg4etCfiCN7ymEYbF av6uvTSTYFE9yUIdeIXUAlX9yexFvtGo/5M66pciynHeUPLdSEUdhg0WcLhp5talBun5VlQ1Eb4 SjLRzmns/cTwA2l7QZSE+QRWGIYA== X-Google-Smtp-Source: AGHT+IFXNoRKMbcr5g2Ch81E0fEb4jgg81eW3pnVWasxIKvPPjCZ2FzJEeKEMLdRIVBw6AvbjS4oRQIz9g== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a25:68ca:0:b0:e28:8f2c:73e6 with SMTP id 3f1490d57ef6-e289391ea39mr8605276.7.1728350339603; Mon, 07 Oct 2024 18:18:59 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:29 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-4-tavip@google.com> Subject: [PATCH v2 03/25] 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, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::114a; envelope-from=3g4gEZwUKCuQZGbOVMUUMRK.IUSWKSa-JKbKRTUTMTa.UXM@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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. Peripheral specific headers contains information such as register layout (using the qemu register fields infrastructure), register names, register write masks and register reset values, the latter using RegisterAccessInfo. Here is an excerpt from a generated header: #pragma once #include "hw/registerfields.h" /* Flexcomm */ #define FLEXCOMM_REGS_NO (1024) /* Peripheral Select and Flexcomm module ID */ REG32(FLEXCOMM_PSELID, 4088); /* Peripheral Select */ FIELD(FLEXCOMM_PSELID, PERSEL, 0, 3); /* No peripheral selected. */ #define FLEXCOMM_PSELID_PERSEL_NO_PERIPH_SELECTED 0 /* USART function selected */ #define FLEXCOMM_PSELID_PERSEL_USART 1 /* SPI function selected */ #define FLEXCOMM_PSELID_PERSEL_SPI 2 /* I2C */ #define FLEXCOMM_PSELID_PERSEL_I2C 3 /* I2S Transmit */ #define FLEXCOMM_PSELID_PERSEL_I2S_TRANSMIT 4 /* I2S Receive */ #define FLEXCOMM_PSELID_PERSEL_I2S_RECEIVE 5 ... #define FLEXCOMM_REGISTER_ACCESS_INFO_ARRAY(_name) \ struct RegisterAccessInfo _name[FLEXCOMM_REGS_NO] = { \ [0 ... FLEXCOMM_REGS_NO -1] = { \ .name = "", \ .addr = -1, \ }, \ [0x3FE] = { \ .name = "PSELID", \ .addr = 0xFF8, \ .ro = 0xFFFFFFF0, \ .reset = 0x101000, \ }, \ [0x3FF] = { \ .name = "PID", \ .addr = 0xFFC, \ .ro = 0xFFFFFFFF, \ .reset = 0x0, \ }, \ } The script has options to control which registers and fields should be generated. Board specific headers contains information about peripheral base register addresses. Signed-off-by: Stefan Stanacar [tavip: pylint fixes, generate layout with qemu register fields instead of bitfields, generate register names, romask and reset values, add options to control which register and fields are generated] Signed-off-by: Octavian Purdila --- meson.build | 4 + scripts/svd-gen-header.py | 415 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 419 insertions(+) create mode 100755 scripts/svd-gen-header.py diff --git a/meson.build b/meson.build index 33954b3eba..5127e67d93 100644 --- a/meson.build +++ b/meson.build @@ -3330,6 +3330,10 @@ tracetool_depends = files( 'scripts/tracetool/__init__.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/scripts/svd-gen-header.py b/scripts/svd-gen-header.py new file mode 100755 index 0000000000..7befa75421 --- /dev/null +++ b/scripts/svd-gen-header.py @@ -0,0 +1,415 @@ +#!/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 fnmatch +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(reg): + """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"[\[\]]", reg.name) + return (split[0], int(split[1]) if len(split) > 1 else 0) + + +def generate_comment(indent, text): + """Generate a comment block with for the given text with the given + indentation level. + + If possible, use a single line /* */ comment block, otherwise use + a multiline comment block. + + Newlines are preseved but tabs are not. + + """ + + # preserve new lines + text = text.replace("\n", " \n ") + text = text.replace(" ", " ") + + if len(text) + len("/* */") + len(" " * indent) <= 80 and "\n" not in text: + return f"{' '* indent}/* {text} */\n" + + out = " " * indent + "/*\n" + line = " " * indent + " *" + for word in re.split(r"[ ]", text): + if len(line) + len(word) >= 79 or word == "\n": + out += line + "\n" + line = " " * indent + " *" + if word != "\n": + line += " " + word + else: + line += " " + word + + out += line + "\n" + + out += " " * indent + " */\n" + return out + + +def get_fields(reg, dictionary): + """Return a list of fields from a register indexed dictionary. + + The dictionary keys may contain wildcards. + + """ + + for key in dictionary.keys(): + if fnmatch.fnmatch(reg, key): + return dictionary[key] + return None + + +def generate_reg(reg, dictionary): + """Check if the register should be generated""" + + if get_fields(reg, dictionary): + return True + return False + + +def skip_reg(reg, dictionary): + """Check if the register should be skipped""" + + for key in dictionary.keys(): + if fnmatch.fnmatch(reg, key) and dictionary[key] is None: + return True + return False + + +def match_field(reg, field, dictionary): + """Match a register and field in a dictionary indexed by registers + that contains a list of fields. + + Both the dictionary keys and the list of fields may contain wildcards. + + """ + fields = get_fields(reg, dictionary) + if not fields: + return False + for f in fields: + if fnmatch.fnmatch(field, f): + return True + return False + + +def generate_field(name, reg_name, field, shared): + """Generate register field.""" + + out = generate_comment(0, field.description) + if shared: + out += "SHARED_" + out += f"FIELD({name}_{reg_name}, {field.name}, " + out += f"{field.bitOffset}, {field.bitWidth});\n" + if hasattr(field, "enumeratedValues") and field.bitWidth > 1: + for enum in field.enumeratedValues.enumeratedValues: + enum_name = f"{name}_{reg_name}_{field.name}_{enum.name}" + out += generate_comment(0, enum.description) + out += f"#define {enum_name} {enum.value}\n" + return out + + +def generate_registers(name, periph, generate, skip): + """Generate register offsets and fields + + Use registerfield macros to define register offsets and fields for + a given peripheral. + + """ + + regs = sorted(periph.registers, key=lambda reg: reg.addressOffset) + out = generate_comment(0, periph.description) + out += f"#define {name}_REGS_NO ({regs[-1].addressOffset // 4 + 1})\n\n" + for reg in regs: + reg_name, reg_array_size = get_register_array_name_and_size(reg) + if not generate_reg(reg_name, generate): + continue + if skip_reg(reg_name, skip): + continue + out += generate_comment(0, reg.description) + if reg_array_size > 1: + for idx in range(0, reg_array_size): + addr = reg.addressOffset + idx * reg.size // 8 + out += f"REG32({name}_{reg_name}{idx}, 0x{addr:X});\n" + else: + addr = reg.addressOffset + out += f"REG32({name}_{reg_name}, 0x{addr:X});\n" + for field in reg.fields: + if not match_field(reg_name, field.name, generate): + continue + if match_field(reg_name, field.name, skip): + continue + out += generate_field( + name, reg_name, field, True if reg_array_size > 1 else False + ) + out += "\n" + + return out + + +def create_wmask(reg): + """Generate write mask for a register. + + Generate a mask with all bits that are writable set to 1 + """ + + wmask = 0 + fields = sorted(reg.fields, key=lambda field: field.bitOffset) + if len(fields) > 0: + for field in fields: + if field.access != pysvd.type.access.read_only: + wmask |= ((1 << field.bitWidth) - 1) << field.bitOffset + else: + if reg.access != pysvd.type.access.read_only: + wmask = 0xFFFFFFFF + return wmask + + +def create_romask(reg): + """Generate write mask for a register. + + Generate a mask with all bits that are readonly set to 1 + """ + + return ~create_wmask(reg) & 0xFFFFFFFF + + +def generate_register_access_info(name, periph): + """Generate RegisterAccessInfo array macro""" + + out = f"\n#define {name}_REGISTER_ACCESS_INFO_ARRAY(_name) \\\n" + out += f" struct RegisterAccessInfo _name[{name}_REGS_NO] = {{ \\\n" + out += f" [0 ... {name}_REGS_NO - 1] = {{ \\\n" + out += ' .name = "", \\\n' + out += " .addr = -1, \\\n" + out += " }, \\\n" + for reg in periph.registers: + reg_name, reg_array_size = get_register_array_name_and_size(reg) + if reg_array_size > 1: + for idx in range(0, reg_array_size): + addr = reg.addressOffset + idx * reg.size // 8 + out += f" [0x{addr // 4:X}] = {{ \\\n" + out += f' .name = "{reg_name}{idx}", \\\n' + out += f" .addr = 0x{addr:X}, \\\n" + out += f" .ro = 0x{create_romask(reg):X}, \\\n" + out += f" .reset = 0x{reg.resetValue:X}, \\\n" + out += " }, \\\n" + else: + out += f" [0x{reg.addressOffset // 4:X}] = {{ \\\n" + out += f' .name = "{reg_name}", \\\n' + out += f" .addr = 0x{reg.addressOffset:X}, \\\n" + out += f" .ro = 0x{create_romask(reg):X}, \\\n" + out += f" .reset = 0x{reg.resetValue:X}, \\\n" + out += " }, \\\n" + out += " }\n" + + return out + + +def generate_peripheral_header(periph, name, args): + """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 + + """ + + generate = {} + for reg in args.fields.split(): + if reg.find(":") > 0: + reg, fields = reg.split(":") + generate[reg] = fields.split(",") + else: + generate[reg] = ["*"] + + skip = {} + for reg in args.no_fields.split(): + if reg.find(":") > 0: + reg, fields = reg.split(":") + skip[reg] = fields.split(",") + else: + skip[reg] = None + + out = generate_registers(name, periph, generate, skip) + + out += generate_register_access_info(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, + ) + parser.add_argument( + "--fields", + help="list of registers and fields that should be generated " + "in the following format 'REG[:FIELDS] ...' " + "where FIELDS is a list of comma separated fields that can be " + "empty; both regsiters and fields can be matched with wildcards; " + "'REG' is an alias for 'REG:*';", + required=False, + default="*:*", + ) + parser.add_argument( + "--no-fields", + type=str, + help="list of register and fields that should not be generated " + "in the following format 'REG[:FIELDS] ...' " + "where FIELDS is a list of comma separated fields that can be " + "empty; both regsiters and fields can be matched with wildcards; " + "note that 'REG' will not generate neither the register nor its " + "fields while REG: will generate the register but none of its fields", + required=False, + default=":", + ) + + args = parser.parse_args() + + node = xml.etree.ElementTree.parse(args.input).getroot() + svd = pysvd.element.Device(node) + + # Write license header + header = svd.licenseText.strip() + header += f"\n\nAutomatically generated by {os.path.basename(__file__)} " + header += f"from {os.path.basename(args.input)}" + out = generate_comment(0, header) + + # 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 += '#include "hw/register.h"\n\n' + out += generate_peripheral_header( + periph, + args.type_name if args.type_name else periph.name, + args, + ) + 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 Tue Oct 8 01:18:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993899 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=QB1Wmc+u; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMysY2TkRz1xth for ; Tue, 8 Oct 2024 12:21:37 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxyt9-00013Z-W7; Mon, 07 Oct 2024 21:19:48 -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 <3hYgEZwUKCuYbIdQXOWWOTM.KWUYMUc-LMdMTVWVOVc.WZO@flex--tavip.bounces.google.com>) id 1sxysU-0007hr-11 for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:07 -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 <3hYgEZwUKCuYbIdQXOWWOTM.KWUYMUc-LMdMTVWVOVc.WZO@flex--tavip.bounces.google.com>) id 1sxysR-00007l-QG for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:05 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id 3f1490d57ef6-e24b43799e9so4992183276.2 for ; Mon, 07 Oct 2024 18:19:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350341; x=1728955141; 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=SRJtDmmyu0p+iYadPI5KNYfcB0hfVULXlSFU/u3kO34=; b=QB1Wmc+uxm4GciIa68XIdQEZga91s+QCkalN+t2ZsDq6kZPP/3APN6A9O35CBayjUO zodkORkCzApKvGhjUoTHEWi2Z9iLze4ed4d6dJ7r1xcRUgjoPgXfOnENCDGoJI/0rupg QgHU1/N4H0L2BVYwSbZ6amS6bBozwQpVvHxE0YhE7BSMqH95yVRl88GmzC5C0peExo25 9LnHwK0IMKMFVHksjYs/n37V3HyKmTmXJb/KLSXwkt7fsmetA1w5109D5WJdRtcWmxkV NNjIQmWaR03yITJ9pccw1P+LiiS5Qx3iUWP+Mt9pv+5M7MdXK1SUA3AJIUWLcyPt5QCI SH2w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350341; x=1728955141; 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=SRJtDmmyu0p+iYadPI5KNYfcB0hfVULXlSFU/u3kO34=; b=HwJQnXpOrxdg1SFgnYV0BIf77L6IvxwY3UWhK+Ql6/unQoQrhlAJKNx62PGPN4NRwS AZpFqO2+HchZ+ZIh2S31Oackp7tYMp3BIrgz2j7EZrpdofw0ofu0+0x25FAyCtkTbe1N OWn9yYAyZRVaV+tSsoeEocbyW1snxfokiqCfBmh9RxCyXqMSyVcxn4y94GFg58F2vZAb XBkEfA2KUvsD/QgN4QKczEaL5yVgXjyMjd1RAwSBJS41ULvax/wYNN5lR8F9iPuArhPs UkFio5/7UMJt4uOvMyciGgYXMlEzsHBvZxqv4w6VQXKP0yED/SfAmDgqj2vhje3LYGwY ZmAw== X-Gm-Message-State: AOJu0Yw5KZdhgc8CeQ/bOGuBNa0TYRELjUvc9uIPORD9NkMvdOCRGS0y 98I7A/Zy6JiZPPZWaXEOsG/vVGPU5G8AOEIxc+fa1Bw0B5vzIMyZYwJzPu6UlxLe5GXwcRo1U04 Sr9bfIdsQxSBxtaVlx1OSunq29JIiwcWM6NNsPsY/oUU14e1xNST+j+5i0vqCeWZ9Kx8wAtt8m6 MV/Q+ByD7pvPiXj8b6q1VgwmqoCQ== X-Google-Smtp-Source: AGHT+IGwqe4AUonStZiddHG8zloPnHdUO/i4be9rIUYNtKyu6KDWl1Kh9fMZKqdIY53NIoUzTLTHblLNEg== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:6902:d49:b0:e05:6532:166 with SMTP id 3f1490d57ef6-e28936c0dabmr30058276.1.1728350341057; Mon, 07 Oct 2024 18:19:01 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:30 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-5-tavip@google.com> Subject: [PATCH v2 04/25] Add mcux-soc-svd subproject From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3hYgEZwUKCuYbIdQXOWWOTM.KWUYMUc-LMdMTVWVOVc.WZO@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add mcux-soc-svd subproject that contains SVD files that are going to be used to generate C header with register layout definitions and other helpers to create device models. Guard the subproject by a configuration option since it is rarely going to be used - whenever new headers will be generated. It is unlikely that already generated headers will be updated, with the exception of minor hardware revisions. Also export the rt595 SVD file which is going to be used by subsequent patches. TBD: switch to a qemu gitlab fork before merge Signed-off-by: Octavian Purdila --- hw/arm/svd/meson.build | 4 ++++ meson_options.txt | 3 +++ scripts/meson-buildoptions.sh | 4 ++++ subprojects/.gitignore | 1 + subprojects/mcux-soc-svd.wrap | 5 +++++ subprojects/packagefiles/mcux-soc-svd/meson.build | 5 +++++ 6 files changed, 22 insertions(+) create mode 100644 hw/arm/svd/meson.build create mode 100644 subprojects/mcux-soc-svd.wrap create mode 100644 subprojects/packagefiles/mcux-soc-svd/meson.build diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build new file mode 100644 index 0000000000..7d83d2ccbc --- /dev/null +++ b/hw/arm/svd/meson.build @@ -0,0 +1,4 @@ +if get_option('mcux-soc-svd') + mcux_soc_svd = subproject('mcux-soc-svd') + rt595 = mcux_soc_svd.get_variable('rt595') +endif diff --git a/meson_options.txt b/meson_options.txt index 5ee1d95c9c..87a412194c 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -373,3 +373,6 @@ option('hexagon_idef_parser', type : 'boolean', value : true, option('x86_version', type : 'combo', choices : ['0', '1', '2', '3', '4'], value: '1', description: 'tweak required x86_64 architecture version beyond compiler default') + +option('mcux-soc-svd', type : 'boolean', value : false, + description: 'enable targets to generate C headers from mcux-soc-svd') diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 3bee1c56df..0918eb1ab2 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -41,6 +41,8 @@ meson_options_help() { printf "%s\n" ' --enable-lto Use link time optimization' printf "%s\n" ' --enable-malloc=CHOICE choose memory allocator to use [system] (choices:' printf "%s\n" ' jemalloc/system/tcmalloc)' + printf "%s\n" ' --enable-mcux-soc-svd enable targets to generate C headers from mcux-' + printf "%s\n" ' soc-svd' printf "%s\n" ' --enable-module-upgrades try to load modules from alternate paths for' printf "%s\n" ' upgrades' printf "%s\n" ' --enable-rng-none dummy RNG, avoid using /dev/(u)random and' @@ -393,6 +395,8 @@ _meson_option_parse() { --enable-malloc-trim) printf "%s" -Dmalloc_trim=enabled ;; --disable-malloc-trim) printf "%s" -Dmalloc_trim=disabled ;; --mandir=*) quote_sh "-Dmandir=$2" ;; + --enable-mcux-soc-svd) printf "%s" -Dmcux-soc-svd=true ;; + --disable-mcux-soc-svd) printf "%s" -Dmcux-soc-svd=false ;; --enable-membarrier) printf "%s" -Dmembarrier=enabled ;; --disable-membarrier) printf "%s" -Dmembarrier=disabled ;; --enable-module-upgrades) printf "%s" -Dmodule_upgrades=true ;; diff --git a/subprojects/.gitignore b/subprojects/.gitignore index adca0266be..bca8693ef4 100644 --- a/subprojects/.gitignore +++ b/subprojects/.gitignore @@ -6,3 +6,4 @@ /keycodemapdb /libvfio-user /slirp +/mcux-soc-svd diff --git a/subprojects/mcux-soc-svd.wrap b/subprojects/mcux-soc-svd.wrap new file mode 100644 index 0000000000..80d18e8561 --- /dev/null +++ b/subprojects/mcux-soc-svd.wrap @@ -0,0 +1,5 @@ +[wrap-git] +url = https://github.com/nxp-mcuxpresso/mcux-soc-svd/ +revision = 7f6f9ef7420144fe14cd9bc4d8e0e3523232da04 +patch_directory = mcux-soc-svd +depth = 1 diff --git a/subprojects/packagefiles/mcux-soc-svd/meson.build b/subprojects/packagefiles/mcux-soc-svd/meson.build new file mode 100644 index 0000000000..37c537d040 --- /dev/null +++ b/subprojects/packagefiles/mcux-soc-svd/meson.build @@ -0,0 +1,5 @@ +project('mcux-soc-svd') + +fs = import('fs') + +rt595 = fs.copyfile('MIMXRT595S/MIMXRT595S_cm33.xml') From patchwork Tue Oct 8 01:18:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993927 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=e7tZ1XEC; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMyyK2t8Gz1xsn for ; Tue, 8 Oct 2024 12:25:45 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxytK-0002Hd-4R; Mon, 07 Oct 2024 21:19:59 -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 <3h4gEZwUKCugdKfSZQYYQVO.MYWaOWe-NOfOVXYXQXe.YbQ@flex--tavip.bounces.google.com>) id 1sxysY-0007mG-7s for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:13 -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 <3h4gEZwUKCugdKfSZQYYQVO.MYWaOWe-NOfOVXYXQXe.YbQ@flex--tavip.bounces.google.com>) id 1sxysT-000087-Au for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:09 -0400 Received: by mail-pg1-x54a.google.com with SMTP id 41be03b00d2f7-7163489149fso5904197a12.3 for ; Mon, 07 Oct 2024 18:19:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350343; x=1728955143; 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=ALEsA5QASCJbactGuKnulwp5BQq6AgOVeo/aeexBENk=; b=e7tZ1XECUozXLGNiUWhFPet0tCpnnNe4TjTrZva0sseGYa1yDePdCx/8blRokeuQXf vOC+GRt7fk83nlzYBMbqIARPL92MLVKBpsL/wSh6wxjb88uZkMicD4Jhfr/yAI6f8zeC BDR1z68GD1KM5TCfTNbZ3zpv4ycCcfqrEo4Rx7f2lev1IyUMnkDpEZbEGsYtDszQVul4 2BnsvvgDFK1R/6lXDLjUBAWt0zlp+8512+66KHNQB3KtR5p07a+/T8NCJA1OUQMH3ut3 d+OIIVfLdH2V6NG+T4uAiR9zko1g/JlzcfYCRotWKoFFLAzv+cF5GAhCNm2jnQPDg4/2 68qg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350343; x=1728955143; 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=ALEsA5QASCJbactGuKnulwp5BQq6AgOVeo/aeexBENk=; b=bj7M27z+kSLXh6fv73gkqEAUCeOoU1hiZYEb+9+JF78oGzXU8UYIzHnoeMs2c9FktG vtlm2SYoBcjm5ZhYLepRfd1dGPJBH797coSY3CWegkGeDiq+eLsgKuEKk+GZWVYOqmO5 s9b8g9U1RcwyO7eBqQQCOkFdQ7Blt1FTZDpA5oasG0YzQ4iKAZC1CCYIEAa3/JfYP7+D p8URZo7FHxNgnDjbjRtJ/BOYYzNBk+toEFYLfTNTY6korcCQn8crW6mbDo746cAQHF3D /zCQCUdCF2DnZItC9Yj5X8yyXoNyKPYDm4CRxzSFrGr/BoKUP/HZy2jNfHeWBoZ0Tbai ZAVg== X-Gm-Message-State: AOJu0Ywy+7DQnANjLAwPXcUNeUP4X6beaKsu0moX7L2eS9w0WF6fDl2p doctJF2GYn8EEct1Zc1Cq6ynthzkYoqxWeQL/U6Ud/+gnc4ckQEr8ro4XEGgC9tuSToP276NbgO k3jT9tZwmUf9xYJnZ2TWLfZgTJD4Lwe8eFpBsmtSaxmgJ4WszFkBQd3lsjrLm5dT0+FxXKVx9mX 91imyIv2Vocq2BfFanw3ZIYeqL9w== X-Google-Smtp-Source: AGHT+IEIb4sVVYf9Xihwanz1RHGbXZOTJR1mNeoEZMZVFcJC0mbKsFiasSizbGv4idJ/j2UV04Srj0a4VA== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a63:d147:0:b0:7d8:449f:1319 with SMTP id 41be03b00d2f7-7e9e5779f24mr20071a12.0.1728350343119; Mon, 07 Oct 2024 18:19:03 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:31 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-6-tavip@google.com> Subject: [PATCH v2 05/25] hw/misc: add support for flexcomm From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::54a; envelope-from=3h4gEZwUKCugdKfSZQYYQVO.MYWaOWe-NOfOVXYXQXe.YbQ@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add support for NXP's FLEXCOMM device model. FLEXCOMM is a generic serial communication module which support multiple functions: UART, SPI and I2C. These are configurable at runtime. An abstract FlexcomFunction class is created that will be extended for specific functions. Each function has a dedicated overlapped MemoryRegion that it is going to be activated when that particular function is selected. A generic MemoryRegion is used to map generic registers (PSELID, PID) that is always active but has a lower priority. The function memory region is trimed to not include the generic registers. The FlexcommFunction object also gets access to the (non-concurrently) shared register backstore. The patch includes an automatically generated header which contains the register layout and helpers. The header can be regenerated with the svd-flexcomm target when the build is configured with --enable-mcux-soc-svd. Signed-off-by: Octavian Purdila --- include/hw/arm/svd/flexcomm.h | 70 ++++++ include/hw/misc/flexcomm.h | 49 +++++ include/hw/misc/flexcomm_function.h | 47 ++++ hw/misc/flexcomm.c | 319 ++++++++++++++++++++++++++++ hw/arm/meson.build | 2 + hw/arm/svd/meson.build | 3 + hw/misc/Kconfig | 3 + hw/misc/meson.build | 2 + hw/misc/trace-events | 5 + 9 files changed, 500 insertions(+) create mode 100644 include/hw/arm/svd/flexcomm.h create mode 100644 include/hw/misc/flexcomm.h create mode 100644 include/hw/misc/flexcomm_function.h create mode 100644 hw/misc/flexcomm.c diff --git a/include/hw/arm/svd/flexcomm.h b/include/hw/arm/svd/flexcomm.h new file mode 100644 index 0000000000..564180bd02 --- /dev/null +++ b/include/hw/arm/svd/flexcomm.h @@ -0,0 +1,70 @@ +/* + * Copyright 2016-2023 NXP SPDX-License-Identifier: BSD-3-Clause + * + * Automatically generated by svd-gen-header.py from MIMXRT595S_cm33.xml + */ +#pragma once + +#include "hw/register.h" + +/* Flexcomm */ +#define FLEXCOMM_REGS_NO (1024) + +/* Peripheral Select and Flexcomm module ID */ +REG32(FLEXCOMM_PSELID, 0xFF8); +/* Peripheral Select */ +FIELD(FLEXCOMM_PSELID, PERSEL, 0, 3); +/* No peripheral selected. */ +#define FLEXCOMM_PSELID_PERSEL_NO_PERIPH_SELECTED 0 +/* USART function selected */ +#define FLEXCOMM_PSELID_PERSEL_USART 1 +/* SPI function selected */ +#define FLEXCOMM_PSELID_PERSEL_SPI 2 +/* I2C */ +#define FLEXCOMM_PSELID_PERSEL_I2C 3 +/* I2S Transmit */ +#define FLEXCOMM_PSELID_PERSEL_I2S_TRANSMIT 4 +/* I2S Receive */ +#define FLEXCOMM_PSELID_PERSEL_I2S_RECEIVE 5 +/* Lock the peripheral select */ +FIELD(FLEXCOMM_PSELID, LOCK, 3, 1); +/* USART present indicator */ +FIELD(FLEXCOMM_PSELID, USARTPRESENT, 4, 1); +/* SPI present indicator */ +FIELD(FLEXCOMM_PSELID, SPIPRESENT, 5, 1); +/* I2C present indicator */ +FIELD(FLEXCOMM_PSELID, I2CPRESENT, 6, 1); +/* I2S Present */ +FIELD(FLEXCOMM_PSELID, I2SPRESENT, 7, 1); +/* Flexcomm ID */ +FIELD(FLEXCOMM_PSELID, ID, 12, 20); + +/* Peripheral Identification */ +REG32(FLEXCOMM_PID, 0xFFC); +/* Minor revision of module implementation */ +FIELD(FLEXCOMM_PID, Minor_Rev, 8, 4); +/* Major revision of module implementation */ +FIELD(FLEXCOMM_PID, Major_Rev, 12, 4); +/* Module identifier for the selected function */ +FIELD(FLEXCOMM_PID, ID, 16, 16); + + +#define FLEXCOMM_REGISTER_ACCESS_INFO_ARRAY(_name) \ + struct RegisterAccessInfo _name[FLEXCOMM_REGS_NO] = { \ + [0 ... FLEXCOMM_REGS_NO - 1] = { \ + .name = "", \ + .addr = -1, \ + }, \ + [0x3FE] = { \ + .name = "PSELID", \ + .addr = 0xFF8, \ + .ro = 0xFFFFFFF0, \ + .reset = 0x101000, \ + }, \ + [0x3FF] = { \ + .name = "PID", \ + .addr = 0xFFC, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + } diff --git a/include/hw/misc/flexcomm.h b/include/hw/misc/flexcomm.h new file mode 100644 index 0000000000..ea0fe77f26 --- /dev/null +++ b/include/hw/misc/flexcomm.h @@ -0,0 +1,49 @@ +/* + * 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 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 + +#define TYPE_FLEXCOMM "flexcomm" +OBJECT_DECLARE_SIMPLE_TYPE(FlexcommState, FLEXCOMM); + +struct FlexcommState { + SysBusDevice parent_obj; + + MemoryRegion container; + MemoryRegion mmio; + uint32_t regs[FLEXCOMM_REGS_NO]; + uint32_t functions; + qemu_irq irq; + bool irq_state; +}; + +#endif /* HW_FLEXCOMM_H */ diff --git a/include/hw/misc/flexcomm_function.h b/include/hw/misc/flexcomm_function.h new file mode 100644 index 0000000000..e498976927 --- /dev/null +++ b/include/hw/misc/flexcomm_function.h @@ -0,0 +1,47 @@ +/* + * 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_FUNCTION_H +#define HW_FLEXCOMM_FUNCTION_H + +#include "qemu/fifo32.h" +#include "hw/sysbus.h" + +#define TYPE_FLEXCOMM_FUNCTION "flexcomm-function" +OBJECT_DECLARE_TYPE(FlexcommFunction, FlexcommFunctionClass, FLEXCOMM_FUNCTION); + +struct FlexcommFunction { + SysBusDevice parent_obj; + + MemoryRegion mmio; + uint32_t *regs; +}; + +typedef void (*FlexcommFunctionSelect)(FlexcommFunction *f, bool selected); + +struct FlexcommFunctionClass { + SysBusDeviceClass parent_class; + + const MemoryRegionOps *mmio_ops; + const char *name; + FlexcommFunctionSelect select; +}; + +static inline void flexcomm_select(FlexcommFunction *obj, bool selected) +{ + FlexcommFunctionClass *klass = FLEXCOMM_FUNCTION_GET_CLASS(obj); + + klass->select(obj, selected); +} + +void flexcomm_set_irq(FlexcommFunction *f, bool irq); + +#endif /* HW_FLEXCOMM_FUNCTION_H */ diff --git a/hw/misc/flexcomm.c b/hw/misc/flexcomm.c new file mode 100644 index 0000000000..2337fb814c --- /dev/null +++ b/hw/misc/flexcomm.c @@ -0,0 +1,319 @@ +/* + * 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 "migration/vmstate.h" +#include "hw/misc/flexcomm.h" + +#define REG(s, reg) (s->regs[R_FLEXCOMM_##reg]) +#define RF_WR(s, reg, field, val) \ + ARRAY_FIELD_DP32(s->regs, FLEXCOMM_##reg, field, val) +#define RF_RD(s, reg, field) \ + ARRAY_FIELD_EX32(s->regs, FLEXCOMM_##reg, field) + +#define modname "FLEXCOMM" + +#define FLEXCOMM_FUNC_MMIO_SIZE \ + ((FLEXCOMM_REGS_NO - 2) * sizeof(uint32_t)) + +static const FLEXCOMM_REGISTER_ACCESS_INFO_ARRAY(reg_info); + +static inline bool has_function(FlexcommState *s, int function) +{ + return s->functions & (1 << function); +} + +static inline int persel_to_function(FlexcommState *s) +{ + switch (RF_RD(s, PSELID, 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) +{ + FlexcommFunction *obj[] = { + FLEXCOMM_FUNCTION(&s->usart), + FLEXCOMM_FUNCTION(&s->spi), + FLEXCOMM_FUNCTION(&s->i2c), + }; + int f = persel_to_function(s); + + if (f >= 0 && f < ARRAY_SIZE(obj)) { + flexcomm_select(obj[f], selected); + } +} + +static void flexcomm_reset_enter(Object *o, ResetType type) +{ + FlexcommState *s = FLEXCOMM(o); + + trace_flexcomm_reset(); + + flexcomm_func_select(s, false); + + for (int i = 0; i < FLEXCOMM_REGS_NO; i++) { + hwaddr addr = reg_info[i].addr; + + if (addr != -1) { + struct RegisterInfo ri = { + .data = &s->regs[addr / 4], + .data_size = 4, + .access = ®_info[i], + }; + + register_reset(&ri); + } + } + + RF_WR(s, PSELID, USARTPRESENT, has_function(s, FLEXCOMM_FUNC_USART)); + RF_WR(s, PSELID, SPIPRESENT, has_function(s, FLEXCOMM_FUNC_SPI)); + RF_WR(s, PSELID, I2CPRESENT, has_function(s, FLEXCOMM_FUNC_I2C)); + RF_WR(s, PSELID, I2SPRESENT, has_function(s, FLEXCOMM_FUNC_I2S)); + + s->irq_state = false; +} + +static void flexcomm_reset_exit(Object *o, ResetType type) +{ + FlexcommState *s = FLEXCOMM(o); + + 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; + const struct RegisterAccessInfo *rai = ®_info[addr / 4]; + + switch (addr) { + case A_FLEXCOMM_PSELID: + case A_FLEXCOMM_PID: + { + *data = s->regs[addr / 4]; + break; + } + default: + return MEMTX_ERROR; + } + + trace_flexcomm_reg_read(DEVICE(s)->id, rai->name, 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; + const struct RegisterAccessInfo *rai = ®_info[addr / 4]; + struct RegisterInfo ri = { + .data = &s->regs[addr / 4], + .data_size = 4, + .access = rai, + }; + + trace_flexcomm_reg_write(DEVICE(s)->id, rai->name, addr, value); + + switch (addr) { + case A_FLEXCOMM_PID: + /* RO register, nothing do to */ + break; + case A_FLEXCOMM_PSELID: + { + if (RF_RD(s, PSELID, LOCK)) { + break; + } + + flexcomm_func_select(s, false); + + register_write(&ri, value, ~0, modname, false); + + if (flexcomm_check_function(s) < 0) { + RF_WR(s, PSELID, PERSEL, 0); + break; + } + + flexcomm_func_select(s, true); + break; + } + default: + return MEMTX_ERROR; + } + + return ret; +} + + +static const MemoryRegionOps flexcomm_ops = { + .read_with_attrs = flexcomm_reg_read, + .write_with_attrs = flexcomm_reg_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +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(&s->container, obj, "container", sizeof(s->regs)); + memory_region_init_io(&s->mmio, obj, &flexcomm_ops, s, + TYPE_FLEXCOMM, sizeof(s->regs)); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->container); + sysbus_init_irq(sbd, &s->irq); +} + +static void flexcomm_func_realize_and_unref(FlexcommFunction *f, Error **errp) +{ + FlexcommState *s = FLEXCOMM(OBJECT(f)->parent); + FlexcommFunctionClass *fc = FLEXCOMM_FUNCTION_GET_CLASS(f); + + f->regs = s->regs; + memory_region_add_subregion_overlap(&s->container, 0, &f->mmio, 0); + DEVICE(f)->id = g_strdup_printf("%s-%s", DEVICE(s)->id, fc->name); + sysbus_realize_and_unref(SYS_BUS_DEVICE(f), errp); + memory_region_set_enabled(&f->mmio, false); +} + +static void flexcomm_realize(DeviceState *dev, Error **errp) +{ + FlexcommState *s = FLEXCOMM(dev); + + memory_region_add_subregion_overlap(&s->container, 0, &s->mmio, -1); +} + +static const VMStateDescription vmstate_flexcomm = { + .name = "flexcomm", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, FlexcommState, FLEXCOMM_REGS_NO), + VMSTATE_BOOL(irq_state, FlexcommState), + VMSTATE_FIFO32(rx_fifo, FlexcommState), + VMSTATE_FIFO32(tx_fifo, FlexcommState), + VMSTATE_END_OF_LIST() + } +}; + +static void flexcomm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.enter = flexcomm_reset_enter; + rc->phases.exit = flexcomm_reset_exit; + device_class_set_props(dc, flexcomm_properties); + dc->realize = flexcomm_realize; + dc->vmsd = &vmstate_flexcomm; +} + +void flexcomm_set_irq(FlexcommFunction *f, bool irq) +{ + FlexcommState *s = FLEXCOMM(OBJECT(f)->parent); + + if (s->irq_state != irq) { + trace_flexcomm_irq(DEVICE(s)->id, irq); + qemu_set_irq(s->irq, irq); + s->irq_state = irq; + } +} + +static void flexcomm_function_select(FlexcommFunction *f, bool selected) +{ + FlexcommFunctionClass *fc = FLEXCOMM_FUNCTION_GET_CLASS(f); + + memory_region_set_enabled(&f->mmio, selected); +} + +static void flexcomm_function_init(Object *obj) +{ + FlexcommFunctionClass *fc = FLEXCOMM_FUNCTION_GET_CLASS(obj); + FlexcommFunction *f = FLEXCOMM_FUNCTION(obj); + + memory_region_init_io(&f->mmio, obj, fc->mmio_ops, obj, fc->name, + FLEXCOMM_FUNC_MMIO_SIZE); +} + +static void flexcomm_function_class_init(ObjectClass *klass, void *data) +{ + FlexcommFunctionClass *fc = FLEXCOMM_FUNCTION_CLASS(klass); + + fc->select = flexcomm_function_select; +} + +static const TypeInfo flexcomm_types[] = { + { + .name = TYPE_FLEXCOMM, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(FlexcommState), + .instance_init = flexcomm_init, + .class_init = flexcomm_class_init, + }, + { + .name = TYPE_FLEXCOMM_FUNCTION, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(FlexcommFunction), + .abstract = true, + .class_size = sizeof(FlexcommFunctionClass), + .instance_init = flexcomm_function_init, + .class_init = flexcomm_function_class_init, + }, +}; + +DEFINE_TYPES(flexcomm_types); diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 490234b3b8..83e4aea10e 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -73,3 +73,5 @@ system_ss.add(when: 'CONFIG_VERSATILE', if_true: files('versatilepb.c')) system_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c')) hw_arch += {'arm': arm_ss} + +subdir('svd') diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build index 7d83d2ccbc..4b0bbbbbdc 100644 --- a/hw/arm/svd/meson.build +++ b/hw/arm/svd/meson.build @@ -1,4 +1,7 @@ if get_option('mcux-soc-svd') mcux_soc_svd = subproject('mcux-soc-svd') rt595 = mcux_soc_svd.get_variable('rt595') + run_target('svd-flexcomm', command: svd_gen_header + + [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/flexcomm.h', + '-p', 'FLEXCOMM0', '-t', 'FLEXCOMM']) endif 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/meson.build b/hw/misc/meson.build index a2951951b5..0d901b9c65 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -151,3 +151,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 1be0717c0c..419879fd65 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -362,3 +362,8 @@ aspeed_sli_read(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx aspeed_sliio_write(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32 aspeed_sliio_read(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32 +# 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" From patchwork Tue Oct 8 01:18:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993907 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=R+dbq+lY; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMyw936lpz1xth for ; Tue, 8 Oct 2024 12:23:53 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxytB-0001Gu-JQ; Mon, 07 Oct 2024 21:19:49 -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 <3iIgEZwUKCukeLgTaRZZRWP.NZXbPXf-OPgPWYZYRYf.ZcR@flex--tavip.bounces.google.com>) id 1sxysY-0007mH-8C for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:15 -0400 Received: from mail-pf1-x449.google.com ([2607:f8b0:4864:20::449]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3iIgEZwUKCukeLgTaRZZRWP.NZXbPXf-OPgPWYZYRYf.ZcR@flex--tavip.bounces.google.com>) id 1sxysV-00008Z-4u for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:08 -0400 Received: by mail-pf1-x449.google.com with SMTP id d2e1a72fcca58-71e11abb22aso517563b3a.1 for ; Mon, 07 Oct 2024 18:19:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350345; x=1728955145; 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=mYb8OnCeZQrVX3cX0gw+0rgqxbLbcVi8KOrSlVTkt1w=; b=R+dbq+lYPKBxoShJVGaECVHtrXWjZzyeL7InCQCZ+Qj0EgFmQTkodR+QRqOUAowVa8 ZbH9shwsQ4mThB9EgjYZrslSSBTb+ZlCdlJdCuSB9I3DizhOELaSwNaTGkSZ1L40cDGi S63PVlsC3lgMjRypOkldSc8DqSvKFpMDdkmIbXHAl9yoTPbj9almi8UE/cxV5LxdBiO0 /Wy/HsA3EhJV8YFaNXLwrYqnjE5CMuAjeIOIkTnY//xeRfuTV5YrEl2pQGl13LmZjlxc u8nel40foteYKxO7WdJN7JDd3MFtUfPux72NbhYSZaIIW3dZU1KMB7wdb9C6FRpkGLgi H58A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350345; x=1728955145; 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=mYb8OnCeZQrVX3cX0gw+0rgqxbLbcVi8KOrSlVTkt1w=; b=GHjD8GiqGS9oF0jg7sb99hk0yRlt/ojKP1rSgPo4Sfbfc3vP9HO/feXKer+iZH6eg3 W2VVQwvvumvd9xRSRnJsF7plMGiA0WGB32OzTZTl8ykGdS8PH9zoU53AMbw1R8ZvLjve NhUrkcmPA6sSie+d7nNaput2BA59j3ymEW8eWJpN/xWxT8kXfmF2c1JCjNJPcOkvtJs6 vpUOhiB5a8HMnUv9e20u6n0u60OsaodSw9eQnVsMAwk1k12GFTxmzeIQTYZDuu8iGT4g jlNstYOa/XriuF6tpLd+FYxiwtxzK4PYg0bR0SkHFReo76xUYNr6OPVkSReSqgE640jv h04A== X-Gm-Message-State: AOJu0YyfgC2Q743aF0Enq6syaEsHkQq+jPVTw7gcwY++y/xIgxuFV2wS rnaszC5IO1eVYp+imUXnlmoXfhddb6+omN3KIiqeK2Wr/yDw7BlFUA1/6bmdPq043MmKDVcg2x+ X4jeRNaWo+L53rTnqSCuFwa/hk//C/JzfKEGph+T7NLr/ofGb43dYOKzJHnLZpVNPf277mRYlzH bP/jg3JfG6OGER2MMFBMhZwB15ow== X-Google-Smtp-Source: AGHT+IGFgJf3vbj7kBTLVjfPMhdKIVaWnTkGtp63eWEPIqhdYAUDElv58c3jqoWBOfsVGgkeJlZGsISX+w== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a62:ae17:0:b0:71d:ef29:82b2 with SMTP id d2e1a72fcca58-71def2984ddmr23497b3a.0.1728350344733; Mon, 07 Oct 2024 18:19:04 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:32 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-7-tavip@google.com> Subject: [PATCH v2 06/25] hw/misc/flexcomm.c: add common fifo functionality From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::449; envelope-from=3iIgEZwUKCukeLgTaRZZRWP.NZXbPXf-OPgPWYZYRYf.ZcR@flex--tavip.bounces.google.com; helo=mail-pf1-x449.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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org FLEXCOMM SPI and USART share FIFO functionality. Add common helper functions to avoid code duplication. Signed-off-by: Octavian Purdila --- include/hw/misc/flexcomm.h | 2 + include/hw/misc/flexcomm_function.h | 8 +++ hw/misc/flexcomm.c | 83 +++++++++++++++++++++++++++++ hw/misc/trace-events | 1 + 4 files changed, 94 insertions(+) diff --git a/include/hw/misc/flexcomm.h b/include/hw/misc/flexcomm.h index ea0fe77f26..832d4cd29d 100644 --- a/include/hw/misc/flexcomm.h +++ b/include/hw/misc/flexcomm.h @@ -44,6 +44,8 @@ struct FlexcommState { uint32_t functions; qemu_irq irq; bool irq_state; + Fifo32 rx_fifo; + Fifo32 tx_fifo; }; #endif /* HW_FLEXCOMM_H */ diff --git a/include/hw/misc/flexcomm_function.h b/include/hw/misc/flexcomm_function.h index e498976927..3ff1677ff6 100644 --- a/include/hw/misc/flexcomm_function.h +++ b/include/hw/misc/flexcomm_function.h @@ -23,6 +23,8 @@ struct FlexcommFunction { MemoryRegion mmio; uint32_t *regs; + Fifo32 *tx_fifo; + Fifo32 *rx_fifo; }; typedef void (*FlexcommFunctionSelect)(FlexcommFunction *f, bool selected); @@ -32,6 +34,7 @@ struct FlexcommFunctionClass { const MemoryRegionOps *mmio_ops; const char *name; + bool has_fifos; FlexcommFunctionSelect select; }; @@ -43,5 +46,10 @@ static inline void flexcomm_select(FlexcommFunction *obj, bool selected) } void flexcomm_set_irq(FlexcommFunction *f, bool irq); +void flexcomm_update_fifostat(FlexcommFunction *f); +void flexcomm_clear_fifostat(FlexcommFunction *f, uint64_t value); +void flexcomm_init_fifos(FlexcommFunction *f, unsigned num); +void flexcomm_cleanup_fifos(FlexcommFunction *f); +void flexcomm_reset_fifos(FlexcommFunction *f); #endif /* HW_FLEXCOMM_FUNCTION_H */ diff --git a/hw/misc/flexcomm.c b/hw/misc/flexcomm.c index 2337fb814c..a98d8845aa 100644 --- a/hw/misc/flexcomm.c +++ b/hw/misc/flexcomm.c @@ -22,6 +22,7 @@ #include "trace.h" #include "migration/vmstate.h" #include "hw/misc/flexcomm.h" +#include "hw/arm/svd/flexcomm_usart.h" #define REG(s, reg) (s->regs[R_FLEXCOMM_##reg]) #define RF_WR(s, reg, field, val) \ @@ -219,12 +220,22 @@ static void flexcomm_init(Object *obj) sysbus_init_irq(sbd, &s->irq); } +static void flexcomm_finalize(Object *obj) +{ + FlexcommState *s = FLEXCOMM(obj); + + /* release resources allocated by the function select (e.g. fifos) */ + flexcomm_func_select(s, false); +} + static void flexcomm_func_realize_and_unref(FlexcommFunction *f, Error **errp) { FlexcommState *s = FLEXCOMM(OBJECT(f)->parent); FlexcommFunctionClass *fc = FLEXCOMM_FUNCTION_GET_CLASS(f); f->regs = s->regs; + f->tx_fifo = &s->tx_fifo; + f->rx_fifo = &s->rx_fifo; memory_region_add_subregion_overlap(&s->container, 0, &f->mmio, 0); DEVICE(f)->id = g_strdup_printf("%s-%s", DEVICE(s)->id, fc->name); sysbus_realize_and_unref(SYS_BUS_DEVICE(f), errp); @@ -274,11 +285,82 @@ void flexcomm_set_irq(FlexcommFunction *f, bool irq) } } +/* FIFO is shared between USART and SPI, provide common functions here */ +#define FIFO_REG(s, reg) (s->regs[R_FLEXCOMM_USART_FIFO##reg]) +#define FIFO_WR(s, reg, field, val) \ + ARRAY_FIELD_DP32(s->regs, FLEXCOMM_USART_FIFO##reg, field, val) +#define FIFO_RD(s, reg, field) \ + ARRAY_FIELD_EX32(s->regs, FLEXCOMM_USART_FIFO##reg, field) + +void flexcomm_update_fifostat(FlexcommFunction *f) +{ + int rxlvl = fifo32_num_used(f->rx_fifo); + int txlvl = fifo32_num_used(f->tx_fifo); + + FIFO_WR(f, STAT, RXLVL, rxlvl); + FIFO_WR(f, STAT, TXLVL, txlvl); + FIFO_WR(f, STAT, RXFULL, fifo32_is_full(f->rx_fifo) ? 1 : 0); + FIFO_WR(f, STAT, RXNOTEMPTY, !fifo32_is_empty(f->rx_fifo) ? 1 : 0); + FIFO_WR(f, STAT, TXNOTFULL, !fifo32_is_full(f->tx_fifo) ? 1 : 0); + FIFO_WR(f, STAT, TXEMPTY, fifo32_is_empty(f->tx_fifo) ? 1 : 0); + + if (FIFO_RD(f, TRIG, RXLVLENA) && (rxlvl > FIFO_RD(f, TRIG, RXLVL))) { + FIFO_WR(f, INTSTAT, RXLVL, 1); + } else { + FIFO_WR(f, INTSTAT, RXLVL, 0); + } + + if (FIFO_RD(f, TRIG, TXLVLENA) && (txlvl <= FIFO_RD(f, TRIG, TXLVL))) { + FIFO_WR(f, INTSTAT, TXLVL, 1); + } else { + FIFO_WR(f, INTSTAT, TXLVL, 0); + } + + trace_flexcomm_fifostat(DEVICE(f)->id, FIFO_REG(f, STAT), + FIFO_REG(f, INTSTAT)); +} + +void flexcomm_reset_fifos(FlexcommFunction *f) +{ + if (FIFO_RD(f, CFG, EMPTYRX)) { + FIFO_WR(f, CFG, EMPTYRX, 0); + fifo32_reset(f->rx_fifo); + } + if (FIFO_RD(f, CFG, EMPTYTX)) { + FIFO_WR(f, CFG, EMPTYTX, 0); + fifo32_reset(f->tx_fifo); + } +} + +void flexcomm_clear_fifostat(FlexcommFunction *f, uint64_t value) +{ + bool rxerr = FIELD_EX32(value, FLEXCOMM_USART_FIFOSTAT, RXERR); + bool txerr = FIELD_EX32(value, FLEXCOMM_USART_FIFOSTAT, TXERR); + + if (rxerr) { + FIFO_WR(f, STAT, RXERR, 0); + } + if (txerr) { + FIFO_WR(f, STAT, TXERR, 0); + } +} + static void flexcomm_function_select(FlexcommFunction *f, bool selected) { FlexcommFunctionClass *fc = FLEXCOMM_FUNCTION_GET_CLASS(f); memory_region_set_enabled(&f->mmio, selected); + if (fc->has_fifos) { + if (selected) { + unsigned num = FIFO_RD(f, SIZE, FIFOSIZE); + + fifo32_create(f->tx_fifo, num); + fifo32_create(f->rx_fifo, num); + } else { + fifo32_destroy(f->tx_fifo); + fifo32_destroy(f->rx_fifo); + } + } } static void flexcomm_function_init(Object *obj) @@ -303,6 +385,7 @@ static const TypeInfo flexcomm_types[] = { .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(FlexcommState), .instance_init = flexcomm_init, + .instance_finalize = flexcomm_finalize, .class_init = flexcomm_class_init, }, { diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 419879fd65..dc245905dc 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -367,3 +367,4 @@ 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" +flexcomm_fifostat(const char *id, uint32_t fifostat, uint32_t fifoinstat) "%s: %08x %08x" From patchwork Tue Oct 8 01:18:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993901 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=odlR4mOh; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMysl5rD6z1xth for ; Tue, 8 Oct 2024 12:21:47 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxytG-0001lq-BO; Mon, 07 Oct 2024 21:19: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 <3iogEZwUKCusgNiVcTbbTYR.PbZdRZh-QRiRYabaTah.beT@flex--tavip.bounces.google.com>) id 1sxysa-0007nM-Nn for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:17 -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 <3iogEZwUKCusgNiVcTbbTYR.PbZdRZh-QRiRYabaTah.beT@flex--tavip.bounces.google.com>) id 1sxysX-00008v-Vp for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:12 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id 3f1490d57ef6-e28690bc290so7535132276.1 for ; Mon, 07 Oct 2024 18:19:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350347; x=1728955147; 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=Vzupf3vt9+CjqF4zkzgvZPteAeoMK9Pq2w9EB8vbI+s=; b=odlR4mOhxesowE5PMylvU9UJ79+ssGRuruZ3GrwUZkjNrxN3tY1V8IEYghq0EjuQgH HNmv+iNkohMwsN8+Q58RZGNHi4TX6Epn4x1n4bvMJlC5aOwk9AGUqfq56yWkMVmJqh3M WzU4pHNr0KZLgellApQnOGYxsWHAd8ZrOOsIzWFc51Qa1HsXd+zhvMHFQ9yPCXKnMbA5 pbrgoTFDVWRGNJBLWO3n4cWxV4x0Lw/qzK8yLFFXrmPOEo81Do8l45mmOj+RHbb6SbAc dVaUtiLoOYeqv/h1ru7GGbmExlBz9Wi+ckgayOm92f+uAxnU4AbnNbNv09uGuOwWN6xa LrcQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350347; x=1728955147; 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=Vzupf3vt9+CjqF4zkzgvZPteAeoMK9Pq2w9EB8vbI+s=; b=g4dQ9aHjRMxTs2FJ98aEZCl7YsJ6Ipx9tcygYO25NTBMHEow5OwCJIFW+jD+iwq79b XLYli5/apL92uQ+etdHiZoZzWJXv9zXGPcbb+JX9raAcUiOPVPXLLv3RVU2g2hKD9NdH 8l/meP4iqh1pTX/+RKvlN2SLLw0wMMj7Y1+RGPZNsQjckVR6iH8FHtKx6Qs0/w29LVEp mRmZukAZhj3LhokQS3OGFkjM5e+AgQXSzrGHptdku1AUT7tM84Zu4iwbk9syTptR+YeM MvM2HHee6eTnIyeLLGbjFOUkmUtzrfdaPZIH1FtTwtZ+ubufP2GTfo20FARScVo70Upw cFYg== X-Gm-Message-State: AOJu0Yw3XhfqXl0DdEMsw3O5CTtTWa9rIrQ1CZqdlunBFpRjVdKaA6GP EtZRxOajWZ0Q7oFQagiJoHsOvbGOcnR0gOW1tklqbD4IgfY2rljwdGHFup/WsmeDhuWSXgL3294 r4gRQUkHpp5hrsDX0KgeDYmJ54/GinIWZBhH7Bhidw/ikfzw5fNA1e3u+ke+lCSEfA1Et7mLoJ9 ePebs3H8CrLLhQTsVk67m70aFI1Q== X-Google-Smtp-Source: AGHT+IF8b+KwDkEfdHpiw3avdhoIJWRKXiRbTxfcFuMGtw+4XiGc6GeHNYWj3ZNVznRFO2FNXD2xTlVYVw== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a25:6b4b:0:b0:e1a:44fa:f09 with SMTP id 3f1490d57ef6-e28936c0e5amr9284276.2.1728350346664; Mon, 07 Oct 2024 18:19:06 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:33 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-8-tavip@google.com> Subject: [PATCH v2 07/25] 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, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3iogEZwUKCusgNiVcTbbTYR.PbZdRZh-QRiRYabaTah.beT@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add support for NXP's flexcomm usart. It supports interupts and FIFO access but no DMA. The patch includes an automatically generated header which contains the register layout and helpers. The header can be regenerated with the svd-flexcomm-usart target when the build is configured with --enable-mcux-soc-svd. Signed-off-by: Octavian Purdila --- include/hw/arm/svd/flexcomm_usart.h | 294 ++++++++++++++++++++++++++++ include/hw/char/flexcomm_usart.h | 33 ++++ include/hw/misc/flexcomm.h | 2 + hw/char/flexcomm_usart.c | 288 +++++++++++++++++++++++++++ hw/misc/flexcomm.c | 3 + hw/arm/svd/meson.build | 4 + hw/char/meson.build | 1 + hw/char/trace-events | 8 + 8 files changed, 633 insertions(+) create mode 100644 include/hw/arm/svd/flexcomm_usart.h create mode 100644 include/hw/char/flexcomm_usart.h create mode 100644 hw/char/flexcomm_usart.c diff --git a/include/hw/arm/svd/flexcomm_usart.h b/include/hw/arm/svd/flexcomm_usart.h new file mode 100644 index 0000000000..a226917182 --- /dev/null +++ b/include/hw/arm/svd/flexcomm_usart.h @@ -0,0 +1,294 @@ +/* + * Copyright 2016-2023 NXP SPDX-License-Identifier: BSD-3-Clause + * + * Automatically generated by svd-gen-header.py from MIMXRT595S_cm33.xml + */ +#pragma once + +#include "hw/register.h" + +/* Flexcomm USART */ +#define FLEXCOMM_USART_REGS_NO (1024) + +/* USART Configuration */ +REG32(FLEXCOMM_USART_CFG, 0x0); +/* USART Enable */ +FIELD(FLEXCOMM_USART_CFG, ENABLE, 0, 1); + +/* USART Control */ +REG32(FLEXCOMM_USART_CTL, 0x4); + +/* USART Status */ +REG32(FLEXCOMM_USART_STAT, 0x8); + +/* Interrupt Enable Read and Set for USART (not FIFO) Status */ +REG32(FLEXCOMM_USART_INTENSET, 0xC); + +/* Interrupt Enable Clear */ +REG32(FLEXCOMM_USART_INTENCLR, 0x10); + +/* Baud Rate Generator */ +REG32(FLEXCOMM_USART_BRG, 0x20); + +/* Interrupt Status */ +REG32(FLEXCOMM_USART_INTSTAT, 0x24); + +/* Oversample Selection Register for Asynchronous Communication */ +REG32(FLEXCOMM_USART_OSR, 0x28); + +/* Address Register for Automatic Address Matching */ +REG32(FLEXCOMM_USART_ADDR, 0x2C); + +/* FIFO Configuration */ +REG32(FLEXCOMM_USART_FIFOCFG, 0xE00); +/* Enable the Transmit FIFO. */ +FIELD(FLEXCOMM_USART_FIFOCFG, ENABLETX, 0, 1); +/* Enable the Receive FIFO */ +FIELD(FLEXCOMM_USART_FIFOCFG, ENABLERX, 1, 1); +/* Empty Command for the Transmit FIFO */ +FIELD(FLEXCOMM_USART_FIFOCFG, EMPTYTX, 16, 1); +/* Empty Command for the Receive FIFO */ +FIELD(FLEXCOMM_USART_FIFOCFG, EMPTYRX, 17, 1); + +/* FIFO Status */ +REG32(FLEXCOMM_USART_FIFOSTAT, 0xE04); +/* TX FIFO Error */ +FIELD(FLEXCOMM_USART_FIFOSTAT, TXERR, 0, 1); +/* RX FIFO Error */ +FIELD(FLEXCOMM_USART_FIFOSTAT, RXERR, 1, 1); +/* Peripheral Interrupt */ +FIELD(FLEXCOMM_USART_FIFOSTAT, PERINT, 3, 1); +/* Transmit FIFO Empty */ +FIELD(FLEXCOMM_USART_FIFOSTAT, TXEMPTY, 4, 1); +/* Transmit FIFO is Not Full */ +FIELD(FLEXCOMM_USART_FIFOSTAT, TXNOTFULL, 5, 1); +/* Receive FIFO is Not Empty */ +FIELD(FLEXCOMM_USART_FIFOSTAT, RXNOTEMPTY, 6, 1); +/* Receive FIFO is Full */ +FIELD(FLEXCOMM_USART_FIFOSTAT, RXFULL, 7, 1); +/* Transmit FIFO Current Level */ +FIELD(FLEXCOMM_USART_FIFOSTAT, TXLVL, 8, 5); +/* Receive FIFO Current Level */ +FIELD(FLEXCOMM_USART_FIFOSTAT, RXLVL, 16, 5); + +/* FIFO Trigger Settings for Interrupt and DMA Request */ +REG32(FLEXCOMM_USART_FIFOTRIG, 0xE08); +/* Transmit FIFO Level Trigger Enable. */ +FIELD(FLEXCOMM_USART_FIFOTRIG, TXLVLENA, 0, 1); +/* Receive FIFO Level Trigger Enable */ +FIELD(FLEXCOMM_USART_FIFOTRIG, RXLVLENA, 1, 1); +/* Transmit FIFO Level Trigger Point */ +FIELD(FLEXCOMM_USART_FIFOTRIG, TXLVL, 8, 4); +/* Trigger when the TX FIFO becomes empty */ +#define FLEXCOMM_USART_FIFOTRIG_TXLVL_TXLVL0 0 +/* Trigger when the TX FIFO level decreases to 1 entry */ +#define FLEXCOMM_USART_FIFOTRIG_TXLVL_TXLVL1 1 +/* Trigger when the TX FIFO level decreases to 15 entries (is no longer full) */ +#define FLEXCOMM_USART_FIFOTRIG_TXLVL_TXLVL15 15 +/* Receive FIFO Level Trigger Point */ +FIELD(FLEXCOMM_USART_FIFOTRIG, RXLVL, 16, 4); +/* Trigger when the RX FIFO has received 1 entry (is no longer empty) */ +#define FLEXCOMM_USART_FIFOTRIG_RXLVL_RXLVL1 0 +/* Trigger when the RX FIFO has received 2 entries */ +#define FLEXCOMM_USART_FIFOTRIG_RXLVL_RXLVL2 1 +/* Trigger when the RX FIFO has received 16 entries (has become full) */ +#define FLEXCOMM_USART_FIFOTRIG_RXLVL_RXLVL15 15 + +/* FIFO Interrupt Enable */ +REG32(FLEXCOMM_USART_FIFOINTENSET, 0xE10); +/* Transmit Error Interrupt Enable */ +FIELD(FLEXCOMM_USART_FIFOINTENSET, TXERR, 0, 1); +/* Receive Error Interrupt Enable */ +FIELD(FLEXCOMM_USART_FIFOINTENSET, RXERR, 1, 1); +/* Transmit FIFO Level Interrupt Enable */ +FIELD(FLEXCOMM_USART_FIFOINTENSET, TXLVL, 2, 1); +/* Receive FIFO Level Interrupt Enable */ +FIELD(FLEXCOMM_USART_FIFOINTENSET, RXLVL, 3, 1); + +/* FIFO Interrupt Enable Clear */ +REG32(FLEXCOMM_USART_FIFOINTENCLR, 0xE14); +/* Transmit Error Interrupt Enable */ +FIELD(FLEXCOMM_USART_FIFOINTENCLR, TXERR, 0, 1); +/* Receive Error Interrupt Enable */ +FIELD(FLEXCOMM_USART_FIFOINTENCLR, RXERR, 1, 1); +/* Transmit FIFO Level Interrupt Enable */ +FIELD(FLEXCOMM_USART_FIFOINTENCLR, TXLVL, 2, 1); +/* Receive FIFO Level Interrupt Enable */ +FIELD(FLEXCOMM_USART_FIFOINTENCLR, RXLVL, 3, 1); + +/* FIFO Interrupt Status */ +REG32(FLEXCOMM_USART_FIFOINTSTAT, 0xE18); +/* TX FIFO Error Interrupt Status */ +FIELD(FLEXCOMM_USART_FIFOINTSTAT, TXERR, 0, 1); +/* RX FIFO Error Interrupt Status */ +FIELD(FLEXCOMM_USART_FIFOINTSTAT, RXERR, 1, 1); +/* Transmit FIFO Level Interrupt Status */ +FIELD(FLEXCOMM_USART_FIFOINTSTAT, TXLVL, 2, 1); +/* Receive FIFO Level Interrupt Status */ +FIELD(FLEXCOMM_USART_FIFOINTSTAT, RXLVL, 3, 1); +/* Peripheral Interrupt Status */ +FIELD(FLEXCOMM_USART_FIFOINTSTAT, PERINT, 4, 1); + +/* FIFO Write Data */ +REG32(FLEXCOMM_USART_FIFOWR, 0xE20); +/* Transmit data to the FIFO */ +FIELD(FLEXCOMM_USART_FIFOWR, TXDATA, 0, 9); + +/* FIFO Read Data */ +REG32(FLEXCOMM_USART_FIFORD, 0xE30); +/* Received Data from the FIFO */ +FIELD(FLEXCOMM_USART_FIFORD, RXDATA, 0, 9); +/* Framing Error Status Flag */ +FIELD(FLEXCOMM_USART_FIFORD, FRAMERR, 13, 1); +/* Parity Error Status Flag */ +FIELD(FLEXCOMM_USART_FIFORD, PARITYERR, 14, 1); +/* Received Noise Flag */ +FIELD(FLEXCOMM_USART_FIFORD, RXNOISE, 15, 1); + +/* FIFO Data Read with No FIFO Pop */ +REG32(FLEXCOMM_USART_FIFORDNOPOP, 0xE40); +/* Received Data from the FIFO */ +FIELD(FLEXCOMM_USART_FIFORDNOPOP, RXDATA, 0, 9); +/* Framing Error Status Flag */ +FIELD(FLEXCOMM_USART_FIFORDNOPOP, FRAMERR, 13, 1); +/* Parity Error Status Flag */ +FIELD(FLEXCOMM_USART_FIFORDNOPOP, PARITYERR, 14, 1); +/* Received Noise Flag */ +FIELD(FLEXCOMM_USART_FIFORDNOPOP, RXNOISE, 15, 1); + +/* FIFO Size */ +REG32(FLEXCOMM_USART_FIFOSIZE, 0xE48); +/* FIFO Size */ +FIELD(FLEXCOMM_USART_FIFOSIZE, FIFOSIZE, 0, 5); + +/* Peripheral Identification */ +REG32(FLEXCOMM_USART_ID, 0xFFC); + + +#define FLEXCOMM_USART_REGISTER_ACCESS_INFO_ARRAY(_name) \ + struct RegisterAccessInfo _name[FLEXCOMM_USART_REGS_NO] = { \ + [0 ... FLEXCOMM_USART_REGS_NO - 1] = { \ + .name = "", \ + .addr = -1, \ + }, \ + [0x0] = { \ + .name = "CFG", \ + .addr = 0x0, \ + .ro = 0xFF032402, \ + .reset = 0x0, \ + }, \ + [0x1] = { \ + .name = "CTL", \ + .addr = 0x4, \ + .ro = 0xFFFEFCB9, \ + .reset = 0x0, \ + }, \ + [0x2] = { \ + .name = "STAT", \ + .addr = 0x8, \ + .ro = 0xFFFE07DF, \ + .reset = 0xA, \ + }, \ + [0x3] = { \ + .name = "INTENSET", \ + .addr = 0xC, \ + .ro = 0xFFFE0797, \ + .reset = 0x0, \ + }, \ + [0x4] = { \ + .name = "INTENCLR", \ + .addr = 0x10, \ + .ro = 0xFFFE0797, \ + .reset = 0x0, \ + }, \ + [0x8] = { \ + .name = "BRG", \ + .addr = 0x20, \ + .ro = 0xFFFF0000, \ + .reset = 0x0, \ + }, \ + [0x9] = { \ + .name = "INTSTAT", \ + .addr = 0x24, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0xA] = { \ + .name = "OSR", \ + .addr = 0x28, \ + .ro = 0xFFFFFFF0, \ + .reset = 0xF, \ + }, \ + [0xB] = { \ + .name = "ADDR", \ + .addr = 0x2C, \ + .ro = 0xFFFFFF00, \ + .reset = 0x0, \ + }, \ + [0x380] = { \ + .name = "FIFOCFG", \ + .addr = 0xE00, \ + .ro = 0xFFF80FFC, \ + .reset = 0x0, \ + }, \ + [0x381] = { \ + .name = "FIFOSTAT", \ + .addr = 0xE04, \ + .ro = 0xFFFFFFFC, \ + .reset = 0x30, \ + }, \ + [0x382] = { \ + .name = "FIFOTRIG", \ + .addr = 0xE08, \ + .ro = 0xFFF0F0FC, \ + .reset = 0x0, \ + }, \ + [0x384] = { \ + .name = "FIFOINTENSET", \ + .addr = 0xE10, \ + .ro = 0xFFFFFFF0, \ + .reset = 0x0, \ + }, \ + [0x385] = { \ + .name = "FIFOINTENCLR", \ + .addr = 0xE14, \ + .ro = 0xFFFFFFF0, \ + .reset = 0x0, \ + }, \ + [0x386] = { \ + .name = "FIFOINTSTAT", \ + .addr = 0xE18, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x388] = { \ + .name = "FIFOWR", \ + .addr = 0xE20, \ + .ro = 0xFFFFFE00, \ + .reset = 0x0, \ + }, \ + [0x38C] = { \ + .name = "FIFORD", \ + .addr = 0xE30, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x390] = { \ + .name = "FIFORDNOPOP", \ + .addr = 0xE40, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x392] = { \ + .name = "FIFOSIZE", \ + .addr = 0xE48, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x10, \ + }, \ + [0x3FF] = { \ + .name = "ID", \ + .addr = 0xFFC, \ + .ro = 0xFFFFFFFF, \ + .reset = 0xE0102100, \ + }, \ + } diff --git a/include/hw/char/flexcomm_usart.h b/include/hw/char/flexcomm_usart.h new file mode 100644 index 0000000000..e67b15208f --- /dev/null +++ b/include/hw/char/flexcomm_usart.h @@ -0,0 +1,33 @@ +/* + * 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_FLEXCOMM_USART_H +#define HW_FLEXCOMM_USART_H + +#include "hw/misc/flexcomm_function.h" +#include "chardev/char-fe.h" + +#define TYPE_FLEXCOMM_USART "flexcomm-usart" +OBJECT_DECLARE_TYPE(FlexcommUsartState, FlexcommUsartClass, FLEXCOMM_USART); + +struct FlexcommUsartState { + FlexcommFunction parent_obj; + + CharBackend chr; +}; + +struct FlexcommUsartClass { + FlexcommFunctionClass parent_obj; + + FlexcommFunctionSelect select; +}; + +#endif /* HW_FLEXCOMM_USART_H */ diff --git a/include/hw/misc/flexcomm.h b/include/hw/misc/flexcomm.h index 832d4cd29d..679b7ea64d 100644 --- a/include/hw/misc/flexcomm.h +++ b/include/hw/misc/flexcomm.h @@ -15,6 +15,7 @@ #include "hw/sysbus.h" #include "hw/arm/svd/flexcomm.h" #include "qemu/fifo32.h" +#include "hw/char/flexcomm_usart.h" #define FLEXCOMM_FUNC_USART 0 #define FLEXCOMM_FUNC_SPI 1 @@ -46,6 +47,7 @@ struct FlexcommState { bool irq_state; Fifo32 rx_fifo; Fifo32 tx_fifo; + FlexcommUsartState usart; }; #endif /* HW_FLEXCOMM_H */ diff --git a/hw/char/flexcomm_usart.c b/hw/char/flexcomm_usart.c new file mode 100644 index 0000000000..53ab5d8379 --- /dev/null +++ b/hw/char/flexcomm_usart.c @@ -0,0 +1,288 @@ +/* + * 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 "hw/qdev-properties-system.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "exec/address-spaces.h" +#include "qapi/error.h" +#include "trace.h" +#include "hw/misc/flexcomm.h" +#include "hw/char/flexcomm_usart.h" +#include "hw/arm/svd/flexcomm_usart.h" + +#define REG(s, reg) (s->regs[R_FLEXCOMM_USART_##reg]) +/* register field write helper macro */ +#define RF_RD(s, reg, field, val) \ + ARRAY_FIELD_DP32(s->regs, FLEXCOMM_USART_##reg, field, val) +/* register field read helper macro */ +#define RF_WR(s, reg, field) \ + ARRAY_FIELD_EX32(s->regs, FLEXCOMM_USART_##reg, field) + +static FLEXCOMM_USART_REGISTER_ACCESS_INFO_ARRAY(reg_info); + +static void flexcomm_usart_reset(FlexcommFunction *f) +{ + for (int i = 0; i < FLEXCOMM_USART_REGS_NO; i++) { + hwaddr addr = reg_info[i].addr; + + if (addr != -1) { + struct RegisterInfo ri = { + .data = &f->regs[addr / 4], + .data_size = 4, + .access = ®_info[i], + }; + + register_reset(&ri); + } + } +} + +static void flexcomm_usart_irq_update(FlexcommFunction *f) +{ + bool irq, per_irqs, fifo_irqs, enabled = RF_WR(f, CFG, ENABLE); + + flexcomm_update_fifostat(f); + fifo_irqs = REG(f, FIFOINTSTAT) & REG(f, FIFOINTENSET); + + REG(f, INTSTAT) = REG(f, STAT) & REG(f, INTENSET); + per_irqs = REG(f, INTSTAT) != 0; + + irq = enabled && (fifo_irqs || per_irqs); + + trace_flexcomm_usart_irq(DEVICE(f)->id, irq, fifo_irqs, per_irqs, enabled); + flexcomm_set_irq(f, irq); +} + +static int flexcomm_usart_rx_space(void *opaque) +{ + FlexcommUsartState *s = FLEXCOMM_USART(opaque); + FlexcommFunction *f = FLEXCOMM_FUNCTION(opaque); + + uint32_t ret = fifo32_num_free(f->rx_fifo); + + if (!RF_WR(f, CFG, ENABLE) || !RF_WR(f, FIFOCFG, 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) +{ + FlexcommFunction *f = FLEXCOMM_FUNCTION(opaque); + + if (!RF_WR(f, CFG, ENABLE) || !RF_WR(f, FIFOCFG, ENABLERX)) { + return; + } + + trace_flexcomm_usart_rx(DEVICE(f)->id); + + while (!fifo32_is_full(f->rx_fifo) && size) { + fifo32_push(f->rx_fifo, *buf++); + size--; + } + + flexcomm_usart_irq_update(f); +} + +static MemTxResult flexcomm_usart_reg_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + FlexcommFunction *f = FLEXCOMM_FUNCTION(opaque); + FlexcommUsartState *s = FLEXCOMM_USART(opaque); + const struct RegisterAccessInfo *rai = ®_info[addr / 4]; + MemTxResult ret = MEMTX_OK; + + if (size != 4) { + ret = MEMTX_ERROR; + goto out; + } + + switch (addr) { + case A_FLEXCOMM_USART_FIFORD: + { + if (!fifo32_is_empty(f->rx_fifo)) { + *data = fifo32_pop(f->rx_fifo); + qemu_chr_fe_accept_input(&s->chr); + } + break; + } + case A_FLEXCOMM_USART_FIFORDNOPOP: + { + if (!fifo32_is_empty(f->rx_fifo)) { + *data = fifo32_peek(f->rx_fifo); + } + break; + } + default: + *data = f->regs[addr / 4]; + break; + } + + flexcomm_usart_irq_update(f); + +out: + trace_flexcomm_usart_reg_read(DEVICE(f)->id, rai->name, addr, *data); + return ret; +} + +static MemTxResult flexcomm_usart_reg_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + FlexcommFunction *f = FLEXCOMM_FUNCTION(opaque); + FlexcommUsartState *s = FLEXCOMM_USART(opaque); + const struct RegisterAccessInfo *rai = ®_info[addr / 4]; + struct RegisterInfo ri = { + .data = &f->regs[addr / 4], + .data_size = 4, + .access = rai, + }; + + trace_flexcomm_usart_reg_write(DEVICE(f)->id, rai->name, addr, value); + + switch (addr) { + case A_FLEXCOMM_USART_INTENCLR: + { + register_write(&ri, value, ~0, NULL, false); + REG(f, INTENSET) &= ~REG(f, INTENCLR); + break; + } + case A_FLEXCOMM_USART_FIFOCFG: + { + register_write(&ri, value, ~0, NULL, false); + flexcomm_reset_fifos(f); + break; + } + case A_FLEXCOMM_USART_FIFOSTAT: + { + flexcomm_clear_fifostat(f, value); + break; + } + case A_FLEXCOMM_USART_FIFOINTENSET: + { + REG(f, FIFOINTENSET) |= value; + break; + } + case A_FLEXCOMM_USART_FIFOINTENCLR: + { + register_write(&ri, value, ~0, NULL, false); + REG(f, FIFOINTENSET) &= ~value; + break; + } + case A_FLEXCOMM_USART_FIFOWR: + { + register_write(&ri, value, ~0, NULL, false); + + if (!fifo32_is_full(f->tx_fifo)) { + fifo32_push(f->tx_fifo, REG(f, FIFOWR)); + } + + if (!RF_WR(f, CFG, ENABLE) || !RF_WR(f, FIFOCFG, ENABLETX)) { + break; + } + + while (!fifo32_is_empty(f->tx_fifo)) { + uint32_t val32 = fifo32_pop(f->tx_fifo); + uint8_t val8 = val32 & 0xff; + + trace_flexcomm_usart_tx(DEVICE(f)->id); + qemu_chr_fe_write_all(&s->chr, &val8, sizeof(val8)); + } + break; + } + case A_FLEXCOMM_USART_CFG: + { + register_write(&ri, value, ~0, NULL, false); + break; + } + default: + register_write(&ri, value, ~0, NULL, false); + break; + } + + flexcomm_usart_irq_update(f); + + return MEMTX_OK; +} + +static void flexcomm_usart_select(FlexcommFunction *f, bool selected) +{ + FlexcommUsartState *s = FLEXCOMM_USART(f); + FlexcommUsartClass *uc = FLEXCOMM_USART_GET_CLASS(f); + + if (selected) { + qemu_chr_fe_set_handlers(&s->chr, flexcomm_usart_rx_space, + flexcomm_usart_rx, NULL, NULL, + s, NULL, true); + flexcomm_usart_reset(f); + } else { + qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL, NULL, NULL, + false); + } + uc->select(f, selected); +} + +static const MemoryRegionOps flexcomm_usart_ops = { + .read_with_attrs = flexcomm_usart_reg_read, + .write_with_attrs = flexcomm_usart_reg_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static Property flexcomm_usart_properties[] = { + DEFINE_PROP_CHR("chardev", FlexcommUsartState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void flexcomm_usart_realize(DeviceState *dev, Error **errp) +{ + qdev_prop_set_chr(dev, "chardev", qemu_chr_find(dev->id)); +} + +static void flexcomm_usart_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + FlexcommFunctionClass *fc = FLEXCOMM_FUNCTION_CLASS(klass); + FlexcommUsartClass *uc = FLEXCOMM_USART_CLASS(klass); + + device_class_set_props(dc, flexcomm_usart_properties); + dc->realize = flexcomm_usart_realize; + uc->select = fc->select; + fc->select = flexcomm_usart_select; + fc->name = "usart"; + fc->has_fifos = true; + fc->mmio_ops = &flexcomm_usart_ops; +} + +static const TypeInfo flexcomm_usart_types[] = { + { + .name = TYPE_FLEXCOMM_USART, + .parent = TYPE_FLEXCOMM_FUNCTION, + .instance_size = sizeof(FlexcommUsartState), + .class_init = flexcomm_usart_class_init, + .class_size = sizeof(FlexcommUsartClass), + }, +}; + +DEFINE_TYPES(flexcomm_usart_types); diff --git a/hw/misc/flexcomm.c b/hw/misc/flexcomm.c index a98d8845aa..a291148f27 100644 --- a/hw/misc/flexcomm.c +++ b/hw/misc/flexcomm.c @@ -23,6 +23,7 @@ #include "migration/vmstate.h" #include "hw/misc/flexcomm.h" #include "hw/arm/svd/flexcomm_usart.h" +#include "hw/char/flexcomm_usart.h" #define REG(s, reg) (s->regs[R_FLEXCOMM_##reg]) #define RF_WR(s, reg, field, val) \ @@ -218,6 +219,7 @@ static void flexcomm_init(Object *obj) TYPE_FLEXCOMM, sizeof(s->regs)); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->container); sysbus_init_irq(sbd, &s->irq); + object_initialize_child(obj, "usart", &s->usart, TYPE_FLEXCOMM_USART); } static void flexcomm_finalize(Object *obj) @@ -247,6 +249,7 @@ static void flexcomm_realize(DeviceState *dev, Error **errp) FlexcommState *s = FLEXCOMM(dev); memory_region_add_subregion_overlap(&s->container, 0, &s->mmio, -1); + flexcomm_func_realize_and_unref(FLEXCOMM_FUNCTION(&s->usart), errp); } static const VMStateDescription vmstate_flexcomm = { diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build index 4b0bbbbbdc..3bff90bcbd 100644 --- a/hw/arm/svd/meson.build +++ b/hw/arm/svd/meson.build @@ -4,4 +4,8 @@ if get_option('mcux-soc-svd') run_target('svd-flexcomm', command: svd_gen_header + [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/flexcomm.h', '-p', 'FLEXCOMM0', '-t', 'FLEXCOMM']) + run_target('svd-flexcomm-usart', command: svd_gen_header + + [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/flexcomm_usart.h', + '-p', 'USART0', '-t', 'FLEXCOMM_USART', + '--fields', 'CFG:ENABLE FIFOCFG:ENABLE*,EMPTY* FIFO*:* *:']) endif diff --git a/hw/char/meson.build b/hw/char/meson.build index 1750834385..5c6aaf8309 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 59e1f734a7..578551b388 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -125,3 +125,11 @@ 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_irq(const char *id, bool irq, bool fifoirqs, bool perirqs, bool enabled) "%s: %d %d %d %d" From patchwork Tue Oct 8 01:18:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993930 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=aKIT0UZA; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMyzC29Xxz1xsn for ; Tue, 8 Oct 2024 12:26:31 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxytI-00024Q-Fi; Mon, 07 Oct 2024 21:19: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 <3jIgEZwUKCu0iPkXeVddVaT.RdbfTbj-STkTacdcVcj.dgV@flex--tavip.bounces.google.com>) id 1sxysc-0007pC-VG for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:18 -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 <3jIgEZwUKCu0iPkXeVddVaT.RdbfTbj-STkTacdcVcj.dgV@flex--tavip.bounces.google.com>) id 1sxysa-00009V-84 for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:14 -0400 Received: by mail-pl1-x649.google.com with SMTP id d9443c01a7336-20c531e38a5so2135035ad.0 for ; Mon, 07 Oct 2024 18:19:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350350; x=1728955150; 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=8QRkphhXNdsPFrr6+C1WirROoZs1K34T9oRkyUJP42U=; b=aKIT0UZADk6D1kbWMMQNAEmdgkvQ82SV224drSOD1h5Zb/fjD8Tk4dpeQBuVtnUCHP IxJo9XOU0wd7GWDtKmLKyPQYBKCQ8/S0qgNJiKkh9+4ieAVgCa9geZCJ0SlcU67DWrzU 5DD7rEQpUeGZHi020DWAFg0+N/GwtrXjpC5nkWfcsFQg6ESB/+W/bVfZ0h5B1tRwRICF syr1lyk5GeoJpjssvGKIIk3G407EZiMAQRFjs+qFJSZetaLsRinoXdOrDs8pB+VWyipf tyuo2YxLLprqglQHHI/eY3RLA4fTPeHP9phasntiVlkbxZwf50geSZT7Tm79K9b0ZtQl ZeBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350350; x=1728955150; 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=8QRkphhXNdsPFrr6+C1WirROoZs1K34T9oRkyUJP42U=; b=tcbmIoH6vBSlP8XKrQG+DzrDkEiT6IdXViWVNaqcfMbOhf8WPZBHEPliUZ6/8yBzLm VCwBfUfzaXif1Zns+qLhRx6xGLbb1ou4eH90No1V/AZBkE8RRpH7C9zcder4FMpOqPKz UFajzdQmKPcdsWzpp+v7MBQj29MrGY8mDVJEHM2d0r2jfkqLweIqbqavPHVDz2VDmfFe 8wEXrEt/Odu0kChPICC8eDKPzxLKPpC5NGmBQhX9o6elEi7fogx9ZKqP5bcisE5QHk57 K0MHFtvCcfuQzC/J0ecaH4VlMIie2im5RPTJzFzHWRaxsl0imVu5l7ksMDWZS3vnPgBz q13Q== X-Gm-Message-State: AOJu0Yzk9FZDqj3Nu1zE+DHaaVhlAvE8fJ0X6Uih1YWDpws+sIiVNZAX UUgYz00sw+ZSleXqziQXe2hwDPMUsU/qhg0VLZpJmFOCH3YTZ/G6cIbeZSM/GgF0VJKFxJOeimx 5IA0AOa7VW+anZowAiyXa5aIp1FMzq0DwOSu7/lRim5STfkTYm+h8H/+nGwEkR54nw/NcU32mng PloV5hs70NMQjl1kf7OVbOhoSgQw== X-Google-Smtp-Source: AGHT+IFV4ejJ05aZUkbHio21LY8L4/lVckYz35q8sBuQeMqIuRtHuEY0pU+3zodaECEAI/wCW3eOByzZlA== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a17:902:e80c:b0:20b:9df1:54a3 with SMTP id d9443c01a7336-20bff1dfc9fmr779915ad.8.1728350348483; Mon, 07 Oct 2024 18:19:08 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:34 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-9-tavip@google.com> Subject: [PATCH v2 08/25] 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, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::649; envelope-from=3jIgEZwUKCu0iPkXeVddVaT.RdbfTbj-STkTacdcVcj.dgV@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add support for NXP's flexcomm i2c. It does not support slave mode or DMA. The patch includes an automatically generated header which contains the register layout and helpers. The header can be regenerated with the svd-flexcomm-i2c target when the build is configured with --enable-mcux-soc-svd. Signed-off-by: Octavian Purdila --- include/hw/arm/svd/flexcomm_i2c.h | 229 +++++++++++++++++++++++++++ include/hw/i2c/flexcomm_i2c.h | 40 +++++ include/hw/misc/flexcomm.h | 2 + hw/i2c/flexcomm_i2c.c | 250 ++++++++++++++++++++++++++++++ hw/misc/flexcomm.c | 3 + hw/arm/svd/meson.build | 4 + hw/i2c/meson.build | 1 + hw/i2c/trace-events | 10 ++ hw/misc/Kconfig | 1 + 9 files changed, 540 insertions(+) create mode 100644 include/hw/arm/svd/flexcomm_i2c.h create mode 100644 include/hw/i2c/flexcomm_i2c.h create mode 100644 hw/i2c/flexcomm_i2c.c diff --git a/include/hw/arm/svd/flexcomm_i2c.h b/include/hw/arm/svd/flexcomm_i2c.h new file mode 100644 index 0000000000..bd1dec16f3 --- /dev/null +++ b/include/hw/arm/svd/flexcomm_i2c.h @@ -0,0 +1,229 @@ +/* + * Copyright 2016-2023 NXP SPDX-License-Identifier: BSD-3-Clause + * + * Automatically generated by svd-gen-header.py from MIMXRT595S_cm33.xml + */ +#pragma once + +#include "hw/register.h" + +/* I2C Bus Interface */ +#define FLEXCOMM_I2C_REGS_NO (1024) + +/* Configuration Register */ +REG32(FLEXCOMM_I2C_CFG, 0x800); +/* Master Enable */ +FIELD(FLEXCOMM_I2C_CFG, MSTEN, 0, 1); +/* Slave Enable */ +FIELD(FLEXCOMM_I2C_CFG, SLVEN, 1, 1); +/* Monitor Enable */ +FIELD(FLEXCOMM_I2C_CFG, MONEN, 2, 1); +/* I2C bus Time-out Enable */ +FIELD(FLEXCOMM_I2C_CFG, TIMEOUTEN, 3, 1); +/* Monitor function Clock Stretching */ +FIELD(FLEXCOMM_I2C_CFG, MONCLKSTR, 4, 1); +/* High Speed mode Capable enable */ +FIELD(FLEXCOMM_I2C_CFG, HSCAPABLE, 5, 1); + +/* Status Register */ +REG32(FLEXCOMM_I2C_STAT, 0x804); +/* Master Pending */ +FIELD(FLEXCOMM_I2C_STAT, MSTPENDING, 0, 1); +/* Master State code */ +FIELD(FLEXCOMM_I2C_STAT, MSTSTATE, 1, 3); +/* Idle. The Master function is available to be used for a new transaction. */ +#define FLEXCOMM_I2C_STAT_MSTSTATE_IDLE 0 +/* + * Receive ready. Received data is available (in Master Receiver mode). Address + * plus Read was previously sent and Acknowledged by a slave. + */ +#define FLEXCOMM_I2C_STAT_MSTSTATE_RECEIVE_READY 1 +/* + * Transmit ready. Data can be transmitted (in Master Transmitter mode). + * Address plus Write was previously sent and Acknowledged by a slave. + */ +#define FLEXCOMM_I2C_STAT_MSTSTATE_TRANSMIT_READY 2 +/* NACK Address. Slave NACKed address. */ +#define FLEXCOMM_I2C_STAT_MSTSTATE_NACK_ADDRESS 3 +/* NACK Data. Slave NACKed transmitted data. */ +#define FLEXCOMM_I2C_STAT_MSTSTATE_NACK_DATA 4 + +/* Interrupt Enable Set Register */ +REG32(FLEXCOMM_I2C_INTENSET, 0x808); +/* Master Pending interrupt Enable */ +FIELD(FLEXCOMM_I2C_INTENSET, MSTPENDINGEN, 0, 1); + +/* Interrupt Enable Clear Register */ +REG32(FLEXCOMM_I2C_INTENCLR, 0x80C); +/* Master Pending interrupt clear */ +FIELD(FLEXCOMM_I2C_INTENCLR, MSTPENDINGCLR, 0, 1); + +/* Time-out Register */ +REG32(FLEXCOMM_I2C_TIMEOUT, 0x810); +/* Time-out time value, the bottom 4 bits */ +FIELD(FLEXCOMM_I2C_TIMEOUT, TOMIN, 0, 4); + +/* Interrupt Status Register */ +REG32(FLEXCOMM_I2C_INTSTAT, 0x818); +/* Master Pending */ +FIELD(FLEXCOMM_I2C_INTSTAT, MSTPENDING, 0, 1); + +/* Master Control Register */ +REG32(FLEXCOMM_I2C_MSTCTL, 0x820); +/* Master Continue(write-only) */ +FIELD(FLEXCOMM_I2C_MSTCTL, MSTCONTINUE, 0, 1); +/* Master Start control(write-only) */ +FIELD(FLEXCOMM_I2C_MSTCTL, MSTSTART, 1, 1); +/* Master Stop control(write-only) */ +FIELD(FLEXCOMM_I2C_MSTCTL, MSTSTOP, 2, 1); +/* Master DMA enable */ +FIELD(FLEXCOMM_I2C_MSTCTL, MSTDMA, 3, 1); + +/* Master Data Register */ +REG32(FLEXCOMM_I2C_MSTDAT, 0x828); +/* Master function data register */ +FIELD(FLEXCOMM_I2C_MSTDAT, DATA, 0, 8); + +/* Slave Control Register */ +REG32(FLEXCOMM_I2C_SLVCTL, 0x840); + +/* Slave Data Register */ +REG32(FLEXCOMM_I2C_SLVDAT, 0x844); + +/* Slave Address Register */ +REG32(FLEXCOMM_I2C_SLVADR0, 0x848); + +/* Slave Address Register */ +REG32(FLEXCOMM_I2C_SLVADR1, 0x84C); + +/* Slave Address Register */ +REG32(FLEXCOMM_I2C_SLVADR2, 0x850); + +/* Slave Address Register */ +REG32(FLEXCOMM_I2C_SLVADR3, 0x854); + +/* Slave Qualification for Address 0 Register */ +REG32(FLEXCOMM_I2C_SLVQUAL0, 0x858); + + +#define FLEXCOMM_I2C_REGISTER_ACCESS_INFO_ARRAY(_name) \ + struct RegisterAccessInfo _name[FLEXCOMM_I2C_REGS_NO] = { \ + [0 ... FLEXCOMM_I2C_REGS_NO - 1] = { \ + .name = "", \ + .addr = -1, \ + }, \ + [0x200] = { \ + .name = "CFG", \ + .addr = 0x800, \ + .ro = 0xFFFFFFC0, \ + .reset = 0x0, \ + }, \ + [0x201] = { \ + .name = "STAT", \ + .addr = 0x804, \ + .ro = 0xFCF57FAF, \ + .reset = 0x801, \ + }, \ + [0x202] = { \ + .name = "INTENSET", \ + .addr = 0x808, \ + .ro = 0xFCF476AE, \ + .reset = 0x0, \ + }, \ + [0x203] = { \ + .name = "INTENCLR", \ + .addr = 0x80C, \ + .ro = 0xFCF476AE, \ + .reset = 0x0, \ + }, \ + [0x204] = { \ + .name = "TIMEOUT", \ + .addr = 0x810, \ + .ro = 0xFFFF0000, \ + .reset = 0xFFFF, \ + }, \ + [0x205] = { \ + .name = "CLKDIV", \ + .addr = 0x814, \ + .ro = 0xFFFF0000, \ + .reset = 0x0, \ + }, \ + [0x206] = { \ + .name = "INTSTAT", \ + .addr = 0x818, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x801, \ + }, \ + [0x208] = { \ + .name = "MSTCTL", \ + .addr = 0x820, \ + .ro = 0xFFFFFFF0, \ + .reset = 0x0, \ + }, \ + [0x209] = { \ + .name = "MSTTIME", \ + .addr = 0x824, \ + .ro = 0xFFFFFF88, \ + .reset = 0x77, \ + }, \ + [0x20A] = { \ + .name = "MSTDAT", \ + .addr = 0x828, \ + .ro = 0xFFFFFF00, \ + .reset = 0x0, \ + }, \ + [0x210] = { \ + .name = "SLVCTL", \ + .addr = 0x840, \ + .ro = 0xFFFFFCF4, \ + .reset = 0x0, \ + }, \ + [0x211] = { \ + .name = "SLVDAT", \ + .addr = 0x844, \ + .ro = 0xFFFFFF00, \ + .reset = 0x0, \ + }, \ + [0x212] = { \ + .name = "SLVADR0", \ + .addr = 0x848, \ + .ro = 0xFFFF7F00, \ + .reset = 0x1, \ + }, \ + [0x213] = { \ + .name = "SLVADR1", \ + .addr = 0x84C, \ + .ro = 0xFFFF7F00, \ + .reset = 0x1, \ + }, \ + [0x214] = { \ + .name = "SLVADR2", \ + .addr = 0x850, \ + .ro = 0xFFFF7F00, \ + .reset = 0x1, \ + }, \ + [0x215] = { \ + .name = "SLVADR3", \ + .addr = 0x854, \ + .ro = 0xFFFF7F00, \ + .reset = 0x1, \ + }, \ + [0x216] = { \ + .name = "SLVQUAL0", \ + .addr = 0x858, \ + .ro = 0xFFFFFF00, \ + .reset = 0x0, \ + }, \ + [0x220] = { \ + .name = "MONRXDAT", \ + .addr = 0x880, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x3FF] = { \ + .name = "ID", \ + .addr = 0xFFC, \ + .ro = 0xFFFFFFFF, \ + .reset = 0xE0301300, \ + }, \ + } diff --git a/include/hw/i2c/flexcomm_i2c.h b/include/hw/i2c/flexcomm_i2c.h new file mode 100644 index 0000000000..7b27e333d7 --- /dev/null +++ b/include/hw/i2c/flexcomm_i2c.h @@ -0,0 +1,40 @@ +/* + * 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_FLEXCOMM_I2C_H +#define HW_FLEXCOMM_I2C_H + +#include "hw/i2c/i2c.h" +#include "hw/misc/flexcomm_function.h" + +#define TYPE_FLEXCOMM_I2C "flexcomm-i2c" +OBJECT_DECLARE_TYPE(FlexcommI2cState, FlexcommI2cClass, FLEXCOMM_I2C); + +struct FlexcommI2cState { + FlexcommFunction parent_obj; + + I2CBus *bus; +}; + +struct FlexcommI2cClass { + FlexcommFunctionClass parent_obj; + + FlexcommFunctionSelect select; +}; + +#define MSTSTATE_IDLE 0 +#define MSTSTATE_RXRDY 1 +#define MSTSTATE_TXRDY 2 +#define MSTSTATE_NAKADR 3 +#define MSTSTATE_NAKDAT 4 + + +#endif /* HW_FLEXCOMM_I2C_H */ diff --git a/include/hw/misc/flexcomm.h b/include/hw/misc/flexcomm.h index 679b7ea64d..c9f1cd3890 100644 --- a/include/hw/misc/flexcomm.h +++ b/include/hw/misc/flexcomm.h @@ -16,6 +16,7 @@ #include "hw/arm/svd/flexcomm.h" #include "qemu/fifo32.h" #include "hw/char/flexcomm_usart.h" +#include "hw/i2c/flexcomm_i2c.h" #define FLEXCOMM_FUNC_USART 0 #define FLEXCOMM_FUNC_SPI 1 @@ -48,6 +49,7 @@ struct FlexcommState { Fifo32 rx_fifo; Fifo32 tx_fifo; FlexcommUsartState usart; + FlexcommI2cState i2c; }; #endif /* HW_FLEXCOMM_H */ diff --git a/hw/i2c/flexcomm_i2c.c b/hw/i2c/flexcomm_i2c.c new file mode 100644 index 0000000000..e5341ec241 --- /dev/null +++ b/hw/i2c/flexcomm_i2c.c @@ -0,0 +1,250 @@ +/* + * 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/i2c/flexcomm_i2c.h" +#include "hw/arm/svd/flexcomm_i2c.h" + +#define REG(s, reg) (s->regs[R_FLEXCOMM_I2C_##reg]) +#define RF_WR(s, reg, field, val) \ + ARRAY_FIELD_DP32(s->regs, FLEXCOMM_I2C_##reg, field, val) +#define RF_RD(s, reg, field) \ + ARRAY_FIELD_EX32(s->regs, FLEXCOMM_I2C_##reg, field) + +static FLEXCOMM_I2C_REGISTER_ACCESS_INFO_ARRAY(reg_info); + +static void flexcomm_i2c_reset(FlexcommFunction *f) +{ + for (int i = 0; i < FLEXCOMM_I2C_REGS_NO; i++) { + hwaddr addr = reg_info[i].addr; + + if (addr != -1) { + struct RegisterInfo ri = { + .data = &f->regs[addr / 4], + .data_size = 4, + .access = ®_info[i], + }; + + register_reset(&ri); + } + } +} + +static void flexcomm_i2c_irq_update(FlexcommFunction *f) +{ + bool enabled = RF_RD(f, CFG, MSTEN); + bool irq, per_irqs; + + REG(f, INTSTAT) = REG(f, STAT) & REG(f, INTENSET); + per_irqs = REG(f, INTSTAT) != 0; + + irq = enabled && per_irqs; + + trace_flexcomm_i2c_irq(DEVICE(f)->id, irq, per_irqs, enabled); + flexcomm_set_irq(f, irq); +} + +static MemTxResult flexcomm_i2c_reg_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + FlexcommFunction *f = FLEXCOMM_FUNCTION(opaque); + MemTxResult ret = MEMTX_OK; + const struct RegisterAccessInfo *rai = ®_info[addr / 4]; + + if (size != 4) { + ret = MEMTX_ERROR; + goto out; + } + + *data = f->regs[addr / 4]; + + flexcomm_i2c_irq_update(f); + +out: + trace_flexcomm_i2c_reg_read(DEVICE(f)->id, rai->name, addr, *data); + return ret; +} + +static MemTxResult flexcomm_i2c_reg_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + FlexcommFunction *f = FLEXCOMM_FUNCTION(opaque); + FlexcommI2cState *s = FLEXCOMM_I2C(opaque); + const struct RegisterAccessInfo *rai = ®_info[addr / 4]; + struct RegisterInfo ri = { + .data = &f->regs[addr / 4], + .data_size = 4, + .access = rai, + }; + + trace_flexcomm_i2c_reg_write(DEVICE(f)->id, rai->name, addr, value); + + if (size != 4) { + return MEMTX_ERROR; + } + + switch (addr) { + case A_FLEXCOMM_I2C_CFG: + { + register_write(&ri, value, ~0, NULL, false); + if (RF_RD(f, CFG, SLVEN)) { + qemu_log_mask(LOG_GUEST_ERROR, "I2C slave not supported"); + } + if (RF_RD(f, CFG, MONEN)) { + qemu_log_mask(LOG_GUEST_ERROR, "I2C monitoring not supported"); + } + break; + } + case A_FLEXCOMM_I2C_INTENCLR: + { + REG(f, INTENSET) &= ~value; + break; + } + case A_FLEXCOMM_I2C_TIMEOUT: + { + register_write(&ri, value, ~0, NULL, false); + /* The bottom 4 bits are hard-wired to 0xF */ + RF_WR(f, TIMEOUT, TOMIN, 0xf); + break; + } + case A_FLEXCOMM_I2C_MSTCTL: + { + register_write(&ri, value, ~0, NULL, false); + if (RF_RD(f, MSTCTL, MSTSTART)) { + uint8_t i2c_addr = RF_RD(f, MSTDAT, DATA); + bool recv = i2c_addr & 1; + + trace_flexcomm_i2c_start(DEVICE(s)->id, i2c_addr, recv); + if (i2c_start_transfer(s->bus, i2c_addr, recv)) { + RF_WR(f, STAT, MSTSTATE, MSTSTATE_NAKADR); + trace_flexcomm_i2c_nak(DEVICE(s)->id); + } else { + if (recv) { + uint8_t data = i2c_recv(s->bus); + + RF_WR(f, MSTDAT, DATA, data); + trace_flexcomm_i2c_rx(DEVICE(s)->id, data); + RF_WR(f, STAT, MSTSTATE, MSTSTATE_RXRDY); + } else { + RF_WR(f, STAT, MSTSTATE, MSTSTATE_TXRDY); + } + } + } + if (RF_RD(f, MSTCTL, MSTSTOP)) { + RF_WR(f, STAT, MSTSTATE, MSTSTATE_IDLE); + i2c_end_transfer(s->bus); + } + if (RF_RD(f, MSTCTL, MSTCONTINUE)) { + if (RF_RD(f, STAT, MSTSTATE) == MSTSTATE_TXRDY) { + uint8_t data = RF_RD(f, MSTDAT, DATA); + + trace_flexcomm_i2c_tx(DEVICE(s)->id, data); + if (i2c_send(s->bus, data)) { + RF_WR(f, STAT, MSTSTATE, MSTSTATE_NAKDAT); + } + } else if (RF_RD(f, STAT, MSTSTATE) == MSTSTATE_RXRDY) { + uint8_t data = i2c_recv(s->bus); + + RF_WR(f, MSTDAT, DATA, data); + trace_flexcomm_i2c_rx(DEVICE(s)->id, data); + } + } + break; + } + case A_FLEXCOMM_I2C_STAT: + { + /* write 1 to clear bits */ + REG(f, STAT) &= ~value; + break; + } + case A_FLEXCOMM_I2C_SLVCTL: + case A_FLEXCOMM_I2C_SLVDAT: + case A_FLEXCOMM_I2C_SLVADR0: + case A_FLEXCOMM_I2C_SLVADR1: + case A_FLEXCOMM_I2C_SLVADR2: + case A_FLEXCOMM_I2C_SLVADR3: + case A_FLEXCOMM_I2C_SLVQUAL0: + { + qemu_log_mask(LOG_GUEST_ERROR, "I2C slave not supported\n"); + break; + } + default: + register_write(&ri, value, ~0, NULL, false); + break; + } + + flexcomm_i2c_irq_update(f); + + return MEMTX_OK; +} + +static void flexcomm_i2c_select(FlexcommFunction *f, bool selected) +{ + FlexcommI2cClass *ic = FLEXCOMM_I2C_GET_CLASS(f); + + if (selected) { + flexcomm_i2c_reset(f); + } + ic->select(f, selected); +} + +static const MemoryRegionOps flexcomm_i2c_ops = { + .read_with_attrs = flexcomm_i2c_reg_read, + .write_with_attrs = flexcomm_i2c_reg_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void flexcomm_i2c_realize(DeviceState *dev, Error **errp) +{ + FlexcommI2cState *s = FLEXCOMM_I2C(dev); + + s->bus = i2c_init_bus(DEVICE(s), "bus"); +} + +static void flexcomm_i2c_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + FlexcommFunctionClass *fc = FLEXCOMM_FUNCTION_CLASS(klass); + FlexcommI2cClass *ic = FLEXCOMM_I2C_CLASS(klass); + + dc->realize = flexcomm_i2c_realize; + ic->select = fc->select; + fc->select = flexcomm_i2c_select; + fc->name = "i2c"; + fc->mmio_ops = &flexcomm_i2c_ops; +} + +static const TypeInfo flexcomm_i2c_types[] = { + { + .name = TYPE_FLEXCOMM_I2C, + .parent = TYPE_FLEXCOMM_FUNCTION, + .instance_size = sizeof(FlexcommI2cState), + .class_init = flexcomm_i2c_class_init, + .class_size = sizeof(FlexcommI2cClass), + }, +}; + +DEFINE_TYPES(flexcomm_i2c_types); diff --git a/hw/misc/flexcomm.c b/hw/misc/flexcomm.c index a291148f27..b1a2f01acf 100644 --- a/hw/misc/flexcomm.c +++ b/hw/misc/flexcomm.c @@ -24,6 +24,7 @@ #include "hw/misc/flexcomm.h" #include "hw/arm/svd/flexcomm_usart.h" #include "hw/char/flexcomm_usart.h" +#include "hw/i2c/flexcomm_i2c.h" #define REG(s, reg) (s->regs[R_FLEXCOMM_##reg]) #define RF_WR(s, reg, field, val) \ @@ -220,6 +221,7 @@ static void flexcomm_init(Object *obj) sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->container); sysbus_init_irq(sbd, &s->irq); object_initialize_child(obj, "usart", &s->usart, TYPE_FLEXCOMM_USART); + object_initialize_child(obj, "i2c", &s->i2c, TYPE_FLEXCOMM_I2C); } static void flexcomm_finalize(Object *obj) @@ -250,6 +252,7 @@ static void flexcomm_realize(DeviceState *dev, Error **errp) memory_region_add_subregion_overlap(&s->container, 0, &s->mmio, -1); flexcomm_func_realize_and_unref(FLEXCOMM_FUNCTION(&s->usart), errp); + flexcomm_func_realize_and_unref(FLEXCOMM_FUNCTION(&s->i2c), errp); } static const VMStateDescription vmstate_flexcomm = { diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build index 3bff90bcbd..2542b56294 100644 --- a/hw/arm/svd/meson.build +++ b/hw/arm/svd/meson.build @@ -8,4 +8,8 @@ if get_option('mcux-soc-svd') [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/flexcomm_usart.h', '-p', 'USART0', '-t', 'FLEXCOMM_USART', '--fields', 'CFG:ENABLE FIFOCFG:ENABLE*,EMPTY* FIFO*:* *:']) + run_target('svd-flexcomm-i2c', command: svd_gen_header + + [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/flexcomm_i2c.h', + '-p', 'I2C0', '-t', 'FLEXCOMM_I2C', + '--fields', 'CFG TIMEOUT:TOMIN MSTCTL MSTDAT STAT:MSTPENDING,MSTSTATE INT*:MSTPENDING* SLV*:']) endif 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/Kconfig b/hw/misc/Kconfig index 14167ae9e8..9a244fa01d 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -215,5 +215,6 @@ config XLNX_VERSAL_TRNG config FLEXCOMM bool + select I2C source macio/Kconfig From patchwork Tue Oct 8 01:18:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993921 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=x1peIlfI; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMyxg6Fglz1xsn for ; Tue, 8 Oct 2024 12:25:11 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxytN-0002Wa-L6; Mon, 07 Oct 2024 21:20:02 -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 <3jogEZwUKCu8kRmZgXffXcV.TfdhVdl-UVmVcefeXel.fiX@flex--tavip.bounces.google.com>) id 1sxysg-0007qG-3U for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:21 -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 <3jogEZwUKCu8kRmZgXffXcV.TfdhVdl-UVmVcefeXel.fiX@flex--tavip.bounces.google.com>) id 1sxysa-00009c-T4 for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:16 -0400 Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-6e2b049b64aso81156477b3.3 for ; Mon, 07 Oct 2024 18:19:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350351; x=1728955151; 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=bFIqfrB60fzUJwtasXiqxuXbxvJUBaZy8yqqf9RYqyc=; b=x1peIlfIAg5KUmhXJxqFRQ2JwbyBiiA2MOZrzbRJn+dFSPPF2i+C7+DLYaupQuDwq9 E2Rt72z3rC2arKSNOc9xO0BhWpTPGwh9UKOSxFsf4UEqCwLoNWlchCN/j/2xcephNA2f n9Xwmg1EkwIaG9Qn3hsDrevPPgRz+a7r67koCKG9uGVmdWh/e+MqXxLB3l+whqcDF+OI AJJ9hzzs1wqOKz8vAg7mdgh98iTGqZdOngksyrbtw2kq1SWKevKLxbfBq2k0HhFd6MsU ZSoHkDuYSQjMF5y+KCEFjnjAfhXHNRPE2so2NEbfAku6dh0T+06gQfkap1BS4bQVP1WU Elxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350351; x=1728955151; 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=bFIqfrB60fzUJwtasXiqxuXbxvJUBaZy8yqqf9RYqyc=; b=CcxDY6DrkVmFXOvBqHwwpaOcsxfDOstM4MunzEqeWI/LOEgcJPz4UUyCrWCvyyfSC3 rsXUdKHZPJplydD/YHQMennAb2M11DR0tw5HO58MqztnNBYkCgQoxMbH5g8pxGBoX5yc E8NOubH+3fIehav7Imew4TC8Nezu8EKOMtNCMe+Ij5UPzkjg6yzDrldWpKVgn3LZ5evx N80N41JhMF+LipH3RUbQLuIuzchLmwtaU3lduRwTW6bFNC3ZM74YKI3T0lNNICHg3LsT GBfdjkJC59kjc6MpiSdfcSJ49Y36AnvaeStBWhfnwlYDJYABNZI/e1nMTCgTa4Vl8Rxw GniA== X-Gm-Message-State: AOJu0YwH4QN0fndhBvGHjC9m1ngrUb2VIU98tTLbUZ/mh7wsPihKKZmR TqNEHHPSjUFMZg5Ik/ZrxRK/I649yr+9pxm9GRC7f2YzC18NHImFGAcc3R05L2CyVG+sioxxvzE dSj45GHj1sQs16E8106w3MNXIXiPtLtnuQWNyk7yCViGGGYRnlTlFJjfbe2yU0gLTVc0vJl0Mbg ZfyfGwV3+WiGYFL4fFZsK8+L963Q== X-Google-Smtp-Source: AGHT+IGkuD7TbREcq6U/rFFH7/EYiI9O0MyX/NGirkYsV/sq33w1AV5NrldGAUI8PuBzb2XtTF0vKNw1DQ== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:690c:945:b0:6db:7b3d:b414 with SMTP id 00721157ae682-6e2c6e9b946mr1970347b3.0.1728350350652; Mon, 07 Oct 2024 18:19:10 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:35 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-10-tavip@google.com> Subject: [PATCH v2 09/25] 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, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::114a; envelope-from=3jogEZwUKCu8kRmZgXffXcV.TfdhVdl-UVmVcefeXel.fiX@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Sebastian Ene Add support for NXP's flexcomm spi. It supports FIFO access, interrupts and master mode only. It does not support DMA. The patch includes an automatically generated header which contains the register layout and helpers. The header can be regenerated with the svd-flexcomm-spi target when the build is configured with --enable-mcux-soc-svd. Signed-off-by: Sebastian Ene [tavip: add suport for CFG.SPOL, CFG.LSBF, TX control flags per FIFO entry and 8/16 bit access to FIFORD and FIFOWR, convert to Resettable interface, add support for migration] Signed-off-by: Octavian Purdila --- include/hw/arm/svd/flexcomm_spi.h | 327 +++++++++++++++++++++++ include/hw/misc/flexcomm.h | 2 + include/hw/ssi/flexcomm_spi.h | 36 +++ hw/misc/flexcomm.c | 3 + hw/ssi/flexcomm_spi.c | 422 ++++++++++++++++++++++++++++++ hw/arm/svd/meson.build | 4 + hw/misc/Kconfig | 1 + hw/ssi/meson.build | 1 + hw/ssi/trace-events | 5 + 9 files changed, 801 insertions(+) create mode 100644 include/hw/arm/svd/flexcomm_spi.h create mode 100644 include/hw/ssi/flexcomm_spi.h create mode 100644 hw/ssi/flexcomm_spi.c diff --git a/include/hw/arm/svd/flexcomm_spi.h b/include/hw/arm/svd/flexcomm_spi.h new file mode 100644 index 0000000000..c9ab2c661a --- /dev/null +++ b/include/hw/arm/svd/flexcomm_spi.h @@ -0,0 +1,327 @@ +/* + * Copyright 2016-2023 NXP SPDX-License-Identifier: BSD-3-Clause + * + * Automatically generated by svd-gen-header.py from MIMXRT595S_cm33.xml + */ +#pragma once + +#include "hw/register.h" + +/* Serial Peripheral Interfaces (SPI) */ +#define FLEXCOMM_SPI_REGS_NO (1024) + +/* Configuration Register */ +REG32(FLEXCOMM_SPI_CFG, 0x400); +/* SPI Enable */ +FIELD(FLEXCOMM_SPI_CFG, ENABLE, 0, 1); +/* Master Mode Select */ +FIELD(FLEXCOMM_SPI_CFG, MASTER, 2, 1); +/* LSB First Mode Enable */ +FIELD(FLEXCOMM_SPI_CFG, LSBF, 3, 1); +/* Clock Phase Select */ +FIELD(FLEXCOMM_SPI_CFG, CPHA, 4, 1); +/* Clock Polarity Select */ +FIELD(FLEXCOMM_SPI_CFG, CPOL, 5, 1); +/* Loopback Mode Enable */ +FIELD(FLEXCOMM_SPI_CFG, LOOP, 7, 1); +/* SSEL0 Polarity Select */ +FIELD(FLEXCOMM_SPI_CFG, SPOL0, 8, 1); +/* SSEL1 Polarity Select */ +FIELD(FLEXCOMM_SPI_CFG, SPOL1, 9, 1); +/* SSEL2 Polarity Select */ +FIELD(FLEXCOMM_SPI_CFG, SPOL2, 10, 1); +/* SSEL3 Polarity Select */ +FIELD(FLEXCOMM_SPI_CFG, SPOL3, 11, 1); + +/* Status Register */ +REG32(FLEXCOMM_SPI_STAT, 0x408); +/* Slave Select Assert */ +FIELD(FLEXCOMM_SPI_STAT, SSA, 4, 1); +/* Slave Select Deassert */ +FIELD(FLEXCOMM_SPI_STAT, SSD, 5, 1); +/* Stalled Status Flag */ +FIELD(FLEXCOMM_SPI_STAT, STALLED, 6, 1); +/* End Transfer Control */ +FIELD(FLEXCOMM_SPI_STAT, ENDTRANSFER, 7, 1); +/* Master Idle Status Flag */ +FIELD(FLEXCOMM_SPI_STAT, MSTIDLE, 8, 1); + +/* Interrupt Enable Register */ +REG32(FLEXCOMM_SPI_INTENSET, 0x40C); + +/* Interrupt Enable Clear Register */ +REG32(FLEXCOMM_SPI_INTENCLR, 0x410); + +/* Interrupt Status Register */ +REG32(FLEXCOMM_SPI_INTSTAT, 0x428); + +/* FIFO Configuration Register */ +REG32(FLEXCOMM_SPI_FIFOCFG, 0xE00); +/* Enable the Transmit FIFO */ +FIELD(FLEXCOMM_SPI_FIFOCFG, ENABLETX, 0, 1); +/* Enable the Receive FIFO */ +FIELD(FLEXCOMM_SPI_FIFOCFG, ENABLERX, 1, 1); +/* Empty Command for the Transmit FIFO */ +FIELD(FLEXCOMM_SPI_FIFOCFG, EMPTYTX, 16, 1); +/* Empty Command for the Receive FIFO */ +FIELD(FLEXCOMM_SPI_FIFOCFG, EMPTYRX, 17, 1); + +/* FIFO Status Register */ +REG32(FLEXCOMM_SPI_FIFOSTAT, 0xE04); +/* TX FIFO Error */ +FIELD(FLEXCOMM_SPI_FIFOSTAT, TXERR, 0, 1); +/* RX FIFO Error */ +FIELD(FLEXCOMM_SPI_FIFOSTAT, RXERR, 1, 1); +/* Peripheral Interrupt */ +FIELD(FLEXCOMM_SPI_FIFOSTAT, PERINT, 3, 1); +/* Transmit FIFO Empty */ +FIELD(FLEXCOMM_SPI_FIFOSTAT, TXEMPTY, 4, 1); +/* Transmit FIFO is Not Full */ +FIELD(FLEXCOMM_SPI_FIFOSTAT, TXNOTFULL, 5, 1); +/* Receive FIFO is Not Empty */ +FIELD(FLEXCOMM_SPI_FIFOSTAT, RXNOTEMPTY, 6, 1); +/* Receive FIFO is Full */ +FIELD(FLEXCOMM_SPI_FIFOSTAT, RXFULL, 7, 1); +/* Transmit FIFO Current Level */ +FIELD(FLEXCOMM_SPI_FIFOSTAT, TXLVL, 8, 5); +/* Receive FIFO Current Level */ +FIELD(FLEXCOMM_SPI_FIFOSTAT, RXLVL, 16, 5); + +/* FIFO Trigger Register */ +REG32(FLEXCOMM_SPI_FIFOTRIG, 0xE08); +/* Transmit FIFO Level Trigger Enable */ +FIELD(FLEXCOMM_SPI_FIFOTRIG, TXLVLENA, 0, 1); +/* Receive FIFO Level Trigger Enable */ +FIELD(FLEXCOMM_SPI_FIFOTRIG, RXLVLENA, 1, 1); +/* Transmit FIFO Level Trigger Point */ +FIELD(FLEXCOMM_SPI_FIFOTRIG, TXLVL, 8, 4); +/* Trigger when the TX FIFO becomes empty */ +#define FLEXCOMM_SPI_FIFOTRIG_TXLVL_TXLVL0 0 +/* Trigger when the TX FIFO level decreases to 1 entry */ +#define FLEXCOMM_SPI_FIFOTRIG_TXLVL_TXLVL1 1 +/* Trigger when the TX FIFO level decreases to 15 entries (is no longer full) */ +#define FLEXCOMM_SPI_FIFOTRIG_TXLVL_TXLVL15 15 +/* Receive FIFO Level Trigger Point */ +FIELD(FLEXCOMM_SPI_FIFOTRIG, RXLVL, 16, 4); +/* Trigger when the RX FIFO has received 1 entry (is no longer empty) */ +#define FLEXCOMM_SPI_FIFOTRIG_RXLVL_RXLVL1 0 +/* Trigger when the RX FIFO has received 2 entries */ +#define FLEXCOMM_SPI_FIFOTRIG_RXLVL_RXLVL2 1 +/* Trigger when the RX FIFO has received 16 entries (has become full) */ +#define FLEXCOMM_SPI_FIFOTRIG_RXLVL_RXLVL15 15 + +/* FIFO Interrupt Enable Register */ +REG32(FLEXCOMM_SPI_FIFOINTENSET, 0xE10); +/* TX Error Interrupt Enable */ +FIELD(FLEXCOMM_SPI_FIFOINTENSET, TXERR, 0, 1); +/* Receive Error Interrupt Enable */ +FIELD(FLEXCOMM_SPI_FIFOINTENSET, RXERR, 1, 1); +/* Transmit FIFO Level Interrupt Enable */ +FIELD(FLEXCOMM_SPI_FIFOINTENSET, TXLVL, 2, 1); +/* Receive FIFO Level Interrupt Enable */ +FIELD(FLEXCOMM_SPI_FIFOINTENSET, RXLVL, 3, 1); + +/* FIFO Interrupt Enable Clear Register */ +REG32(FLEXCOMM_SPI_FIFOINTENCLR, 0xE14); +/* TX Error Interrupt Enable */ +FIELD(FLEXCOMM_SPI_FIFOINTENCLR, TXERR, 0, 1); +/* Receive Error Interrupt Enable */ +FIELD(FLEXCOMM_SPI_FIFOINTENCLR, RXERR, 1, 1); +/* Transmit FIFO Level Interrupt Enable */ +FIELD(FLEXCOMM_SPI_FIFOINTENCLR, TXLVL, 2, 1); +/* Receive FIFO Level Interrupt Enable */ +FIELD(FLEXCOMM_SPI_FIFOINTENCLR, RXLVL, 3, 1); + +/* FIFO Interrupt Status Register */ +REG32(FLEXCOMM_SPI_FIFOINTSTAT, 0xE18); +/* TX FIFO Error Interrupt Status */ +FIELD(FLEXCOMM_SPI_FIFOINTSTAT, TXERR, 0, 1); +/* RX FIFO Error Interrupt Status */ +FIELD(FLEXCOMM_SPI_FIFOINTSTAT, RXERR, 1, 1); +/* Transmit FIFO Level Interrupt Status */ +FIELD(FLEXCOMM_SPI_FIFOINTSTAT, TXLVL, 2, 1); +/* Receive FIFO Level Interrupt Status */ +FIELD(FLEXCOMM_SPI_FIFOINTSTAT, RXLVL, 3, 1); +/* Peripheral Interrupt Status */ +FIELD(FLEXCOMM_SPI_FIFOINTSTAT, PERINT, 4, 1); + +/* FIFO Write Data Register */ +REG32(FLEXCOMM_SPI_FIFOWR, 0xE20); +/* Transmit Data to the FIFO */ +FIELD(FLEXCOMM_SPI_FIFOWR, TXDATA, 0, 16); +/* Transmit Slave Select 0 */ +FIELD(FLEXCOMM_SPI_FIFOWR, TXSSEL0_N, 16, 1); +/* Transmit Slave Select 1 */ +FIELD(FLEXCOMM_SPI_FIFOWR, TXSSEL1_N, 17, 1); +/* Transmit Slave Select 2 */ +FIELD(FLEXCOMM_SPI_FIFOWR, TXSSEL2_N, 18, 1); +/* Transmit Slave Select 3 */ +FIELD(FLEXCOMM_SPI_FIFOWR, TXSSEL3_N, 19, 1); +/* End of Transfer */ +FIELD(FLEXCOMM_SPI_FIFOWR, EOT, 20, 1); +/* End of Frame */ +FIELD(FLEXCOMM_SPI_FIFOWR, EOF, 21, 1); +/* Receive Ignore */ +FIELD(FLEXCOMM_SPI_FIFOWR, RXIGNORE, 22, 1); +/* Transmit Ignore */ +FIELD(FLEXCOMM_SPI_FIFOWR, TXIGNORE, 23, 1); +/* Data Length */ +FIELD(FLEXCOMM_SPI_FIFOWR, LEN, 24, 4); +/* Data transfer is 4 bits in length */ +#define FLEXCOMM_SPI_FIFOWR_LEN_LEN_4BITS 3 +/* Data transfer is 5 bits in length */ +#define FLEXCOMM_SPI_FIFOWR_LEN_LEN_5BITS 4 +/* Data transfer is 16 bits in length */ +#define FLEXCOMM_SPI_FIFOWR_LEN_LEN_16BITS 15 + +/* FIFO Read Data Register */ +REG32(FLEXCOMM_SPI_FIFORD, 0xE30); +/* Received Data from the FIFO */ +FIELD(FLEXCOMM_SPI_FIFORD, RXDATA, 0, 16); +/* Slave Select 0 for Receive */ +FIELD(FLEXCOMM_SPI_FIFORD, RXSSEL0_N, 16, 1); +/* Slave Select 1 for Receive */ +FIELD(FLEXCOMM_SPI_FIFORD, RXSSEL1_N, 17, 1); +/* Slave Select 2 for Receive */ +FIELD(FLEXCOMM_SPI_FIFORD, RXSSEL2_N, 18, 1); +/* Slave Select 3 for Receive */ +FIELD(FLEXCOMM_SPI_FIFORD, RXSSEL3_N, 19, 1); +/* Start of Transfer Flag */ +FIELD(FLEXCOMM_SPI_FIFORD, SOT, 20, 1); + +/* FIFO Data Read with no FIFO Pop Register */ +REG32(FLEXCOMM_SPI_FIFORDNOPOP, 0xE40); +/* Received Data from the FIFO */ +FIELD(FLEXCOMM_SPI_FIFORDNOPOP, RXDATA, 0, 16); +/* Slave Select 0 for Receive */ +FIELD(FLEXCOMM_SPI_FIFORDNOPOP, RXSSEL0_N, 16, 1); +/* Slave Select 1 for Receive */ +FIELD(FLEXCOMM_SPI_FIFORDNOPOP, RXSSEL1_N, 17, 1); +/* Slave Select 2 for Receive */ +FIELD(FLEXCOMM_SPI_FIFORDNOPOP, RXSSEL2_N, 18, 1); +/* Slave Select 3 for Receive */ +FIELD(FLEXCOMM_SPI_FIFORDNOPOP, RXSSEL3_N, 19, 1); +/* Start of Transfer Flag */ +FIELD(FLEXCOMM_SPI_FIFORDNOPOP, SOT, 20, 1); + +/* FIFO Size Register */ +REG32(FLEXCOMM_SPI_FIFOSIZE, 0xE48); +/* FIFO Size */ +FIELD(FLEXCOMM_SPI_FIFOSIZE, FIFOSIZE, 0, 5); + + +#define FLEXCOMM_SPI_REGISTER_ACCESS_INFO_ARRAY(_name) \ + struct RegisterAccessInfo _name[FLEXCOMM_SPI_REGS_NO] = { \ + [0 ... FLEXCOMM_SPI_REGS_NO - 1] = { \ + .name = "", \ + .addr = -1, \ + }, \ + [0x100] = { \ + .name = "CFG", \ + .addr = 0x400, \ + .ro = 0xFFFFF042, \ + .reset = 0x0, \ + }, \ + [0x101] = { \ + .name = "DLY", \ + .addr = 0x404, \ + .ro = 0xFFFF0000, \ + .reset = 0x0, \ + }, \ + [0x102] = { \ + .name = "STAT", \ + .addr = 0x408, \ + .ro = 0xFFFFFF4F, \ + .reset = 0x100, \ + }, \ + [0x103] = { \ + .name = "INTENSET", \ + .addr = 0x40C, \ + .ro = 0xFFFFFECF, \ + .reset = 0x0, \ + }, \ + [0x104] = { \ + .name = "INTENCLR", \ + .addr = 0x410, \ + .ro = 0xFFFFFECF, \ + .reset = 0x0, \ + }, \ + [0x109] = { \ + .name = "DIV", \ + .addr = 0x424, \ + .ro = 0xFFFF0000, \ + .reset = 0x0, \ + }, \ + [0x10A] = { \ + .name = "INTSTAT", \ + .addr = 0x428, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x380] = { \ + .name = "FIFOCFG", \ + .addr = 0xE00, \ + .ro = 0xFFF80FFC, \ + .reset = 0x0, \ + }, \ + [0x381] = { \ + .name = "FIFOSTAT", \ + .addr = 0xE04, \ + .ro = 0xFFFFFFFC, \ + .reset = 0x30, \ + }, \ + [0x382] = { \ + .name = "FIFOTRIG", \ + .addr = 0xE08, \ + .ro = 0xFFF0F0FC, \ + .reset = 0x0, \ + }, \ + [0x384] = { \ + .name = "FIFOINTENSET", \ + .addr = 0xE10, \ + .ro = 0xFFFFFFF0, \ + .reset = 0x0, \ + }, \ + [0x385] = { \ + .name = "FIFOINTENCLR", \ + .addr = 0xE14, \ + .ro = 0xFFFFFFF0, \ + .reset = 0x0, \ + }, \ + [0x386] = { \ + .name = "FIFOINTSTAT", \ + .addr = 0xE18, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x388] = { \ + .name = "FIFOWR", \ + .addr = 0xE20, \ + .ro = 0xF0000000, \ + .reset = 0x0, \ + }, \ + [0x38C] = { \ + .name = "FIFORD", \ + .addr = 0xE30, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x390] = { \ + .name = "FIFORDNOPOP", \ + .addr = 0xE40, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x392] = { \ + .name = "FIFOSIZE", \ + .addr = 0xE48, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x3FF] = { \ + .name = "ID", \ + .addr = 0xFFC, \ + .ro = 0xFFFFFFFF, \ + .reset = 0xE0201200, \ + }, \ + } diff --git a/include/hw/misc/flexcomm.h b/include/hw/misc/flexcomm.h index c9f1cd3890..757453df97 100644 --- a/include/hw/misc/flexcomm.h +++ b/include/hw/misc/flexcomm.h @@ -17,6 +17,7 @@ #include "qemu/fifo32.h" #include "hw/char/flexcomm_usart.h" #include "hw/i2c/flexcomm_i2c.h" +#include "hw/ssi/flexcomm_spi.h" #define FLEXCOMM_FUNC_USART 0 #define FLEXCOMM_FUNC_SPI 1 @@ -50,6 +51,7 @@ struct FlexcommState { Fifo32 tx_fifo; FlexcommUsartState usart; FlexcommI2cState i2c; + FlexcommSpiState spi; }; #endif /* HW_FLEXCOMM_H */ diff --git a/include/hw/ssi/flexcomm_spi.h b/include/hw/ssi/flexcomm_spi.h new file mode 100644 index 0000000000..c39cc33de4 --- /dev/null +++ b/include/hw/ssi/flexcomm_spi.h @@ -0,0 +1,36 @@ +/* + * 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_FLEXCOMM_SPI_H +#define HW_FLEXCOMM_SPI_H + +#include "hw/misc/flexcomm_function.h" +#include "hw/ssi/ssi.h" + +#define TYPE_FLEXCOMM_SPI "flexcomm-spi" +OBJECT_DECLARE_TYPE(FlexcommSpiState, FlexcommSpiClass, FLEXCOMM_SPI); + +struct FlexcommSpiState { + FlexcommFunction parent_obj; + + SSIBus *bus; + qemu_irq cs[4]; + bool cs_asserted[4]; + uint32_t tx_ctrl; +}; + +struct FlexcommSpiClass { + FlexcommFunctionClass parent_obj; + + FlexcommFunctionSelect select; +}; + +#endif /* HW_FLEXCOMM_SPI_H */ diff --git a/hw/misc/flexcomm.c b/hw/misc/flexcomm.c index b1a2f01acf..fef220eb5b 100644 --- a/hw/misc/flexcomm.c +++ b/hw/misc/flexcomm.c @@ -25,6 +25,7 @@ #include "hw/arm/svd/flexcomm_usart.h" #include "hw/char/flexcomm_usart.h" #include "hw/i2c/flexcomm_i2c.h" +#include "hw/ssi/flexcomm_spi.h" #define REG(s, reg) (s->regs[R_FLEXCOMM_##reg]) #define RF_WR(s, reg, field, val) \ @@ -222,6 +223,7 @@ static void flexcomm_init(Object *obj) sysbus_init_irq(sbd, &s->irq); object_initialize_child(obj, "usart", &s->usart, TYPE_FLEXCOMM_USART); object_initialize_child(obj, "i2c", &s->i2c, TYPE_FLEXCOMM_I2C); + object_initialize_child(obj, "spi", &s->spi, TYPE_FLEXCOMM_SPI); } static void flexcomm_finalize(Object *obj) @@ -253,6 +255,7 @@ static void flexcomm_realize(DeviceState *dev, Error **errp) memory_region_add_subregion_overlap(&s->container, 0, &s->mmio, -1); flexcomm_func_realize_and_unref(FLEXCOMM_FUNCTION(&s->usart), errp); flexcomm_func_realize_and_unref(FLEXCOMM_FUNCTION(&s->i2c), errp); + flexcomm_func_realize_and_unref(FLEXCOMM_FUNCTION(&s->spi), errp); } static const VMStateDescription vmstate_flexcomm = { diff --git a/hw/ssi/flexcomm_spi.c b/hw/ssi/flexcomm_spi.c new file mode 100644 index 0000000000..d8ecd37024 --- /dev/null +++ b/hw/ssi/flexcomm_spi.c @@ -0,0 +1,422 @@ +/* + * 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 "migration/vmstate.h" +#include "hw/misc/flexcomm.h" +#include "hw/arm/svd/flexcomm_spi.h" + +#define REG(s, reg) (s->regs[R_FLEXCOMM_SPI_##reg]) +#define RF_WR(s, reg, field, val) \ + ARRAY_FIELD_DP32(s->regs, FLEXCOMM_SPI_##reg, field, val) +#define RF_RD(s, reg, field) \ + ARRAY_FIELD_EX32(s->regs, FLEXCOMM_SPI_##reg, field) + +#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 const FLEXCOMM_SPI_REGISTER_ACCESS_INFO_ARRAY(reg_info); + +static void flexcomm_spi_reset(FlexcommFunction *f) +{ + for (int i = 0; i < FLEXCOMM_SPI_REGS_NO; i++) { + hwaddr addr = reg_info[i].addr; + + if (addr != -1) { + struct RegisterInfo ri = { + .data = &f->regs[addr / 4], + .data_size = 4, + .access = ®_info[i], + }; + + register_reset(&ri); + } + } + + RF_WR(f, FIFOSIZE, FIFOSIZE, 0x8); +} + +static void flexcomm_spi_irq_update(FlexcommFunction *f) +{ + bool irq, per_irqs, fifo_irqs, enabled = RF_RD(f, CFG, ENABLE); + + flexcomm_update_fifostat(f); + fifo_irqs = REG(f, FIFOINTSTAT) & REG(f, FIFOINTENSET); + + REG(f, INTSTAT) = REG(f, STAT) & REG(f, INTENSET); + per_irqs = REG(f, INTSTAT) != 0; + + irq = enabled && (fifo_irqs || per_irqs); + + trace_flexcomm_spi_irq(DEVICE(f)->id, irq, fifo_irqs, per_irqs, enabled); + flexcomm_set_irq(f, irq); +} + +static void flexcomm_spi_select(FlexcommFunction *f, bool selected) +{ + FlexcommSpiState *s = FLEXCOMM_SPI(f); + FlexcommSpiClass *sc = FLEXCOMM_SPI_GET_CLASS(f); + + if (selected) { + bool spol[] = { + RF_RD(f, CFG, SPOL0), RF_RD(f, CFG, SPOL1), RF_RD(f, CFG, SPOL2), + RF_RD(f, CFG, SPOL3), + }; + + flexcomm_spi_reset(f); + for (int i = 0; i < ARRAY_SIZE(s->cs); i++) { + s->cs_asserted[i] = false; + qemu_set_irq(s->cs[i], !spol[i]); + } + } + sc->select(f, selected); +} + +static MemTxResult flexcomm_spi_reg_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + FlexcommFunction *f = FLEXCOMM_FUNCTION(opaque); + MemTxResult ret = MEMTX_OK; + const struct RegisterAccessInfo *rai = ®_info[addr / 4]; + + /* + * 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 (size != 4 && addr != A_FLEXCOMM_SPI_FIFORD) { + ret = MEMTX_ERROR; + goto out; + } + + switch (addr) { + case A_FLEXCOMM_SPI_FIFORD: + { + /* If we are running in loopback mode get the data from TX FIFO */ + if (RF_RD(f, CFG, LOOP) && + RF_RD(f, CFG, MASTER)) + { + if (!fifo32_is_empty(f->tx_fifo)) { + *data = fifo32_pop(f->tx_fifo); + } + break; + } + + if (!fifo32_is_empty(f->rx_fifo)) { + *data = fifo32_pop(f->rx_fifo); + } + break; + } + case A_FLEXCOMM_SPI_FIFORDNOPOP: + { + if (!fifo32_is_empty(f->rx_fifo)) { + *data = fifo32_peek(f->rx_fifo); + } + break; + } + default: + *data = f->regs[addr / 4]; + break; + } + + flexcomm_spi_irq_update(f); + +out: + trace_flexcomm_spi_reg_read(DEVICE(f)->id, rai->name, addr, *data); + return ret; +} + +static uint32_t fifowr_len_bits(uint32_t val) +{ + int len = FIELD_EX32(val, FLEXCOMM_SPI_FIFOWR, LEN); + + 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_bytes(uint32_t val) +{ + return fifowr_len_bits(val) > 8 ? 2 : 1; +} + +static uint32_t flexcomm_spi_xfer_word(FlexcommSpiState *s, uint32_t out_data, + int bytes, bool be) +{ + uint32_t word = 0; + int out = 0; + + for (int 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->bus, out) << byte_offset * 8; + } else { + out = (out_data & (0xFF << i * 8)) >> i * 8; + word |= ssi_transfer(s->bus, out) << i * 8; + } + } + + return word; +} + +static uint32_t flexcomm_spi_get_ss_mask(FlexcommSpiState *s, + uint32_t txfifo_val) +{ + FlexcommFunction *f = FLEXCOMM_FUNCTION(s); + + uint32_t slave_select_mask = 0; + bool ss[] = { + FIELD_EX32(txfifo_val, FLEXCOMM_SPI_FIFOWR, TXSSEL0_N), + FIELD_EX32(txfifo_val, FLEXCOMM_SPI_FIFOWR, TXSSEL1_N), + FIELD_EX32(txfifo_val, FLEXCOMM_SPI_FIFOWR, TXSSEL2_N), + FIELD_EX32(txfifo_val, FLEXCOMM_SPI_FIFOWR, TXSSEL3_N), + }; + bool spol[] = { + RF_RD(f, CFG, SPOL0), RF_RD(f, CFG, SPOL1), RF_RD(f, CFG, SPOL2), + RF_RD(f, CFG, SPOL3), + }; + + for (int i = 0; i < ARRAY_SIZE(s->cs); i++) { + int irq_level = ss[i] ? spol[i] : !spol[i]; + + slave_select_mask |= (ss[i] << i); + s->cs_asserted[i] = ss[i]; + qemu_set_irq(s->cs[i], irq_level); + } + + return slave_select_mask; +} + +static MemTxResult flexcomm_spi_reg_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + FlexcommFunction *f = FLEXCOMM_FUNCTION(opaque); + FlexcommSpiState *s = FLEXCOMM_SPI(opaque); + const struct RegisterAccessInfo *rai = ®_info[addr / 4]; + struct RegisterInfo ri = { + .data = &f->regs[addr / 4], + .data_size = 4, + .access = rai, + }; + MemTxResult ret = MEMTX_OK; + + trace_flexcomm_spi_reg_write(DEVICE(f)->id, rai->name, addr, value); + + /* + * 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 (size != 4 && (addr / 4 != R_FLEXCOMM_SPI_FIFOWR)) { + return MEMTX_ERROR; + } + + switch (addr) { + case A_FLEXCOMM_SPI_CFG: + { + register_write(&ri, value, ~0, NULL, false); + break; + } + case A_FLEXCOMM_SPI_INTENCLR: + { + register_write(&ri, value, ~0, NULL, false); + REG(f, INTENSET) &= ~REG(f, INTENCLR); + break; + } + case A_FLEXCOMM_SPI_FIFOCFG: + { + register_write(&ri, value, ~0, NULL, false); + flexcomm_reset_fifos(f); + break; + } + case A_FLEXCOMM_SPI_FIFOSTAT: + { + flexcomm_clear_fifostat(f, value); + break; + } + case A_FLEXCOMM_SPI_FIFOINTENSET: + { + REG(f, FIFOINTENSET) |= value; + break; + } + case A_FLEXCOMM_SPI_FIFOINTENCLR: + { + register_write(&ri, value, ~0, NULL, false); + REG(f, FIFOINTENSET) &= ~REG(f, FIFOINTENCLR); + break; + } + /* update control bits but don't push into the FIFO */ + case A_FLEXCOMM_SPI_FIFOWR + 2: + { + if (value != 0) { + s->tx_ctrl = value << 16; + } + break; + } + /* update control bits but don't push into the FIFO */ + case A_FLEXCOMM_SPI_FIFOWR + 3: + { + if (value != 0) { + s->tx_ctrl = value << 24; + } + break; + } + case A_FLEXCOMM_SPI_FIFOWR: + { + /* fifo value contains both data and control bits */ + uint32_t txfifo_val; + uint16_t tx_data = FIELD_EX32(value, FLEXCOMM_SPI_FIFOWR, TXDATA); + uint32_t tx_ctrl = value & 0xffff0000; + + if (size > 2 && tx_ctrl != 0) { + /* non-zero writes to control bits updates them */ + s->tx_ctrl = tx_ctrl; + } + + /* push the data and control bits into the FIFO */ + txfifo_val = tx_data | s->tx_ctrl; + + if (!fifo32_is_full(f->tx_fifo)) { + fifo32_push(f->tx_fifo, txfifo_val); + } + + if (!RF_RD(f, CFG, ENABLE) || !RF_RD(f, FIFOCFG, 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 (RF_RD(f, CFG, LOOP) || !RF_RD(f, CFG, MASTER)) { + break; + } + + while (!fifo32_is_empty(f->tx_fifo)) { + txfifo_val = fifo32_pop(f->tx_fifo); + + uint32_t ss_mask = flexcomm_spi_get_ss_mask(s, txfifo_val); + uint32_t data = FIELD_EX32(txfifo_val, FLEXCOMM_SPI_FIFOWR, TXDATA); + uint8_t bytes = fifowr_len_bytes(txfifo_val); + bool msb = !RF_RD(f, CFG, LSBF); + uint32_t val32; + + val32 = flexcomm_spi_xfer_word(s, data, bytes, msb); + + if (!fifo32_is_full(f->rx_fifo)) { + /* Append the mask that informs which client is active */ + val32 |= (ss_mask << R_FLEXCOMM_SPI_FIFORD_RXSSEL0_N_SHIFT); + fifo32_push(f->rx_fifo, val32); + } + + /* If this is the end of the transfer raise the CS line */ + if (FIELD_EX32(txfifo_val, FLEXCOMM_SPI_FIFOWR, EOT)) { + bool spol[ARRAY_SIZE(s->cs)] = { + RF_RD(f, CFG, SPOL0), + RF_RD(f, CFG, SPOL1), + RF_RD(f, CFG, SPOL2), + RF_RD(f, CFG, 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: + register_write(&ri, value, ~0, NULL, false); + break; + } + + flexcomm_spi_irq_update(f); + + return ret; +} + +static const MemoryRegionOps flexcomm_spi_ops = { + .read_with_attrs = flexcomm_spi_reg_read, + .write_with_attrs = flexcomm_spi_reg_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void flexcomm_spi_realize(DeviceState *dev, Error **error) +{ + FlexcommSpiState *s = FLEXCOMM_SPI(dev); + + s->bus = ssi_create_bus(DEVICE(s), "bus"); + qdev_init_gpio_out_named(DEVICE(s), s->cs, "cs", ARRAY_SIZE(s->cs)); +} + +static const VMStateDescription vmstate_flexcomm_spi = { + .name = "flexcomm-spi", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_BOOL_ARRAY(cs_asserted, FlexcommSpiState, 4), + VMSTATE_UINT32(tx_ctrl, FlexcommSpiState), + VMSTATE_END_OF_LIST() + } +}; + +static void flexcomm_spi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + FlexcommFunctionClass *fc = FLEXCOMM_FUNCTION_CLASS(klass); + FlexcommSpiClass *sc = FLEXCOMM_SPI_CLASS(klass); + + dc->realize = flexcomm_spi_realize; + dc->vmsd = &vmstate_flexcomm_spi; + sc->select = fc->select; + fc->select = flexcomm_spi_select; + fc->name = "spi"; + fc->has_fifos = true; + fc->mmio_ops = &flexcomm_spi_ops; +} + +static const TypeInfo flexcomm_spi_types[] = { + { + .name = TYPE_FLEXCOMM_SPI, + .parent = TYPE_FLEXCOMM_FUNCTION, + .instance_size = sizeof(FlexcommSpiState), + .class_init = flexcomm_spi_class_init, + .class_size = sizeof(FlexcommSpiClass), + }, +}; + +DEFINE_TYPES(flexcomm_spi_types); diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build index 2542b56294..e7d62a7f35 100644 --- a/hw/arm/svd/meson.build +++ b/hw/arm/svd/meson.build @@ -12,4 +12,8 @@ if get_option('mcux-soc-svd') [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/flexcomm_i2c.h', '-p', 'I2C0', '-t', 'FLEXCOMM_I2C', '--fields', 'CFG TIMEOUT:TOMIN MSTCTL MSTDAT STAT:MSTPENDING,MSTSTATE INT*:MSTPENDING* SLV*:']) + run_target('svd-flexcomm-spi', command: svd_gen_header + + [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/flexcomm_spi.h', + '-p', 'SPI0', '-t', 'FLEXCOMM_SPI', + '--fields', 'CFG FIFOCFG:ENABLE*,EMPTY* FIFO*:* INT*: STAT']) endif diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 9a244fa01d..b373e651e1 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -216,5 +216,6 @@ config XLNX_VERSAL_TRNG config FLEXCOMM bool select I2C + select SSI source macio/Kconfig diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build index 23cd425ab0..58e0d14b37 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_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_PNV_SPI', if_true: files('pnv_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 089d269994..f849f1f8be 100644 --- a/hw/ssi/trace-events +++ b/hw/ssi/trace-events @@ -53,3 +53,8 @@ pnv_spi_rx_read_N2frame(void) "" pnv_spi_shift_rx(uint8_t byte, uint32_t index) "byte = 0x%2.2x into RDR from payload index %d" pnv_spi_sequencer_stop_requested(const char* reason) "due to %s" pnv_spi_RDR_match(const char* result) "%s" + +# 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_irq(const char *id, bool irq, bool fifoirqs, bool perirqs, bool enabled) "%s: %d %d %d %d" From patchwork Tue Oct 8 01:18:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993900 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=BWB2Afny; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMysZ1dBFz1xvB for ; Tue, 8 Oct 2024 12:21:38 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxytc-0002zq-JK; Mon, 07 Oct 2024 21:20:18 -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 <3kIgEZwUKCvEmTobiZhhZeX.VhfjXfn-WXoXeghgZgn.hkZ@flex--tavip.bounces.google.com>) id 1sxysp-0007zm-OZ for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:29 -0400 Received: from mail-pf1-x449.google.com ([2607:f8b0:4864:20::449]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3kIgEZwUKCvEmTobiZhhZeX.VhfjXfn-WXoXeghgZgn.hkZ@flex--tavip.bounces.google.com>) id 1sxysf-0000A7-Sb for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:24 -0400 Received: by mail-pf1-x449.google.com with SMTP id d2e1a72fcca58-71dfa361499so2100343b3a.0 for ; Mon, 07 Oct 2024 18:19:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350353; x=1728955153; 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=h0g2XEqh5TFAysQ/4BwAuoGhpRYdqAqx4UCuVxyPc+Q=; b=BWB2Afny75Rb0luKXPj/Z3aE7bLX6KYxuUTSFvJ7HRHxF9UZaj+zJnI55M88rD+VUe dSNji5xYX+9n6ZrXv8ra0AkVbpKOu9/cSRIeyw+HCBmQ6aQlYSvXQqRJyoBLRLmgb3l+ OdGB8X9E9uKFbXnW7s7Dja7jzj8tMDi34PQAdTOdyzefcebOtQcUVverPPoY/RP2jwAN 8ZQYoyYRXySh/u6jLaJ3E1i+Rr61RZqAsVRlRuahGWg2DsbmaIsbQN8u2jRMsQh6Gsr6 a4FfrYqavMp6rHv/rjawNJii7DCYa9SOh06Fmq3Uc4uIG1EB+E6hinegJDCsVsZ3dzR7 jPTg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350353; x=1728955153; 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=h0g2XEqh5TFAysQ/4BwAuoGhpRYdqAqx4UCuVxyPc+Q=; b=CjQQajGiCt2hOKja+sKAjx0lYZALqwr13oueE+EbtrR+88uV5IpMTg5n8121zlmhCQ Pi98GxguByRPyzIvut/8lvaDbwJf0QXc/0eIbNuCQxX8N1buJGA2/9dwEkwrkvBH1CqK 29Bn+C5cE5/vBdTp3m96Q/75WCnqOUdnsBrgUh/B4RDISVdNY/R0qQQfzJtWaIe0w70m y/IuIB/jaaYyev+hCPnN22ixuMl75/qB6Hluyj1jlGuo6eFhyhfFQLGC+4DUIcoQ5vrw cCQ+ZvOCbxNIz0lrWZzri8R+AnNy2RIh35I8yVbaK9K6QTz+4topabosFdtYflcniiqu uC+g== X-Gm-Message-State: AOJu0Yyko5ovDbanV1rLzcN2wtnzIoKT8wqdL0PSdgWutG3TWWMICMyL NqT7KhFwjbUhBez6jBGi0O6B7DZ1OZVM98l0PygLBl8RhVCezDv7nyMvFDNoCtpGUaNJdmbW7xV mLmPxIR8L5po26S8p1DAla0f/X+ulv5uI0xhheQqXxyweuN+3cee6ih45wHodizT/rj+NEPgfl6 4eeqnWlkktE52u36BDkGYu/h5rhQ== X-Google-Smtp-Source: AGHT+IH2ojZoS4xw100tm4xI4XQvhwctpObQyFtqT+tL5TSw0PUe+TwGlkFXiGZ6lPViV1qB2g5VhYD54w== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:6a00:7687:b0:71d:fb06:e79b with SMTP id d2e1a72fcca58-71dfb06ea3amr14557b3a.0.1728350352051; Mon, 07 Oct 2024 18:19:12 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:36 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-11-tavip@google.com> Subject: [PATCH v2 10/25] 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, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::449; envelope-from=3kIgEZwUKCvEmTobiZhhZeX.VhfjXfn-WXoXeghgZgn.hkZ@flex--tavip.bounces.google.com; helo=mail-pf1-x449.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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org It supports system and audio PLL initialization and SYSTICK and OSTIMER clock source selection. The patch includes automatically generated headers which contains the register layout and helpers. The headers can be regenerated with the svd-rt500-clkctl0 and svd-rt500-clkctl1 targets when the build is configured with --enable-mcux-soc-svd. Signed-off-by: Octavian Purdila --- include/hw/arm/svd/rt500_clkctl0.h | 509 ++++++++++++++++++++++ include/hw/arm/svd/rt500_clkctl1.h | 675 +++++++++++++++++++++++++++++ include/hw/misc/rt500_clk_freqs.h | 18 + include/hw/misc/rt500_clkctl0.h | 35 ++ include/hw/misc/rt500_clkctl1.h | 36 ++ hw/misc/rt500_clkctl0.c | 253 +++++++++++ hw/misc/rt500_clkctl1.c | 238 ++++++++++ hw/arm/Kconfig | 5 + hw/arm/svd/meson.build | 8 + hw/misc/Kconfig | 3 + hw/misc/meson.build | 1 + hw/misc/trace-events | 8 + 12 files changed, 1789 insertions(+) create mode 100644 include/hw/arm/svd/rt500_clkctl0.h create mode 100644 include/hw/arm/svd/rt500_clkctl1.h 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 create mode 100644 hw/misc/rt500_clkctl0.c create mode 100644 hw/misc/rt500_clkctl1.c diff --git a/include/hw/arm/svd/rt500_clkctl0.h b/include/hw/arm/svd/rt500_clkctl0.h new file mode 100644 index 0000000000..89be8ff5fb --- /dev/null +++ b/include/hw/arm/svd/rt500_clkctl0.h @@ -0,0 +1,509 @@ +/* + * Copyright 2016-2023 NXP SPDX-License-Identifier: BSD-3-Clause + * + * Automatically generated by svd-gen-header.py from MIMXRT595S_cm33.xml + */ +#pragma once + +#include "hw/register.h" + +/* Clock Controller 0 */ +#define RT500_CLKCTL0_REGS_NO (490) + +/* Clock Control 0 */ +REG32(RT500_CLKCTL0_PSCCTL0, 0x10); +/* DSP clock control */ +FIELD(RT500_CLKCTL0_PSCCTL0, DSP_CLK, 1, 1); +/* 128KB ROM Controller clock control */ +FIELD(RT500_CLKCTL0_PSCCTL0, ROM_CTRLR_CLK, 2, 1); + +/* Clock Control 1 */ +REG32(RT500_CLKCTL0_PSCCTL1, 0x14); + +/* Clock Control 2 */ +REG32(RT500_CLKCTL0_PSCCTL2, 0x18); + +/* Clock Control 0 Set */ +REG32(RT500_CLKCTL0_PSCCTL0_SET, 0x40); +/* DSP clock set */ +FIELD(RT500_CLKCTL0_PSCCTL0_SET, DSP_CLK, 1, 1); +/* 128KB ROM Controller clock set */ +FIELD(RT500_CLKCTL0_PSCCTL0_SET, ROM_CTRLR_CLK, 2, 1); + +/* Clock Control 1 Set */ +REG32(RT500_CLKCTL0_PSCCTL1_SET, 0x44); + +/* Clock Control 2 Set */ +REG32(RT500_CLKCTL0_PSCCTL2_SET, 0x48); + +/* Clock Control 0 Clear */ +REG32(RT500_CLKCTL0_PSCCTL0_CLR, 0x70); +/* DSP clock clear */ +FIELD(RT500_CLKCTL0_PSCCTL0_CLR, DSP_CLK, 1, 1); +/* 128KB ROM Controller clock clear */ +FIELD(RT500_CLKCTL0_PSCCTL0_CLR, ROM_CTRLR_CLK, 2, 1); + +/* Clock Control 1 Clear */ +REG32(RT500_CLKCTL0_PSCCTL1_CLR, 0x74); + +/* Clock Control 2 Clear */ +REG32(RT500_CLKCTL0_PSCCTL2_CLR, 0x78); + +/* FRO Clock Status */ +REG32(RT500_CLKCTL0_FROCLKSTATUS, 0x10C); + +/* System PLL0 PFD */ +REG32(RT500_CLKCTL0_SYSPLL0PFD, 0x218); +/* PLL Fractional Divider 0 */ +FIELD(RT500_CLKCTL0_SYSPLL0PFD, PFD0, 0, 6); +/* PFD0 Clock Ready Status Flag */ +FIELD(RT500_CLKCTL0_SYSPLL0PFD, PFD0_CLKRDY, 6, 1); +/* PFD0 Clock Gate */ +FIELD(RT500_CLKCTL0_SYSPLL0PFD, PFD0_CLKGATE, 7, 1); +/* PLL Fractional Divider 1 */ +FIELD(RT500_CLKCTL0_SYSPLL0PFD, PFD1, 8, 6); +/* PFD1 Clock Ready Status Flag */ +FIELD(RT500_CLKCTL0_SYSPLL0PFD, PFD1_CLKRDY, 14, 1); +/* PFD1 Clock Gate */ +FIELD(RT500_CLKCTL0_SYSPLL0PFD, PFD1_CLKGATE, 15, 1); +/* PLL Fractional Divider 2 */ +FIELD(RT500_CLKCTL0_SYSPLL0PFD, PFD2, 16, 6); +/* PFD2 Clock Ready Status Flag */ +FIELD(RT500_CLKCTL0_SYSPLL0PFD, PFD2_CLKRDY, 22, 1); +/* PFD2 Clock Gate */ +FIELD(RT500_CLKCTL0_SYSPLL0PFD, PFD2_CLKGATE, 23, 1); +/* PLL Fractional Divider 3 */ +FIELD(RT500_CLKCTL0_SYSPLL0PFD, PFD3, 24, 6); +/* PFD3 Clock Ready Status Flag */ +FIELD(RT500_CLKCTL0_SYSPLL0PFD, PFD3_CLKRDY, 30, 1); +/* PFD3 Clock Gate */ +FIELD(RT500_CLKCTL0_SYSPLL0PFD, PFD3_CLKGATE, 31, 1); + +/* SYSTICK Functional Clock Select */ +REG32(RT500_CLKCTL0_SYSTICKFCLKSEL, 0x760); +/* Select Clock Source */ +FIELD(RT500_CLKCTL0_SYSTICKFCLKSEL, SEL, 0, 3); +/* Systick Divider Output Clock */ +#define RT500_CLKCTL0_SYSTICKFCLKSEL_SEL_SYSTICK_DIV_OUTPUT 0 +/* Low Power Oscillator Clock (LPOSC) */ +#define RT500_CLKCTL0_SYSTICKFCLKSEL_SEL_LPOSC 1 +/* 32 KHz RTC Clock */ +#define RT500_CLKCTL0_SYSTICKFCLKSEL_SEL_A32KHZ_RTC 2 +/* None; this may be selected to reduce power when no output is needed. */ +#define RT500_CLKCTL0_SYSTICKFCLKSEL_SEL_NONE 7 + +/* SYSTICK Functional Clock Divider */ +REG32(RT500_CLKCTL0_SYSTICKFCLKDIV, 0x764); +/* Clock Divider Value Selection */ +FIELD(RT500_CLKCTL0_SYSTICKFCLKDIV, DIV, 0, 8); +/* Reset the Divider Counter */ +FIELD(RT500_CLKCTL0_SYSTICKFCLKDIV, RESET, 29, 1); +/* Halt the Divider Counter */ +FIELD(RT500_CLKCTL0_SYSTICKFCLKDIV, HALT, 30, 1); +/* Divider status flag */ +FIELD(RT500_CLKCTL0_SYSTICKFCLKDIV, REQFLAG, 31, 1); + + +#define RT500_CLKCTL0_REGISTER_ACCESS_INFO_ARRAY(_name) \ + struct RegisterAccessInfo _name[RT500_CLKCTL0_REGS_NO] = { \ + [0 ... RT500_CLKCTL0_REGS_NO - 1] = { \ + .name = "", \ + .addr = -1, \ + }, \ + [0x4] = { \ + .name = "PSCCTL0", \ + .addr = 0x10, \ + .ro = 0xA208E0E1, \ + .reset = 0x5, \ + }, \ + [0x5] = { \ + .name = "PSCCTL1", \ + .addr = 0x14, \ + .ro = 0xFEFE7FF3, \ + .reset = 0x0, \ + }, \ + [0x6] = { \ + .name = "PSCCTL2", \ + .addr = 0x18, \ + .ro = 0xDFFFFFFC, \ + .reset = 0x0, \ + }, \ + [0x10] = { \ + .name = "PSCCTL0_SET", \ + .addr = 0x40, \ + .ro = 0xA208E0E1, \ + .reset = 0x0, \ + }, \ + [0x11] = { \ + .name = "PSCCTL1_SET", \ + .addr = 0x44, \ + .ro = 0xFEFE7FF3, \ + .reset = 0x0, \ + }, \ + [0x12] = { \ + .name = "PSCCTL2_SET", \ + .addr = 0x48, \ + .ro = 0xDFFFFFFC, \ + .reset = 0x0, \ + }, \ + [0x1C] = { \ + .name = "PSCCTL0_CLR", \ + .addr = 0x70, \ + .ro = 0xA208E0E1, \ + .reset = 0x0, \ + }, \ + [0x1D] = { \ + .name = "PSCCTL1_CLR", \ + .addr = 0x74, \ + .ro = 0xFEFE7FF3, \ + .reset = 0x0, \ + }, \ + [0x1E] = { \ + .name = "PSCCTL2_CLR", \ + .addr = 0x78, \ + .ro = 0xDFFFFFFC, \ + .reset = 0x0, \ + }, \ + [0x20] = { \ + .name = "FRO_CONTROL", \ + .addr = 0x80, \ + .ro = 0x7C000000, \ + .reset = 0x0, \ + }, \ + [0x21] = { \ + .name = "FRO_CAPVAL", \ + .addr = 0x84, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x23] = { \ + .name = "FRO_RDTRIM", \ + .addr = 0x8C, \ + .ro = 0xFFFFF800, \ + .reset = 0x3BF, \ + }, \ + [0x24] = { \ + .name = "FRO_SCTRIM", \ + .addr = 0x90, \ + .ro = 0xFFFFFFC0, \ + .reset = 0x20, \ + }, \ + [0x42] = { \ + .name = "FRODIVSEL", \ + .addr = 0x108, \ + .ro = 0xFFFFFFFC, \ + .reset = 0x0, \ + }, \ + [0x43] = { \ + .name = "FROCLKSTATUS", \ + .addr = 0x10C, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x44] = { \ + .name = "FRODIVOEN", \ + .addr = 0x110, \ + .ro = 0xFFFFFFE0, \ + .reset = 0x0, \ + }, \ + [0x4C] = { \ + .name = "LOWFREQCLKDIV", \ + .addr = 0x130, \ + .ro = 0x1FFFFF00, \ + .reset = 0x0, \ + }, \ + [0x58] = { \ + .name = "SYSOSCCTL0", \ + .addr = 0x160, \ + .ro = 0xFFFFFFFC, \ + .reset = 0x0, \ + }, \ + [0x5A] = { \ + .name = "SYSOSCBYPASS", \ + .addr = 0x168, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x0, \ + }, \ + [0x64] = { \ + .name = "LPOSCCTL0", \ + .addr = 0x190, \ + .ro = 0x7FFFFFFF, \ + .reset = 0x807BC4D4, \ + }, \ + [0x70] = { \ + .name = "OSC32KHZCTL0", \ + .addr = 0x1C0, \ + .ro = 0xFFFFFFFE, \ + .reset = 0x0, \ + }, \ + [0x80] = { \ + .name = "SYSPLL0CLKSEL", \ + .addr = 0x200, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x81] = { \ + .name = "SYSPLL0CTL0", \ + .addr = 0x204, \ + .ro = 0xFF00DFFC, \ + .reset = 0x160002, \ + }, \ + [0x83] = { \ + .name = "SYSPLL0LOCKTIMEDIV2", \ + .addr = 0x20C, \ + .ro = 0xFFFF0000, \ + .reset = 0xCAFE, \ + }, \ + [0x84] = { \ + .name = "SYSPLL0NUM", \ + .addr = 0x210, \ + .ro = 0xC0000000, \ + .reset = 0x4DD2F15, \ + }, \ + [0x85] = { \ + .name = "SYSPLL0DENOM", \ + .addr = 0x214, \ + .ro = 0xC0000000, \ + .reset = 0x1FFFFFDB, \ + }, \ + [0x86] = { \ + .name = "SYSPLL0PFD", \ + .addr = 0x218, \ + .ro = 0x0, \ + .reset = 0x80808080, \ + }, \ + [0x90] = { \ + .name = "MAINPLLCLKDIV", \ + .addr = 0x240, \ + .ro = 0x1FFFFF00, \ + .reset = 0x0, \ + }, \ + [0x91] = { \ + .name = "DSPPLLCLKDIV", \ + .addr = 0x244, \ + .ro = 0x1FFFFF00, \ + .reset = 0x0, \ + }, \ + [0x92] = { \ + .name = "AUX0PLLCLKDIV", \ + .addr = 0x248, \ + .ro = 0x1FFFFF00, \ + .reset = 0x0, \ + }, \ + [0x93] = { \ + .name = "AUX1PLLCLKDIV", \ + .addr = 0x24C, \ + .ro = 0x1FFFFF00, \ + .reset = 0x0, \ + }, \ + [0x100] = { \ + .name = "SYSCPUAHBCLKDIV", \ + .addr = 0x400, \ + .ro = 0x7FFFFF00, \ + .reset = 0x0, \ + }, \ + [0x10C] = { \ + .name = "MAINCLKSELA", \ + .addr = 0x430, \ + .ro = 0xFFFFFFFC, \ + .reset = 0x0, \ + }, \ + [0x10D] = { \ + .name = "MAINCLKSELB", \ + .addr = 0x434, \ + .ro = 0xFFFFFFFC, \ + .reset = 0x0, \ + }, \ + [0x140] = { \ + .name = "PFC0DIV", \ + .addr = 0x500, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x141] = { \ + .name = "PFC1DIV", \ + .addr = 0x504, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x188] = { \ + .name = "FLEXSPI0FCLKSEL", \ + .addr = 0x620, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x189] = { \ + .name = "FLEXSPI0FCLKDIV", \ + .addr = 0x624, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x18C] = { \ + .name = "FLEXSPI1FCLKSEL", \ + .addr = 0x630, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x18D] = { \ + .name = "FLEXSPI1FCLKDIV", \ + .addr = 0x634, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x190] = { \ + .name = "SCTFCLKSEL", \ + .addr = 0x640, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x191] = { \ + .name = "SCTIN7CLKDIV", \ + .addr = 0x644, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x198] = { \ + .name = "USBHSFCLKSEL", \ + .addr = 0x660, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x199] = { \ + .name = "USBHSFCLKDIV", \ + .addr = 0x664, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x1A0] = { \ + .name = "SDIO0FCLKSEL", \ + .addr = 0x680, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1A1] = { \ + .name = "SDIO0FCLKDIV", \ + .addr = 0x684, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x1A4] = { \ + .name = "SDIO1FCLKSEL", \ + .addr = 0x690, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1A5] = { \ + .name = "SDIO1FCLKDIV", \ + .addr = 0x694, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x1B4] = { \ + .name = "ADC0FCLKSEL0", \ + .addr = 0x6D0, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1B5] = { \ + .name = "ADC0FCLKSEL1", \ + .addr = 0x6D4, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1B6] = { \ + .name = "ADC0FCLKDIV", \ + .addr = 0x6D8, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x1C0] = { \ + .name = "UTICKFCLKSEL", \ + .addr = 0x700, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1C8] = { \ + .name = "WDT0FCLKSEL", \ + .addr = 0x720, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x0, \ + }, \ + [0x1CC] = { \ + .name = "A32KHZWAKECLKSEL", \ + .addr = 0x730, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x1, \ + }, \ + [0x1CD] = { \ + .name = "A32KHZWAKECLKDIV", \ + .addr = 0x734, \ + .ro = 0x1FFFFF00, \ + .reset = 0x1F, \ + }, \ + [0x1D8] = { \ + .name = "SYSTICKFCLKSEL", \ + .addr = 0x760, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1D9] = { \ + .name = "SYSTICKFCLKDIV", \ + .addr = 0x764, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x1DC] = { \ + .name = "DPHYCLKSEL", \ + .addr = 0x770, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1DD] = { \ + .name = "DPHYCLKDIV", \ + .addr = 0x774, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x1DE] = { \ + .name = "DPHYESCCLKSEL", \ + .addr = 0x778, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1DF] = { \ + .name = "DPHYESCRXCLKDIV", \ + .addr = 0x77C, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000010, \ + }, \ + [0x1E0] = { \ + .name = "DPHYESCTXCLKDIV", \ + .addr = 0x780, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000011, \ + }, \ + [0x1E4] = { \ + .name = "GPUCLKSEL", \ + .addr = 0x790, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1E5] = { \ + .name = "GPUCLKDIV", \ + .addr = 0x794, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x1E8] = { \ + .name = "DCPIXELCLKSEL", \ + .addr = 0x7A0, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1E9] = { \ + .name = "DCPIXELCLKDIV", \ + .addr = 0x7A4, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + } diff --git a/include/hw/arm/svd/rt500_clkctl1.h b/include/hw/arm/svd/rt500_clkctl1.h new file mode 100644 index 0000000000..baa24eb0fd --- /dev/null +++ b/include/hw/arm/svd/rt500_clkctl1.h @@ -0,0 +1,675 @@ +/* + * Copyright 2016-2023 NXP SPDX-License-Identifier: BSD-3-Clause + * + * Automatically generated by svd-gen-header.py from MIMXRT595S_cm33.xml + */ +#pragma once + +#include "hw/register.h" + +/* Clock Controller 1 */ +#define RT500_CLKCTL1_REGS_NO (526) + +/* Clock Control 0 */ +REG32(RT500_CLKCTL1_PSCCTL0, 0x10); +/* FlexIO clock control */ +FIELD(RT500_CLKCTL1_PSCCTL0, FlexIO, 29, 1); + +/* Clock Control 1 */ +REG32(RT500_CLKCTL1_PSCCTL1, 0x14); + +/* Clock Control 2 */ +REG32(RT500_CLKCTL1_PSCCTL2, 0x18); + +/* Clock Set 0 */ +REG32(RT500_CLKCTL1_PSCCTL0_SET, 0x40); +/* FlexIO clock control */ +FIELD(RT500_CLKCTL1_PSCCTL0_SET, FlexIO, 29, 1); + +/* Clock Set 1 */ +REG32(RT500_CLKCTL1_PSCCTL1_SET, 0x44); + +/* Clock Set 2 */ +REG32(RT500_CLKCTL1_PSCCTL2_SET, 0x48); + +/* Clock Clear 0 */ +REG32(RT500_CLKCTL1_PSCCTL0_CLR, 0x70); +/* FlexIO clock control clear */ +FIELD(RT500_CLKCTL1_PSCCTL0_CLR, FlexIO, 29, 1); + +/* Clock Clear 1 */ +REG32(RT500_CLKCTL1_PSCCTL1_CLR, 0x74); + +/* Clock Clear 2 */ +REG32(RT500_CLKCTL1_PSCCTL2_CLR, 0x78); + +/* Audio PLL0 PFD */ +REG32(RT500_CLKCTL1_AUDIOPLL0PFD, 0x218); +/* PLL Fractional Divider 0 */ +FIELD(RT500_CLKCTL1_AUDIOPLL0PFD, PFD0, 0, 6); +/* PFD0 Clock Ready Status Flag */ +FIELD(RT500_CLKCTL1_AUDIOPLL0PFD, PFD0_CLKRDY, 6, 1); +/* PFD0 Clock Gate */ +FIELD(RT500_CLKCTL1_AUDIOPLL0PFD, PFD0_CLKGATE, 7, 1); +/* PLL Fractional Divider 1 */ +FIELD(RT500_CLKCTL1_AUDIOPLL0PFD, PFD1, 8, 6); +/* PFD1 Clock Ready Status Flag */ +FIELD(RT500_CLKCTL1_AUDIOPLL0PFD, PFD1_CLKRDY, 14, 1); +/* PFD1 Clock Gate */ +FIELD(RT500_CLKCTL1_AUDIOPLL0PFD, PFD1_CLKGATE, 15, 1); +/* PLL Fractional Divider 2 */ +FIELD(RT500_CLKCTL1_AUDIOPLL0PFD, PFD2, 16, 6); +/* PFD2 Clock Ready Status Flag */ +FIELD(RT500_CLKCTL1_AUDIOPLL0PFD, PFD2_CLKRDY, 22, 1); +/* PFD2 Clock Gate */ +FIELD(RT500_CLKCTL1_AUDIOPLL0PFD, PFD2_CLKGATE, 23, 1); +/* PLL Fractional Divider 3 */ +FIELD(RT500_CLKCTL1_AUDIOPLL0PFD, PFD3, 24, 6); +/* PFD3 Clock Ready Status Flag */ +FIELD(RT500_CLKCTL1_AUDIOPLL0PFD, PFD3_CLKRDY, 30, 1); +/* PFD3 Clock Gate */ +FIELD(RT500_CLKCTL1_AUDIOPLL0PFD, PFD3_CLKGATE, 31, 1); + +/* OS Event Timer Functional Clock Select */ +REG32(RT500_CLKCTL1_OSEVENTTFCLKSEL, 0x480); +/* OS Event Timer Functional Clock Source */ +FIELD(RT500_CLKCTL1_OSEVENTTFCLKSEL, SEL, 0, 3); +/* Low Power Oscillator Clock (LPOSC) */ +#define RT500_CLKCTL1_OSEVENTTFCLKSEL_SEL_LPOSC 0 +/* RTC 32 KHz Clock */ +#define RT500_CLKCTL1_OSEVENTTFCLKSEL_SEL_RTC_32KHZ 1 +/* HCLK Free-Running Clock (Global Time Stamping) */ +#define RT500_CLKCTL1_OSEVENTTFCLKSEL_SEL_TEAL 2 +/* None, output gated to reduce power */ +#define RT500_CLKCTL1_OSEVENTTFCLKSEL_SEL_NONE 7 + + +#define RT500_CLKCTL1_REGISTER_ACCESS_INFO_ARRAY(_name) \ + struct RegisterAccessInfo _name[RT500_CLKCTL1_REGS_NO] = { \ + [0 ... RT500_CLKCTL1_REGS_NO - 1] = { \ + .name = "", \ + .addr = -1, \ + }, \ + [0x4] = { \ + .name = "PSCCTL0", \ + .addr = 0x10, \ + .ro = 0xD40000FF, \ + .reset = 0x0, \ + }, \ + [0x5] = { \ + .name = "PSCCTL1", \ + .addr = 0x14, \ + .ro = 0x4E7EFF00, \ + .reset = 0x0, \ + }, \ + [0x6] = { \ + .name = "PSCCTL2", \ + .addr = 0x18, \ + .ro = 0x3FFCFA60, \ + .reset = 0x0, \ + }, \ + [0x10] = { \ + .name = "PSCCTL0_SET", \ + .addr = 0x40, \ + .ro = 0xD40000FF, \ + .reset = 0x0, \ + }, \ + [0x11] = { \ + .name = "PSCCTL1_SET", \ + .addr = 0x44, \ + .ro = 0x4E7EFF00, \ + .reset = 0x0, \ + }, \ + [0x12] = { \ + .name = "PSCCTL2_SET", \ + .addr = 0x48, \ + .ro = 0x3FFCFA60, \ + .reset = 0x0, \ + }, \ + [0x1C] = { \ + .name = "PSCCTL0_CLR", \ + .addr = 0x70, \ + .ro = 0xD40000FF, \ + .reset = 0x0, \ + }, \ + [0x1D] = { \ + .name = "PSCCTL1_CLR", \ + .addr = 0x74, \ + .ro = 0x4E7EFF00, \ + .reset = 0x0, \ + }, \ + [0x1E] = { \ + .name = "PSCCTL2_CLR", \ + .addr = 0x78, \ + .ro = 0x3FFCFA60, \ + .reset = 0x0, \ + }, \ + [0x80] = { \ + .name = "AUDIOPLL0CLKSEL", \ + .addr = 0x200, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x81] = { \ + .name = "AUDIOPLL0CTL0", \ + .addr = 0x204, \ + .ro = 0xFF00DFFC, \ + .reset = 0x160002, \ + }, \ + [0x83] = { \ + .name = "AUDIOPLL0LOCKTIMEDIV2", \ + .addr = 0x20C, \ + .ro = 0xFFFF0000, \ + .reset = 0xCAFE, \ + }, \ + [0x84] = { \ + .name = "AUDIOPLL0NUM", \ + .addr = 0x210, \ + .ro = 0xC0000000, \ + .reset = 0x4DD2F15, \ + }, \ + [0x85] = { \ + .name = "AUDIOPLL0DENOM", \ + .addr = 0x214, \ + .ro = 0xC0000000, \ + .reset = 0x1FFFFFDB, \ + }, \ + [0x86] = { \ + .name = "AUDIOPLL0PFD", \ + .addr = 0x218, \ + .ro = 0x0, \ + .reset = 0x80808080, \ + }, \ + [0x90] = { \ + .name = "AUDIOPLLCLKDIV", \ + .addr = 0x240, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x100] = { \ + .name = "DSPCPUCLKDIV", \ + .addr = 0x400, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x10C] = { \ + .name = "DSPCPUCLKSELA", \ + .addr = 0x430, \ + .ro = 0xFFFFFFFC, \ + .reset = 0x0, \ + }, \ + [0x10D] = { \ + .name = "DSPCPUCLKSELB", \ + .addr = 0x434, \ + .ro = 0xFFFFFFFC, \ + .reset = 0x0, \ + }, \ + [0x120] = { \ + .name = "OSEVENTTFCLKSEL", \ + .addr = 0x480, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x0, \ + }, \ + [0x140] = { \ + .name = "FRG0CLKSEL", \ + .addr = 0x500, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x141] = { \ + .name = "FRG0CTL", \ + .addr = 0x504, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x142] = { \ + .name = "FC0FCLKSEL", \ + .addr = 0x508, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x148] = { \ + .name = "FRG1CLKSEL", \ + .addr = 0x520, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x149] = { \ + .name = "FRG1CTL", \ + .addr = 0x524, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x14A] = { \ + .name = "FC1FCLKSEL", \ + .addr = 0x528, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x150] = { \ + .name = "FRG2CLKSEL", \ + .addr = 0x540, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x151] = { \ + .name = "FRG2CTL", \ + .addr = 0x544, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x152] = { \ + .name = "FC2FCLKSEL", \ + .addr = 0x548, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x158] = { \ + .name = "FRG3CLKSEL", \ + .addr = 0x560, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x159] = { \ + .name = "FRG3CTL", \ + .addr = 0x564, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x15A] = { \ + .name = "FC3FCLKSEL", \ + .addr = 0x568, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x160] = { \ + .name = "FRG4CLKSEL", \ + .addr = 0x580, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x161] = { \ + .name = "FRG4CTL", \ + .addr = 0x584, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x162] = { \ + .name = "FC4FCLKSEL", \ + .addr = 0x588, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x168] = { \ + .name = "FRG5CLKSEL", \ + .addr = 0x5A0, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x169] = { \ + .name = "FRG5CTL", \ + .addr = 0x5A4, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x16A] = { \ + .name = "FC5FCLKSEL", \ + .addr = 0x5A8, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x170] = { \ + .name = "FRG6CLKSEL", \ + .addr = 0x5C0, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x171] = { \ + .name = "FRG6CTL", \ + .addr = 0x5C4, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x172] = { \ + .name = "FC6FCLKSEL", \ + .addr = 0x5C8, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x178] = { \ + .name = "FRG7CLKSEL", \ + .addr = 0x5E0, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x179] = { \ + .name = "FRG7CTL", \ + .addr = 0x5E4, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x17A] = { \ + .name = "FC7FCLKSEL", \ + .addr = 0x5E8, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x180] = { \ + .name = "FRG8CLKSEL", \ + .addr = 0x600, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x181] = { \ + .name = "FRG8CTL", \ + .addr = 0x604, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x182] = { \ + .name = "FC8FCLKSEL", \ + .addr = 0x608, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x188] = { \ + .name = "FRG9CLKSEL", \ + .addr = 0x620, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x189] = { \ + .name = "FRG9CTL", \ + .addr = 0x624, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x18A] = { \ + .name = "FC9FCLKSEL", \ + .addr = 0x628, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x190] = { \ + .name = "FRG10CLKSEL", \ + .addr = 0x640, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x191] = { \ + .name = "FRG10CTL", \ + .addr = 0x644, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x192] = { \ + .name = "FC10FCLKSEL", \ + .addr = 0x648, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x198] = { \ + .name = "FRG11CLKSEL", \ + .addr = 0x660, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x199] = { \ + .name = "FRG11CTL", \ + .addr = 0x664, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x19A] = { \ + .name = "FC11FCLKSEL", \ + .addr = 0x668, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1A0] = { \ + .name = "FRG12CLKSEL", \ + .addr = 0x680, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1A1] = { \ + .name = "FRG12CTL", \ + .addr = 0x684, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x1A2] = { \ + .name = "FC12FCLKSEL", \ + .addr = 0x688, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1A8] = { \ + .name = "FRG13CLKSEL", \ + .addr = 0x6A0, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1A9] = { \ + .name = "FRG13CTL", \ + .addr = 0x6A4, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x1AA] = { \ + .name = "FC13FCLKSEL", \ + .addr = 0x6A8, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1B0] = { \ + .name = "FRG14CLKSEL", \ + .addr = 0x6C0, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1B1] = { \ + .name = "FRG14CTL", \ + .addr = 0x6C4, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x1B2] = { \ + .name = "FC14FCLKSEL", \ + .addr = 0x6C8, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1B8] = { \ + .name = "FRG15CLKSEL", \ + .addr = 0x6E0, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1B9] = { \ + .name = "FRG15CTL", \ + .addr = 0x6E4, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x1BA] = { \ + .name = "FC15FCLKSEL", \ + .addr = 0x6E8, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1C0] = { \ + .name = "FRG16CLKSEL", \ + .addr = 0x700, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1C1] = { \ + .name = "FRG16CTL", \ + .addr = 0x704, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x1C2] = { \ + .name = "FC16FCLKSEL", \ + .addr = 0x708, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1C8] = { \ + .name = "FRG17CLKSEL", \ + .addr = 0x720, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1C9] = { \ + .name = "FRG17CTL", \ + .addr = 0x724, \ + .ro = 0xFFFF0000, \ + .reset = 0xFF, \ + }, \ + [0x1CA] = { \ + .name = "FLEXIOCLKSEL", \ + .addr = 0x728, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1D0] = { \ + .name = "FLEXIOCLKDIV", \ + .addr = 0x740, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x1D8] = { \ + .name = "FRGPLLCLKDIV", \ + .addr = 0x760, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x1E0] = { \ + .name = "DMIC0FCLKSEL", \ + .addr = 0x780, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1E1] = { \ + .name = "DMIC0FCLKDIV", \ + .addr = 0x784, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x1E8] = { \ + .name = "CT32BITFCLKSEL0", \ + .addr = 0x7A0, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1E9] = { \ + .name = "CT32BITFCLKSEL1", \ + .addr = 0x7A4, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1EA] = { \ + .name = "CT32BITFCLKSEL2", \ + .addr = 0x7A8, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1EB] = { \ + .name = "CT32BITFCLKSEL3", \ + .addr = 0x7AC, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1EC] = { \ + .name = "CT32BITFCLKSEL4", \ + .addr = 0x7B0, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1F0] = { \ + .name = "AUDIOMCLKSEL", \ + .addr = 0x7C0, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1F1] = { \ + .name = "AUDIOMCLKDIV", \ + .addr = 0x7C4, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x1F8] = { \ + .name = "CLKOUTSEL0", \ + .addr = 0x7E0, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1F9] = { \ + .name = "CLKOUTSEL1", \ + .addr = 0x7E4, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x1FA] = { \ + .name = "CLKOUTFCLKDIV", \ + .addr = 0x7E8, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x200] = { \ + .name = "I3C01FCLKSEL", \ + .addr = 0x800, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x201] = { \ + .name = "I3C01FCLKSTCSEL", \ + .addr = 0x804, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x202] = { \ + .name = "I3C01FCLKSTCDIV", \ + .addr = 0x808, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x203] = { \ + .name = "I3C01FCLKSDIV", \ + .addr = 0x80C, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x204] = { \ + .name = "I3C01FCLKDIV", \ + .addr = 0x810, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + [0x205] = { \ + .name = "I3C01FCLKSTSTCLKSEL", \ + .addr = 0x814, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x0, \ + }, \ + [0x208] = { \ + .name = "WDT1FCLKSEL", \ + .addr = 0x820, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x0, \ + }, \ + [0x20C] = { \ + .name = "ACMP0FCLKSEL", \ + .addr = 0x830, \ + .ro = 0xFFFFFFF8, \ + .reset = 0x7, \ + }, \ + [0x20D] = { \ + .name = "ACMP0FCLKDIV", \ + .addr = 0x834, \ + .ro = 0x1FFFFF00, \ + .reset = 0x40000000, \ + }, \ + } 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..890743a2ce --- /dev/null +++ b/include/hw/misc/rt500_clkctl0.h @@ -0,0 +1,35 @@ +/* + * 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; + uint32_t regs[RT500_CLKCTL0_REGS_NO]; + 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..8b012b1357 --- /dev/null +++ b/include/hw/misc/rt500_clkctl1.h @@ -0,0 +1,36 @@ +/* + * 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; + uint32_t regs[RT500_CLKCTL1_REGS_NO]; + Clock *sysclk; + Clock *ostimer_clk; +} RT500ClkCtl1State; + +#endif /* HW_MISC_RT500_CLKCTL1_H */ diff --git a/hw/misc/rt500_clkctl0.c b/hw/misc/rt500_clkctl0.c new file mode 100644 index 0000000000..7e7b176719 --- /dev/null +++ b/hw/misc/rt500_clkctl0.c @@ -0,0 +1,253 @@ +/* + * 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 "migration/vmstate.h" +#include "hw/misc/rt500_clkctl0.h" +#include "hw/misc/rt500_clk_freqs.h" + +#include "trace.h" + +#define REG(s, reg) (s->regs[R_RT500_CLKCTL0_##reg]) +#define RF_RD(s, reg, field) \ + ARRAY_FIELD_EX32(s->regs, RT500_CLKCTL0_##reg, field) +#define RF_WR(s, reg, field, val) \ + ARRAY_FIELD_DP32(s->regs, RT500_CLKCTL0_##reg, field, val) + +static const RT500_CLKCTL0_REGISTER_ACCESS_INFO_ARRAY(reg_info); + +static MemTxResult rt500_clkctl0_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + RT500ClkCtl0State *s = opaque; + const struct RegisterAccessInfo *rai = ®_info[addr / 4]; + + switch (addr) { + case A_RT500_CLKCTL0_PSCCTL0_SET: + case A_RT500_CLKCTL0_PSCCTL1_SET: + case A_RT500_CLKCTL0_PSCCTL2_SET: + case A_RT500_CLKCTL0_PSCCTL0_CLR: + case A_RT500_CLKCTL0_PSCCTL1_CLR: + case A_RT500_CLKCTL0_PSCCTL2_CLR: + /* write only registers */ + return MEMTX_ERROR; + default: + *data = s->regs[addr / 4]; + break; + } + + trace_rt500_clkctl0_reg_read(rai->name, addr, *data); + return MEMTX_OK; +} + +static inline void set_systick_clk_from_div(RT500ClkCtl0State *s) +{ + uint32_t div = RF_RD(s, SYSTICKFCLKDIV, 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; + const struct RegisterAccessInfo *rai = ®_info[addr / 4]; + struct RegisterInfo ri = { + .data = &s->regs[addr / 4], + .data_size = 4, + .access = rai, + }; + + trace_rt500_clkctl0_reg_write(rai->name, addr, value); + + switch (addr) { + case A_RT500_CLKCTL0_PSCCTL0: + case A_RT500_CLKCTL0_PSCCTL1: + case A_RT500_CLKCTL0_PSCCTL2: + { + register_write(&ri, value, ~0, NULL, false); + break; + } + case A_RT500_CLKCTL0_PSCCTL0_SET: + case A_RT500_CLKCTL0_PSCCTL1_SET: + case A_RT500_CLKCTL0_PSCCTL2_SET: + { + uint32_t tmp; + + tmp = A_RT500_CLKCTL0_PSCCTL0 + (addr - A_RT500_CLKCTL0_PSCCTL0_SET); + s->regs[tmp / 4] |= value; + break; + } + case A_RT500_CLKCTL0_PSCCTL0_CLR: + case A_RT500_CLKCTL0_PSCCTL1_CLR: + case A_RT500_CLKCTL0_PSCCTL2_CLR: + { + uint32_t tmp; + + tmp = A_RT500_CLKCTL0_PSCCTL0 + (addr - A_RT500_CLKCTL0_PSCCTL0_CLR); + s->regs[tmp / 4] &= ~value; + break; + } + default: + register_write(&ri, value, ~0, NULL, false); + } + + switch (addr) { + case A_RT500_CLKCTL0_SYSPLL0PFD: + { + if (!RF_RD(s, SYSPLL0PFD, PFD0_CLKGATE)) { + RF_WR(s, SYSPLL0PFD, PFD0_CLKRDY, 1); + } else { + RF_WR(s, SYSPLL0PFD, PFD0_CLKRDY, 0); + } + if (!RF_RD(s, SYSPLL0PFD, PFD1_CLKGATE)) { + RF_WR(s, SYSPLL0PFD, PFD1_CLKRDY, 1); + } else { + RF_WR(s, SYSPLL0PFD, PFD1_CLKRDY, 0); + } + if (!RF_RD(s, SYSPLL0PFD, PFD2_CLKGATE)) { + RF_WR(s, SYSPLL0PFD, PFD2_CLKRDY, 1); + } else { + RF_WR(s, SYSPLL0PFD, PFD2_CLKRDY, 0); + } + if (!RF_RD(s, SYSPLL0PFD, PFD3_CLKGATE)) { + RF_WR(s, SYSPLL0PFD, PFD3_CLKRDY, 1); + } else { + RF_WR(s, SYSPLL0PFD, PFD3_CLKRDY, 0); + } + break; + } + case A_RT500_CLKCTL0_SYSTICKFCLKSEL: + { + switch (RF_RD(s, SYSTICKFCLKSEL, 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 A_RT500_CLKCTL0_SYSTICKFCLKDIV: + { + if (RF_RD(s, SYSTICKFCLKSEL, SEL) == SYSTICKFCLKSEL_DIVOUT) { + set_systick_clk_from_div(s); + clock_propagate(s->systick_clk); + } + break; + } + } + + 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, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void rt500_clkctl0_reset_enter(Object *obj, ResetType type) +{ + RT500ClkCtl0State *s = RT500_CLKCTL0(obj); + + for (int i = 0; i < RT500_CLKCTL0_REGS_NO; i++) { + hwaddr addr = reg_info[i].addr; + + if (addr != -1) { + struct RegisterInfo ri = { + .data = &s->regs[addr / 4], + .data_size = 4, + .access = ®_info[i], + }; + + register_reset(&ri); + } + } + + /* clock OK immediately after reset */ + REG(s, 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 const VMStateDescription vmstate_rt500_clkctl0 = { + .name = "rt500-clkctl0", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, RT500ClkCtl0State, RT500_CLKCTL0_REGS_NO), + VMSTATE_CLOCK(systick_clk, RT500ClkCtl0State), + VMSTATE_END_OF_LIST() + } +}; + +static void rt500_clkctl0_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.enter = rt500_clkctl0_reset_enter; + dc->vmsd = &vmstate_rt500_clkctl0; +} + +static const TypeInfo rt500_clkctl0_types[] = { + { + .name = TYPE_RT500_CLKCTL0, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RT500ClkCtl0State), + .instance_init = rt500_clkctl0_init, + .class_init = rt500_clkctl0_class_init, + }, +}; + +DEFINE_TYPES(rt500_clkctl0_types); + diff --git a/hw/misc/rt500_clkctl1.c b/hw/misc/rt500_clkctl1.c new file mode 100644 index 0000000000..ed234ce0f6 --- /dev/null +++ b/hw/misc/rt500_clkctl1.c @@ -0,0 +1,238 @@ +/* + * 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 "migration/vmstate.h" +#include "hw/misc/rt500_clkctl1.h" +#include "hw/misc/rt500_clk_freqs.h" + +#include "trace.h" + +#define REG(s, reg) (s->regs[R_RT500_CLKCTL1_##reg]) +#define RF_RD(s, reg, field) \ + ARRAY_FIELD_EX32(s->regs, RT500_CLKCTL1_##reg, field) +#define RF_WR(s, reg, field, val) \ + ARRAY_FIELD_DP32(s->regs, RT500_CLKCTL1_##reg, field, val) + +static RT500_CLKCTL1_REGISTER_ACCESS_INFO_ARRAY(reg_info); + +static MemTxResult rt500_clkctl1_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + RT500ClkCtl1State *s = opaque; + const struct RegisterAccessInfo *rai = ®_info[addr / 4]; + MemTxResult ret = MEMTX_OK; + + switch (addr) { + case A_RT500_CLKCTL1_PSCCTL0_SET: + case A_RT500_CLKCTL1_PSCCTL1_SET: + case A_RT500_CLKCTL1_PSCCTL2_SET: + case A_RT500_CLKCTL1_PSCCTL0_CLR: + case A_RT500_CLKCTL1_PSCCTL1_CLR: + case A_RT500_CLKCTL1_PSCCTL2_CLR: + /* write only registers */ + ret = MEMTX_ERROR; + break; + default: + *data = s->regs[addr / 4]; + break; + } + + trace_rt500_clkctl1_reg_read(rai->name, addr, *data); + return ret; +} + +static MemTxResult rt500_clkctl1_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + RT500ClkCtl1State *s = opaque; + const struct RegisterAccessInfo *rai = ®_info[addr / 4]; + struct RegisterInfo ri = { + .data = &s->regs[addr / 4], + .data_size = 4, + .access = rai, + }; + + trace_rt500_clkctl1_reg_write(rai->name, addr, value); + + switch (addr) { + case A_RT500_CLKCTL1_PSCCTL0: + case A_RT500_CLKCTL1_PSCCTL1: + case A_RT500_CLKCTL1_PSCCTL2: + { + s->regs[addr / 4] = value | s->regs[addr / 4]; + break; + } + case A_RT500_CLKCTL1_PSCCTL0_SET: + case A_RT500_CLKCTL1_PSCCTL1_SET: + case A_RT500_CLKCTL1_PSCCTL2_SET: + { + uint32_t tmp; + + tmp = A_RT500_CLKCTL1_PSCCTL0 + (addr - A_RT500_CLKCTL1_PSCCTL0_SET); + s->regs[tmp / 4] |= value; + break; + } + case A_RT500_CLKCTL1_PSCCTL0_CLR: + case A_RT500_CLKCTL1_PSCCTL1_CLR: + case A_RT500_CLKCTL1_PSCCTL2_CLR: + { + uint32_t tmp; + + tmp = A_RT500_CLKCTL1_PSCCTL0 + (addr - A_RT500_CLKCTL1_PSCCTL0_CLR); + s->regs[tmp / 4] &= ~value; + break; + } + default: + register_write(&ri, value, ~0, NULL, false); + } + + switch (addr) { + case A_RT500_CLKCTL1_AUDIOPLL0PFD: + { + if (!RF_RD(s, AUDIOPLL0PFD, PFD0_CLKGATE)) { + RF_WR(s, AUDIOPLL0PFD, PFD0_CLKRDY, 1); + } else { + RF_WR(s, AUDIOPLL0PFD, PFD0_CLKRDY, 0); + } + if (!RF_RD(s, AUDIOPLL0PFD, PFD1_CLKGATE)) { + RF_WR(s, AUDIOPLL0PFD, PFD1_CLKRDY, 1); + } else { + RF_WR(s, AUDIOPLL0PFD, PFD1_CLKRDY, 0); + } + if (!RF_RD(s, AUDIOPLL0PFD, PFD2_CLKGATE)) { + RF_WR(s, AUDIOPLL0PFD, PFD2_CLKRDY, 1); + } else { + RF_WR(s, AUDIOPLL0PFD, PFD2_CLKRDY, 0); + } + if (!RF_RD(s, AUDIOPLL0PFD, PFD3_CLKGATE)) { + RF_WR(s, AUDIOPLL0PFD, PFD3_CLKRDY, 1); + } else { + RF_WR(s, AUDIOPLL0PFD, PFD3_CLKRDY, 0); + } + break; + } + case A_RT500_CLKCTL1_OSEVENTTFCLKSEL: + { + switch (RF_RD(s, OSEVENTTFCLKSEL, 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; + } + } + + 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, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void rt500_clkctl1_reset(Object *obj, ResetType type) +{ + RT500ClkCtl1State *s = RT500_CLKCTL1(obj); + + for (int i = 0; i < RT500_CLKCTL1_REGS_NO; i++) { + hwaddr addr = reg_info[i].addr; + + if (addr != -1) { + struct RegisterInfo ri = { + .data = &s->regs[addr / 4], + .data_size = 4, + .access = ®_info[i], + }; + + register_reset(&ri); + } + } +} + +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 const VMStateDescription vmstate_rt500_clkctl1 = { + .name = "rt500-clkctl1", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, RT500ClkCtl1State, RT500_CLKCTL1_REGS_NO), + VMSTATE_CLOCK(ostimer_clk, RT500ClkCtl1State), + VMSTATE_END_OF_LIST() + } +}; + +static void rt500_clkctl1_class_init(ObjectClass *klass, void *data) +{ + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + rc->phases.enter = rt500_clkctl1_reset; + dc->vmsd = &vmstate_rt500_clkctl1; + +} + +static const TypeInfo rt500_clkctl1_types[] = { + { + .name = TYPE_RT500_CLKCTL1, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RT500ClkCtl1State), + .instance_init = rt500_clkctl1_init, + .class_init = rt500_clkctl1_class_init, + } +}; + +DEFINE_TYPES(rt500_clkctl1_types); diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index eac5070514..658af0dace 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -629,3 +629,8 @@ config ARMSSE select UNIMP select SSE_COUNTER select SSE_TIMER + +config RT500 + bool + select FLEXCOMM + select RT500_CLKCTL diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build index e7d62a7f35..9c458b314c 100644 --- a/hw/arm/svd/meson.build +++ b/hw/arm/svd/meson.build @@ -16,4 +16,12 @@ if get_option('mcux-soc-svd') [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/flexcomm_spi.h', '-p', 'SPI0', '-t', 'FLEXCOMM_SPI', '--fields', 'CFG FIFOCFG:ENABLE*,EMPTY* FIFO*:* INT*: STAT']) + run_target('svd-rt500-clkctl0', command: svd_gen_header + + [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/rt500_clkctl0.h', + '-p', 'CLKCTL0', '-t', 'RT500_CLKCTL0', + '--fields', 'PSCCTL*:ROM_CTRLR_CLK,DSP_CLK SYSPLL0PFD SYSTICKFCLKSEL SYSTICKFCLKDIV FROCLKSTATUS:']) + run_target('svd-rt500-clkctl1', command: svd_gen_header + + [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/rt500_clkctl1.h', + '-p', 'CLKCTL1', '-t', 'RT500_CLKCTL1', + '--fields', 'PSCCTL*:FlexIO AUDIOPLL0PFD OSEVENTTFCLKSEL']) endif diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index b373e651e1..02feb93840 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -218,4 +218,7 @@ config FLEXCOMM select I2C select SSI +config RT500_CLKCTL + bool + source macio/Kconfig diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 0d901b9c65..15f9153be4 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -153,3 +153,4 @@ 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_CLKCTL', if_true: files('rt500_clkctl0.c', 'rt500_clkctl1.c')) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index dc245905dc..b19393dd36 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -368,3 +368,11 @@ 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" flexcomm_fifostat(const char *id, uint32_t fifostat, uint32_t fifoinstat) "%s: %08x %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" From patchwork Tue Oct 8 01:18:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993918 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=ayqP1izt; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMyxD4NfFz1xth for ; Tue, 8 Oct 2024 12:24:48 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxyt5-0000Sy-MY; Mon, 07 Oct 2024 21:19: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 <3kYgEZwUKCvInUpcjaiiafY.WigkYgo-XYpYfhihaho.ila@flex--tavip.bounces.google.com>) id 1sxysi-0007rU-TT for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:21 -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 <3kYgEZwUKCvInUpcjaiiafY.WigkYgo-XYpYfhihaho.ila@flex--tavip.bounces.google.com>) id 1sxyse-0000AH-3C for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:20 -0400 Received: by mail-yb1-xb49.google.com with SMTP id 3f1490d57ef6-e28690bc290so7535228276.1 for ; Mon, 07 Oct 2024 18:19:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350354; x=1728955154; 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=0eZ20KWycrpoAWSK7v7xZhJPuQ4t9+MXTd5omboFwxE=; b=ayqP1iztqATkPL7eEDLYvjwruRwu8EIZADTsb8Uu3uppQUfSasSdSx/U007jqitfgg F470M+sif/tftqGUB7EBgHTBpEgO/sBDAmqns+quTtDsdyYqiM677VUAoLKVRXP6RYUc VSho5mQ5ocVB29boFRnMe+1hGQkGxaORyKluhGeh1e9+xm14+7Dh22cnWvYdHnqo1JL0 kqPhngvF6q5a7Wkd9+yMadV1/b4UZYzFzq7PKdU0ufb7ywX504WVUDun0GOiSGJ1R4y5 voL/fRGalzNp9zcK5qJ5B0u5tQdlYQPN0m9oEZ69piqKTr1VKylEouEUKk/fomRr+bV7 tFpA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350354; x=1728955154; 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=0eZ20KWycrpoAWSK7v7xZhJPuQ4t9+MXTd5omboFwxE=; b=P7+me+SYRX7LFkJPQqZIwTiJnXT3zI7H22Htz8Q+u8xCQjbVs9oSgwcCQFNIp1Ax9f thG9pgXBtjfkYKqdINdFug2Mw0UiukEJpZd77WAEHwmG3lbGQ7hcyM5ONwgoErCkTFYZ CI6r6+cs4jsJtk5eZqpZec6A5FC0nMScHIa/t4KqrZ155M8P/q/hTGz3PGoWPoIxJ0SD BQRoPfcZcRRoZ1+Ka3A4rFuG4BITAZjmAfv8RueUJWgq9/PSJX/aSsqQsB6M//Vff3Gr r1ecSWUZ+iyddGMfoIO1zD9UENO99M1Vhbe/TqUZufm58mXBkRBfLSzR6bAnVwc+ow9R 7BTA== X-Gm-Message-State: AOJu0YyG1BBNSplQs526F/+ewEPL0WvDdhQWq6TSpKacVnnWjujp018B JC49nEN3ZEtfMbILVPLG+3L0Ja0F/ACp7vuGizjkews4Xbrku6MhjlU7lTxiNoC7KlsTM529dar bXx/LIc2iLwc9fVgQAgD+Gmoy2IMRQGq5NE9O0Cg6+w9bxpAAnohnVb8dgwxvgW+MjtOsv59md3 +k+sa6asmWZBMI9rqKCO8BSzXH2w== X-Google-Smtp-Source: AGHT+IHSUmcJnw1C/+86tM9pY+DBOVdB9rYfekCN7zWgSpmD4h6ImtNtH8wO9EKcNCt9vM3jVhBUP7duBg== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a25:a444:0:b0:e13:e11c:507 with SMTP id 3f1490d57ef6-e28936d614bmr11062276.3.1728350353966; Mon, 07 Oct 2024 18:19:13 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:37 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-12-tavip@google.com> Subject: [PATCH v2 11/25] 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, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::b49; envelope-from=3kYgEZwUKCvInUpcjaiiafY.WigkYgo-XYpYfhihaho.ila@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.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. The patch includes an automatically generated header which contains the register layout and helpers. The header can be regenerated with the svd-flexspi target when the build is configured with --enable-mcux-soc-svd. Signed-off-by: Octavian Purdila --- include/hw/arm/svd/flexspi.h | 1085 ++++++++++++++++++++++++++++++++++ include/hw/ssi/flexspi.h | 31 + hw/ssi/flexspi.c | 181 ++++++ hw/arm/svd/meson.build | 4 + hw/ssi/Kconfig | 4 + hw/ssi/meson.build | 1 + hw/ssi/trace-events | 4 + 7 files changed, 1310 insertions(+) create mode 100644 include/hw/arm/svd/flexspi.h create mode 100644 include/hw/ssi/flexspi.h create mode 100644 hw/ssi/flexspi.c diff --git a/include/hw/arm/svd/flexspi.h b/include/hw/arm/svd/flexspi.h new file mode 100644 index 0000000000..6e7e715d51 --- /dev/null +++ b/include/hw/arm/svd/flexspi.h @@ -0,0 +1,1085 @@ +/* + * Copyright 2016-2023 NXP SPDX-License-Identifier: BSD-3-Clause + * + * Automatically generated by svd-gen-header.py from MIMXRT595S_cm33.xml + */ +#pragma once + +#include "hw/register.h" + +/* FlexSPI */ +#define FLEXSPI_REGS_NO (267) + +/* Module Control Register 0 */ +REG32(FLEXSPI_MCR0, 0x0); +/* Software Reset */ +FIELD(FLEXSPI_MCR0, SWRESET, 0, 1); + +/* Interrupt Register */ +REG32(FLEXSPI_INTR, 0x14); +/* + * IP triggered Command Sequences Execution finished interrupt. This interrupt + * is also generated when there is IPCMDGE or IPCMDERR interrupt generated. + */ +FIELD(FLEXSPI_INTR, IPCMDDONE, 0, 1); + +/* Status Register 0 */ +REG32(FLEXSPI_STS0, 0xE0); +/* + * This status bit indicates the state machine in SEQ_CTL is idle and there is + * command sequence executing on FlexSPI interface. + */ +FIELD(FLEXSPI_STS0, SEQIDLE, 0, 1); + + +#define FLEXSPI_REGISTER_ACCESS_INFO_ARRAY(_name) \ + struct RegisterAccessInfo _name[FLEXSPI_REGS_NO] = { \ + [0 ... FLEXSPI_REGS_NO - 1] = { \ + .name = "", \ + .addr = -1, \ + }, \ + [0x0] = { \ + .name = "MCR0", \ + .addr = 0x0, \ + .ro = 0x20CC, \ + .reset = 0xFFFF80C2, \ + }, \ + [0x1] = { \ + .name = "MCR1", \ + .addr = 0x4, \ + .ro = 0x0, \ + .reset = 0xFFFFFFFF, \ + }, \ + [0x2] = { \ + .name = "MCR2", \ + .addr = 0x8, \ + .ro = 0xFF37FF, \ + .reset = 0x200081F7, \ + }, \ + [0x3] = { \ + .name = "AHBCR", \ + .addr = 0xC, \ + .ro = 0xFFFFFB02, \ + .reset = 0x18, \ + }, \ + [0x4] = { \ + .name = "INTEN", \ + .addr = 0x10, \ + .ro = 0xFFFFC000, \ + .reset = 0x0, \ + }, \ + [0x5] = { \ + .name = "INTR", \ + .addr = 0x14, \ + .ro = 0xFFFFE000, \ + .reset = 0x0, \ + }, \ + [0x6] = { \ + .name = "LUTKEY", \ + .addr = 0x18, \ + .ro = 0x0, \ + .reset = 0x5AF05AF0, \ + }, \ + [0x7] = { \ + .name = "LUTCR", \ + .addr = 0x1C, \ + .ro = 0xFFFFFFFC, \ + .reset = 0x2, \ + }, \ + [0x8] = { \ + .name = "AHBRXBUF0CR0", \ + .addr = 0x20, \ + .ro = 0x78F0FF00, \ + .reset = 0x80000010, \ + }, \ + [0x9] = { \ + .name = "AHBRXBUF1CR0", \ + .addr = 0x24, \ + .ro = 0x78F0FF00, \ + .reset = 0x80010010, \ + }, \ + [0xA] = { \ + .name = "AHBRXBUF2CR0", \ + .addr = 0x28, \ + .ro = 0x78F0FF00, \ + .reset = 0x80020010, \ + }, \ + [0xB] = { \ + .name = "AHBRXBUF3CR0", \ + .addr = 0x2C, \ + .ro = 0x78F0FF00, \ + .reset = 0x80030010, \ + }, \ + [0xC] = { \ + .name = "AHBRXBUF4CR0", \ + .addr = 0x30, \ + .ro = 0x78F0FF00, \ + .reset = 0x80040010, \ + }, \ + [0xD] = { \ + .name = "AHBRXBUF5CR0", \ + .addr = 0x34, \ + .ro = 0x78F0FF00, \ + .reset = 0x80050010, \ + }, \ + [0xE] = { \ + .name = "AHBRXBUF6CR0", \ + .addr = 0x38, \ + .ro = 0x78F0FF00, \ + .reset = 0x80060010, \ + }, \ + [0xF] = { \ + .name = "AHBRXBUF7CR0", \ + .addr = 0x3C, \ + .ro = 0x78F0FF00, \ + .reset = 0x80070010, \ + }, \ + [0x18] = { \ + .name = "FLSHA1CR0", \ + .addr = 0x60, \ + .ro = 0xFF800000, \ + .reset = 0x10000, \ + }, \ + [0x19] = { \ + .name = "FLSHA2CR0", \ + .addr = 0x64, \ + .ro = 0xFF800000, \ + .reset = 0x10000, \ + }, \ + [0x1A] = { \ + .name = "FLSHB1CR0", \ + .addr = 0x68, \ + .ro = 0xFF800000, \ + .reset = 0x10000, \ + }, \ + [0x1B] = { \ + .name = "FLSHB2CR0", \ + .addr = 0x6C, \ + .ro = 0xFF800000, \ + .reset = 0x10000, \ + }, \ + [0x1C] = { \ + .name = "FLSHCR1A1", \ + .addr = 0x70, \ + .ro = 0x0, \ + .reset = 0x63, \ + }, \ + [0x1D] = { \ + .name = "FLSHCR1A2", \ + .addr = 0x74, \ + .ro = 0x0, \ + .reset = 0x63, \ + }, \ + [0x1E] = { \ + .name = "FLSHCR1B1", \ + .addr = 0x78, \ + .ro = 0x0, \ + .reset = 0x63, \ + }, \ + [0x1F] = { \ + .name = "FLSHCR1B2", \ + .addr = 0x7C, \ + .ro = 0x0, \ + .reset = 0x63, \ + }, \ + [0x20] = { \ + .name = "FLSHCR2A1", \ + .addr = 0x80, \ + .ro = 0x1010, \ + .reset = 0x0, \ + }, \ + [0x21] = { \ + .name = "FLSHCR2A2", \ + .addr = 0x84, \ + .ro = 0x1010, \ + .reset = 0x0, \ + }, \ + [0x22] = { \ + .name = "FLSHCR2B1", \ + .addr = 0x88, \ + .ro = 0x1010, \ + .reset = 0x0, \ + }, \ + [0x23] = { \ + .name = "FLSHCR2B2", \ + .addr = 0x8C, \ + .ro = 0x1010, \ + .reset = 0x0, \ + }, \ + [0x25] = { \ + .name = "FLSHCR4", \ + .addr = 0x94, \ + .ro = 0xFFFFFFFA, \ + .reset = 0x0, \ + }, \ + [0x28] = { \ + .name = "IPCR0", \ + .addr = 0xA0, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x29] = { \ + .name = "IPCR1", \ + .addr = 0xA4, \ + .ro = 0x78F00000, \ + .reset = 0x0, \ + }, \ + [0x2C] = { \ + .name = "IPCMD", \ + .addr = 0xB0, \ + .ro = 0xFFFFFFFE, \ + .reset = 0x0, \ + }, \ + [0x2D] = { \ + .name = "DLPR", \ + .addr = 0xB4, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x2E] = { \ + .name = "IPRXFCR", \ + .addr = 0xB8, \ + .ro = 0xFFFFFE00, \ + .reset = 0x0, \ + }, \ + [0x2F] = { \ + .name = "IPTXFCR", \ + .addr = 0xBC, \ + .ro = 0xFFFFFE00, \ + .reset = 0x0, \ + }, \ + [0x30] = { \ + .name = "DLLCRA", \ + .addr = 0xC0, \ + .ro = 0xFFFF8084, \ + .reset = 0x100, \ + }, \ + [0x31] = { \ + .name = "DLLCRB", \ + .addr = 0xC4, \ + .ro = 0xFFFF8084, \ + .reset = 0x100, \ + }, \ + [0x38] = { \ + .name = "STS0", \ + .addr = 0xE0, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x2, \ + }, \ + [0x39] = { \ + .name = "STS1", \ + .addr = 0xE4, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x3A] = { \ + .name = "STS2", \ + .addr = 0xE8, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x1000100, \ + }, \ + [0x3B] = { \ + .name = "AHBSPNDSTS", \ + .addr = 0xEC, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x3C] = { \ + .name = "IPRXFSTS", \ + .addr = 0xF0, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x3D] = { \ + .name = "IPTXFSTS", \ + .addr = 0xF4, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x40] = { \ + .name = "RFDR0", \ + .addr = 0x100, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x41] = { \ + .name = "RFDR1", \ + .addr = 0x104, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x42] = { \ + .name = "RFDR2", \ + .addr = 0x108, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x43] = { \ + .name = "RFDR3", \ + .addr = 0x10C, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x44] = { \ + .name = "RFDR4", \ + .addr = 0x110, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x45] = { \ + .name = "RFDR5", \ + .addr = 0x114, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x46] = { \ + .name = "RFDR6", \ + .addr = 0x118, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x47] = { \ + .name = "RFDR7", \ + .addr = 0x11C, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x48] = { \ + .name = "RFDR8", \ + .addr = 0x120, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x49] = { \ + .name = "RFDR9", \ + .addr = 0x124, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x4A] = { \ + .name = "RFDR10", \ + .addr = 0x128, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x4B] = { \ + .name = "RFDR11", \ + .addr = 0x12C, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x4C] = { \ + .name = "RFDR12", \ + .addr = 0x130, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x4D] = { \ + .name = "RFDR13", \ + .addr = 0x134, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x4E] = { \ + .name = "RFDR14", \ + .addr = 0x138, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x4F] = { \ + .name = "RFDR15", \ + .addr = 0x13C, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x50] = { \ + .name = "RFDR16", \ + .addr = 0x140, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x51] = { \ + .name = "RFDR17", \ + .addr = 0x144, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x52] = { \ + .name = "RFDR18", \ + .addr = 0x148, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x53] = { \ + .name = "RFDR19", \ + .addr = 0x14C, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x54] = { \ + .name = "RFDR20", \ + .addr = 0x150, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x55] = { \ + .name = "RFDR21", \ + .addr = 0x154, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x56] = { \ + .name = "RFDR22", \ + .addr = 0x158, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x57] = { \ + .name = "RFDR23", \ + .addr = 0x15C, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x58] = { \ + .name = "RFDR24", \ + .addr = 0x160, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x59] = { \ + .name = "RFDR25", \ + .addr = 0x164, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x5A] = { \ + .name = "RFDR26", \ + .addr = 0x168, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x5B] = { \ + .name = "RFDR27", \ + .addr = 0x16C, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x5C] = { \ + .name = "RFDR28", \ + .addr = 0x170, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x5D] = { \ + .name = "RFDR29", \ + .addr = 0x174, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x5E] = { \ + .name = "RFDR30", \ + .addr = 0x178, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x5F] = { \ + .name = "RFDR31", \ + .addr = 0x17C, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x0, \ + }, \ + [0x60] = { \ + .name = "TFDR0", \ + .addr = 0x180, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x61] = { \ + .name = "TFDR1", \ + .addr = 0x184, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x62] = { \ + .name = "TFDR2", \ + .addr = 0x188, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x63] = { \ + .name = "TFDR3", \ + .addr = 0x18C, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x64] = { \ + .name = "TFDR4", \ + .addr = 0x190, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x65] = { \ + .name = "TFDR5", \ + .addr = 0x194, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x66] = { \ + .name = "TFDR6", \ + .addr = 0x198, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x67] = { \ + .name = "TFDR7", \ + .addr = 0x19C, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x68] = { \ + .name = "TFDR8", \ + .addr = 0x1A0, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x69] = { \ + .name = "TFDR9", \ + .addr = 0x1A4, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x6A] = { \ + .name = "TFDR10", \ + .addr = 0x1A8, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x6B] = { \ + .name = "TFDR11", \ + .addr = 0x1AC, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x6C] = { \ + .name = "TFDR12", \ + .addr = 0x1B0, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x6D] = { \ + .name = "TFDR13", \ + .addr = 0x1B4, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x6E] = { \ + .name = "TFDR14", \ + .addr = 0x1B8, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x6F] = { \ + .name = "TFDR15", \ + .addr = 0x1BC, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x70] = { \ + .name = "TFDR16", \ + .addr = 0x1C0, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x71] = { \ + .name = "TFDR17", \ + .addr = 0x1C4, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x72] = { \ + .name = "TFDR18", \ + .addr = 0x1C8, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x73] = { \ + .name = "TFDR19", \ + .addr = 0x1CC, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x74] = { \ + .name = "TFDR20", \ + .addr = 0x1D0, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x75] = { \ + .name = "TFDR21", \ + .addr = 0x1D4, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x76] = { \ + .name = "TFDR22", \ + .addr = 0x1D8, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x77] = { \ + .name = "TFDR23", \ + .addr = 0x1DC, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x78] = { \ + .name = "TFDR24", \ + .addr = 0x1E0, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x79] = { \ + .name = "TFDR25", \ + .addr = 0x1E4, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x7A] = { \ + .name = "TFDR26", \ + .addr = 0x1E8, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x7B] = { \ + .name = "TFDR27", \ + .addr = 0x1EC, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x7C] = { \ + .name = "TFDR28", \ + .addr = 0x1F0, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x7D] = { \ + .name = "TFDR29", \ + .addr = 0x1F4, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x7E] = { \ + .name = "TFDR30", \ + .addr = 0x1F8, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x7F] = { \ + .name = "TFDR31", \ + .addr = 0x1FC, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x80] = { \ + .name = "LUT0", \ + .addr = 0x200, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x81] = { \ + .name = "LUT1", \ + .addr = 0x204, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x82] = { \ + .name = "LUT2", \ + .addr = 0x208, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x83] = { \ + .name = "LUT3", \ + .addr = 0x20C, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x84] = { \ + .name = "LUT4", \ + .addr = 0x210, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x85] = { \ + .name = "LUT5", \ + .addr = 0x214, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x86] = { \ + .name = "LUT6", \ + .addr = 0x218, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x87] = { \ + .name = "LUT7", \ + .addr = 0x21C, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x88] = { \ + .name = "LUT8", \ + .addr = 0x220, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x89] = { \ + .name = "LUT9", \ + .addr = 0x224, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x8A] = { \ + .name = "LUT10", \ + .addr = 0x228, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x8B] = { \ + .name = "LUT11", \ + .addr = 0x22C, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x8C] = { \ + .name = "LUT12", \ + .addr = 0x230, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x8D] = { \ + .name = "LUT13", \ + .addr = 0x234, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x8E] = { \ + .name = "LUT14", \ + .addr = 0x238, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x8F] = { \ + .name = "LUT15", \ + .addr = 0x23C, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x90] = { \ + .name = "LUT16", \ + .addr = 0x240, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x91] = { \ + .name = "LUT17", \ + .addr = 0x244, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x92] = { \ + .name = "LUT18", \ + .addr = 0x248, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x93] = { \ + .name = "LUT19", \ + .addr = 0x24C, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x94] = { \ + .name = "LUT20", \ + .addr = 0x250, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x95] = { \ + .name = "LUT21", \ + .addr = 0x254, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x96] = { \ + .name = "LUT22", \ + .addr = 0x258, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x97] = { \ + .name = "LUT23", \ + .addr = 0x25C, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x98] = { \ + .name = "LUT24", \ + .addr = 0x260, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x99] = { \ + .name = "LUT25", \ + .addr = 0x264, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x9A] = { \ + .name = "LUT26", \ + .addr = 0x268, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x9B] = { \ + .name = "LUT27", \ + .addr = 0x26C, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x9C] = { \ + .name = "LUT28", \ + .addr = 0x270, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x9D] = { \ + .name = "LUT29", \ + .addr = 0x274, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x9E] = { \ + .name = "LUT30", \ + .addr = 0x278, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x9F] = { \ + .name = "LUT31", \ + .addr = 0x27C, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xA0] = { \ + .name = "LUT32", \ + .addr = 0x280, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xA1] = { \ + .name = "LUT33", \ + .addr = 0x284, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xA2] = { \ + .name = "LUT34", \ + .addr = 0x288, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xA3] = { \ + .name = "LUT35", \ + .addr = 0x28C, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xA4] = { \ + .name = "LUT36", \ + .addr = 0x290, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xA5] = { \ + .name = "LUT37", \ + .addr = 0x294, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xA6] = { \ + .name = "LUT38", \ + .addr = 0x298, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xA7] = { \ + .name = "LUT39", \ + .addr = 0x29C, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xA8] = { \ + .name = "LUT40", \ + .addr = 0x2A0, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xA9] = { \ + .name = "LUT41", \ + .addr = 0x2A4, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xAA] = { \ + .name = "LUT42", \ + .addr = 0x2A8, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xAB] = { \ + .name = "LUT43", \ + .addr = 0x2AC, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xAC] = { \ + .name = "LUT44", \ + .addr = 0x2B0, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xAD] = { \ + .name = "LUT45", \ + .addr = 0x2B4, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xAE] = { \ + .name = "LUT46", \ + .addr = 0x2B8, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xAF] = { \ + .name = "LUT47", \ + .addr = 0x2BC, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xB0] = { \ + .name = "LUT48", \ + .addr = 0x2C0, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xB1] = { \ + .name = "LUT49", \ + .addr = 0x2C4, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xB2] = { \ + .name = "LUT50", \ + .addr = 0x2C8, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xB3] = { \ + .name = "LUT51", \ + .addr = 0x2CC, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xB4] = { \ + .name = "LUT52", \ + .addr = 0x2D0, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xB5] = { \ + .name = "LUT53", \ + .addr = 0x2D4, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xB6] = { \ + .name = "LUT54", \ + .addr = 0x2D8, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xB7] = { \ + .name = "LUT55", \ + .addr = 0x2DC, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xB8] = { \ + .name = "LUT56", \ + .addr = 0x2E0, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xB9] = { \ + .name = "LUT57", \ + .addr = 0x2E4, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xBA] = { \ + .name = "LUT58", \ + .addr = 0x2E8, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xBB] = { \ + .name = "LUT59", \ + .addr = 0x2EC, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xBC] = { \ + .name = "LUT60", \ + .addr = 0x2F0, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xBD] = { \ + .name = "LUT61", \ + .addr = 0x2F4, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xBE] = { \ + .name = "LUT62", \ + .addr = 0x2F8, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0xBF] = { \ + .name = "LUT63", \ + .addr = 0x2FC, \ + .ro = 0x0, \ + .reset = 0x0, \ + }, \ + [0x108] = { \ + .name = "HADDRSTART", \ + .addr = 0x420, \ + .ro = 0xFFE, \ + .reset = 0x0, \ + }, \ + [0x109] = { \ + .name = "HADDREND", \ + .addr = 0x424, \ + .ro = 0xFFF, \ + .reset = 0x0, \ + }, \ + [0x10A] = { \ + .name = "HADDROFFSET", \ + .addr = 0x428, \ + .ro = 0xFFF, \ + .reset = 0x0, \ + }, \ + } diff --git a/include/hw/ssi/flexspi.h b/include/hw/ssi/flexspi.h new file mode 100644 index 0000000000..51699e1ceb --- /dev/null +++ b/include/hw/ssi/flexspi.h @@ -0,0 +1,31 @@ +/* + * 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; + uint32_t regs[FLEXSPI_REGS_NO]; + MemoryRegion mem; + uint64_t mmap_size; +} FlexSpiState; + +#endif /* HW_RT500_FLEXSPI_H */ diff --git a/hw/ssi/flexspi.c b/hw/ssi/flexspi.c new file mode 100644 index 0000000000..d5d9e4f098 --- /dev/null +++ b/hw/ssi/flexspi.c @@ -0,0 +1,181 @@ +/* + * 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/ssi/flexspi.h" +#include "hw/arm/svd/flexspi.h" + +#include "trace.h" + +#define REG(s, reg) (s->regs[R_FLEXSPI_##reg]) +#define RF_WR(s, reg, field, val) \ + ARRAY_FIELD_DP32(s->regs, FLEXSPI_##reg, field, val) +#define RF_RD(s, reg, field) \ + ARRAY_FIELD_EX32(s->regs, FLEXSPI_##reg, field) + +static FLEXSPI_REGISTER_ACCESS_INFO_ARRAY(reg_info); + +static void flexspi_reset_enter(Object *obj, ResetType type) +{ + FlexSpiState *s = FLEXSPI(obj); + + for (int i = 0; i < FLEXSPI_REGS_NO; i++) { + hwaddr addr = reg_info[i].addr; + + if (addr != -1) { + struct RegisterInfo ri = { + .data = &s->regs[addr / 4], + .data_size = 4, + .access = ®_info[i], + }; + + register_reset(&ri); + } + } + + /* idle immediately after reset */ + RF_WR(s, STS0, SEQIDLE, 1); +} + +static MemTxResult flexspi_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + FlexSpiState *s = opaque; + const struct RegisterAccessInfo *rai = ®_info[addr / 4]; + MemTxResult ret = MEMTX_OK; + + switch (addr) { + default: + *data = s->regs[addr / 4]; + break; + } + + trace_flexspi_reg_read(DEVICE(s)->id, rai->name, addr, *data); + return ret; +} + + +static MemTxResult flexspi_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + FlexSpiState *s = opaque; + const struct RegisterAccessInfo *rai = ®_info[addr / 4]; + struct RegisterInfo ri = { + .data = &s->regs[addr / 4], + .data_size = 4, + .access = rai, + }; + + trace_flexspi_reg_write(DEVICE(s)->id, rai->name, addr, value); + + switch (addr) { + case A_FLEXSPI_MCR0: + { + register_write(&ri, value, ~0, NULL, false); + + if (RF_RD(s, MCR0, SWRESET)) { + RF_WR(s, MCR0, SWRESET, 0); + } + break; + } + case A_FLEXSPI_INTR: + { + /* fake SPI transfer completion */ + RF_WR(s, INTR, IPCMDDONE, 1); + break; + } + default: + register_write(&ri, value, ~0, NULL, false); + break; + } + + return MEMTX_OK; +} + +static const MemoryRegionOps flexspi_ops = { + .read_with_attrs = flexspi_read, + .write_with_attrs = flexspi_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static Property flexspi_properties[] = { + DEFINE_PROP_UINT64("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(s->regs)); + 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); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mem); + } +} + +static const VMStateDescription vmstate_flexspi = { + .name = "flexspi", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, FlexSpiState, FLEXSPI_REGS_NO), + VMSTATE_END_OF_LIST() + } +}; + +static void flexspi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.enter = flexspi_reset_enter; + dc->realize = flexspi_realize; + dc->vmsd = &vmstate_flexspi; + device_class_set_props(dc, flexspi_properties); +} + +static const TypeInfo flexspi_types[] = { + { + .name = TYPE_FLEXSPI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(FlexSpiState), + .instance_init = flexspi_init, + .class_init = flexspi_class_init, + }, +}; + +DEFINE_TYPES(flexspi_types); diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build index 9c458b314c..adf0f8327a 100644 --- a/hw/arm/svd/meson.build +++ b/hw/arm/svd/meson.build @@ -24,4 +24,8 @@ if get_option('mcux-soc-svd') [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/rt500_clkctl1.h', '-p', 'CLKCTL1', '-t', 'RT500_CLKCTL1', '--fields', 'PSCCTL*:FlexIO AUDIOPLL0PFD OSEVENTTFCLKSEL']) + run_target('svd-flexspi', command: svd_gen_header + + [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/flexspi.h', + '-p', 'FLEXSPI0', '-t', 'FLEXSPI', + '--fields', 'STS0:SEQIDLE MCR0:SWRESET INTR:IPCMDDONE']) endif diff --git a/hw/ssi/Kconfig b/hw/ssi/Kconfig index 8d180de7cf..e3de40e6b6 100644 --- a/hw/ssi/Kconfig +++ b/hw/ssi/Kconfig @@ -28,3 +28,7 @@ config BCM2835_SPI config PNV_SPI bool select SSI + +config FLEXSPI + bool + select SSI diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build index 58e0d14b37..31a2618d52 100644 --- a/hw/ssi/meson.build +++ b/hw/ssi/meson.build @@ -13,3 +13,4 @@ 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_PNV_SPI', if_true: files('pnv_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 f849f1f8be..dd2f04cb22 100644 --- a/hw/ssi/trace-events +++ b/hw/ssi/trace-events @@ -58,3 +58,7 @@ pnv_spi_RDR_match(const char* result) "%s" 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_irq(const char *id, bool irq, bool fifoirqs, bool perirqs, bool enabled) "%s: %d %d %d %d" + +# 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" From patchwork Tue Oct 8 01:18:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993916 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=u7ui+LIm; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMyx50d24z1xvN for ; Tue, 8 Oct 2024 12:24:41 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxytB-0001Gt-Jz; Mon, 07 Oct 2024 21:19:50 -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 <3k4gEZwUKCvQpWrelckkcha.Ykimaiq-Zarahjkjcjq.knc@flex--tavip.bounces.google.com>) id 1sxysp-0007zo-SQ for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:30 -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 <3k4gEZwUKCvQpWrelckkcha.Ykimaiq-Zarahjkjcjq.knc@flex--tavip.bounces.google.com>) id 1sxysi-0000Aj-DS for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:24 -0400 Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-6e2e5e376fcso36890017b3.2 for ; Mon, 07 Oct 2024 18:19:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350356; x=1728955156; 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=YIWmowqh9ilBPFqbJVFwbgPlrwHIw046vPnX3/duUf8=; b=u7ui+LImFaOOJ5kLN/Jmoe0p2opkvfDsBTOeA0VDRthZMHvRzGRU5al3GHV9mtUeWc gFaEX2ivu3B0QGomD11CP4sbBhZVIzyIeYZDH5AGYUdTXPZp5b3Ni8KIDe9Zle0oMgnL YIv2d82Qcl2gLSaTeljpdRwY5KINJQF6BhO//9aX6d9DDHpluZg+g4eorTdTnOXDfNYe DkrqnfDhL/5P+sGfbnb50VfErshZA0k5jrHG7KJ8F8bg3xjOMzuniH1umvw7eKx9z4FT 5vJhje+nwb3sqFlt4dZeI+YkVPXV+BUdAOajR6jALm+dl0plhhXSlgTbkqK1ZR4ssM4C q/jQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350356; x=1728955156; 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=YIWmowqh9ilBPFqbJVFwbgPlrwHIw046vPnX3/duUf8=; b=mSoH8JIS3KSl8/20t1cqmkOB5MeBga5iuw5ckaqFEKILFpLt51yk29y1kTfziVaRRr Ji8BOp1GqXQBhb2LyA3WVAtYkdEHuApLEfaHDkKyzolP8B563TEPcOwrAxK4f1dP3geL R0hhWbouHgvasWznYKOvX/s0DMfSElaiTw67BSO8+3Vb3SQ4fBWVD9KDoagnkHQPIsCj kwcthTnVFzW3v6XhL+n4wlka2DNQdf27IR0TblWklrFktuDvFwYAf63dszi5sMmxUb8G Ty6vC5iTQsjGhqBDG068yLkORGNjrbFFL0+LyrK4VX7h42cxWK/3ZPT41xG5zMvHru1l 25HQ== X-Gm-Message-State: AOJu0Ywevsl+797gUNv/iCkr0J37B1lE5I83l7bkQbpH0UZHZh67vTEX 460yLztxGn9CFh5S6xwJbTm7A3FqrcO5JIhUQuCjADpWTLgVPASe5k0ubkfPY5F9lH4O71H/UOD 9uCeQrR8JmY8yqh7KuJypfuZV6yY87MLytxHkEan5WPflnOaE8TCh/10R3LIXDl1TFlzjq4T52e A4fJQs7dlZtq9BIjvsaVw7bsOZ9g== X-Google-Smtp-Source: AGHT+IESayc9Ykh3LqzVr2AuC96ugMENmY3SXvFs8UUnrZxFn5w0W5/UBHaqraEly00eTLOFk6KJH0+Pgg== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:690c:2c87:b0:6e2:b263:1040 with SMTP id 00721157ae682-6e2c6e88722mr1437387b3.0.1728350355919; Mon, 07 Oct 2024 18:19:15 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:38 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-13-tavip@google.com> Subject: [PATCH v2 12/25] hw/misc: add support for RT500's reset controller From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::1149; envelope-from=3k4gEZwUKCvQpWrelckkcha.Ykimaiq-Zarahjkjcjq.knc@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.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. The patch includes automatically generated headers which contains the register layout and helpers. The header can be regenerated with the svd-rstctl0 and svd-rstctl1 targets when the build is configured with --enable-mcux-soc-svd. Signed-off-by: Octavian Purdila --- include/hw/arm/svd/rt500_rstctl0.h | 110 ++++++++++++ include/hw/arm/svd/rt500_rstctl1.h | 110 ++++++++++++ include/hw/misc/rt500_rstctl.h | 32 ++++ hw/misc/rt500_rstctl.c | 258 +++++++++++++++++++++++++++++ hw/arm/svd/meson.build | 8 + hw/misc/Kconfig | 3 + hw/misc/meson.build | 1 + hw/misc/trace-events | 4 + 8 files changed, 526 insertions(+) create mode 100644 include/hw/arm/svd/rt500_rstctl0.h create mode 100644 include/hw/arm/svd/rt500_rstctl1.h create mode 100644 include/hw/misc/rt500_rstctl.h create mode 100644 hw/misc/rt500_rstctl.c diff --git a/include/hw/arm/svd/rt500_rstctl0.h b/include/hw/arm/svd/rt500_rstctl0.h new file mode 100644 index 0000000000..da25f22208 --- /dev/null +++ b/include/hw/arm/svd/rt500_rstctl0.h @@ -0,0 +1,110 @@ +/* + * Copyright 2016-2023 NXP SPDX-License-Identifier: BSD-3-Clause + * + * Automatically generated by svd-gen-header.py from MIMXRT595S_cm33.xml + */ +#pragma once + +#include "hw/register.h" + +/* Reset Controller 0 */ +#define RT500_RSTCTL0_REGS_NO (31) + +/* System Reset Status Register */ +REG32(RT500_RSTCTL0_SYSRSTSTAT, 0x0); + +/* Peripheral Reset Control Register 0 */ +REG32(RT500_RSTCTL0_PRSTCTL0, 0x10); + +/* Peripheral Reset Control Register 1 */ +REG32(RT500_RSTCTL0_PRSTCTL1, 0x14); + +/* Peripheral Reset Control Register 2 */ +REG32(RT500_RSTCTL0_PRSTCTL2, 0x18); + +/* Peripheral Reset Control Register 0 SET */ +REG32(RT500_RSTCTL0_PRSTCTL0_SET, 0x40); + +/* Peripheral Reset Control Register 1 SET */ +REG32(RT500_RSTCTL0_PRSTCTL1_SET, 0x44); + +/* Peripheral Reset Control Register 2 SET */ +REG32(RT500_RSTCTL0_PRSTCTL2_SET, 0x48); + +/* Peripheral Reset Control Register 0 CLR */ +REG32(RT500_RSTCTL0_PRSTCTL0_CLR, 0x70); + +/* Peripheral Reset Control Register 1 CLR */ +REG32(RT500_RSTCTL0_PRSTCTL1_CLR, 0x74); + +/* Peripheral Reset Control Register 2 CLR */ +REG32(RT500_RSTCTL0_PRSTCTL2_CLR, 0x78); + + +#define RT500_RSTCTL0_REGISTER_ACCESS_INFO_ARRAY(_name) \ + struct RegisterAccessInfo _name[RT500_RSTCTL0_REGS_NO] = { \ + [0 ... RT500_RSTCTL0_REGS_NO - 1] = { \ + .name = "", \ + .addr = -1, \ + }, \ + [0x0] = { \ + .name = "SYSRSTSTAT", \ + .addr = 0x0, \ + .ro = 0xFFFFFF0E, \ + .reset = 0x1, \ + }, \ + [0x4] = { \ + .name = "PRSTCTL0", \ + .addr = 0x10, \ + .ro = 0x820AE0F5, \ + .reset = 0x7DF51F0A, \ + }, \ + [0x5] = { \ + .name = "PRSTCTL1", \ + .addr = 0x14, \ + .ro = 0xFEFE7FF3, \ + .reset = 0x101800C, \ + }, \ + [0x6] = { \ + .name = "PRSTCTL2", \ + .addr = 0x18, \ + .ro = 0xFFFFFFFC, \ + .reset = 0x1C000001, \ + }, \ + [0x10] = { \ + .name = "PRSTCTL0_SET", \ + .addr = 0x40, \ + .ro = 0x820AE0F5, \ + .reset = 0x0, \ + }, \ + [0x11] = { \ + .name = "PRSTCTL1_SET", \ + .addr = 0x44, \ + .ro = 0xFEFE7FF3, \ + .reset = 0x0, \ + }, \ + [0x12] = { \ + .name = "PRSTCTL2_SET", \ + .addr = 0x48, \ + .ro = 0xFFFFFFFC, \ + .reset = 0x0, \ + }, \ + [0x1C] = { \ + .name = "PRSTCTL0_CLR", \ + .addr = 0x70, \ + .ro = 0x820AE0F5, \ + .reset = 0x0, \ + }, \ + [0x1D] = { \ + .name = "PRSTCTL1_CLR", \ + .addr = 0x74, \ + .ro = 0xFEFE7FF3, \ + .reset = 0x0, \ + }, \ + [0x1E] = { \ + .name = "PRSTCTL2_CLR", \ + .addr = 0x78, \ + .ro = 0xFFFFFFFC, \ + .reset = 0x0, \ + }, \ + } diff --git a/include/hw/arm/svd/rt500_rstctl1.h b/include/hw/arm/svd/rt500_rstctl1.h new file mode 100644 index 0000000000..7b0380798f --- /dev/null +++ b/include/hw/arm/svd/rt500_rstctl1.h @@ -0,0 +1,110 @@ +/* + * Copyright 2016-2023 NXP SPDX-License-Identifier: BSD-3-Clause + * + * Automatically generated by svd-gen-header.py from MIMXRT595S_cm33.xml + */ +#pragma once + +#include "hw/register.h" + +/* Reset Controller 1 */ +#define RT500_RSTCTL1_REGS_NO (31) + +/* System Reset Status Register */ +REG32(RT500_RSTCTL1_SYSRSTSTAT, 0x0); + +/* Peripheral Reset Control Register 0 */ +REG32(RT500_RSTCTL1_PRSTCTL0, 0x10); + +/* Peripheral Reset Control Register 1 */ +REG32(RT500_RSTCTL1_PRSTCTL1, 0x14); + +/* Peripheral Reset Control Register 2 */ +REG32(RT500_RSTCTL1_PRSTCTL2, 0x18); + +/* Peripheral Reset Control Register 0 SET */ +REG32(RT500_RSTCTL1_PRSTCTL0_SET, 0x40); + +/* Peripheral Reset Control Register 1 SET */ +REG32(RT500_RSTCTL1_PRSTCTL1_SET, 0x44); + +/* Peripheral Reset Control Register 2 SET */ +REG32(RT500_RSTCTL1_PRSTCTL2_SET, 0x48); + +/* Peripheral Reset Control Register 0 CLR */ +REG32(RT500_RSTCTL1_PRSTCTL0_CLR, 0x70); + +/* Peripheral Reset Control Register 1 CLR */ +REG32(RT500_RSTCTL1_PRSTCTL1_CLR, 0x74); + +/* Peripheral Reset Control Register 2 CLR */ +REG32(RT500_RSTCTL1_PRSTCTL2_CLR, 0x78); + + +#define RT500_RSTCTL1_REGISTER_ACCESS_INFO_ARRAY(_name) \ + struct RegisterAccessInfo _name[RT500_RSTCTL1_REGS_NO] = { \ + [0 ... RT500_RSTCTL1_REGS_NO - 1] = { \ + .name = "", \ + .addr = -1, \ + }, \ + [0x0] = { \ + .name = "SYSRSTSTAT", \ + .addr = 0x0, \ + .ro = 0xFFFFFFFF, \ + .reset = 0x1, \ + }, \ + [0x4] = { \ + .name = "PRSTCTL0", \ + .addr = 0x10, \ + .ro = 0xD40000FF, \ + .reset = 0x1C0FF00, \ + }, \ + [0x5] = { \ + .name = "PRSTCTL1", \ + .addr = 0x14, \ + .ro = 0x4E7EFF00, \ + .reset = 0xB18100FF, \ + }, \ + [0x6] = { \ + .name = "PRSTCTL2", \ + .addr = 0x18, \ + .ro = 0x3FFCFAE0, \ + .reset = 0xC001011F, \ + }, \ + [0x10] = { \ + .name = "PRSTCTL0_SET", \ + .addr = 0x40, \ + .ro = 0xD40000FF, \ + .reset = 0x0, \ + }, \ + [0x11] = { \ + .name = "PRSTCTL1_SET", \ + .addr = 0x44, \ + .ro = 0x4E7EFF00, \ + .reset = 0x0, \ + }, \ + [0x12] = { \ + .name = "PRSTCTL2_SET", \ + .addr = 0x48, \ + .ro = 0x3FFCFAE0, \ + .reset = 0x0, \ + }, \ + [0x1C] = { \ + .name = "PRSTCTL0_CLR", \ + .addr = 0x70, \ + .ro = 0xD40000FF, \ + .reset = 0x0, \ + }, \ + [0x1D] = { \ + .name = "PRSTCTL1_CLR", \ + .addr = 0x74, \ + .ro = 0x4E7EFF00, \ + .reset = 0x0, \ + }, \ + [0x1E] = { \ + .name = "PRSTCTL2_CLR", \ + .addr = 0x78, \ + .ro = 0x3FFCFAE0, \ + .reset = 0x0, \ + }, \ + } diff --git a/include/hw/misc/rt500_rstctl.h b/include/hw/misc/rt500_rstctl.h new file mode 100644 index 0000000000..ae7e304b2e --- /dev/null +++ b/include/hw/misc/rt500_rstctl.h @@ -0,0 +1,32 @@ +/* + * 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 TYPE_RT500_RSTCTL "rt500-rstctl" +#define RT500_RSTCTL(o) OBJECT_CHECK(RT500RstCtlState, o, TYPE_RT500_RSTCTL) + +#define TYPE_RT500_RSTCTL0 "rt500-rstctl0" +#define TYPE_RT500_RSTCTL1 "rt500-rstctl1" + +typedef struct { + SysBusDevice parent_obj; + + MemoryRegion mmio; + uint32_t regs[RT500_RSTCTL1_REGS_NO]; +} RT500RstCtlState; + +#endif /* HW_MISC_RT500_RSTCTL_H */ diff --git a/hw/misc/rt500_rstctl.c b/hw/misc/rt500_rstctl.c new file mode 100644 index 0000000000..a6e818c0a0 --- /dev/null +++ b/hw/misc/rt500_rstctl.c @@ -0,0 +1,258 @@ +/* + * 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 "qapi/error.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "exec/address-spaces.h" +#include "migration/vmstate.h" +#include "hw/misc/rt500_rstctl.h" + +#include "trace.h" + +/* + * There are two intances for RSTCTL with the same register names and layout but + * with different fields. + */ +#define BUILD_BUG_REG_ADDR(reg) \ + QEMU_BUILD_BUG_ON((int)A_RT500_RSTCTL0_##reg != (int)A_RT500_RSTCTL1_##reg) + +#define REG(s, reg) (s->regs[R_RT500_RSTCTL0_##reg]) +#define RF_WR(s, reg, field, val) \ + ARRAY_FIELD_DP32(s->regs, RT500_RSTCTL0_##reg, field, val) +#define RF_RD(s, reg, field) \ + ARRAY_FIELD_EX32(s->regs, RT500_RSTCTL0_##reg, field) + +#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)) + + +/* + * The two RSTCLK modules have different write register masks. + */ +typedef struct { + SysBusDeviceClass parent; + const struct RegisterAccessInfo *reg_info; + int reg_info_num; +} RT500RstCtlClass; + +#define RT500_RSTCTL_CLASS(klass) \ + OBJECT_CLASS_CHECK(RT500RstCtlClass, (klass), TYPE_RT500_RSTCTL) +#define RT500_RSTCTL_GET_CLASS(obj) \ + OBJECT_GET_CLASS(RT500RstCtlClass, (obj), TYPE_RT500_RSTCTL) + +BUILD_BUG_REG_ADDR(SYSRSTSTAT); +BUILD_BUG_REG_ADDR(PRSTCTL0); +BUILD_BUG_REG_ADDR(PRSTCTL1); +BUILD_BUG_REG_ADDR(PRSTCTL2); +BUILD_BUG_REG_ADDR(PRSTCTL0_SET); +BUILD_BUG_REG_ADDR(PRSTCTL1_SET); +BUILD_BUG_REG_ADDR(PRSTCTL2_SET); +BUILD_BUG_REG_ADDR(PRSTCTL0_CLR); +BUILD_BUG_REG_ADDR(PRSTCTL1_CLR); +BUILD_BUG_REG_ADDR(PRSTCTL2_CLR); + +static MemTxResult rt500_rstctl_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + RT500RstCtlState *s = opaque; + RT500RstCtlClass *c = RT500_RSTCTL_GET_CLASS(s); + const struct RegisterAccessInfo *rai = &c->reg_info[addr / 4]; + MemTxResult ret = MEMTX_OK; + + switch (addr) { + case A_RT500_RSTCTL0_SYSRSTSTAT: + case A_RT500_RSTCTL0_PRSTCTL0: + case A_RT500_RSTCTL0_PRSTCTL1: + case A_RT500_RSTCTL0_PRSTCTL2: + *data = s->regs[addr / 4]; + break; + default: + ret = MEMTX_ERROR; + } + + trace_rt500_rstctl_reg_read(DEVICE(s)->id, rai->name, addr, *data); + return ret; +} + +static MemTxResult rt500_rstctl_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + RT500RstCtlState *s = opaque; + RT500RstCtlClass *c = RT500_RSTCTL_GET_CLASS(s); + const struct RegisterAccessInfo *rai = &c->reg_info[addr / 4]; + struct RegisterInfo ri = { + .data = &s->regs[addr / 4], + .data_size = 4, + .access = rai, + }; + + trace_rt500_rstctl_reg_write(DEVICE(s)->id, rai->name, addr, value); + + switch (addr) { + case A_RT500_RSTCTL0_SYSRSTSTAT: + { + /* write 1 to clear bits */ + REG(s, SYSRSTSTAT) &= ~value; + break; + } + case A_RT500_RSTCTL0_PRSTCTL0: + case A_RT500_RSTCTL0_PRSTCTL1: + case A_RT500_RSTCTL0_PRSTCTL2: + { + register_write(&ri, value, ~0, NULL, false); + break; + } + case A_RT500_RSTCTL0_PRSTCTL0_SET: + case A_RT500_RSTCTL0_PRSTCTL1_SET: + case A_RT500_RSTCTL0_PRSTCTL2_SET: + { + uint32_t tmp; + + tmp = A_RT500_RSTCTL0_PRSTCTL0 + (addr - A_RT500_RSTCTL0_PRSTCTL0_SET); + s->regs[tmp / 4] |= value; + break; + } + case A_RT500_RSTCTL0_PRSTCTL0_CLR: + case A_RT500_RSTCTL0_PRSTCTL1_CLR: + case A_RT500_RSTCTL0_PRSTCTL2_CLR: + { + uint32_t tmp; + + tmp = A_RT500_RSTCTL0_PRSTCTL0 + (addr - A_RT500_RSTCTL0_PRSTCTL0_CLR); + s->regs[tmp / 4] &= ~value; + 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, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void rt500_rstctl_reset_enter(Object *obj, ResetType type) +{ + RT500RstCtlState *s = RT500_RSTCTL(obj); + RT500RstCtlClass *c = RT500_RSTCTL_GET_CLASS(s); + + for (int i = 0; i < c->reg_info_num; i++) { + hwaddr addr = c->reg_info[i].addr; + + if (addr != -1) { + struct RegisterInfo ri = { + .data = &s->regs[addr / 4], + .data_size = 4, + .access = &c->reg_info[i], + }; + + register_reset(&ri); + } + } +} + +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 const VMStateDescription vmstate_rt500_rstcl0 = { + .name = "rt500-rstctl0", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, RT500RstCtlState, RT500_RSTCTL0_REGS_NO), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_rt500_rstcl1 = { + .name = "rt500-rstctl1", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, RT500RstCtlState, RT500_RSTCTL1_REGS_NO), + VMSTATE_END_OF_LIST() + } +}; + +static void rt500_rstctl0_class_init(ObjectClass *klass, void *data) +{ + RT500RstCtlClass *rc = RT500_RSTCTL_CLASS(klass); + static const RT500_RSTCTL0_REGISTER_ACCESS_INFO_ARRAY(reg_info); + DeviceClass *dc = DEVICE_CLASS(klass); + + RESETTABLE_CLASS(klass)->phases.enter = rt500_rstctl_reset_enter; + dc->vmsd = &vmstate_rt500_rstcl0; + rc->reg_info = reg_info; + rc->reg_info_num = ARRAY_SIZE(reg_info); +} + +static void rt500_rstctl1_class_init(ObjectClass *klass, void *data) +{ + RT500RstCtlClass *rc = RT500_RSTCTL_CLASS(klass); + static const RT500_RSTCTL1_REGISTER_ACCESS_INFO_ARRAY(reg_info); + DeviceClass *dc = DEVICE_CLASS(klass); + + RESETTABLE_CLASS(klass)->phases.enter = rt500_rstctl_reset_enter; + dc->vmsd = &vmstate_rt500_rstcl1; + rc->reg_info = reg_info; + rc->reg_info_num = ARRAY_SIZE(reg_info); +} + +static const TypeInfo rt500_rstctl_types[] = { + { + .name = TYPE_RT500_RSTCTL, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RT500RstCtlState), + .instance_init = rt500_rstctl_init, + .abstract = true, + }, + { + .name = TYPE_RT500_RSTCTL0, + .parent = TYPE_RT500_RSTCTL, + .class_init = rt500_rstctl0_class_init, + .class_size = sizeof(RT500RstCtlClass), + }, + { + .name = TYPE_RT500_RSTCTL1, + .parent = TYPE_RT500_RSTCTL, + .class_init = rt500_rstctl1_class_init, + .class_size = sizeof(RT500RstCtlClass), + }, +}; + +DEFINE_TYPES(rt500_rstctl_types); diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build index adf0f8327a..eb2fab54f5 100644 --- a/hw/arm/svd/meson.build +++ b/hw/arm/svd/meson.build @@ -28,4 +28,12 @@ if get_option('mcux-soc-svd') [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/flexspi.h', '-p', 'FLEXSPI0', '-t', 'FLEXSPI', '--fields', 'STS0:SEQIDLE MCR0:SWRESET INTR:IPCMDDONE']) + run_target('svd-rt500-rstctl0', command: svd_gen_header + + [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/rt500_rstctl0.h', + '-p', 'RSTCTL0', '-t', 'RT500_RSTCTL0', + '--fields', 'SYSRSTSTAT: PRSTCTL*:']) + run_target('svd-rt500-rstctl1', command: svd_gen_header + + [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/rt500_rstctl1.h', + '-p', 'RSTCTL1', '-t', 'RT500_RSTCTL1', + '--fields', 'SYSRSTSTAT: PRSTCTL*:']) endif diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 02feb93840..4b688aead2 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -221,4 +221,7 @@ config FLEXCOMM config RT500_CLKCTL bool +config RT500_RSTCTL + bool + source macio/Kconfig diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 15f9153be4..bf0988fd43 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -154,3 +154,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_CLKCTL', if_true: files('rt500_clkctl0.c', 'rt500_clkctl1.c')) +system_ss.add(when: 'CONFIG_RT500_RSTCTL', if_true: files('rt500_rstctl.c')) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index b19393dd36..721ebe4bb7 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -376,3 +376,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" From patchwork Tue Oct 8 01:18:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993913 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=qORONHHo; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMywb4fXVz1xth for ; Tue, 8 Oct 2024 12:24:15 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxytf-000352-FQ; Mon, 07 Oct 2024 21:20:19 -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 <3lYgEZwUKCvYrYtgnemmejc.amkocks-bctcjlmlels.mpe@flex--tavip.bounces.google.com>) id 1sxysq-0007zr-1g for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:30 -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 <3lYgEZwUKCvYrYtgnemmejc.amkocks-bctcjlmlels.mpe@flex--tavip.bounces.google.com>) id 1sxysi-0000B3-RC for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:24 -0400 Received: by mail-pg1-x549.google.com with SMTP id 41be03b00d2f7-7db4c1a55f5so3866530a12.3 for ; Mon, 07 Oct 2024 18:19:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350359; x=1728955159; 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=MU5YuE7TbN7tgwjXYtOFaVtjIUQzKCZ1o/vW2KAogII=; b=qORONHHoVHs2rgA0YywavVNLu/wtwfjSQ87uDzc0EdFMohQG26PJm9GECnuOpjxbKK DZ9FoQNOG6uzx69mh8/iOjYaPzQnPfk593hmyMb8MTuOB4exCSxzRs0Pdb+YUX+NjBOU mQeQNUskZgZKaAXnyok8sXX2GAk2ao7jPBsuE3bQFo+PGIXqFmhSCxwW5ChNOuYSoim+ O2drsJ+cw23fVkBimtHawNQDziI6iT1DJjsa6dcNCwyavz+e3xr5F1PeOIWq5GHXR35q kkxYkep857gfAMYTBFqOVuBaIzr1QFjSjpHo0zuhmprzCxRl8y7msazunHhdcYqbNE4v 5WBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350359; x=1728955159; 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=MU5YuE7TbN7tgwjXYtOFaVtjIUQzKCZ1o/vW2KAogII=; b=kX3gTDpiV05mZUhVKmXRE044D8ocx27RZ8QA0PczWgEAReOP3485GVYGZt0MaIFa9u 8BZohdNqfGz35nrUom+Omhj41kj27BSbKiNdrqTK/j9wvdxNij0NBuSqZkVmlohcoy9w elRIjDoZ4o+ddX1Q7lhRG2cXcn5Vg9NX9sbfxrMoEo9dPDPoSUSwqTKnxC/0IObFi80u pJlBlDmtCinoXV8kwvDhLPHH5d/uHvGq3cxqleEDTMCgdIWu+Dgb1p3SHfQmpth09pCk EpooJNpqXfAiedbmC8GI1WZ6dav1RBWykcyriIKkyFxPyES6AIMYGenJfJmj+8nhORKC mDYQ== X-Gm-Message-State: AOJu0YxtYXOExUYUsZMjnXxb/OXz5WgioRFG1D8BiRgnFEWhzyjfsX+t wPf4TaY4Cxdqav0EBTKd5Bc5+0UxxTCcnqkhbDwkqNj8+2xdoKUrg/faDhRGdUfRIOSOoUcOoun huZd7dSbL88FD5x7jOWsNzc0iD71/pgeXw2/96Sv2BDToi3YwAizKlSuBLvKtkBXC30yLt+k6Hv fOkkEkdaTxyVrZSelfsBCEm22LPw== X-Google-Smtp-Source: AGHT+IF9HmhXENweSQdSkW/S0XYyeFBm6fSlA4GmVOmyIujg2iYLS3N7nrXt7nYk0lLC8ZtlqSu12hmCww== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a63:131a:0:b0:6e7:95d3:b35c with SMTP id 41be03b00d2f7-7e9e5a05778mr15039a12.5.1728350357755; Mon, 07 Oct 2024 18:19:17 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:39 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-14-tavip@google.com> Subject: [PATCH v2 13/25] 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, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::549; envelope-from=3lYgEZwUKCvYrYtgnemmejc.amkocks-bctcjlmlels.mpe@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add basic support for the RT500 SoC. It supports enough peripherals to run the NXP's microXpresso SDK hello world example. The patch includes an automatically generated header which contains peripheral base addreses and interrupt numbers. The header can be regenerated with the svd-rt500 target when the build is configured with --enable-mcux-soc-svd. Signed-off-by: Octavian Purdila --- include/hw/arm/rt500.h | 44 +++++ include/hw/arm/svd/rt500.h | 63 +++++++ hw/arm/rt500.c | 329 +++++++++++++++++++++++++++++++++++++ hw/arm/Kconfig | 2 + hw/arm/meson.build | 1 + hw/arm/svd/meson.build | 4 + 6 files changed, 443 insertions(+) create mode 100644 include/hw/arm/rt500.h create mode 100644 include/hw/arm/svd/rt500.h create mode 100644 hw/arm/rt500.c diff --git a/include/hw/arm/rt500.h b/include/hw/arm/rt500.h new file mode 100644 index 0000000000..26e08c39a6 --- /dev/null +++ b/include/hw/arm/rt500.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#ifndef HW_ARM_RT500_H +#define HW_ARM_RT500_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 { + SysBusDevice parent_obj; + + 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 */ diff --git a/include/hw/arm/svd/rt500.h b/include/hw/arm/svd/rt500.h new file mode 100644 index 0000000000..3594258f2e --- /dev/null +++ b/include/hw/arm/svd/rt500.h @@ -0,0 +1,63 @@ +/* + * Copyright 2016-2023 NXP SPDX-License-Identifier: BSD-3-Clause + * + * Automatically generated by svd-gen-header.py from MIMXRT595S_cm33.xml + */ +#pragma once + +#define RT500_FLEXCOMM0_BASE 0x40106000UL +#define RT500_FLEXCOMM1_BASE 0x40107000UL +#define RT500_FLEXCOMM2_BASE 0x40108000UL +#define RT500_FLEXCOMM3_BASE 0x40109000UL +#define RT500_FLEXCOMM4_BASE 0x40122000UL +#define RT500_FLEXCOMM5_BASE 0x40123000UL +#define RT500_FLEXCOMM6_BASE 0x40124000UL +#define RT500_FLEXCOMM7_BASE 0x40125000UL +#define RT500_FLEXCOMM14_BASE 0x40126000UL +#define RT500_FLEXCOMM15_BASE 0x40127000UL +#define RT500_FLEXCOMM16_BASE 0x40128000UL +#define RT500_FLEXCOMM8_BASE 0x40209000UL +#define RT500_FLEXCOMM9_BASE 0x4020A000UL +#define RT500_FLEXCOMM10_BASE 0x4020B000UL +#define RT500_FLEXCOMM11_BASE 0x4020C000UL +#define RT500_FLEXCOMM12_BASE 0x4020D000UL +#define RT500_FLEXCOMM13_BASE 0x4020E000UL + +#define RT500_FLEXCOMM0_IRQn 0x14UL +#define RT500_FLEXCOMM1_IRQn 0x15UL +#define RT500_FLEXCOMM2_IRQn 0x16UL +#define RT500_FLEXCOMM3_IRQn 0x17UL +#define RT500_FLEXCOMM4_IRQn 0x18UL +#define RT500_FLEXCOMM5_IRQn 0x19UL +#define RT500_FLEXCOMM6_IRQn 0x43UL +#define RT500_FLEXCOMM7_IRQn 0x44UL +#define RT500_FLEXCOMM14_IRQn 0x20UL +#define RT500_FLEXCOMM15_IRQn 0x21UL +#define RT500_FLEXCOMM16_IRQn 0x66UL +#define RT500_FLEXCOMM8_IRQn 0x60UL +#define RT500_FLEXCOMM9_IRQn 0x61UL +#define RT500_FLEXCOMM10_IRQn 0x62UL +#define RT500_FLEXCOMM11_IRQn 0x63UL +#define RT500_FLEXCOMM12_IRQn 0x64UL +#define RT500_FLEXCOMM13_IRQn 0x65UL + +#define RT500_CLKCTL0_BASE 0x40001000UL + + +#define RT500_CLKCTL1_BASE 0x40021000UL + + +#define RT500_FLEXSPI0_BASE 0x40134000UL + +#define RT500_FLEXSPI0_FLEXSPI1_IRQn 0x42UL + +#define RT500_FLEXSPI1_BASE 0x4013C000UL + +#define RT500_FLEXSPI0_FLEXSPI1_IRQn 0x42UL + +#define RT500_RSTCTL0_BASE 0x40000000UL + + +#define RT500_RSTCTL1_BASE 0x40020000UL + + diff --git a/hw/arm/rt500.c b/hw/arm/rt500.c new file mode 100644 index 0000000000..9e4cfb539e --- /dev/null +++ b/hw/arm/rt500.c @@ -0,0 +1,329 @@ +/* + * 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 "qemu/units.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) + +#define RT500_NUM_IRQ (RT500_FLEXCOMM16_IRQn + 1) + +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); + + /* Add ARMv7-M device */ + object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M); + + for (int i = 0; i < RT500_FLEXCOMM_NUM; i++) { + char *id = g_strdup_printf("flexcomm%d", i); + + object_initialize_child(obj, id, &s->flexcomm[i], TYPE_FLEXCOMM); + DEVICE(&s->flexcomm[i])->id = 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 (int i = 0; i < RT500_FLEXSPI_NUM; i++) { + char *id = g_strdup_printf("flexspi%d", i); + + object_initialize_child(obj, id, &s->flexspi[i], TYPE_FLEXSPI); + DEVICE(&s->flexspi[i])->id = id; + } + + for (int i = 0; i < RT500_RSTCTL_NUM; i++) { + static const char *types[] = { + TYPE_RT500_RSTCTL0, TYPE_RT500_RSTCTL1 + }; + char *id = g_strdup_printf("rstctl%d", i); + + object_initialize_child(obj, id, &s->rstctl[i], types[i]); + DEVICE(&s->rstctl[i])->id = id; + } +} + +static void rt500_realize_memory(RT500State *s, Error **errp) +{ + static 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 + }, + }; + + s->mem = g_malloc_n(2 * ARRAY_SIZE(mem_info), sizeof(MemoryRegion)); + for (int 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); + + rt500_realize_memory(s, errp); + + /* Setup ARMv7M CPU */ + qdev_prop_set_uint32(DEVICE(&s->armv7m), "num-irq", RT500_NUM_IRQ); + qdev_prop_set_uint8(DEVICE(&s->armv7m), "num-prio-bits", 3); + qdev_prop_set_string(DEVICE(&s->armv7m), "cpu-type", "cortex-m33-arm-cpu"); + 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 (int i = 0; i < RT500_FLEXCOMM_NUM; i++) { + static 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 + }; + static 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 + }; + static 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]); + + qdev_prop_set_uint32(ds, "functions", functions[i]); + 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 (int i = 0; i < RT500_FLEXSPI_NUM; i++) { + static const uint32_t addr[] = { + RT500_FLEXSPI0_BASE, RT500_FLEXSPI1_BASE + }; + static const uint32_t mmap_base[] = { + MMAP_FLEXSPI0_BASE, MMAP_FLEXSPI1_BASE + }; + static const uint32_t mmap_size[] = { + MMAP_FLEXSPI0_SIZE, MMAP_FLEXSPI1_SIZE, + }; + DeviceState *ds = DEVICE(&s->flexspi[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]); + sysbus_mmio_map(SYS_BUS_DEVICE(ds), 1, mmap_base[i]); + } + + /* Setup reset controllers */ + for (int i = 0; i < RT500_RSTCTL_NUM; i++) { + DeviceState *ds = DEVICE(&s->rstctl[i]); + static const uint32_t addr[] = { + RT500_RSTCTL0_BASE, RT500_RSTCTL1_BASE + }; + + sysbus_realize_and_unref(SYS_BUS_DEVICE(ds), errp); + sysbus_mmio_map(SYS_BUS_DEVICE(ds), 0, addr[i]); + } +} + +static void rt500_unrealize(DeviceState *ds) +{ + RT500State *s = RT500(ds); + + g_free(s->mem); +} + +static void rt500_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = rt500_realize; + dc->unrealize = rt500_unrealize; + dc->desc = "RT500 (ARM Cortex-M33)"; +} + +static const TypeInfo rt500_types[] = { + { + .name = TYPE_RT500, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RT500State), + .instance_init = rt500_init, + .class_init = rt500_class_init, + }, +}; + +DEFINE_TYPES(rt500_types); + diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 658af0dace..5bc9438945 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -634,3 +634,5 @@ config RT500 bool select FLEXCOMM select RT500_CLKCTL + select FLEXSPI + select RT500_RSTCTL diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 83e4aea10e..a2b20617c9 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -60,6 +60,7 @@ arm_ss.add(when: 'CONFIG_XEN', if_true: files( 'xen-stubs.c', 'xen-pvh.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_COLLIE', if_true: files('collie.c')) diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build index eb2fab54f5..07bcc523fd 100644 --- a/hw/arm/svd/meson.build +++ b/hw/arm/svd/meson.build @@ -36,4 +36,8 @@ if get_option('mcux-soc-svd') [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/rt500_rstctl1.h', '-p', 'RSTCTL1', '-t', 'RT500_RSTCTL1', '--fields', 'SYSRSTSTAT: PRSTCTL*:']) + run_target('svd-rt500', command: svd_gen_header + + [ '-i', rt595, '-o', '@SOURCE_ROOT@/include/hw/arm/svd/rt500.h', + '-s', 'RT500', '-p', 'FLEXCOMM0', '-p', 'CLKCTL0', '-p', 'CLKCTL1', + '-p', 'FLEXSPI0', '-p', 'FLEXSPI1', '-p', 'RSTCTL0', '-p', 'RSTCTL1']) endif From patchwork Tue Oct 8 01:18:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993912 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=p3nmD6Yy; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMywS4gpfz1xth for ; Tue, 8 Oct 2024 12:24:08 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxytn-0003cR-4o; Mon, 07 Oct 2024 21:20:29 -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 <3l4gEZwUKCvgyf0nulttlqj.htrvjrz-ij0jqstslsz.twl@flex--tavip.bounces.google.com>) id 1sxysr-00080y-J2 for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:31 -0400 Received: from mail-pf1-x449.google.com ([2607:f8b0:4864:20::449]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3l4gEZwUKCvgyf0nulttlqj.htrvjrz-ij0jqstslsz.twl@flex--tavip.bounces.google.com>) id 1sxysp-0000BZ-Fj for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:28 -0400 Received: by mail-pf1-x449.google.com with SMTP id d2e1a72fcca58-71e026caf8bso2116850b3a.2 for ; Mon, 07 Oct 2024 18:19:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350361; x=1728955161; 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=PbhHf80sfK7VkwcTgOuxP6owcvc4suokU3ESxbdaOWI=; b=p3nmD6YyOLnCh8I7N+pee3b7RdHGVDUmDIRf502IYwADTz7FUyYvVoq/UJOrJj2xyU ySGGGpm6HhHDxYSFYuHHRiOvMRKPY7jzt+9DQ922dS34CmzZoomBKZ6YzaBKffw5fTMy AbXWdBGl3qYoQ90brls7UJeFtWvqyQ+IFY9qwa1vWTKOUMmnfDVnDpNF1QQWpaEfXjap /0QAdOJzi5jURBDy6lJqkFtoy+5R4x4X7ccEKBygeJ+QvTAwDJjw7Stm3WCo7/1Ve8es M9FFJccNxxswdxP9oCyzeci7eKPsV8PiPTgT5phcStkjIUeMveLVPB/yv6P1K73i2vWg IH3Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350361; x=1728955161; 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=PbhHf80sfK7VkwcTgOuxP6owcvc4suokU3ESxbdaOWI=; b=n/k4SKkAUdCrKwgdhE2wucr2Ra8xTsEnnWTRXBoz545M8Tb7RsGCgOWe+1i5THf+en fhjaZwpQqMYhlIWHbWffkroyALKOzcKAGAJEdYLL8sVDm9bgjcTM17XYy0L2siqrhaIi 6LolKas0F7BBTLLF+qInon1KMGWXcz09fgw2Ml5Xvhqrqe1RlzBg3rIPif56n5+7zB6X niIV2Zg+0WAl8u/8LLfNMKgiAOxrULCRanKvf/BJlcL5iY56PsX9A6VBuEUyYC552UaC 8njdbo33MmCmGH4GJYLmcvF++QrmEeLesxqCa1myoc6xLI0NUcfUSlBrutrIfQwXSF89 bdIA== X-Gm-Message-State: AOJu0Yxj31/ADEgjt5dg9h+21ol/uMdykHkuy2W6IokIcBq7Wv/kOC76 FTX7UVPRxcdiPVhU9nqrbzBJO8htn8+0TFQ+2EGKZcv6oy9cdwJEBmWkwNIHmOSzSpKEvnyS0MJ kU5zkVtTxjRH4ZWhJFldLM8ThZ5X/GYp26+stjy2XSRJ0DCtn2SnHA1wDuIm1qm9ymtiLJG1FxT QUrOSWiaJW/3AponEK4SOeufdnoA== X-Google-Smtp-Source: AGHT+IGgWk8SsfLPaKZ6EeNQEn7lqPAjr3nNGIfVhoWq8dK9fBgwYbuZn6HlAwnrjRMlMn/Um+WXHuNkwA== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:6a00:7687:b0:71d:fb06:e79b with SMTP id d2e1a72fcca58-71dfb06ea3amr14561b3a.0.1728350359669; Mon, 07 Oct 2024 18:19:19 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:40 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-15-tavip@google.com> Subject: [PATCH v2 14/25] 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, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::449; envelope-from=3l4gEZwUKCvgyf0nulttlqj.htrvjrz-ij0jqstslsz.twl@flex--tavip.bounces.google.com; helo=mail-pf1-x449.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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.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/rt595-evk.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++ hw/arm/Kconfig | 5 ++++ hw/arm/meson.build | 1 + 3 files changed, 70 insertions(+) create mode 100644 hw/arm/rt595-evk.c diff --git a/hw/arm/rt595-evk.c b/hw/arm/rt595-evk.c new file mode 100644 index 0000000000..4f875a0b12 --- /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/arm/boot.h" +#include "qapi/error.h" +#include "hw/arm/rt500.h" +#include "hw/qdev-clock.h" +#include "sysemu/reset.h" + +static void rt595_evk_reset(MachineState *ms, ResetType 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->ignore_memory_transaction_failures = true; +} + +DEFINE_MACHINE("rt595-evk", rt595_evk_machine_init); diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 5bc9438945..86d704cf1b 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -636,3 +636,8 @@ config RT500 select RT500_CLKCTL 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 a2b20617c9..48ae30acef 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -61,6 +61,7 @@ arm_ss.add(when: 'CONFIG_XEN', if_true: files( 'xen-pvh.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_COLLIE', if_true: files('collie.c')) From patchwork Tue Oct 8 01:18:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993905 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=0rSL9sYh; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMyvK5Nkyz1xth for ; Tue, 8 Oct 2024 12:23:09 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxyuB-0004eG-A8; Mon, 07 Oct 2024 21:20:51 -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 <3mYgEZwUKCvovcxkriqqing.eqosgow-fgxgnpqpipw.qti@flex--tavip.bounces.google.com>) id 1sxysx-0008CI-J4 for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:36 -0400 Received: from mail-pf1-x449.google.com ([2607:f8b0:4864:20::449]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3mYgEZwUKCvovcxkriqqing.eqosgow-fgxgnpqpipw.qti@flex--tavip.bounces.google.com>) id 1sxyss-0000CG-Ps for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:33 -0400 Received: by mail-pf1-x449.google.com with SMTP id d2e1a72fcca58-71dfeda9ac0so1866077b3a.1 for ; Mon, 07 Oct 2024 18:19:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350363; x=1728955163; 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=ohI0GInatBpkkVc6LlITBXAa2f8u1GNul4wGD6o5kbw=; b=0rSL9sYhIKVm/xcP036gFjJ38oSIMXgXDHlZUNXIz4M2K8wHivHlEp7LRBarCHzD4J OmoVRMD/qJEn8rqnEkwfQa0f3kigbBBVKY4CMbiB++JSdEAVoCBMkbtxiVtXEPgWF0NO tqswvX8g9jeNPnuBNA84sNC0oOepRWggVs8jz2twPcGpmsZZ1vH+BGyu9RF4zjMyCzHr vAj5zWJk87Q6wysAhYRolVZWvt70s59I9csy0VI0oezUw8WndS1WsXvMhkTGIMPkmspp ZL9J8OoGrCKlVJ4dFxmfqghuF54CUlKbLHIMR4ZVOEiNW+exs+LGDhqVTrR0RVGVR0i4 lWEg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350363; x=1728955163; 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=ohI0GInatBpkkVc6LlITBXAa2f8u1GNul4wGD6o5kbw=; b=UEKRgPMkBAaTYG/t85t2s1bqIW/u/rJZDxmYjIkDfE/eOs/bc9uRF+dhter8txpQPL ky1ud0w4+60KRpy8J6Z2yhjai1VN5XY2U2hLkCC9dD0dMfW33MmBcSPhM8qs50Ui4BJx zNNMOgDmuC6T/4Uy64LQfJ5Zdr3Jefqmq1CyWqu5u0Om1MdHj0jh11AapXOphKCm2XZ1 I1gNRFcS+5LsIgXMVTUzqFqJ0IlWnQRJXKKYubwVMX4V6QRXBCcJcmcVe6+PP5dcmM61 iIPDYqEpB12OvEeyqPjaNa+L8nU2SbrpYRCWmmAHZsMVPa2NZ2c2XygnBYP7dnfhlOt7 d8Vg== X-Gm-Message-State: AOJu0Yy/LegDmbSxLNCq4XSYXjJmTCO8FkF0MmVYiQIaA8GtlsERmsPZ JMRgq3VAeuN3YO0yAlkF9NT23kS347DAuPgqHlEbODHNwtd43dtpfIYNnkIx2f+oXE1FveefbNI /MF1e42I2D8Vs3jDDkXJl2F/0mq0EQA1by2R1QeXhn4rz8ZTMUjhI5fhCEruuBqIHv32pMiovJA Mw6F/DNTKsAdVfzTJZMHHuDuUSbg== X-Google-Smtp-Source: AGHT+IHfJoafZ1Gh1mSTL3YA6IgQyHpvaYVZtycBjAalruHqjj2i1J3dSMeXAFCXYRQlu7eKJ3STxUEy6Q== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:6a00:91db:b0:71e:401:6580 with SMTP id d2e1a72fcca58-71e040166f7mr10095b3a.6.1728350361548; Mon, 07 Oct 2024 18:19:21 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:41 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-16-tavip@google.com> Subject: [PATCH v2 15/25] tests/qtest: 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, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::449; envelope-from=3mYgEZwUKCvovcxkriqqing.eqosgow-fgxgnpqpipw.qti@flex--tavip.bounces.google.com; helo=mail-pf1-x449.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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add utility macros for accessing register or register bit fields in tests, e.g.: REG32_WRITE(FLEXCOMM, PSELID, persel); g_assert(REG32_READ_FIELD(FLEXCOMM, PSELID, PERSEL) == persel); Signed-off-by: Octavian Purdila --- tests/qtest/reg-utils.h | 70 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 tests/qtest/reg-utils.h diff --git a/tests/qtest/reg-utils.h b/tests/qtest/reg-utils.h new file mode 100644 index 0000000000..e09aaf3333 --- /dev/null +++ b/tests/qtest/reg-utils.h @@ -0,0 +1,70 @@ +/* + * Register access utilities for 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 + +#include "libqtest-single.h" +#include "hw/registerfields.h" + +#ifdef DEBUG_REG +#define debug(fmt, args...) fprintf(stderr, fmt, ## args) +#else +#define debug(fmt, args...) +#endif + +#define _REG_OFF(mod, reg) (A_##mod##_##reg) + +#define REG32_READ(mod, reg) \ + ({ \ + uint32_t value; \ + value = readl(mod##_BASE + _REG_OFF(mod, reg)); \ + debug("[%s] -> %08x\n", #reg, value); \ + value; \ + }) + +#define REG32_WRITE(mod, reg, value) \ + do { \ + debug("[%s] <- %08x\n", #reg, value); \ + writel(mod##_BASE + _REG_OFF(mod, reg), value); \ + } while (0) + +#define REG_FIELD_VAL(v, mod, reg, field) \ + FIELD_EX32(v, mod##_##reg, field) \ + +#define REG32_READ_FIELD(mod, reg, field) \ + REG_FIELD_VAL(REG32_READ(mod, reg), mod, reg, field) + +#define REG32_WRITE_FIELD(mod, reg, field, val) \ + do { \ + uint32_t _tmp = REG32_READ(mod, reg); \ + _tmp = FIELD_DP32(_tmp, mod##_##reg, field, val); \ + REG32_WRITE(mod, reg, _tmp); \ + } while (0) + +#define REG32_WRITE_FIELD_NOUPDATE(mod, reg, field, val) \ + do { \ + uint32_t _tmp = FIELD_DP32(0, mod##_##reg, field, val); \ + REG32_WRITE(mod, reg, _tmp); \ + } while (0) + +#define WAIT_REG32_FIELD(ns, mod, reg, field, val) \ + do { \ + clock_step(ns); \ + g_assert_cmpuint(REG32_READ_FIELD(mod, reg, field), ==, val); \ + } while (0) + +#define REG32_READ_FAIL(mod, reg) \ + readl_fail(mod##_BASE + _REG_OFF(mod, reg)) + +#define REG32_WRITE_FAIL(mod, reg, value) \ + writel_fail(mod##_BASE + _REG_OFF(mod, reg), value) + +#endif /* _REG_UTILS_H */ From patchwork Tue Oct 8 01:18:42 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993923 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=a7goeXj4; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMyy6665tz1xsn for ; Tue, 8 Oct 2024 12:25:34 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxyuF-0005Jt-N9; Mon, 07 Oct 2024 21:20:55 -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 <3m4gEZwUKCvwxezmtksskpi.gsquiqy-hiziprsrkry.svk@flex--tavip.bounces.google.com>) id 1sxysx-0008CE-JD for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:36 -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 <3m4gEZwUKCvwxezmtksskpi.gsquiqy-hiziprsrkry.svk@flex--tavip.bounces.google.com>) id 1sxyst-0000CW-74 for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:34 -0400 Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-6e2b049b64aso81158297b3.3 for ; Mon, 07 Oct 2024 18:19:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350364; x=1728955164; 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=UWggVGt8pbE9ZLsUZv4jH44X5yOt44e5jHCMlGNjp7Y=; b=a7goeXj4xpd6QVZucbFLqeoo/qPRNmaftLcNPO5RqWa4dtcwb5fvbAOo/gFAuj1eI8 yTqXbWYK5kULLpevzOiSJCy8RTEKyXi1vOw+k/9c9u4ChJTA41b+fuXAaVk8PZCGjCe9 Z6dCam6aESV/eqE8L/a0RvwPlAZrgKpC+SNemGQA7wJAHol0r3R/B/YNyDrAS2/NXMiM 1Q3uY3+F4dRSf+OSSBeyDpJR7ztZb+3gzaXttRYqoYxFv4CQ+3LdPhtStBTOu1md9Oui 1VgEYaekDdL1auVUopeUaVbrUDpGk6s9IoAbnQMUXqH5tsNXyvpsVvHK1PRJ/tIT9ylI Gi6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350364; x=1728955164; 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=UWggVGt8pbE9ZLsUZv4jH44X5yOt44e5jHCMlGNjp7Y=; b=mZ+Yz8s1krXk77laXY97zVaKm9+WD7gIgTDatbze/B2QZnod5q9vCnzekqB0rO5/QF H9GMF2HAeEu7nJvHNyySIqQDjvtsN9OhNU0J0M5dcCTq9MkcaGlw00AjIeOrFgiUtuPX E9+7s6XkayJGYAMfqBPsmjd4vL3xOrkNk3DJGewZ14X43v4LLePCinUbhy9kSHe81YMk xH0VqhmkHuoRJC5FNUMIHsPHHCgWBSHGgH+6KBzknPa8c+ncTc91JyUza8/yJUGvCfmH RqUZ/weEtJSrkS204OkgFqjiwyMl1RNXHqMUkPhV4M71CEsimhHkBhpBrKGMSxdbMoIb huFg== X-Gm-Message-State: AOJu0YzGkHnS7f6a2VuKYVDhnr6wyBBs+CyPJpsCwioV1BubJ2d+dBQ4 FC9epnrthHjVOM5fTOOoaup9BFsWHR/zsX1wefwzKHB97DviRGli8cRh825MLFelAJ9uWyOtW9r +zFkqqsowIn7QcJq1FuBm+tRtvOh0FB8gMkCoNH6TutT+lhRPjQ6/fooKO5+I8tTwfB8urc0esK jz26cEWfZiWZBQfgKXMp2KyyIhpQ== X-Google-Smtp-Source: AGHT+IEnKoproXBmyAwcgsF2f2+HISyD0A+czH81es2a+FVh2KqZfn9xb+61J5CW4nGtkj6QDLnqUisx7g== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a25:26d0:0:b0:e17:8e73:866c with SMTP id 3f1490d57ef6-e2893945130mr35092276.10.1728350363413; Mon, 07 Oct 2024 18:19:23 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:42 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-17-tavip@google.com> Subject: [PATCH v2 16/25] system/qtest: add APIS to check for memory access failures From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::1149; envelope-from=3m4gEZwUKCvwxezmtksskpi.gsquiqy-hiziprsrkry.svk@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add read*/write*_fail qtest APIs to check for memory access failures. Signed-off-by: Octavian Purdila --- tests/qtest/libqtest-single.h | 92 +++++++++++++++++++++++++++++++++++ tests/qtest/libqtest.h | 76 +++++++++++++++++++++++++++++ system/qtest.c | 44 ++++++++++------- tests/qtest/libqtest.c | 73 ++++++++++++++++++++++++++- 4 files changed, 265 insertions(+), 20 deletions(-) diff --git a/tests/qtest/libqtest-single.h b/tests/qtest/libqtest-single.h index 851724cbcb..c22037c8b2 100644 --- a/tests/qtest/libqtest-single.h +++ b/tests/qtest/libqtest-single.h @@ -265,6 +265,98 @@ static inline uint64_t readq(uint64_t addr) return qtest_readq(global_qtest, addr); } +/** + * writeb_fail: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes an 8-bit value to memory expecting a failure. + */ +static inline void writeb_fail(uint64_t addr, uint8_t value) +{ + qtest_writeb_fail(global_qtest, addr, value); +} + +/** + * writew_fail: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 16-bit value to memory expecting a failure. + */ +static inline void writew_fail(uint64_t addr, uint16_t value) +{ + qtest_writew_fail(global_qtest, addr, value); +} + +/** + * writel_fail: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 32-bit value to memory expecting a failure. + */ +static inline void writel_fail(uint64_t addr, uint32_t value) +{ + qtest_writel_fail(global_qtest, addr, value); +} + +/** + * writeq_fail: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 64-bit value to memory expecting a failure. + */ +static inline void writeq_fail(uint64_t addr, uint64_t value) +{ + qtest_writeq_fail(global_qtest, addr, value); +} + +/** + * readb_fail: + * @addr: Guest address to read from. + * + * Reads an 8-bit value from memory expecting a failure. + */ +static inline void readb_fail(uint64_t addr) +{ + qtest_readb_fail(global_qtest, addr); +} + +/** + * readw_fail: + * @addr: Guest address to read from. + * + * Reads a 16-bit value from memory expecting a failure. + */ +static inline void readw_fail(uint64_t addr) +{ + qtest_readw_fail(global_qtest, addr); +} + +/** + * readl_fail: + * @addr: Guest address to read from. + * + * Reads a 32-bit value from memory expecting a failure. + */ +static inline void readl_fail(uint64_t addr) +{ + qtest_readl_fail(global_qtest, addr); +} + +/** + * readq_fail: + * @addr: Guest address to read from. + * + * Reads a 64-bit value from memory expecting a failure. + */ +static inline void readq_fail(uint64_t addr) +{ + qtest_readq_fail(global_qtest, addr); +} + /** * memread: * @addr: Guest address to read from. diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h index beb96b18eb..f9bbeb2e60 100644 --- a/tests/qtest/libqtest.h +++ b/tests/qtest/libqtest.h @@ -549,6 +549,82 @@ uint32_t qtest_readl(QTestState *s, uint64_t addr); */ uint64_t qtest_readq(QTestState *s, uint64_t addr); +/** + * qtest_writeb_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes an 8-bit value to memory expecting a failure. + */ +void qtest_writeb_fail(QTestState *s, uint64_t addr, uint8_t value); + +/** + * qtest_writew_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 16-bit value to memory expecting a failure. + */ +void qtest_writew_fail(QTestState *s, uint64_t addr, uint16_t value); + +/** + * qtest_writel_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 32-bit value to memory expecting a failure. + */ +void qtest_writel_fail(QTestState *s, uint64_t addr, uint32_t value); + +/** + * qtest_writeq_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 64-bit value to memory expecting a failure. + */ +void qtest_writeq_fail(QTestState *s, uint64_t addr, uint64_t value); + +/** + * qtest_readb_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to read from. + * + * Reads an 8-bit value from memory expecting a failure. + */ +void qtest_readb_fail(QTestState *s, uint64_t addr); + +/** + * qtest_readw_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to read from. + * + * Reads a 16-bit value from memory expecting a failure. + */ +void qtest_readw_fail(QTestState *s, uint64_t addr); + +/** + * qtest_readl_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to read from. + * + * Reads a 32-bit value from memory expecting a failure. + */ +void qtest_readl_fail(QTestState *s, uint64_t addr); + +/** + * qtest_readq_fail: + * @s: #QTestState instance to operate on. + * @addr: Guest address to read from. + * + * Reads a 64-bit value from memory expecting a failure. + */ +void qtest_readq_fail(QTestState *s, uint64_t addr); + /** * qtest_memread: * @s: #QTestState instance to operate on. diff --git a/system/qtest.c b/system/qtest.c index 12703a2045..95bb80a2bc 100644 --- a/system/qtest.c +++ b/system/qtest.c @@ -514,26 +514,30 @@ static void qtest_process_command(CharBackend *chr, gchar **words) if (words[0][5] == 'b') { uint8_t data = value; - address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &data, 1); + ret = address_space_write(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &data, 1); } else if (words[0][5] == 'w') { uint16_t data = value; tswap16s(&data); - address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &data, 2); + ret = address_space_write(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &data, 2); } else if (words[0][5] == 'l') { uint32_t data = value; tswap32s(&data); - address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &data, 4); + ret = address_space_write(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &data, 4); } else if (words[0][5] == 'q') { uint64_t data = value; tswap64s(&data); - address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &data, 8); + ret = address_space_write(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &data, 8); } qtest_send_prefix(chr); - qtest_send(chr, "OK\n"); + if (ret == MEMTX_OK) { + qtest_send(chr, "OK\n"); + } else { + qtest_send(chr, "FAIL\n"); + } } else if (strcmp(words[0], "readb") == 0 || strcmp(words[0], "readw") == 0 || strcmp(words[0], "readl") == 0 || @@ -548,26 +552,30 @@ static void qtest_process_command(CharBackend *chr, gchar **words) if (words[0][4] == 'b') { uint8_t data; - address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &data, 1); + ret = address_space_read(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &data, 1); value = data; } else if (words[0][4] == 'w') { uint16_t data; - address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &data, 2); + ret = address_space_read(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &data, 2); value = tswap16(data); } else if (words[0][4] == 'l') { uint32_t data; - address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &data, 4); + ret = address_space_read(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &data, 4); value = tswap32(data); } else if (words[0][4] == 'q') { - address_space_read(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, - &value, 8); + ret = address_space_read(first_cpu->as, addr, + MEMTXATTRS_UNSPECIFIED, &value, 8); tswap64s(&value); } qtest_send_prefix(chr); - qtest_sendf(chr, "OK 0x%016" PRIx64 "\n", value); + if (ret == MEMTX_OK) { + qtest_sendf(chr, "OK 0x%016" PRIx64 "\n", value); + } else { + qtest_sendf(chr, "FAIL\n"); + } } else if (strcmp(words[0], "read") == 0) { g_autoptr(GString) enc = NULL; uint64_t addr, len; diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 9d07de1fbd..4055d6b953 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -666,7 +666,7 @@ static GString *qtest_client_socket_recv_line(QTestState *s) return line; } -static gchar **qtest_rsp_args(QTestState *s, int expected_args) +static gchar **_qtest_rsp_args(QTestState *s, int expected_args, bool fail) { GString *line; gchar **words; @@ -700,7 +700,11 @@ redo: } g_assert(words[0] != NULL); - g_assert_cmpstr(words[0], ==, "OK"); + if (fail) { + g_assert_cmpstr(words[0], ==, "FAIL"); + } else { + g_assert_cmpstr(words[0], ==, "OK"); + } for (i = 0; i < expected_args; i++) { g_assert(words[i] != NULL); @@ -709,6 +713,11 @@ redo: return words; } +static gchar **qtest_rsp_args(QTestState *s, int expected_args) +{ + return _qtest_rsp_args(s, expected_args, false); +} + static void qtest_rsp(QTestState *s) { gchar **words = qtest_rsp_args(s, 0); @@ -716,6 +725,13 @@ static void qtest_rsp(QTestState *s) g_strfreev(words); } +static void qtest_rsp_fail(QTestState *s) +{ + gchar **words = _qtest_rsp_args(s, 0, true); + + g_strfreev(words); +} + static int qtest_query_target_endianness(QTestState *s) { gchar **args; @@ -1103,6 +1119,13 @@ static void qtest_write(QTestState *s, const char *cmd, uint64_t addr, qtest_rsp(s); } +static void qtest_write_fail(QTestState *s, const char *cmd, uint64_t addr, + uint64_t value) +{ + qtest_sendf(s, "%s 0x%" PRIx64 " 0x%" PRIx64 "\n", cmd, addr, value); + qtest_rsp_fail(s); +} + void qtest_writeb(QTestState *s, uint64_t addr, uint8_t value) { qtest_write(s, "writeb", addr, value); @@ -1123,6 +1146,26 @@ void qtest_writeq(QTestState *s, uint64_t addr, uint64_t value) qtest_write(s, "writeq", addr, value); } +void qtest_writeb_fail(QTestState *s, uint64_t addr, uint8_t value) +{ + qtest_write_fail(s, "writeb", addr, value); +} + +void qtest_writew_fail(QTestState *s, uint64_t addr, uint16_t value) +{ + qtest_write_fail(s, "writew", addr, value); +} + +void qtest_writel_fail(QTestState *s, uint64_t addr, uint32_t value) +{ + qtest_write_fail(s, "writel", addr, value); +} + +void qtest_writeq_fail(QTestState *s, uint64_t addr, uint64_t value) +{ + qtest_write_fail(s, "writeq", addr, value); +} + static uint64_t qtest_read(QTestState *s, const char *cmd, uint64_t addr) { gchar **args; @@ -1138,6 +1181,12 @@ static uint64_t qtest_read(QTestState *s, const char *cmd, uint64_t addr) return value; } +static void qtest_read_fail(QTestState *s, const char *cmd, uint64_t addr) +{ + qtest_sendf(s, "%s 0x%" PRIx64 "\n", cmd, addr); + qtest_rsp_fail(s); +} + uint8_t qtest_readb(QTestState *s, uint64_t addr) { return qtest_read(s, "readb", addr); @@ -1158,6 +1207,26 @@ uint64_t qtest_readq(QTestState *s, uint64_t addr) return qtest_read(s, "readq", addr); } +void qtest_readb_fail(QTestState *s, uint64_t addr) +{ + qtest_read_fail(s, "readb", addr); +} + +void qtest_readw_fail(QTestState *s, uint64_t addr) +{ + qtest_read_fail(s, "readw", addr); +} + +void qtest_readl_fail(QTestState *s, uint64_t addr) +{ + qtest_read_fail(s, "readl", addr); +} + +void qtest_readq_fail(QTestState *s, uint64_t addr) +{ + qtest_read(s, "readq", addr); +} + static int hex2nib(char ch) { if (ch >= '0' && ch <= '9') { From patchwork Tue Oct 8 01:18:43 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993928 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=gcV5sD3h; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMyyZ2XBPz1xsn for ; Tue, 8 Oct 2024 12:25:58 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxyuI-0005bQ-2w; Mon, 07 Oct 2024 21:20:58 -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 <3nIgEZwUKCv0yf0nulttlqj.htrvjrz-ij0jqstslsz.twl@flex--tavip.bounces.google.com>) id 1sxysv-00089N-LA for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:35 -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 <3nIgEZwUKCv0yf0nulttlqj.htrvjrz-ij0jqstslsz.twl@flex--tavip.bounces.google.com>) id 1sxyss-0000Cg-1v for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:32 -0400 Received: by mail-pj1-x104a.google.com with SMTP id 98e67ed59e1d1-2e08c6fd74fso6742404a91.0 for ; Mon, 07 Oct 2024 18:19:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350365; x=1728955165; 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=HOp7WmLBwFJSSIU5qqNv1E/gmBAstHCHNzzXu4V4CBY=; b=gcV5sD3hgDjDnWMy3BmQm1g9rgsrSLYaaLPiQ13VmiDPVXfnjSQI39+PJS0b2QijWx oamPPd5TuH9unpmiNMyeBNJf0fkl4Sg5Ki0Q5cSrMpWl8IH6oskPZSnhNjSw7JJdJf+3 Phj7ve9b5iydeZb0EgKwGUuQmBYNsI66Wuy5eYGIp2ezkWD/+g9pi6FLMI9zLFkPu0RQ HchOV2UhAKWlDaVLVVPEesJY6vSYQQqMYSt2HVguk8U/PW0htF5NHXv/ddaumKmSIFSv xcUqZ3O5CTsuJCtqYIZGZ7dg538hKy/hBX/AYWRE9EWTvaaKC7uJqzx3BIdOYe2FraIS f7ew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350365; x=1728955165; 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=HOp7WmLBwFJSSIU5qqNv1E/gmBAstHCHNzzXu4V4CBY=; b=YDTNy7DKqrPunxYnBB6zpjV/9SFbkPlmCkVmPQJy7tyymIE6DzyKvoAQyqkFpImx4r lbn4Ogtwh+z2r+GjBcSW60jtqGaKPxo92N8cl+OH+soAj8j4Qaf6zufty1OBk71hriRE JK8Xks05+tMew1srHeaWwokhR6ge2kPwWZvTyBee62w0EE57/eawei45yUgykYt0XveZ vYcK1z6g6zP0iEjwSiIs+tXTGV5zglm1uxbxlKSDy3VcqelJLQYvWeLrpFL/DFv5sErx bMKVtkHmcuJoRRY5HLVLXtyIZXr02d4x3/t0fe24hcurJkevlyUSqGJpPHVCGVK+twL6 Ozyg== X-Gm-Message-State: AOJu0YybfRttPAIdB+sXfbbxR6MfLnFB9CMg91uFAqsyQPaMnWJFxDha azj05bwjr7Oye5XtpJV2NYwwekE3VfgM9umgb4xmS/tRgPs9akNCI0tDju43yCrbvlXghK15fJ8 lvDbepuENoYUKf4JoH+g7j+IYiKV3FG8HPgoDu6CMD92kwLQkqKNwH2pQDmKYLMZfRLG6gdQPMj 8Sg56CmC5z7g2u3GK8OGYgAYuEbQ== X-Google-Smtp-Source: AGHT+IFJXWzm9uvmfE9DGIxc/k5/9wTOYabBReC34NNJb04CYptvSM3L/sEK2L2WeiVcgcOnDgOuaxXMJg== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a17:903:234e:b0:206:96ae:dc30 with SMTP id d9443c01a7336-20bff1c282bmr3551625ad.10.1728350364927; Mon, 07 Oct 2024 18:19:24 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:43 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-18-tavip@google.com> Subject: [PATCH v2 17/25] tests/qtest: add flexcomm tests From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::104a; envelope-from=3nIgEZwUKCv0yf0nulttlqj.htrvjrz-ij0jqstslsz.twl@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add flexcomm function selection unit tests. Signed-off-by: Octavian Purdila --- tests/qtest/flexcomm-test.c | 82 +++++++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 1 + 2 files changed, 83 insertions(+) create mode 100644 tests/qtest/flexcomm-test.c diff --git a/tests/qtest/flexcomm-test.c b/tests/qtest/flexcomm-test.c new file mode 100644 index 0000000000..ffbee8bfb8 --- /dev/null +++ b/tests/qtest/flexcomm-test.c @@ -0,0 +1,82 @@ +/* + * 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 "hw/arm/svd/flexcomm.h" +#include "hw/arm/svd/rt500.h" +#include "reg-utils.h" + +#define FLEXCOMM_BASE RT500_FLEXCOMM0_BASE + +static void select_test(gconstpointer data) +{ + static const unsigned persel[] = { + FLEXCOMM_PERSEL_USART, + FLEXCOMM_PERSEL_SPI, + FLEXCOMM_PERSEL_I2C, + }; + + g_assert(REG32_READ_FIELD(FLEXCOMM, PSELID, PERSEL) == 0); + + /* no register access until a function is selected */ + readl_fail(FLEXCOMM_BASE); + writel_fail(FLEXCOMM_BASE, 0); + + for (int i = 0; i < ARRAY_SIZE(persel); i++) { + + REG32_WRITE(FLEXCOMM, PSELID, persel[i]); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM, PSELID, PERSEL), ==, + persel[i]); + + /* test that we can access function registers */ + writel(FLEXCOMM_BASE, 0xabcd); + readl(FLEXCOMM_BASE); + } + + /* try to select something invalid */ + REG32_WRITE(FLEXCOMM, PSELID, 7); + /* check for no function selected */ + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM, PSELID, PERSEL), ==, 0); + + /* now select and lock USART */ + REG32_WRITE(FLEXCOMM, PSELID, + FIELD_DP32(FLEXCOMM_PERSEL_USART, FLEXCOMM_PSELID, LOCK, 1)); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM, PSELID, PERSEL), ==, + FLEXCOMM_PERSEL_USART); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM, PSELID, LOCK), ==, 1); + + /* try to change the selection to spi */ + REG32_WRITE(FLEXCOMM, PSELID, FLEXCOMM_PERSEL_SPI); + /* it should still be locked USART */ + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM, PSELID, PERSEL), ==, + FLEXCOMM_PERSEL_USART); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM, PSELID, LOCK), ==, 1); +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + + qtest_add_data_func("/flexcomm/select", NULL, select_test); + qtest_start("-M rt595-evk"); + ret = g_test_run(); + qtest_end(); + + return ret; +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 2b90abf000..f35bb52aa2 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -233,6 +233,7 @@ qtests_arm = \ (config_all_devices.has_key('CONFIG_FSI_APB2OPB_ASPEED') ? ['aspeed_fsi-test'] : []) + \ (config_all_devices.has_key('CONFIG_STM32L4X5_SOC') and config_all_devices.has_key('CONFIG_DM163')? ['dm163-test'] : []) + \ + (config_all_devices.has_key('CONFIG_FLEXCOMM')? ['flexcomm-test'] : []) + \ ['arm-cpu-features', 'boot-serial-test'] From patchwork Tue Oct 8 01:18:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993902 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=E2IPreJg; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMytW0Trfz1xth for ; Tue, 8 Oct 2024 12:22:27 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxyu6-0004AN-Mu; Mon, 07 Oct 2024 21:20:47 -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 <3nogEZwUKCgEubwjqhpphmf.dpnrfnv-efwfmopohov.psh@flex--tavip.bounces.google.com>) id 1sxysx-0008CR-Ja for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:36 -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 <3nogEZwUKCgEubwjqhpphmf.dpnrfnv-efwfmopohov.psh@flex--tavip.bounces.google.com>) id 1sxyst-0000DM-7E for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:34 -0400 Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-6e2baf2ff64so75973027b3.0 for ; Mon, 07 Oct 2024 18:19:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350367; x=1728955167; 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=KH/2xv+ry9E6fErLW4rxS6RZmIvXaaOZIkrg/WhK4hs=; b=E2IPreJg/qpe9C4HZIVYUl2AoLpgWNToFGeYZsH+sMaXZz3c31uhCKtffKNXPBwNZR 3CXoacMfTSpq8TOnLP9S86M/HI3SJ/NwPeP/B52CunBCG1ecXHXugSQPg5hOVPbUz//0 j6Rwm+THEUt/hOKd9dDX+i8goQw5ndtBptBe/bNXwGsCFz+BYN4Pr5vZFsIw8unH8xmR I9/XArOEGjwu7wjaELZlQcxd1oivqpJhmHGuxWZaSJp/ESqHur71Q0xhWeeUFtcXOE8M adWbHJl0xIbX8ogLBSsTllQb14XvWg5Bjxfq4f8UaqV9rHbRvyUPcVxCN2B/wdfGWIE4 9N2g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350367; x=1728955167; 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=KH/2xv+ry9E6fErLW4rxS6RZmIvXaaOZIkrg/WhK4hs=; b=uhh8X65gXBBchvyOtfp1kmbC4VlS4xR9H2bpPUGHzFOd+sQISIRdYws6j0+KMJ4dh1 LcRV90bD9IJD7htsy8Gg99rSJOmxlsf1Wzm0eWF7n5BeLhN5WeIZ+PW/KVcUEifqieMw irf6RKePbUbpb2cWi7md33k9sxLgdyfueexnZqi96PlzdWbwloV8zkEHsNwoGtCiWPYX WQ0Qj4wVkP4JqXSXerb2954GE1TRdpzDSG5ZJmCWEutUSajRub6k3du37ZvEgg0j1FTb 3PFQe5+yNDQatPOGyVUiAoG9JJDtHcfJ4pG1kThq/JnAoIdIQDkADfS1AEZ8AhXcENSg DJCw== X-Gm-Message-State: AOJu0YwYBAmhugtdk33HXbNbSmavuKHm2AWsg+jWr4l/TZ9KgZ+/1YDe ZSqKB1Q8rWQHIEKwMG7T5jYpkxr6Tn5kgbHQcyHJFV8cn7PKgw1ePuDdm4NxYXBYwoHVnYNtF/x aLf13jNWMsKtzjCNS61FzGRQ5ECVaq4K7m08lO4oWz0+Y9ohPoHHXNuJ6dGVG86FuQFUoBkubPs frbAkZKUehlnVW+dFaYcHSoS3g8Q== X-Google-Smtp-Source: AGHT+IEPgy4jBCEt/GAlr5KBC579+z7N16RaMIrOgzKSXWJPySuiz34MQJTVEkI0pz4USPrVQ52UP1boKg== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a81:ad0b:0:b0:6e2:121c:4509 with SMTP id 00721157ae682-6e2c72bbd4bmr1572397b3.7.1728350366897; Mon, 07 Oct 2024 18:19:26 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:44 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-19-tavip@google.com> Subject: [PATCH v2 18/25] tests/qtest: add flexcomm usart tests From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::1149; envelope-from=3nogEZwUKCgEubwjqhpphmf.dpnrfnv-efwfmopohov.psh@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add flexcomm usart polling and irq unit tests. Signed-off-by: Octavian Purdila --- tests/qtest/flexcomm-usart-test.c | 316 ++++++++++++++++++++++++++++++ tests/qtest/meson.build | 3 +- 2 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 tests/qtest/flexcomm-usart-test.c diff --git a/tests/qtest/flexcomm-usart-test.c b/tests/qtest/flexcomm-usart-test.c new file mode 100644 index 0000000000..0ffa49dd6f --- /dev/null +++ b/tests/qtest/flexcomm-usart-test.c @@ -0,0 +1,316 @@ +/* + * 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 + +#include "io/channel-socket.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 "hw/arm/svd/flexcomm_usart.h" +#include "hw/arm/svd/rt500.h" +#include "reg-utils.h" + +#define FLEXCOMM_BASE RT500_FLEXCOMM0_BASE +#define FLEXCOMM_USART_BASE RT500_FLEXCOMM0_BASE +#define DEVICE_NAME "/machine/soc/flexcomm0" + +struct TestState { + QTestState *qtest; + QIOChannel *ioc; +}; + +static void polling_test(gconstpointer user_data) +{ + struct TestState *t = (struct TestState *)user_data; + uint32_t tmp; + char byte; + int fifo_size; + QDict *resp; + + resp = qmp("{\"execute\": \"system_reset\"}"); + qdict_unref(resp); + + /* select and lock USART */ + tmp = FIELD_DP32(FLEXCOMM_PERSEL_USART, FLEXCOMM_PSELID, LOCK, 1); + REG32_WRITE(FLEXCOMM, PSELID, tmp); + + fifo_size = REG32_READ_FIELD(FLEXCOMM_USART, FIFOSIZE, FIFOSIZE); + + /* enable USART */ + REG32_WRITE_FIELD(FLEXCOMM_USART, CFG, ENABLE, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, CFG, ENABLE), ==, 1); + + /* enable TX and RX FIFO */ + REG32_WRITE_FIELD(FLEXCOMM_USART, FIFOCFG, ENABLETX, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOCFG, ENABLETX), + ==, 1); + REG32_WRITE_FIELD(FLEXCOMM_USART, FIFOCFG, ENABLERX, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOCFG, ENABLERX), + ==, 1); + + /* test writes and fifo counters wrap */ + for (int i = 0; i < fifo_size / 2; i++) { + /* check fifostat */ + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, RXFULL), + ==, 0); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, RXNOTEMPTY), + ==, 0); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, TXNOTFULL), + ==, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, TXEMPTY), + ==, 1); + + REG32_WRITE(FLEXCOMM_USART, FIFOWR, 'a' + i); + qio_channel_read(t->ioc, &byte, 1, &error_abort); + g_assert_cmpuint(byte, ==, 'a' + i); + } + + /* test reads and fifo level */ + + for (int i = 0; i < fifo_size / 2; i++) { + byte = 'A' + i; + g_assert_cmpuint(qio_channel_write(t->ioc, &byte, 1, &error_abort), + ==, 1); + } + + /* wait for the RXLVL to update */ + WAIT_REG32_FIELD(1000, FLEXCOMM_USART, FIFOSTAT, RXLVL, + fifo_size / 2); + + /* check fifo stat */ + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, RXFULL), + ==, 0); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, RXNOTEMPTY), + ==, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, TXNOTFULL), + ==, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, TXEMPTY), + ==, 1); + + /* send until FIFO is full */ + for (int i = fifo_size / 2; i < fifo_size; i++) { + byte = 'A' + i; + g_assert_cmpuint(qio_channel_write(t->ioc, &byte, 1, &error_abort), + ==, 1); + } + + /* wait for the RXLVL to update */ + WAIT_REG32_FIELD(1000, FLEXCOMM_USART, FIFOSTAT, RXLVL, fifo_size); + + /* check fifo stat */ + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, RXFULL), + ==, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, RXNOTEMPTY), + ==, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, TXNOTFULL), + ==, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, TXEMPTY), + ==, 1); + + /* check read no pop */ + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFORDNOPOP, RXDATA), + ==, 'A'); + + /* now read from the fifo */ + for (int i = 0; i < fifo_size; i++) { + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFORD, RXDATA), + ==, 'A' + i); + } + + /* check fifostat */ + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, RXFULL), ==, 0); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, RXNOTEMPTY), + ==, 0); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, TXNOTFULL), + ==, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, TXEMPTY), + ==, 1); +} + +static void irq_test(gconstpointer user_data) +{ + struct TestState *t = (struct TestState *)user_data; + char buf[256] = { 0, }; + uint32_t tmp; + QDict *resp; + + resp = qmp("{\"execute\": \"system_reset\"}"); + qdict_unref(resp); + + qtest_irq_intercept_out_named(t->qtest, DEVICE_NAME, + SYSBUS_DEVICE_GPIO_IRQ); + + /* select and lock FLEXCOMM_USART */ + tmp = FIELD_DP32(FLEXCOMM_PERSEL_USART, FLEXCOMM_PSELID, LOCK, 1); + REG32_WRITE(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(FLEXCOMM_USART, FIFOTRIG, RXLVL, 3); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOTRIG, RXLVL), + ==, 3); + + /* enable RX trigger for IRQ/DMA */ + REG32_WRITE_FIELD(FLEXCOMM_USART, FIFOTRIG, RXLVLENA, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOTRIG, RXLVLENA), + ==, 1); + + /* enable RXLVL interrupt */ + REG32_WRITE_FIELD(FLEXCOMM_USART, FIFOINTENSET, RXLVL, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOINTENSET, RXLVL), + ==, 1); + + /* enable FLEXCOMM_USART */ + REG32_WRITE_FIELD(FLEXCOMM_USART, CFG, ENABLE, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, CFG, ENABLE), + ==, 1); + + /* enable TX and RX FIFO */ + REG32_WRITE_FIELD(FLEXCOMM_USART, FIFOCFG, ENABLETX, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOCFG, ENABLETX), + ==, 1); + REG32_WRITE_FIELD(FLEXCOMM_USART, FIFOCFG, ENABLERX, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOCFG, ENABLERX), + ==, 1); + + /* check interrupt status */ + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOINTSTAT, RXLVL), + ==, 0); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOINTSTAT, TXLVL), + ==, 0); + g_assert_false(get_irq(0)); + + /* enable TX trigger for IRQ/DMA */ + REG32_WRITE_FIELD(FLEXCOMM_USART, FIFOTRIG, TXLVLENA, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOTRIG, TXLVLENA), + ==, 1); + + /* enable irq for TX */ + REG32_WRITE_FIELD(FLEXCOMM_USART, FIFOINTENSET, TXLVL, 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOINTENSET, TXLVL), + ==, 1); + + /* check TX irq */ + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOINTSTAT, TXLVL), + ==, 1); + g_assert_true(get_irq(0)); + + /* disable irq for TX */ + REG32_WRITE_FIELD(FLEXCOMM_USART, FIFOTRIG, TXLVLENA, 0); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOTRIG, TXLVLENA), + ==, 0); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOINTSTAT, TXLVL), + ==, 0); + g_assert_false(get_irq(0)); + + /* send 3 bytes */ + g_assert_cmpuint(qio_channel_write(t->ioc, buf, 3, &error_abort), + ==, 3); + + /* check that we have 3 bytes in the fifo */ + WAIT_REG32_FIELD(1000, FLEXCOMM_USART, FIFOSTAT, RXLVL, 3); + + /* and no interrupt has been triggered yet */ + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOINTSTAT, RXLVL), + ==, 0); + g_assert_false(get_irq(0)); + + /* push it over the edge */ + g_assert_cmpuint(qio_channel_write(t->ioc, buf, 1, &error_abort), ==, 1); + + /* check that we have 4 bytes in the fifo */ + WAIT_REG32_FIELD(1000, FLEXCOMM_USART, FIFOSTAT, RXLVL, 4); + + /* and the interrupt has been triggered */ + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOINTSTAT, RXLVL), + ==, 1); + g_assert_true(get_irq(0)); + + /* read one byte from the fifo */ + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFORD, RXDATA), + ==, 0); + + /* we should have 3 bytes in the FIFO */ + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOSTAT, RXLVL), + ==, 3); + + /* and no interrupts active */ + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_USART, FIFOINTSTAT, RXLVL), + ==, 0); + g_assert_false(get_irq(0)); +} + +static void close_ioc(void *ioc) +{ + qio_channel_close(ioc, NULL); +} + +int main(int argc, char **argv) +{ + int ret; + struct TestState test; + char *tmp_path = g_dir_make_tmp("qemu-flexcomm-usart-test.XXXXXX", NULL); + SocketAddress addr = { + .type = SOCKET_ADDRESS_TYPE_UNIX, + .u.q_unix.path = g_build_filename(tmp_path, "sock", NULL), + }; + char *args; + QIOChannelSocket *lioc; + + module_call_init(MODULE_INIT_QOM); + g_test_init(&argc, &argv, NULL); + + lioc = qio_channel_socket_new(); + qio_channel_socket_listen_sync(lioc, &addr, 1, &error_abort); + + qtest_add_data_func("/flexcomm-usart/polling", &test, polling_test); + qtest_add_data_func("/flexcomm-usart/irq", &test, irq_test); + + args = g_strdup_printf("-M rt595-evk " + "-chardev socket,id=flexcomm0-usart,path=%s", + addr.u.q_unix.path); + test.qtest = qtest_start(args); + + qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN); + test.ioc = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort)); + g_assert(test.ioc); + qtest_add_abrt_handler(close_ioc, test.ioc); + + ret = g_test_run(); + + qtest_end(); + + qtest_remove_abrt_handler(test.ioc); + g_unlink(addr.u.q_unix.path); + g_free(addr.u.q_unix.path); + g_rmdir(tmp_path); + g_free(tmp_path); + g_free(args); + object_unref(OBJECT(test.ioc)); + object_unref(OBJECT(lioc)); + + return ret; +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index f35bb52aa2..c7a5bb61e9 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -233,7 +233,7 @@ qtests_arm = \ (config_all_devices.has_key('CONFIG_FSI_APB2OPB_ASPEED') ? ['aspeed_fsi-test'] : []) + \ (config_all_devices.has_key('CONFIG_STM32L4X5_SOC') and config_all_devices.has_key('CONFIG_DM163')? ['dm163-test'] : []) + \ - (config_all_devices.has_key('CONFIG_FLEXCOMM')? ['flexcomm-test'] : []) + \ + (config_all_devices.has_key('CONFIG_FLEXCOMM') ? ['flexcomm-test', 'flexcomm-usart-test'] : []) + \ ['arm-cpu-features', 'boot-serial-test'] @@ -350,6 +350,7 @@ qtests = { 'virtio-net-failover': files('migration-helpers.c'), 'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'), 'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'), + 'flexcomm-usart-test': [io], } if vnc.found() From patchwork Tue Oct 8 01:18:45 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993906 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=p8iTvODx; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMyvZ3sJ0z1xth for ; Tue, 8 Oct 2024 12:23:22 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxyuE-0005Ac-HH; Mon, 07 Oct 2024 21:20: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 <3oIgEZwUKCgMwdylsjrrjoh.frpthpx-ghyhoqrqjqx.ruj@flex--tavip.bounces.google.com>) id 1sxysy-0008Co-3e for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:36 -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 <3oIgEZwUKCgMwdylsjrrjoh.frpthpx-ghyhoqrqjqx.ruj@flex--tavip.bounces.google.com>) id 1sxysv-0000Da-8r for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:35 -0400 Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-6e2270a147aso75604587b3.0 for ; Mon, 07 Oct 2024 18:19:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350369; x=1728955169; 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=nCq9fs8MJ+mFnJecQKMchHHydT4SahSTnFv0Noo9rMg=; b=p8iTvODxXhY3EuP2vWuOgIN8T9ZfHG8xPTdYuYj8qiiKd+ua3Lrp4CMOkaZsVYZvCY G/M74SrW5rBZND41lCygiPQVEVEiPv/ERz4QISklBjuDOL7J5Yk5gt5uMR/kj2HXffv4 SLLetMgjy6iXCClodZ9fcdLrRWDuxKsa/NsxKLXPutUOBbFUfXZbyMHswxsf0nGhGIAw wtKk+UrlSQjRVa5+n0o+ajawpxBSNdvh8AWk0h3Cv1AYNGxTx+uoLUL2EmcRn01VS4fo YgAT03tdHW0QhLtfWd8GpGrTqBJBwhWCbDl+PQE8XNt/5JqGDMrKSdwp9WgKQ+QFxHqv wumQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350369; x=1728955169; 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=nCq9fs8MJ+mFnJecQKMchHHydT4SahSTnFv0Noo9rMg=; b=Qy/g/0ztU4ZYCJcvSSCHHbsiiH3TDmO4xHgeztpF39esCkMXH/KNyga29D0Ug24bR8 XPQh9i4svMGJpX6QADvHiMHGOslu3Uut4AinrFI1M+d/CFxD4BcC6DMiU0A1H3cIGqZq pU1VJtG7VIaWXkP4ZeSzKkCdl0A649V5zFbORxOh0K13v5QaTMNNe8FEfryXd6J0p6z9 6jwVwIIzWF06N74VEBrrvBYRHAkCIxAZ1ki7Aimmg0UReUSqUR+GCQI66TKshW6Y+rfW SOLouC6n4yrggLrmd1QqMHTuTKSy1HqxVvbRYLh7yNYj5HRW1pusg2wHLn9yxh+5njnt kfIA== X-Gm-Message-State: AOJu0YzutnqIMEcyJJW3d6PHx/49Iajvcbo6+FCA9b86LrIwgP6O2V3T SKJ81G9pkHXXuuCzg11vaBUGaQ2Cr0LP4iAdQgOY0/kbSScz7ZXw+rT1kl8pRulYJ/3gQ4hapyz vkr4X0fo+YvZHAmX1SyyU5qNvHV01Q53mjW5jtfarXFcqZ/4eL+di8mxxMYUC32noTwHQdS/eoQ 6vV6otTwmC3G+H7LOXuET5fs2TYw== X-Google-Smtp-Source: AGHT+IFUmkLVVZH+vWL0zyz0TcYFmOI86jHuXPIUgCaHGoy2/OH/FDqpkkmIBwci5b1oJCfJzaV6kvhkUQ== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:6902:4a8:b0:e28:e4a7:3206 with SMTP id 3f1490d57ef6-e28e4a732e6mr15578276.8.1728350368601; Mon, 07 Oct 2024 18:19:28 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:45 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-20-tavip@google.com> Subject: [PATCH v2 19/25] hw/misc: add i2c-tester From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::114a; envelope-from=3oIgEZwUKCgMwdylsjrrjoh.frpthpx-ghyhoqrqjqx.ruj@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.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 --- include/hw/misc/i2c_tester.h | 43 ++++++++++++++ hw/misc/i2c_tester.c | 109 +++++++++++++++++++++++++++++++++++ hw/misc/Kconfig | 5 ++ hw/misc/meson.build | 2 + 4 files changed, 159 insertions(+) create mode 100644 include/hw/misc/i2c_tester.h create mode 100644 hw/misc/i2c_tester.c diff --git a/include/hw/misc/i2c_tester.h b/include/hw/misc/i2c_tester.h new file mode 100644 index 0000000000..f8292fc219 --- /dev/null +++ b/include/hw/misc/i2c_tester.h @@ -0,0 +1,43 @@ +/* + * Simple I2C peripheral for testing I2C device models. + * + * At the moment of introducing this not all of the functionality can be tested + * with an existing QEMU peripheral device, notably error paths such as when a + * peripheral device responds with an I2C_NACK during a transaction. + * + * It also provides a place where new future functionality can be added to help + * with more kinds of tests rather than trying to hack it in a real device where + * it might not even be possible. + * + * The peripheral allows reading and writing to a fixed number of registers. + * The first transmitted byte in a transaction sets the index register. Note + * that the index register is not auto-incremented on neither reads nor writes. + * + * 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_I2C_TESTER_H +#define HW_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 /* HW_I2C_TESTER_H */ diff --git a/hw/misc/i2c_tester.c b/hw/misc/i2c_tester.c new file mode 100644 index 0000000000..77ce8bf91a --- /dev/null +++ b/hw/misc/i2c_tester.c @@ -0,0 +1,109 @@ +/* + * 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 "hw/misc/i2c_tester.h" + +#include "qemu/log.h" +#include "qemu/module.h" +#include "migration/vmstate.h" + +static void i2c_tester_reset_enter(Object *o, ResetType type) +{ + I2cTesterState *s = I2C_TESTER(o); + + 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 const VMStateDescription vmstate_i2c_tester = { + .name = "i2c-tester", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_I2C_SLAVE(i2c, I2cTesterState), + VMSTATE_BOOL(set_reg_idx, I2cTesterState), + VMSTATE_UINT8(reg_idx, I2cTesterState), + VMSTATE_UINT8_ARRAY(regs, I2cTesterState, I2C_TESTER_NUM_REGS), + VMSTATE_END_OF_LIST() + } +}; + +static void i2c_tester_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); + I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc); + + rc->phases.enter = i2c_tester_reset_enter; + dc->vmsd = &vmstate_i2c_tester; + isc->event = i2c_tester_event; + isc->recv = i2c_tester_rx; + isc->send = i2c_tester_tx; +} + +static const TypeInfo i2c_tester_types[] = { + { + .name = TYPE_I2C_TESTER, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(I2cTesterState), + .class_init = i2c_tester_class_init + }, +}; + +DEFINE_TYPES(i2c_tester_types); diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 4b688aead2..3e93c12c8e 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -213,6 +213,11 @@ config IOSB config XLNX_VERSAL_TRNG bool +config I2C_TESTER + bool + default y if TEST_DEVICES + depends on I2C + config FLEXCOMM bool select I2C diff --git a/hw/misc/meson.build b/hw/misc/meson.build index bf0988fd43..cd29db37d7 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -152,6 +152,8 @@ 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_I2C_TESTER', if_true: files('i2c_tester.c')) + system_ss.add(when: 'CONFIG_FLEXCOMM', if_true: files('flexcomm.c')) system_ss.add(when: 'CONFIG_RT500_CLKCTL', if_true: files('rt500_clkctl0.c', 'rt500_clkctl1.c')) system_ss.add(when: 'CONFIG_RT500_RSTCTL', if_true: files('rt500_rstctl.c')) From patchwork Tue Oct 8 01:18:46 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993926 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=P6q/CdY2; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMyyD2Cw5z1xsv for ; Tue, 8 Oct 2024 12:25:40 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxyuK-0005iY-Qx; Mon, 07 Oct 2024 21:21:01 -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 <3oogEZwUKCgUyf0nulttlqj.htrvjrz-ij0jqstslsz.twl@flex--tavip.bounces.google.com>) id 1sxysz-0008OB-KP for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:38 -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 <3oogEZwUKCgUyf0nulttlqj.htrvjrz-ij0jqstslsz.twl@flex--tavip.bounces.google.com>) id 1sxysx-0000EB-9V for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:37 -0400 Received: by mail-yb1-xb49.google.com with SMTP id 3f1490d57ef6-e2605ce4276so8766179276.3 for ; Mon, 07 Oct 2024 18:19:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350371; x=1728955171; 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=1slVDOqEB8KWMUfUEIu1Co2wfDTjYSlNZhTPxBm4iBk=; b=P6q/CdY2awtYAOESYIzSPypj0ywt66EHkHcaQ4Ik6RCVsKPZcpdlagLWu2EA9E/qkx kPWPqSogwcG9NFEjbOqhckGS1WXgG4qdQZV3eYnDauQ+RPyljgHmdVxAMjRNLQNJBbUA aszKSpEEukX6Dm5Ymm9yRK38GfC37D7TcY3FKag2cz4S/ofkK52wuluJ0tyoPjcU7nz0 i0AlFclQ5h5Fn5O72lJD3R19/Y3QAJA30KydLPUrajKiOrfvG5GIcPJexaApoW5Cq8nN q4uelEFGtVW9X/of+XOu6LU1/DAY32WDfJlOh1zTeAdX+ZU4qHYSWxvudHq3pSfc9K79 oWyw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350371; x=1728955171; 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=1slVDOqEB8KWMUfUEIu1Co2wfDTjYSlNZhTPxBm4iBk=; b=RQMW/EScZxu+RZ37/31blft+ehXqqrR3H5n6Pr9htV9w67Yjj2D+i33Xymjd/HHUfs 7BqbuKKjz3U5rchTTBEonGTPZxieHhUil+AqheW7iQaxbY+Gvb7Dkh4it9cs909ZCP1T 9CZ5+XyiR4AmccVJbap3cCJeL60MvcAz0potETMRoel4WjMVJ5aTmh4QhWxSQ+w6ZEjw HGVIQlGCOUTKr+FH2GGSHSpbEF9xkDtbfYvthymZPPtIvPuYRx801zp7x3255F7L1W42 h2J0CFBsgFWgYIDEJ9cO797WKvPKp1nqhLYcCD9hJJIujUsufTBMEprnmNJ7UFrfEBCs pJ1g== X-Gm-Message-State: AOJu0YxCqNnRn0S9tNB5loauc5rb8Y6wOIfZkgn1lIq7b8vu6IUpty1B yYJYyhVquGkuE277DsnlrWJopyDEbllLsY3Z09XBXMDsiCpcBRbIvnyJ/gb6Fc1F4fkq3OYxM7M HwWp5qQiXjwoWrI0xar+rgdIiLqHEwSJeMYi1ZGJxIEV2IHpk7qxNID3S1hqT4FDgfycH21RKmn /1oaCjOq2I37EnrCaV8GLGV3gAKA== X-Google-Smtp-Source: AGHT+IHxB5sCWH5nkCL2OyLmSweayfDOeEQuNrJr5rUOJUR090O0aNAKrhs0d0x92rZnK79q0Qx+PG1vCw== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a5b:388:0:b0:e20:2502:be14 with SMTP id 3f1490d57ef6-e289391f4abmr10789276.7.1728350370295; Mon, 07 Oct 2024 18:19:30 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:46 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-21-tavip@google.com> Subject: [PATCH v2 20/25] tests/qtest: add tests for flexcomm i2c From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::b49; envelope-from=3oogEZwUKCgUyf0nulttlqj.htrvjrz-ij0jqstslsz.twl@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add master mode tests for flexcomm i2c. Signed-off-by: Octavian Purdila --- tests/qtest/flexcomm-i2c-test.c | 170 ++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 2 +- 2 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 tests/qtest/flexcomm-i2c-test.c diff --git a/tests/qtest/flexcomm-i2c-test.c b/tests/qtest/flexcomm-i2c-test.c new file mode 100644 index 0000000000..45f31da7de --- /dev/null +++ b/tests/qtest/flexcomm-i2c-test.c @@ -0,0 +1,170 @@ +/* + * 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 "hw/arm/svd/flexcomm_i2c.h" +#include "hw/arm/svd/rt500.h" +#include "hw/misc/i2c_tester.h" +#include "reg-utils.h" + +#define PERIPH_ADDR (0x50) +#define INVALID_ADDR (0x10) + +#define REG_ADDR 11 +#define REG_VALUE 0xAA + +#define FLEXCOMM_BASE RT500_FLEXCOMM0_BASE +#define FLEXCOMM_I2C_BASE RT500_FLEXCOMM0_BASE +#define DEVICE_NAME "/machine/soc/flexcomm0" + +struct TestState { + QTestState *qtest; +}; + +static void master_test(gconstpointer user_data) +{ + struct TestState *t = (struct TestState *)user_data; + uint32_t tmp; + + qtest_irq_intercept_out_named(t->qtest, DEVICE_NAME, + SYSBUS_DEVICE_GPIO_IRQ); + + /* Select and lock I2C */ + tmp = FLEXCOMM_PERSEL_I2C; + FIELD_DP32(tmp, FLEXCOMM_PSELID, LOCK, 1); + REG32_WRITE(FLEXCOMM, PSELID, tmp); + + /* Enable master mode */ + REG32_WRITE_FIELD(FLEXCOMM_I2C, CFG, MSTEN, 1); + g_assert(REG32_READ_FIELD(FLEXCOMM_I2C, CFG, MSTEN) == 1); + + g_assert(REG32_READ_FIELD(FLEXCOMM_I2C, STAT, MSTPENDING) == 1); + g_assert(REG32_READ_FIELD(FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_IDLE); + + /* Enable interrupts */ + REG32_WRITE_FIELD(FLEXCOMM_I2C, INTENSET, MSTPENDINGEN, 1); + g_assert_true(get_irq(0)); + + /* start for invalid address */ + REG32_WRITE(FLEXCOMM_I2C, MSTDAT, INVALID_ADDR); + REG32_WRITE_FIELD_NOUPDATE(FLEXCOMM_I2C, MSTCTL, MSTSTART, 1); + g_assert(REG32_READ_FIELD(FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_NAKADR); + g_assert_true(get_irq(0)); + REG32_WRITE_FIELD_NOUPDATE(FLEXCOMM_I2C, MSTCTL, MSTSTOP, 1); + + /* write past the last register */ + REG32_WRITE_FIELD(FLEXCOMM_I2C, MSTDAT, DATA, PERIPH_ADDR); + REG32_WRITE_FIELD_NOUPDATE(FLEXCOMM_I2C, MSTCTL, MSTSTART, 1); + g_assert_true(get_irq(0)); + g_assert(REG32_READ_FIELD(FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_TXRDY); + REG32_WRITE_FIELD(FLEXCOMM_I2C, MSTDAT, DATA, I2C_TESTER_NUM_REGS + 10); + REG32_WRITE_FIELD_NOUPDATE(FLEXCOMM_I2C, MSTCTL, MSTCONTINUE, 1); + g_assert_true(get_irq(0)); + g_assert(REG32_READ_FIELD(FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_TXRDY); + REG32_WRITE_FIELD_NOUPDATE(FLEXCOMM_I2C, MSTCTL, MSTCONTINUE, 1); + g_assert_true(get_irq(0)); + g_assert(REG32_READ_FIELD(FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_NAKDAT); + REG32_WRITE_FIELD_NOUPDATE(FLEXCOMM_I2C, MSTCTL, MSTSTOP, 1); + + /* write value to register */ + REG32_WRITE_FIELD(FLEXCOMM_I2C, MSTDAT, DATA, PERIPH_ADDR); + REG32_WRITE_FIELD_NOUPDATE(FLEXCOMM_I2C, MSTCTL, MSTSTART, 1); + g_assert_true(get_irq(0)); + g_assert(REG32_READ_FIELD(FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_TXRDY); + REG32_WRITE_FIELD(FLEXCOMM_I2C, MSTDAT, DATA, REG_ADDR); + REG32_WRITE_FIELD_NOUPDATE(FLEXCOMM_I2C, MSTCTL, MSTCONTINUE, 1); + g_assert_true(get_irq(0)); + g_assert(REG32_READ_FIELD(FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_TXRDY); + REG32_WRITE_FIELD(FLEXCOMM_I2C, MSTDAT, DATA, REG_VALUE); + REG32_WRITE_FIELD_NOUPDATE(FLEXCOMM_I2C, MSTCTL, MSTCONTINUE, 1); + g_assert_true(get_irq(0)); + g_assert(REG32_READ_FIELD(FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_TXRDY); + REG32_WRITE_FIELD_NOUPDATE(FLEXCOMM_I2C, MSTCTL, MSTSTOP, 1); + g_assert_true(get_irq(0)); + g_assert(REG32_READ_FIELD(FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_IDLE); + + /* read value back from register */ + REG32_WRITE_FIELD(FLEXCOMM_I2C, MSTDAT, DATA, PERIPH_ADDR); + REG32_WRITE_FIELD_NOUPDATE(FLEXCOMM_I2C, MSTCTL, MSTSTART, 1); + g_assert_true(get_irq(0)); + g_assert(REG32_READ_FIELD(FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_TXRDY); + REG32_WRITE_FIELD(FLEXCOMM_I2C, MSTDAT, DATA, REG_ADDR); + REG32_WRITE_FIELD_NOUPDATE(FLEXCOMM_I2C, MSTCTL, MSTCONTINUE, 1); + g_assert_true(get_irq(0)); + g_assert(REG32_READ_FIELD(FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_TXRDY); + REG32_WRITE_FIELD(FLEXCOMM_I2C, MSTDAT, DATA, (PERIPH_ADDR + 1)); + REG32_WRITE_FIELD_NOUPDATE(FLEXCOMM_I2C, MSTCTL, MSTSTART, 1); + g_assert_true(get_irq(0)); + g_assert(REG32_READ_FIELD(FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_RXRDY); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_I2C, MSTDAT, DATA), ==, + REG_VALUE); + REG32_WRITE_FIELD_NOUPDATE(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(FLEXCOMM_I2C, MSTDAT, DATA, INVALID_ADDR); + REG32_WRITE_FIELD_NOUPDATE(FLEXCOMM_I2C, MSTCTL, MSTSTART, 1); + + g_assert(REG32_READ_FIELD(FLEXCOMM_I2C, STAT, MSTSTATE) == + MSTSTATE_NAKADR); + g_assert_true(get_irq(0)); + REG32_WRITE_FIELD_NOUPDATE(FLEXCOMM_I2C, MSTCTL, MSTSTOP, 1); + + /* Disable interrupts */ + REG32_WRITE_FIELD(FLEXCOMM_I2C, INTENCLR, MSTPENDINGCLR, 1); + g_assert_false(get_irq(0)); +} + +int main(int argc, char **argv) +{ + int ret; + struct TestState test; + + module_call_init(MODULE_INIT_QOM); + g_test_init(&argc, &argv, NULL); + + qtest_add_data_func("/flexcomm-i2c/master", &test, master_test); + + test.qtest = qtest_start("-M rt595-evk " + "-device i2c-tester,address=0x50,bus=/flexcomm0-i2c"); + ret = g_test_run(); + qtest_end(); + + return ret; +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index c7a5bb61e9..c21b18c304 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -233,7 +233,7 @@ qtests_arm = \ (config_all_devices.has_key('CONFIG_FSI_APB2OPB_ASPEED') ? ['aspeed_fsi-test'] : []) + \ (config_all_devices.has_key('CONFIG_STM32L4X5_SOC') and config_all_devices.has_key('CONFIG_DM163')? ['dm163-test'] : []) + \ - (config_all_devices.has_key('CONFIG_FLEXCOMM') ? ['flexcomm-test', 'flexcomm-usart-test'] : []) + \ + (config_all_devices.has_key('CONFIG_FLEXCOMM') ? ['flexcomm-test', 'flexcomm-usart-test', 'flexcomm-i2c-test'] : []) + \ ['arm-cpu-features', 'boot-serial-test'] From patchwork Tue Oct 8 01:18:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993898 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=X0SQlrhA; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMysN2mqvz1xth for ; Tue, 8 Oct 2024 12:21:28 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxyug-00073b-1g; Mon, 07 Oct 2024 21:21:22 -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 <3pIgEZwUKCgc0h2pwnvvnsl.jvtxlt1-kl2lsuvunu1.vyn@flex--tavip.bounces.google.com>) id 1sxysy-0008JJ-Py for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:36 -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 <3pIgEZwUKCgc0h2pwnvvnsl.jvtxlt1-kl2lsuvunu1.vyn@flex--tavip.bounces.google.com>) id 1sxysx-0000EV-9b for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:36 -0400 Received: by mail-yb1-xb49.google.com with SMTP id 3f1490d57ef6-e0b8fa94718so7692684276.0 for ; Mon, 07 Oct 2024 18:19:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350372; x=1728955172; 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=1mTGypMKoK88/Cq8OZic1Nsr2IiKXj3+YmHX8y0r+W0=; b=X0SQlrhAI/Nu+zoWl5WzXxCALs4PbN01LsaFsGHJIVaxsj8Ua/zm1l+t5bwOQgS7j1 cRqjdBe/Y4RHO4Lg6/XKR+vzt6A4gNqUP+FqeEwUK//t8QCIQVvV1NcCWza6MmLZ+XJZ BpbIk6IzZkTjerZI7Km5A/A6rWf5YlOnmZ4DsrwptZGspIS2qU1FlwE/Mg++OTyQjfg5 WuCaoyC8w7eC2sxG9A0H6w+ZAH5zYNlzghfXMBKeUZggDI1v0OGP7/Zuma60ORNyrBs1 OS+kO18UhDO/u9orvlqm8LeY7NyRA9TGhNrD8NtaFcryB2vln6XwU2XPoNjLO85UrBVq nrKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350372; x=1728955172; 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=1mTGypMKoK88/Cq8OZic1Nsr2IiKXj3+YmHX8y0r+W0=; b=O2D2/Ajqlge1+Famdvn44oba72mHHuLHMMmXdNP6jNYZhc+wAU9cNF6TCbKlfN7kUW VlIhdVnGIjioJXzFq1HuE6TLOW+fhg1zU7uApTTX/JuX0reX75pcRmsti7m8SE+eamR5 L+jxAOJubBNLfDgf9d3Cn/3xxM6VpVY8sYjsnGBYHFKbQhCJiJImW4LhzvcugPDHGsfM UI2qY/D5meLA9KlzVtYREIplPTVKIfRe8+7zpXJGZqbtk0OuYSVRwvin6z/glKED4fc9 XVPH9wkfQh/PU+8g+QcP8QFSv+bYqhfnPEdRkFH6neTe7j3uJtfRyI3ViRERk4CGC7qT uo8A== X-Gm-Message-State: AOJu0YzC8Q5MzVSVEOIF4zp9ryOUJ0gxhGuCB5te3MGWb4udg/XoFWHU j81/Q7TvK1ETdSqvakS5PtDRkD2v2Ltg0KjpGUYflNfYmea5WgeAjMWnxRHZSg5znIA/eND03tJ E7+YBmZMDkzb8HC8V8IXw1+x3P0W4MGO4/wFuDbhiZKF99PfmSqaEmMI44yiHGjLdu0/cRi1bEv iVsOpTujFs6fZidJ1zgSy6XTdC5Q== X-Google-Smtp-Source: AGHT+IF/ARdhONsx0FgU3D7YbNyHJC6S0I67yHm7MDoA26Xb/wKvXX1888vusp101w+M9RfBvBAteQE5BQ== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a25:dc01:0:b0:e25:fcb:3205 with SMTP id 3f1490d57ef6-e289394d93cmr58923276.8.1728350372143; Mon, 07 Oct 2024 18:19:32 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:47 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-22-tavip@google.com> Subject: [PATCH v2 21/25] hw/ssi: allow NULL realize callbacks for peripherals From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::b49; envelope-from=3pIgEZwUKCgc0h2pwnvvnsl.jvtxlt1-kl2lsuvunu1.vyn@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Signed-off-by: Octavian Purdila --- hw/ssi/ssi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index 3f357e8f16..d1f3ce7c22 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -105,7 +105,9 @@ static void ssi_peripheral_realize(DeviceState *dev, Error **errp) } s->spc = ssc; - ssc->realize(s, errp); + if (ssc->realize) { + ssc->realize(s, errp); + } } static Property ssi_peripheral_properties[] = { From patchwork Tue Oct 8 01:18:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993910 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=F3C+IC6e; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMywG2VL6z1xvB for ; Tue, 8 Oct 2024 12:23:58 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxyuP-0006Mi-3e; Mon, 07 Oct 2024 21:21:05 -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 <3pYgEZwUKCgg1i3qxowwotm.kwuymu2-lm3mtvwvov2.wzo@flex--tavip.bounces.google.com>) id 1sxyt1-0008WK-H9 for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:39 -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 <3pYgEZwUKCgg1i3qxowwotm.kwuymu2-lm3mtvwvov2.wzo@flex--tavip.bounces.google.com>) id 1sxysz-0000Fg-SG for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:39 -0400 Received: by mail-pg1-x54a.google.com with SMTP id 41be03b00d2f7-7e9a3e3ec4fso3887702a12.2 for ; Mon, 07 Oct 2024 18:19:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350376; x=1728955176; 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=YKQ9trFugufZOwGY7NmDfogxKbP5q2hRcs5m3sq43O4=; b=F3C+IC6eC4epdm1kGJmbzRUBQVciVWYyA6WR++rji0yQXHhKvTj8/YBSgjztwcIfm1 xIIsNyU50ibZzVecbd4jPj4RXIdVWQXe8A0ouXkbWVvDxoI6dP8kYjF5HaVd2bMiY43I O+y+XApvJMW3iCZ9XmhfHFrlySewGLHT4NQ6z+TXkZrtjZ/beakGCvKYgCBYsjcSm2Fo 3wzesY3r5pavjGusJMRONqs8RevX99bWte05zFSWdB9takPn1q16Ys1fbrC8GxTRzxsM I/ckidQqFPOn5DH7KxCqXwKXx/kHoZ2XDjOvVKZiwLsVZfAEDpGZa1x9wA1iTp/cYhTy FKGg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350376; x=1728955176; 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=YKQ9trFugufZOwGY7NmDfogxKbP5q2hRcs5m3sq43O4=; b=Qh0vw1tZROxgVlD5uY5tUqG9NdnvH+ovBoeDACBMo9tzCeVjBfuQC5ITntXa5RKe14 2TqIBwSRlafcx99MhJQR3/P+n3gEIN6VtvA/iFFp3+cprp8MeXZi/UI9MLQilBOrGC35 ONSCdxUX/VrhOtlpP6YExucE77ScgKg72H8LppbaclUvgv8fMMXT6yYbTeytMwAyqXCI s1nOXD+ShbtWaEvjHo6wXm/b7vG2IbqGiKj4K2Zo3ViVikK2rGrLKoF8XppEcmfWFzoT xwGoJIU5DXBTY55wOa2h+xZvDvW5R5vYeJmGA1gpDAQullcVuob0yLISyGX8j0rCqxbC sIgg== X-Gm-Message-State: AOJu0YyDWlC7OtiU1+GXckA9GwQSDNSldUC84IDNMPSPKfndgeYEv8xF SHVAkkDnh2RdT/hh4RVKIHKt/veE0KG6eQ311tcIN0+6moLUBeO44cT5ajWlVUP7PWLroqr/WIT a1MjFjxcB4YvMrQn91EsdvuQDbwWYTdIita/xYoQIZLAJmzTy4rzMjqMmfnNEdikrH4Xf6MD52B +AAHktWwFIQtGmmNVm7igKitlE/A== X-Google-Smtp-Source: AGHT+IHwubTVu63fd9TNbX+TuT3dtVb6xAFFJn5bPr3LB3psw+utH20gvzpptkphd+9FIomlKJBYbnH7kQ== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a17:90a:8a8c:b0:2c9:7616:dec5 with SMTP id 98e67ed59e1d1-2e1e620b95fmr18689a91.2.1728350373992; Mon, 07 Oct 2024 18:19:33 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:48 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-23-tavip@google.com> Subject: [PATCH v2 22/25] hw/misc: add spi-tester From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::54a; envelope-from=3pYgEZwUKCgg1i3qxowwotm.kwuymu2-lm3mtvwvov2.wzo@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add a simple SPI peripheral that echoes back received data. Useful for testing SPI controllers. Signed-off-by: Octavian Purdila --- include/hw/misc/spi_tester.h | 32 +++++++++++++++++ hw/misc/spi_tester.c | 67 ++++++++++++++++++++++++++++++++++++ hw/misc/Kconfig | 5 +++ hw/misc/meson.build | 1 + 4 files changed, 105 insertions(+) create mode 100644 include/hw/misc/spi_tester.h create mode 100644 hw/misc/spi_tester.c diff --git a/include/hw/misc/spi_tester.h b/include/hw/misc/spi_tester.h new file mode 100644 index 0000000000..8935f3f1af --- /dev/null +++ b/include/hw/misc/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 HW_SPI_TESTER_H +#define HW_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 /* HW_SPI_TESTER_H */ diff --git a/hw/misc/spi_tester.c b/hw/misc/spi_tester.c new file mode 100644 index 0000000000..2793ce52dc --- /dev/null +++ b/hw/misc/spi_tester.c @@ -0,0 +1,67 @@ +/* + * 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 "qemu/osdep.h" +#include "migration/vmstate.h" +#include "hw/misc/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 int spi_tester_set_cs(SSIPeripheral *dev, bool select) +{ + SpiTesterState *s = SPI_TESTER(dev); + + s->cs = select; + + return 0; +} + +static const VMStateDescription vmstate_spi_tester = { + .name = "spi-tester", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_SSI_PERIPHERAL(ssidev, SpiTesterState), + VMSTATE_BOOL(cs, SpiTesterState), + VMSTATE_END_OF_LIST() + } +}; + +static void spi_tester_class_init(ObjectClass *klass, void *data) +{ + SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_spi_tester; + k->transfer = spi_tester_transfer; + k->set_cs = spi_tester_set_cs; + k->cs_polarity = SSI_CS_LOW; +} + +static const TypeInfo spi_tester_types[] = { + { + .name = TYPE_SPI_TESTER, + .parent = TYPE_SSI_PERIPHERAL, + .instance_size = sizeof(SpiTesterState), + .class_init = spi_tester_class_init, + }, +}; + +DEFINE_TYPES(spi_tester_types); diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 3e93c12c8e..484ee3149f 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -218,6 +218,11 @@ config I2C_TESTER default y if TEST_DEVICES depends on I2C +config SPI_TESTER + bool + default y if TEST_DEVICES + depends on SSI + config FLEXCOMM bool select I2C diff --git a/hw/misc/meson.build b/hw/misc/meson.build index cd29db37d7..0cece9a964 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -153,6 +153,7 @@ 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_I2C_TESTER', if_true: files('i2c_tester.c')) +system_ss.add(when: 'CONFIG_SPI_TESTER', if_true: files('spi_tester.c')) system_ss.add(when: 'CONFIG_FLEXCOMM', if_true: files('flexcomm.c')) system_ss.add(when: 'CONFIG_RT500_CLKCTL', if_true: files('rt500_clkctl0.c', 'rt500_clkctl1.c')) From patchwork Tue Oct 8 01:18:49 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993929 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=mIuqcCO3; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMyyn5cq4z1xsn for ; Tue, 8 Oct 2024 12:26:09 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxyur-00085g-DX; Mon, 07 Oct 2024 21:21: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 <3qIgEZwUKCgs4l6t0rzzrwp.nzx1px5-op6pwyzyry5.z2r@flex--tavip.bounces.google.com>) id 1sxyt5-0000Xn-Ff for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:43 -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 <3qIgEZwUKCgs4l6t0rzzrwp.nzx1px5-op6pwyzyry5.z2r@flex--tavip.bounces.google.com>) id 1sxyt0-0000GH-KG for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:43 -0400 Received: by mail-pf1-x44a.google.com with SMTP id d2e1a72fcca58-7174c6cbdbaso5838164b3a.2 for ; Mon, 07 Oct 2024 18:19:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350377; x=1728955177; 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=6ZAi4gulNhaksWV2hV6e+8oRvcK8JyjNz4xRR0r3KZA=; b=mIuqcCO3I+GMI85RVK4eeZvdlM8e2J0QEjuyj570kUH8/ZzIM/fQtJCi47FaP0nwd5 Anid2Poew2RKM2xa0DwtJOymo3y/djxh6ch9RTkBw1Z3j/PwkiglZR3Taa5kmiNo3QvR w0jKirWPnMlXaMuQJQAfFBw9MFwZ76bLmaWude4SfozqTSvW7Lo6EKMQ/fSGj5QxdZC1 WuF7DFWIk/pFJwI6UOdMcDkONKwDzZBcKnqBfCTYKeMqKpdsu46cVDbD1ElHesW+WKsf e3V8B/+uDe4DxRMJAReYhCwDboOQ78zXauBi9faP6UtyiW6Nyj+QMx1bvBqRZJ40RdI9 BYjw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350377; x=1728955177; 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=6ZAi4gulNhaksWV2hV6e+8oRvcK8JyjNz4xRR0r3KZA=; b=ouUYmeY3Apj6LmciqKADQZGZvD1v2rOtx7J+JtmVMkMwDSTogcGqDkmUF2Zr7NfzGv hPwsp69O8w3BKnySMoPlZh76oP4nFF25A+XqUOLel01TiMEykY8gKestNgaqyjCPfnKm gK8kj7bfTb9E5gWEn0FM90f7fep0fSaxEUqx4tNEXnQy46JojOT6X+rK9PcELG7dUaw3 8MZ4Be3cZ8yTJ9jgIli5xfyVKvxHunIr0KFvsfo9JperU0+TMoVwUeM6atgAKVbo3/sB QVp97anmWW8hkz1XkyNPMd1qtGcBc9BZgPkkRj1YKe27D81smBMwn2pxffsNs61PbfLz UrqQ== X-Gm-Message-State: AOJu0Yx9kwOnXYJSm1F2LQ+SAb2W29h7BY76wWvsXlhPiOJCHP4efMI6 R0dmRTJ31EkZWGATGX3IVKPItCfCycURl5ZjRUBFxCW9/kRoF+OPLffO+KKLsIiEYNvfBThacj2 Emb5bjXG3LB367OBOGFiDi7w2gqxlwz2n0sYrPCUGDVz7JLqflVED43WgsNAHsg2a+c3cap4yTv 0tJM6WthcaQ+Ejzlhb4//pXzbKRg== X-Google-Smtp-Source: AGHT+IH7/MV6R5ex7R/s8YoXOodTUCEW4seC2LmeSVI6mh5M/35dcwCp5grJHjlS8iaBVFJyIoSE+XHi7g== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:6a00:2cf:b0:71d:f324:bd3e with SMTP id d2e1a72fcca58-71df324be2cmr39081b3a.3.1728350376065; Mon, 07 Oct 2024 18:19:36 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:49 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-24-tavip@google.com> Subject: [PATCH v2 23/25] tests/qtest: add tests for flexcomm spi From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::44a; envelope-from=3qIgEZwUKCgs4l6t0rzzrwp.nzx1px5-op6pwyzyry5.z2r@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Sebastian Ene Add master and loopback tests for flexcomm spi. Signed-off-by: Sebastian Ene [tavip: add master mode test, convert to qtest] Signed-off-by: Octavian Purdila --- tests/qtest/flexcomm-spi-test.c | 145 ++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 2 +- 2 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 tests/qtest/flexcomm-spi-test.c diff --git a/tests/qtest/flexcomm-spi-test.c b/tests/qtest/flexcomm-spi-test.c new file mode 100644 index 0000000000..4658835b8f --- /dev/null +++ b/tests/qtest/flexcomm-spi-test.c @@ -0,0 +1,145 @@ +/* + * 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 "hw/arm/svd/flexcomm_spi.h" +#include "hw/arm/svd/rt500.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 RT500_FLEXCOMM0_BASE +#define FLEXCOMM_SPI_BASE RT500_FLEXCOMM0_BASE +#define DEVICE_NAME "/machine/soc/flexcomm0" + +static void configure_spi(bool master, bool is_loopback_mode) +{ + uint32_t tmp; + + /* Select and lock SPI */ + tmp = FLEXCOMM_PERSEL_SPI; + FIELD_DP32(tmp, FLEXCOMM_PSELID, LOCK, 1); + REG32_WRITE(FLEXCOMM, PSELID, tmp); + + /* Disable the FIFO */ + REG32_WRITE_FIELD(FLEXCOMM_SPI, CFG, ENABLE, 0); + REG32_WRITE_FIELD(FLEXCOMM_SPI, FIFOCFG, ENABLETX, 0); + REG32_WRITE_FIELD(FLEXCOMM_SPI, FIFOCFG, ENABLERX, 0); + + if (is_loopback_mode) { + /* Set up SPI interface - loop mode, master mode */ + REG32_WRITE_FIELD(FLEXCOMM_SPI, CFG, LOOP, 1); + g_assert(REG32_READ_FIELD(FLEXCOMM_SPI, CFG, LOOP) == 1); + } + + if (master) { + REG32_WRITE_FIELD(FLEXCOMM_SPI, CFG, MASTER, 1); + g_assert(REG32_READ_FIELD(FLEXCOMM_SPI, CFG, MASTER) == 1); + } else { + REG32_WRITE_FIELD(FLEXCOMM_SPI, CFG, MASTER, 0); + g_assert(REG32_READ_FIELD(FLEXCOMM_SPI, CFG, MASTER) == 0); + } + + /* Enable the FIFO */ + REG32_WRITE_FIELD(FLEXCOMM_SPI, FIFOCFG, ENABLETX, 1); + REG32_WRITE_FIELD(FLEXCOMM_SPI, FIFOCFG, ENABLERX, 1); + + /* Enable the SPI */ + REG32_WRITE_FIELD(FLEXCOMM_SPI, CFG, ENABLE, 1); + g_assert(REG32_READ_FIELD(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(gconstpointer user_data) +{ + configure_spi(true, true); + + /* Write a sequence */ + for (int i = 0; i < SEQ_LOOPBACK_MODE; i++) { + REG32_WRITE(FLEXCOMM_SPI, FIFOWR, i); + } + + /* Read the sequence back */ + for (int i = 0; i < SEQ_LOOPBACK_MODE; i++) { + g_assert(REG32_READ_FIELD(FLEXCOMM_SPI, FIFORD, RXDATA) == i); + } +} + +static void master_test(gconstpointer user_data) +{ + uint32_t tmp; + + configure_spi(true, false); + + REG32_WRITE_FIELD(FLEXCOMM_SPI, CFG, LSBF, 1); + + /* single 16bit word transfer */ + + tmp = FIELD_DP32(0x1122, FLEXCOMM_SPI_FIFOWR, EOT, 1); + tmp = FIELD_DP32(tmp, FLEXCOMM_SPI_FIFOWR, TXSSEL0_N, 1); + tmp = FIELD_DP32(tmp, FLEXCOMM_SPI_FIFOWR, LEN, 0xF); + REG32_WRITE(FLEXCOMM_SPI, FIFOWR, tmp); + g_assert(REG32_READ_FIELD(FLEXCOMM_SPI, FIFOSTAT, RXNOTEMPTY) == 1); + g_assert_cmpuint(REG32_READ_FIELD(FLEXCOMM_SPI, FIFORD, RXDATA), + ==, 0x1122); + g_assert(REG32_READ_FIELD(FLEXCOMM_SPI, FIFOSTAT, RXNOTEMPTY) == 0); + + /* multi word 8 bits transfer */ + + tmp = FIELD_DP32(0x11, FLEXCOMM_SPI_FIFOWR, TXSSEL0_N, 1); + tmp = FIELD_DP32(tmp, FLEXCOMM_SPI_FIFOWR, LEN, 0x7); + REG32_WRITE(FLEXCOMM_SPI, FIFOWR, tmp); + tmp = 0x22; + FIELD_DP32(tmp, FLEXCOMM_SPI_FIFOWR, EOT, 1); + FIELD_DP32(tmp, FLEXCOMM_SPI_FIFOWR, TXSSEL0_N, 1); + FIELD_DP32(tmp, FLEXCOMM_SPI_FIFOWR, LEN, 0x7); + REG32_WRITE(FLEXCOMM_SPI, FIFOWR, tmp); + g_assert(REG32_READ_FIELD(FLEXCOMM_SPI, FIFOSTAT, RXNOTEMPTY) == 1); + g_assert(REG32_READ_FIELD(FLEXCOMM_SPI, FIFORD, RXDATA) == 0x11); + g_assert(REG32_READ_FIELD(FLEXCOMM_SPI, FIFOSTAT, RXNOTEMPTY) == 1); + g_assert(REG32_READ_FIELD(FLEXCOMM_SPI, FIFORD, RXDATA) == 0x22); + g_assert(REG32_READ_FIELD(FLEXCOMM_SPI, FIFOSTAT, RXNOTEMPTY) == 0); +} + +int main(int argc, char **argv) +{ + int ret; + + module_call_init(MODULE_INIT_QOM); + g_test_init(&argc, &argv, NULL); + + qtest_add_data_func("/flexcomm-spi/loopack", NULL, loopback_test); + qtest_add_data_func("/flexcomm-spi/master", NULL, master_test); + + qtest_start("-M rt595-evk -device spi-tester,bus=/flexcomm0-spi"); + ret = g_test_run(); + qtest_end(); + + return ret; +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index c21b18c304..d3bf33b855 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -233,7 +233,7 @@ qtests_arm = \ (config_all_devices.has_key('CONFIG_FSI_APB2OPB_ASPEED') ? ['aspeed_fsi-test'] : []) + \ (config_all_devices.has_key('CONFIG_STM32L4X5_SOC') and config_all_devices.has_key('CONFIG_DM163')? ['dm163-test'] : []) + \ - (config_all_devices.has_key('CONFIG_FLEXCOMM') ? ['flexcomm-test', 'flexcomm-usart-test', 'flexcomm-i2c-test'] : []) + \ + (config_all_devices.has_key('CONFIG_FLEXCOMM') ? ['flexcomm-test', 'flexcomm-usart-test', 'flexcomm-i2c-test', 'flexcomm-spi-test'] : []) + \ ['arm-cpu-features', 'boot-serial-test'] From patchwork Tue Oct 8 01:18:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993904 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=dRNmDKoq; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMyv12bVFz1xth for ; Tue, 8 Oct 2024 12:22:53 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxyuh-000782-9r; Mon, 07 Oct 2024 21:21:24 -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 <3qYgEZwUKCgw5m7u1s00sxq.o0y2qy6-pq7qxz0zsz6.03s@flex--tavip.bounces.google.com>) id 1sxyt5-0000Vc-49 for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:43 -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 <3qYgEZwUKCgw5m7u1s00sxq.o0y2qy6-pq7qxz0zsz6.03s@flex--tavip.bounces.google.com>) id 1sxyt3-0000Gf-8X for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:42 -0400 Received: by mail-yb1-xb49.google.com with SMTP id 3f1490d57ef6-e2605a8c7e0so7835850276.0 for ; Mon, 07 Oct 2024 18:19:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350378; x=1728955178; 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=4/p/dqyX4FDV19scC8uVsqmc4fVxq0udNnyaIq4QvGw=; b=dRNmDKoqGYJKz8PvcVLvateHdv0/LjTyXs3i9pC5R6VozwdL1isHYoN9bWZCTM0oaa mjsa4doJKgz+6W+zOH8rorErIEKmGYqPtejTxLrYDnDeRnhGYPp1mTxRhg48Vu7bFtak IzkillXatDI/zLTvT2Elgw+4noX0qZ5f9aTEkA3YtktRog7xAvwM4ZuJ341ekUECA2x0 Psi9LtUmhIHJpv3X77x6bCmYgl9Ccd/rS15yLwSifOfXJPusQDndwdUDabaSDCHGHhko 86O54MQ6Uwf/Sj6z0wdK9aMmBp8jE7EFio5q6Q6u6DlaowCJ8z/7Y8L3ZG5BwI/O6ya1 HyWA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350378; x=1728955178; 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=4/p/dqyX4FDV19scC8uVsqmc4fVxq0udNnyaIq4QvGw=; b=HFC6RTlZ9dqTCke8cXZuzeLfOKzjt95i/hwRmcfM0fUWjUFBDOJUUE9EFndMd5f36z 5k8TTMgt6Gk5ONFMjBhoiyoSdv/sMjtQe2KTUo13hSi9NpI2fdrwCyi7XjzdWX9r+tRN sg7TMDchCoyYFfPa8jziG2IHQQ3z0m29aQIfbJ8eRq8c39p1RUrpL8g3dl74RFX6Ued/ ct9lgLHagIjeUmRSj55hxKL3XjeyKzVrB6TmL9ndireL7Eewc5+rKjlRAWNedV+LvCcN Em7rolP7rtu6L0sJ+xyp0WZ3kIrE11tAerNBEUa3BhTHFbFXvEDNZzL2hgVfXj4ngDOZ adYA== X-Gm-Message-State: AOJu0YwnLfnSot5pFwUIsZPxiJCjnxtzaU7FWwvoTXE6yN9pOBRFa+bm k5Ep7SFwrsJQyjWfh38uMpbmWlZHN7OB5TzLMdkfzShcIO1PyUe7ngNVVfR5mOy0GsCuaQ7wBSp EqMW0V78ZgVsr/+epEIHYJyHk+zrZ9fCuLjAcLYqNSFCWLxL8s+4I64Zz7ad8TBfs2TzH+wnz7r 2XaaTfy+wP+np3CQVU4cGPy+IeMA== X-Google-Smtp-Source: AGHT+IEoeuT9lk85qy1pXmXRYWYcENTbtYkdXXuFKfukech2eGzywLrqJOXChcePRGtAMnAtL77NjiAJIQ== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:6902:1786:b0:e25:d202:d376 with SMTP id 3f1490d57ef6-e28be89b1a9mr5368276.6.1728350377903; Mon, 07 Oct 2024 18:19:37 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:50 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-25-tavip@google.com> Subject: [PATCH v2 24/25] systems/qtest: add device clock APIs From: Octavian Purdila To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, stefanst@google.com, pbonzini@redhat.com, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::b49; envelope-from=3qYgEZwUKCgw5m7u1s00sxq.o0y2qy6-pq7qxz0zsz6.03s@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.024, 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, WEIRD_QUOTING=0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add qtest APIs to check the device clock frequency. Signed-off-by: Octavian Purdila --- include/hw/qdev-clock.h | 10 +++++++ tests/qtest/libqtest-single.h | 24 +++++++++++++++++ tests/qtest/libqtest.h | 22 +++++++++++++++ hw/core/qdev-clock.c | 2 +- system/qtest.c | 51 +++++++++++++++++++++++++++++++++++ tests/qtest/libqtest.c | 29 ++++++++++++++++++++ 6 files changed, 137 insertions(+), 1 deletion(-) diff --git a/include/hw/qdev-clock.h b/include/hw/qdev-clock.h index ffa0f7ba09..19ed34ae88 100644 --- a/include/hw/qdev-clock.h +++ b/include/hw/qdev-clock.h @@ -15,6 +15,7 @@ #define QDEV_CLOCK_H #include "hw/clock.h" +#include "hw/qdev-core.h" /** * qdev_init_clock_in: @@ -161,4 +162,13 @@ typedef struct ClockPortInitElem ClockPortInitArray[]; */ void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks); +/** + * qdev_get_clocklist: + * @dev: the device to find clock for + * @name: clock name + * + * Returns: a named clock list entry or NULL if the clock was not found + */ +NamedClockList *qdev_get_clocklist(DeviceState *dev, const char *name); + #endif /* QDEV_CLOCK_H */ diff --git a/tests/qtest/libqtest-single.h b/tests/qtest/libqtest-single.h index c22037c8b2..51eb69ff74 100644 --- a/tests/qtest/libqtest-single.h +++ b/tests/qtest/libqtest-single.h @@ -408,4 +408,28 @@ static inline int64_t clock_step(int64_t step) return qtest_clock_step(global_qtest, step); } +/** + * qtest_qdev_clock_in_get_hz: + * @path: QOM path of a device. + * @name: Clock name. + * + * Returns: device clock frequency in HZ + */ +static inline uint64_t dev_clock_in_get_hz(const char *path, const char *name) +{ + return qtest_dev_clock_in_get_hz(global_qtest, path, name); +} + +/** + * qtest_qdev_clock_out_get_hz: + * @path: QOM path of a device. + * @name: Clock name. + * + * Returns: device clock frequency in HZ + */ +static inline uint64_t dev_clock_out_get_hz(const char *path, const char *name) +{ + return qtest_dev_clock_out_get_hz(global_qtest, path, name); +} + #endif diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h index f9bbeb2e60..cfb7098985 100644 --- a/tests/qtest/libqtest.h +++ b/tests/qtest/libqtest.h @@ -1169,4 +1169,26 @@ bool have_qemu_img(void); */ bool mkimg(const char *file, const char *fmt, unsigned size_mb); +/** + * qtest_qdev_clock_in_get_hz: + * @s: #QTestState instance to operate on. + * @path: QOM path of a device. + * @name: Clock name. + * + * Returns: device clock frequency in HZ + */ +uint64_t qtest_dev_clock_in_get_hz(QTestState *s, const char *path, + const char *name); + +/** + * qtest_qdev_clock_out_get_hz: + * @s: #QTestState instance to operate on. + * @path: QOM path of a device. + * @name: Clock name. + * + * Returns: device clock frequency in HZ + */ +uint64_t qtest_dev_clock_out_get_hz(QTestState *s, const char *path, + const char *name); + #endif diff --git a/hw/core/qdev-clock.c b/hw/core/qdev-clock.c index 82799577f3..3c9e2d5d73 100644 --- a/hw/core/qdev-clock.c +++ b/hw/core/qdev-clock.c @@ -144,7 +144,7 @@ void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks) } } -static NamedClockList *qdev_get_clocklist(DeviceState *dev, const char *name) +NamedClockList *qdev_get_clocklist(DeviceState *dev, const char *name) { NamedClockList *ncl; diff --git a/system/qtest.c b/system/qtest.c index 95bb80a2bc..465666a416 100644 --- a/system/qtest.c +++ b/system/qtest.c @@ -19,6 +19,7 @@ #include "exec/ioport.h" #include "exec/memory.h" #include "exec/tswap.h" +#include "hw/qdev-clock.h" #include "hw/qdev-core.h" #include "hw/irq.h" #include "hw/core/cpu.h" @@ -245,6 +246,20 @@ static void *qtest_server_send_opaque; * * Forcibly set the given interrupt pin to the given level. * + * Device clock frequency + * """""""""""""""""""""" + * + * .. code-block:: none + * + * > qdev_clock_out_get_hz QOM-PATH CLOCK-NAME + * < OK HZ + * + * .. code-block:: none + * + * > qdev_clock_in_get_hz QOM-PATH CLOCK-NAME + * < OK HZ + * + * where HZ is the clock frequency in hertz. */ static int hex2nib(char ch) @@ -758,6 +773,42 @@ static void qtest_process_command(CharBackend *chr, gchar **words) qtest_send_prefix(chr); qtest_sendf(chr, "OK %"PRIi64"\n", (int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); + } else if (strcmp(words[0], "qdev_clock_in_get_hz") == 0 || + strcmp(words[0], "qdev_clock_out_get_hz") == 0) { + bool is_outbound = words[0][11] == 'o'; + DeviceState *dev; + NamedClockList *ncl; + + g_assert(words[1]); + g_assert(words[2]); + + dev = DEVICE(object_resolve_path(words[1], NULL)); + if (!dev) { + qtest_send_prefix(chr); + qtest_send(chr, "FAIL Unknown device\n"); + return; + } + + ncl = qdev_get_clocklist(dev, words[2]); + if (!ncl) { + qtest_send_prefix(chr); + qtest_send(chr, "FAIL Unknown clock\n"); + return; + } + + if (is_outbound && !ncl->output) { + qtest_send_prefix(chr); + qtest_send(chr, "FAIL Not an output clock\n"); + return; + } + + if (!is_outbound && ncl->output) { + qtest_send_prefix(chr); + qtest_send(chr, "FAIL Not an input clock\n"); + return; + } + + qtest_sendf(chr, "OK %u\n", clock_get_hz(ncl->clock)); } else if (process_command_cb && process_command_cb(chr, words)) { /* Command got consumed by the callback handler */ } else { diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 4055d6b953..cc11b5f42e 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -2065,3 +2065,32 @@ bool mkimg(const char *file, const char *fmt, unsigned size_mb) return ret && !err; } + +static uint64_t qtest_dev_clock_get_hz(QTestState *s, const char *path, + const char *name, bool out) +{ + gchar **args; + int ret; + uint64_t value; + + qtest_sendf(s, "qdev_clock_%s_get_hz %s %s\n", out ? "out" : "in", + path, name); + args = qtest_rsp_args(s, 2); + ret = qemu_strtou64(args[1], NULL, 0, &value); + g_assert(!ret); + g_strfreev(args); + + return value; +} + +uint64_t qtest_dev_clock_out_get_hz(QTestState *s, const char *path, + const char *name) +{ + return qtest_dev_clock_get_hz(s, path, name, true); +} + +uint64_t qtest_dev_clock_in_get_hz(QTestState *s, const char *path, + const char *name) +{ + return qtest_dev_clock_get_hz(s, path, name, false); +} From patchwork Tue Oct 8 01:18:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Octavian Purdila X-Patchwork-Id: 1993917 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20230601 header.b=ZbGg8t+q; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XMyx90hBpz1xth for ; Tue, 8 Oct 2024 12:24:45 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sxyuo-0007qZ-D3; Mon, 07 Oct 2024 21:21: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 <3q4gEZwUKCg47o9w3u22uzs.q204s08-rs9sz121u18.25u@flex--tavip.bounces.google.com>) id 1sxyt6-0000c9-Ax for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:44 -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 <3q4gEZwUKCg47o9w3u22uzs.q204s08-rs9sz121u18.25u@flex--tavip.bounces.google.com>) id 1sxyt3-0000HA-R1 for qemu-devel@nongnu.org; Mon, 07 Oct 2024 21:19:44 -0400 Received: by mail-pf1-x44a.google.com with SMTP id d2e1a72fcca58-71e11abb22aso518153b3a.1 for ; Mon, 07 Oct 2024 18:19:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728350380; x=1728955180; 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=49FquaWPsQCXDvZ+9iOGQgsSq0aM4lH+3lh+RTdFI2o=; b=ZbGg8t+qbV8sonNVz0B5vAy1Q0OrO5tMy1xHL4d5DTHJstdZK0I3leAavZ7yUwJ5/K HzzcIG0Emk/za25DfQrPu4xxJWzP9b5d8Apai9CO3wWRVSCIG8/rv2QWPVH0csLuYVcm GMh2PhjyZ1COo381ynQF4BUECvcjCRnXXiQCR33b4NvfKLEPB8h2qZ10uDfkUG0o1IKH hUFSpHWyeuCGAEyfwZA8w5r8JBMFwesiVKsC9vGt0ByRTH1sx88VE+OIZA9uC3061nx/ jBeEqqvcyqYy1S9CQEi/lp0TNLawL8sa0N6AJsf7O0qu9ccT1m5CUfliHJ7j6/Qshbqd nHlQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728350380; x=1728955180; 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=49FquaWPsQCXDvZ+9iOGQgsSq0aM4lH+3lh+RTdFI2o=; b=kN7aUTSKEOpU4Gf12JSfxUUo4KvXdTkpD1YnXJrcZIgtKaFYrnqRnCLTz3m/EMPatc M87MVvbvq4GyxhvvM56bNu/8/BiK5PFeSjUT7IORxyPRVT7y2F/P6A/mHKzpn+tRc4cS Okj8kIzsbHhjGCKA9gWHR4oDz3CALEq2ZX8NCW94UjzqgagO1c4IXbQHav0+VLmuytBl ix4c2NON2PyFSJkSD56hMW6ngpk7X101z00MZm9qxh/8Wt9SmG7yB+QtBXNcHY9fohCs /9/J5XAjyVEna5cc5I/7OzVpQycaQyJnTRYKF3kejTFjezvBUP++EeJ+YTiZ9mt9ILUF pTKQ== X-Gm-Message-State: AOJu0Yz7/DheuOcfHVxyQ9dpJkLQMcS+MIAIWKnEK9rRn2Z/gDcoLE6C 9kcr/Kve4s3A7jtzeULvdr1gRMjnLIjvKX62h8SsN7wa72QzlULbTHKjS1zqY6YS0j3v7Z/4VcH 69kYiezcxHmtTzUuPS78mJSysypWfB+tbeCY+TVHGgy4CXfohyVvlj7VGGGbRWEAbnIxDRdoCjm 1KEOQb3tCgXPa1sWYNyxmyYTfyNQ== X-Google-Smtp-Source: AGHT+IHJH7MDeTk7Nh7rloj7vbrxdaiHNNx6zsfSUnM9QveGoJqzgfjpJEuaUwn1zp3dxVmynOyZGpE3ag== X-Received: from warp10.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:750]) (user=tavip job=sendgmr) by 2002:a05:6a00:324b:b0:71d:eb98:7341 with SMTP id d2e1a72fcca58-71deb987431mr22279b3a.2.1728350379687; Mon, 07 Oct 2024 18:19:39 -0700 (PDT) Date: Mon, 7 Oct 2024 18:18:51 -0700 In-Reply-To: <20241008011852.1439154-1-tavip@google.com> Mime-Version: 1.0 References: <20241008011852.1439154-1-tavip@google.com> X-Mailer: git-send-email 2.47.0.rc0.187.ge670bccf7e-goog Message-ID: <20241008011852.1439154-26-tavip@google.com> Subject: [PATCH v2 25/25] tests/qtest: add 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, peter.maydell@linaro.org, marcandre.lureau@redhat.com, berrange@redhat.com, eduardo@habkost.net, luc@lmichel.fr, damien.hedde@dahe.fr, alistair@alistair23.me, thuth@redhat.com, philmd@linaro.org, jsnow@redhat.com, crosa@redhat.com, lvivier@redhat.com Received-SPF: pass client-ip=2607:f8b0:4864:20::44a; envelope-from=3q4gEZwUKCg47o9w3u22uzs.q204s08-rs9sz121u18.25u@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.024, 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.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/qtest/rt500-clkctl-test.c | 195 ++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 1 + 2 files changed, 196 insertions(+) create mode 100644 tests/qtest/rt500-clkctl-test.c diff --git a/tests/qtest/rt500-clkctl-test.c b/tests/qtest/rt500-clkctl-test.c new file mode 100644 index 0000000000..d5b83d81da --- /dev/null +++ b/tests/qtest/rt500-clkctl-test.c @@ -0,0 +1,195 @@ +/* + * 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 "hw/arm/svd/rt500.h" +#include "reg-utils.h" + +#define SYSCLK_HZ 200000000 +#define CLKCTL0_NAME "/machine/soc/clkctl0" +#define CLKCTL1_NAME "/machine/soc/clkctl1" + +static void pscctl_test(gconstpointer user_data) +{ + /* rom controller clock should be enabled at reset */ + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, PSCCTL0, ROM_CTRLR_CLK) == 1); + + /* DSP clk is disabled at reset */ + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, PSCCTL0, DSP_CLK) == 0); + + /* check PSCTL_SET functionality */ + REG32_WRITE_FIELD_NOUPDATE(RT500_CLKCTL0, PSCCTL0_SET, DSP_CLK, 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, PSCCTL0, DSP_CLK) == 1); + + /* check PSCTL_CLR functionality */ + REG32_WRITE_FIELD_NOUPDATE(RT500_CLKCTL0, PSCCTL0_CLR, DSP_CLK, 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, PSCCTL0, DSP_CLK) == 0); + + /* FLEXIO clk is disabled at reset */ + g_assert(REG32_READ_FIELD(RT500_CLKCTL1, PSCCTL0, FlexIO) == 0); + + /* check PSCTL_SET functionality */ + REG32_WRITE_FIELD_NOUPDATE(RT500_CLKCTL1, PSCCTL0_SET, FlexIO, 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL1, PSCCTL0, FlexIO) == 1); + + /* check PSCTL_CLR functionality */ + REG32_WRITE_FIELD_NOUPDATE(RT500_CLKCTL1, PSCCTL0_CLR, FlexIO, 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL1, PSCCTL0, FlexIO) == 0); +} + +static void audiopll0pfd_test(gconstpointer user_data) +{ + /* audio plls are gated at boot */ + g_assert(REG32_READ_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD3_CLKGATE) == 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD2_CLKGATE) == 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD1_CLKGATE) == 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD0_CLKGATE) == 1); + + /* ,,, and clocks are not ready */ + g_assert(REG32_READ_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD3_CLKRDY) == 0); + g_assert(REG32_READ_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD2_CLKRDY) == 0); + g_assert(REG32_READ_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD1_CLKRDY) == 0); + g_assert(REG32_READ_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD0_CLKRDY) == 0); + + /* ungate all plls and check that clocks are ready */ + REG32_WRITE_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD3_CLKGATE, 0); + REG32_WRITE_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD2_CLKGATE, 0); + REG32_WRITE_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD1_CLKGATE, 0); + REG32_WRITE_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD0_CLKGATE, 0); + + g_assert(REG32_READ_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD3_CLKRDY) == 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD2_CLKRDY) == 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD1_CLKRDY) == 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL1, AUDIOPLL0PFD, PFD0_CLKRDY) == 1); +} + +static void syspll0pfd_test(gconstpointer user_data) +{ + /* system plls are gated at boot */ + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD3_CLKGATE) == 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD2_CLKGATE) == 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD1_CLKGATE) == 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD0_CLKGATE) == 1); + + /* ,,, and clocks are not ready */ + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD3_CLKRDY) == 0); + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD2_CLKRDY) == 0); + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD1_CLKRDY) == 0); + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD0_CLKRDY) == 0); + + /* ungate all plls and check that clocks are ready */ + REG32_WRITE_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD3_CLKGATE, 0); + REG32_WRITE_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD2_CLKGATE, 0); + REG32_WRITE_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD1_CLKGATE, 0); + REG32_WRITE_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD0_CLKGATE, 0); + + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD3_CLKRDY) == 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD2_CLKRDY) == 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD1_CLKRDY) == 1); + g_assert(REG32_READ_FIELD(RT500_CLKCTL0, SYSPLL0PFD, PFD0_CLKRDY) == 1); +} + +static void systick_clk_test(gconstpointer user_data) +{ + /* systick is not running at reset */ + g_assert_cmpuint(dev_clock_out_get_hz(CLKCTL0_NAME, "systick_clk"), ==, 0); + + /* select divout no divisor */ + REG32_WRITE_FIELD(RT500_CLKCTL0, SYSTICKFCLKSEL, SEL, + SYSTICKFCLKSEL_DIVOUT); + g_assert_cmpuint(dev_clock_out_get_hz(CLKCTL0_NAME, "systick_clk"), + ==, SYSCLK_HZ); + + /* change divisor to 2 */ + REG32_WRITE_FIELD(RT500_CLKCTL0, SYSTICKFCLKDIV, DIV, 1); + g_assert_cmpuint(dev_clock_out_get_hz(CLKCTL0_NAME, "systick_clk"), + ==, SYSCLK_HZ / 2); + + /* select lpsoc */ + REG32_WRITE_FIELD(RT500_CLKCTL0, SYSTICKFCLKSEL, SEL, + SYSTICKFCLKSEL_LPOSC); + g_assert_cmpuint(dev_clock_out_get_hz(CLKCTL0_NAME, "systick_clk"), + ==, LPOSC_CLK_HZ); + + /* select lpsoc */ + REG32_WRITE_FIELD(RT500_CLKCTL0, SYSTICKFCLKSEL, SEL, + SYSTICKFCLKSEL_32KHZRTC); + g_assert_cmpuint(dev_clock_out_get_hz(CLKCTL0_NAME, "systick_clk"), + ==, RTC32KHZ_CLK_HZ); + + /* disable clock */ + REG32_WRITE_FIELD(RT500_CLKCTL0, SYSTICKFCLKSEL, SEL, + SYSTICKFCLKSEL_NONE); + g_assert_cmpuint(dev_clock_out_get_hz(CLKCTL0_NAME, "systick_clk"), + ==, 0); +} + +static void ostimer_clk_test(gconstpointer user_data) +{ + /* systick is not running at reset */ + g_assert_cmpuint(dev_clock_out_get_hz(CLKCTL1_NAME, "ostimer_clk"), ==, 0); + + /* select lpsoc */ + REG32_WRITE_FIELD(RT500_CLKCTL1, OSEVENTTFCLKSEL, SEL, + OSEVENTTFCLKSEL_LPOSC); + g_assert_cmpuint(dev_clock_out_get_hz(CLKCTL1_NAME, "ostimer_clk"), ==, + LPOSC_CLK_HZ); + + /* select 32khz RTC */ + REG32_WRITE_FIELD(RT500_CLKCTL1, OSEVENTTFCLKSEL, SEL, + OSEVENTTFCLKSEL_32KHZRTC); + g_assert_cmpuint(dev_clock_out_get_hz(CLKCTL1_NAME, "ostimer_clk"), ==, + RTC32KHZ_CLK_HZ); + + /* select hclk */ + REG32_WRITE_FIELD(RT500_CLKCTL1, OSEVENTTFCLKSEL, SEL, + OSEVENTTFCLKSEL_HCLK); + g_assert_cmpuint(dev_clock_out_get_hz(CLKCTL1_NAME, "ostimer_clk"), ==, + SYSCLK_HZ); + + /* disable clock */ + REG32_WRITE_FIELD(RT500_CLKCTL1, OSEVENTTFCLKSEL, SEL, + OSEVENTTFCLKSEL_NONE); + g_assert_cmpuint(dev_clock_out_get_hz(CLKCTL1_NAME, "ostimer_clk"), ==, 0); +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + + qtest_add_data_func("/rt500-clkctl/pscctl-test", NULL, pscctl_test); + qtest_add_data_func("/rt500-clkctl/syspll0pfd-test", NULL, + syspll0pfd_test); + qtest_add_data_func("/rt500-clkctl/audiopll0pfd-test", NULL, + audiopll0pfd_test); + g_test_add_data_func("/rt500-clkctl/systick-test", NULL, + systick_clk_test); + g_test_add_data_func("/rt500-clkctl/ostimer-clk-test", NULL, + ostimer_clk_test); + + qtest_start("-M rt595-evk"); + ret = g_test_run(); + qtest_end(); + + return ret; +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index d3bf33b855..1a2d2ca3e1 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -234,6 +234,7 @@ qtests_arm = \ (config_all_devices.has_key('CONFIG_STM32L4X5_SOC') and config_all_devices.has_key('CONFIG_DM163')? ['dm163-test'] : []) + \ (config_all_devices.has_key('CONFIG_FLEXCOMM') ? ['flexcomm-test', 'flexcomm-usart-test', 'flexcomm-i2c-test', 'flexcomm-spi-test'] : []) + \ + (config_all_devices.has_key('CONFIG_RT500_CLKCTL') ? ['rt500-clkctl-test'] : []) + \ ['arm-cpu-features', 'boot-serial-test']