get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/1585742/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 1585742,
    "url": "http://patchwork.ozlabs.org/api/patches/1585742/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20220128153009.2467560-11-peter.maydell@linaro.org/",
    "project": {
        "id": 14,
        "url": "http://patchwork.ozlabs.org/api/projects/14/?format=api",
        "name": "QEMU Development",
        "link_name": "qemu-devel",
        "list_id": "qemu-devel.nongnu.org",
        "list_email": "qemu-devel@nongnu.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20220128153009.2467560-11-peter.maydell@linaro.org>",
    "list_archive_url": null,
    "date": "2022-01-28T15:29:47",
    "name": "[PULL,10/32] hw/ssi: Add a model of Xilinx Versal's OSPI flash memory controller",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "e4821cc248d1736f11a1479edbefe3736bcaa641",
    "submitter": {
        "id": 5111,
        "url": "http://patchwork.ozlabs.org/api/people/5111/?format=api",
        "name": "Peter Maydell",
        "email": "peter.maydell@linaro.org"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20220128153009.2467560-11-peter.maydell@linaro.org/mbox/",
    "series": [
        {
            "id": 283405,
            "url": "http://patchwork.ozlabs.org/api/series/283405/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=283405",
            "date": "2022-01-28T15:29:53",
            "name": "[PULL,01/32] Update copyright dates to 2022",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/283405/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/1585742/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/1585742/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org",
        "Authentication-Results": [
            "bilbo.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256\n header.s=google header.b=afftvLLm;\n\tdkim-atps=neutral",
            "ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=<UNKNOWN>)"
        ],
        "Received": [
            "from lists.gnu.org (lists.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby bilbo.ozlabs.org (Postfix) with ESMTPS id 4Jlhq12Pgwz9t56\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 29 Jan 2022 02:54:35 +1100 (AEDT)",
            "from localhost ([::1]:34732 helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1nDTa4-0007A2-5F\n\tfor incoming@patchwork.ozlabs.org; Fri, 28 Jan 2022 10:54:32 -0500",
            "from eggs.gnu.org ([209.51.188.92]:57810)\n by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <peter.maydell@linaro.org>)\n id 1nDTDF-0002BA-LD\n for qemu-devel@nongnu.org; Fri, 28 Jan 2022 10:30:59 -0500",
            "from [2a00:1450:4864:20::335] (port=36641\n helo=mail-wm1-x335.google.com)\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.90_1) (envelope-from <peter.maydell@linaro.org>)\n id 1nDTD5-0006PW-BN\n for qemu-devel@nongnu.org; Fri, 28 Jan 2022 10:30:55 -0500",
            "by mail-wm1-x335.google.com with SMTP id\n i187-20020a1c3bc4000000b0034d2ed1be2aso8466699wma.1\n for <qemu-devel@nongnu.org>; Fri, 28 Jan 2022 07:30:28 -0800 (PST)",
            "from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2])\n by smtp.gmail.com with ESMTPSA id j3sm4749485wrb.57.2022.01.28.07.30.25\n for <qemu-devel@nongnu.org>\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Fri, 28 Jan 2022 07:30:26 -0800 (PST)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google;\n h=from:to:subject:date:message-id:in-reply-to:references:mime-version\n :content-transfer-encoding;\n bh=ZocGjyXoW3xnunoEdkQ3nGOaPRWl1DaMiQJgkn0nm4Y=;\n b=afftvLLmnmReVBtDLXzRAgQR6lxA93ghhUpwcP/119yi3A9XhsamUhepfggXdHH3K7\n ActjCjK/lbKgGDLK68+0U56HD9NzwXIg/8ywmm21xJPRR6/fG09Q8FOXf/j+pSFmICtr\n yrCJB1YzWQSKHkNrkoK/MM8j53Ov+KyITdyTNd6Lfz2EE4pQyDme6cTWbYFh5UnugBve\n etHSgjkjbcQ+REP2oK7ou5SHYG9BJxhEHJt5hBSF8kkDyygSo5MDCIWWX8j+dgufarah\n PxUy7LXxR+eZ8vG2EIkmoCQj3kqmJBBlGu7ZXH8AU5E+UQYARzWKCWcqkMiVgILgU4zI\n Z98g==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20210112;\n h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to\n :references:mime-version:content-transfer-encoding;\n bh=ZocGjyXoW3xnunoEdkQ3nGOaPRWl1DaMiQJgkn0nm4Y=;\n b=bQBzdedRX0wXTRHuLtowQna4MeC7ZrcgL2lIwArojRNpA714bqzQuEoVPd4ki2tDWe\n lAbfb5eXm3qHEvFB+pWd2MRlWbVm7BWDwB7kMyS1LVQlRs1ZvQgSzTCl98gAL+QA8DHQ\n wSWqjy17xG8kqu/nfZzj2/XdJB1jMyC2DW7rMhBH0gINxmShcd3d1MAWALVgNOl/hIOZ\n 0Z14wSKS1LOXITdlSSnAjXE4hbZ+p3LXD45I9P1Ugq9pmLKAThc4LiUYKI49THuxQz0+\n ledJK/e9xfBq4zLiveHNcPRy+4aMxDoQchDWlgy8F6AA3riB75csxD/zw9934Hg7osE9\n 0fAw==",
        "X-Gm-Message-State": "AOAM531SZx1EVSF9Ir8phJ+JCU1jYVFkfO2Mlca0DwIQhx1dNgBl45Jt\n wuRa1hwvuXNjXUCPVw1vYs9hb7ryNcJByA==",
        "X-Google-Smtp-Source": "\n ABdhPJz5siJ+hGrIrSTP65YK2GrvsyTYOc3DDQUmuVx1Vae1hrrZoXEsmKfR92mafEYIT8uQ8cPhcg==",
        "X-Received": "by 2002:a05:600c:19d4:: with SMTP id\n u20mr2894925wmq.28.1643383826808;\n Fri, 28 Jan 2022 07:30:26 -0800 (PST)",
        "From": "Peter Maydell <peter.maydell@linaro.org>",
        "To": "qemu-devel@nongnu.org",
        "Subject": "[PULL 10/32] hw/ssi: Add a model of Xilinx Versal's OSPI flash memory\n controller",
        "Date": "Fri, 28 Jan 2022 15:29:47 +0000",
        "Message-Id": "<20220128153009.2467560-11-peter.maydell@linaro.org>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20220128153009.2467560-1-peter.maydell@linaro.org>",
        "References": "<20220128153009.2467560-1-peter.maydell@linaro.org>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-Host-Lookup-Failed": "Reverse DNS lookup failed for 2a00:1450:4864:20::335\n (failed)",
        "Received-SPF": "pass client-ip=2a00:1450:4864:20::335;\n envelope-from=peter.maydell@linaro.org; helo=mail-wm1-x335.google.com",
        "X-Spam_score_int": "-12",
        "X-Spam_score": "-1.3",
        "X-Spam_bar": "-",
        "X-Spam_report": "(-1.3 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,\n DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n PDS_HP_HELO_NORDNS=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793,\n SPF_HELO_NONE=0.001, SPF_PASS=-0.001,\n T_SCC_BODY_TEXT_LINE=-0.01 autolearn=no autolearn_force=no",
        "X-Spam_action": "no action",
        "X-BeenThere": "qemu-devel@nongnu.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<qemu-devel.nongnu.org>",
        "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.nongnu.org/archive/html/qemu-devel>",
        "List-Post": "<mailto:qemu-devel@nongnu.org>",
        "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>",
        "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>",
        "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org",
        "Sender": "\"Qemu-devel\"\n <qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>"
    },
    "content": "From: Francisco Iglesias <francisco.iglesias@xilinx.com>\n\nAdd a model of Xilinx Versal's OSPI flash memory controller.\n\nSigned-off-by: Francisco Iglesias <francisco.iglesias@xilinx.com>\nReviewed-by: Luc Michel <luc@lmichel.fr>\nMessage-id: 20220121161141.14389-7-francisco.iglesias@xilinx.com\n[PMM: fixed indent]\nSigned-off-by: Peter Maydell <peter.maydell@linaro.org>\n---\n include/hw/ssi/xlnx-versal-ospi.h |  111 ++\n hw/ssi/xlnx-versal-ospi.c         | 1853 +++++++++++++++++++++++++++++\n hw/ssi/meson.build                |    1 +\n 3 files changed, 1965 insertions(+)\n create mode 100644 include/hw/ssi/xlnx-versal-ospi.h\n create mode 100644 hw/ssi/xlnx-versal-ospi.c",
    "diff": "diff --git a/include/hw/ssi/xlnx-versal-ospi.h b/include/hw/ssi/xlnx-versal-ospi.h\nnew file mode 100644\nindex 00000000000..14d12634979\n--- /dev/null\n+++ b/include/hw/ssi/xlnx-versal-ospi.h\n@@ -0,0 +1,111 @@\n+/*\n+ * Header file for the Xilinx Versal's OSPI controller\n+ *\n+ * Copyright (C) 2021 Xilinx Inc\n+ * Written by Francisco Iglesias <francisco.iglesias@xilinx.com>\n+ *\n+ * Permission is hereby granted, free of charge, to any person obtaining a copy\n+ * of this software and associated documentation files (the \"Software\"), to deal\n+ * in the Software without restriction, including without limitation the rights\n+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+ * copies of the Software, and to permit persons to whom the Software is\n+ * furnished to do so, subject to the following conditions:\n+ *\n+ * The above copyright notice and this permission notice shall be included in\n+ * all copies or substantial portions of the Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n+ * THE SOFTWARE.\n+ */\n+\n+/*\n+ * This is a model of Xilinx Versal's Octal SPI flash memory controller\n+ * documented in Versal's Technical Reference manual [1] and the Versal ACAP\n+ * Register reference [2].\n+ *\n+ * References:\n+ *\n+ * [1] Versal ACAP Technical Reference Manual,\n+ *     https://www.xilinx.com/support/documentation/architecture-manuals/am011-versal-acap-trm.pdf\n+ *\n+ * [2] Versal ACAP Register Reference,\n+ *     https://www.xilinx.com/html_docs/registers/am012/am012-versal-register-reference.html#mod___ospi.html\n+ *\n+ *\n+ * QEMU interface:\n+ * + sysbus MMIO region 0: MemoryRegion for the device's registers\n+ * + sysbus MMIO region 1: MemoryRegion for flash memory linear address space\n+ *   (data transfer).\n+ * + sysbus IRQ 0: Device interrupt.\n+ * + Named GPIO input \"ospi-mux-sel\": 0: enables indirect access mode\n+ *   and 1: enables direct access mode.\n+ * + Property \"dac-with-indac\": Allow both direct accesses and indirect\n+ *   accesses simultaneously.\n+ * + Property \"indac-write-disabled\": Disable indirect access writes.\n+ */\n+\n+#ifndef XILINX_VERSAL_OSPI_H\n+#define XILINX_VERSAL_OSPI_H\n+\n+#include \"hw/register.h\"\n+#include \"hw/ssi/ssi.h\"\n+#include \"qemu/fifo8.h\"\n+#include \"hw/dma/xlnx_csu_dma.h\"\n+\n+#define TYPE_XILINX_VERSAL_OSPI \"xlnx.versal-ospi\"\n+\n+OBJECT_DECLARE_SIMPLE_TYPE(XlnxVersalOspi, XILINX_VERSAL_OSPI)\n+\n+#define XILINX_VERSAL_OSPI_R_MAX (0xfc / 4 + 1)\n+\n+/*\n+ * Indirect operations\n+ */\n+typedef struct IndOp {\n+    uint32_t flash_addr;\n+    uint32_t num_bytes;\n+    uint32_t done_bytes;\n+    bool completed;\n+} IndOp;\n+\n+struct XlnxVersalOspi {\n+    SysBusDevice parent_obj;\n+\n+    MemoryRegion iomem;\n+    MemoryRegion iomem_dac;\n+\n+    uint8_t num_cs;\n+    qemu_irq *cs_lines;\n+\n+    SSIBus *spi;\n+\n+    Fifo8 rx_fifo;\n+    Fifo8 tx_fifo;\n+\n+    Fifo8 rx_sram;\n+    Fifo8 tx_sram;\n+\n+    qemu_irq irq;\n+\n+    XlnxCSUDMA *dma_src;\n+    bool ind_write_disabled;\n+    bool dac_with_indac;\n+    bool dac_enable;\n+    bool src_dma_inprog;\n+\n+    IndOp rd_ind_op[2];\n+    IndOp wr_ind_op[2];\n+\n+    uint32_t regs[XILINX_VERSAL_OSPI_R_MAX];\n+    RegisterInfo regs_info[XILINX_VERSAL_OSPI_R_MAX];\n+\n+    /* Maximum inferred membank size is 512 bytes */\n+    uint8_t stig_membank[512];\n+};\n+\n+#endif /* XILINX_VERSAL_OSPI_H */\ndiff --git a/hw/ssi/xlnx-versal-ospi.c b/hw/ssi/xlnx-versal-ospi.c\nnew file mode 100644\nindex 00000000000..7ecd148fdf3\n--- /dev/null\n+++ b/hw/ssi/xlnx-versal-ospi.c\n@@ -0,0 +1,1853 @@\n+/*\n+ * QEMU model of Xilinx Versal's OSPI controller.\n+ *\n+ * Copyright (c) 2021 Xilinx Inc.\n+ * Written by Francisco Iglesias <francisco.iglesias@xilinx.com>\n+ *\n+ * Permission is hereby granted, free of charge, to any person obtaining a copy\n+ * of this software and associated documentation files (the \"Software\"), to deal\n+ * in the Software without restriction, including without limitation the rights\n+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+ * copies of the Software, and to permit persons to whom the Software is\n+ * furnished to do so, subject to the following conditions:\n+ *\n+ * The above copyright notice and this permission notice shall be included in\n+ * all copies or substantial portions of the Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n+ * THE SOFTWARE.\n+ */\n+#include \"qemu/osdep.h\"\n+#include \"hw/sysbus.h\"\n+#include \"migration/vmstate.h\"\n+#include \"hw/qdev-properties.h\"\n+#include \"qemu/bitops.h\"\n+#include \"qemu/log.h\"\n+#include \"hw/irq.h\"\n+#include \"hw/ssi/xlnx-versal-ospi.h\"\n+\n+#ifndef XILINX_VERSAL_OSPI_ERR_DEBUG\n+#define XILINX_VERSAL_OSPI_ERR_DEBUG 0\n+#endif\n+\n+REG32(CONFIG_REG, 0x0)\n+    FIELD(CONFIG_REG, IDLE_FLD, 31, 1)\n+    FIELD(CONFIG_REG, DUAL_BYTE_OPCODE_EN_FLD, 30, 1)\n+    FIELD(CONFIG_REG, CRC_ENABLE_FLD, 29, 1)\n+    FIELD(CONFIG_REG, CONFIG_RESV2_FLD, 26, 3)\n+    FIELD(CONFIG_REG, PIPELINE_PHY_FLD, 25, 1)\n+    FIELD(CONFIG_REG, ENABLE_DTR_PROTOCOL_FLD, 24, 1)\n+    FIELD(CONFIG_REG, ENABLE_AHB_DECODER_FLD, 23, 1)\n+    FIELD(CONFIG_REG, MSTR_BAUD_DIV_FLD, 19, 4)\n+    FIELD(CONFIG_REG, ENTER_XIP_MODE_IMM_FLD, 18, 1)\n+    FIELD(CONFIG_REG, ENTER_XIP_MODE_FLD, 17, 1)\n+    FIELD(CONFIG_REG, ENB_AHB_ADDR_REMAP_FLD, 16, 1)\n+    FIELD(CONFIG_REG, ENB_DMA_IF_FLD, 15, 1)\n+    FIELD(CONFIG_REG, WR_PROT_FLASH_FLD, 14, 1)\n+    FIELD(CONFIG_REG, PERIPH_CS_LINES_FLD, 10, 4)\n+    FIELD(CONFIG_REG, PERIPH_SEL_DEC_FLD, 9, 1)\n+    FIELD(CONFIG_REG, ENB_LEGACY_IP_MODE_FLD, 8, 1)\n+    FIELD(CONFIG_REG, ENB_DIR_ACC_CTLR_FLD, 7, 1)\n+    FIELD(CONFIG_REG, RESET_CFG_FLD, 6, 1)\n+    FIELD(CONFIG_REG, RESET_PIN_FLD, 5, 1)\n+    FIELD(CONFIG_REG, HOLD_PIN_FLD, 4, 1)\n+    FIELD(CONFIG_REG, PHY_MODE_ENABLE_FLD, 3, 1)\n+    FIELD(CONFIG_REG, SEL_CLK_PHASE_FLD, 2, 1)\n+    FIELD(CONFIG_REG, SEL_CLK_POL_FLD, 1, 1)\n+    FIELD(CONFIG_REG, ENB_SPI_FLD, 0, 1)\n+REG32(DEV_INSTR_RD_CONFIG_REG, 0x4)\n+    FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV5_FLD, 29, 3)\n+    FIELD(DEV_INSTR_RD_CONFIG_REG, DUMMY_RD_CLK_CYCLES_FLD, 24, 5)\n+    FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV4_FLD, 21, 3)\n+    FIELD(DEV_INSTR_RD_CONFIG_REG, MODE_BIT_ENABLE_FLD, 20, 1)\n+    FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV3_FLD, 18, 2)\n+    FIELD(DEV_INSTR_RD_CONFIG_REG, DATA_XFER_TYPE_EXT_MODE_FLD, 16, 2)\n+    FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV2_FLD, 14, 2)\n+    FIELD(DEV_INSTR_RD_CONFIG_REG, ADDR_XFER_TYPE_STD_MODE_FLD, 12, 2)\n+    FIELD(DEV_INSTR_RD_CONFIG_REG, PRED_DIS_FLD, 11, 1)\n+    FIELD(DEV_INSTR_RD_CONFIG_REG, DDR_EN_FLD, 10, 1)\n+    FIELD(DEV_INSTR_RD_CONFIG_REG, INSTR_TYPE_FLD, 8, 2)\n+    FIELD(DEV_INSTR_RD_CONFIG_REG, RD_OPCODE_NON_XIP_FLD, 0, 8)\n+REG32(DEV_INSTR_WR_CONFIG_REG, 0x8)\n+    FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV4_FLD, 29, 3)\n+    FIELD(DEV_INSTR_WR_CONFIG_REG, DUMMY_WR_CLK_CYCLES_FLD, 24, 5)\n+    FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV3_FLD, 18, 6)\n+    FIELD(DEV_INSTR_WR_CONFIG_REG, DATA_XFER_TYPE_EXT_MODE_FLD, 16, 2)\n+    FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV2_FLD, 14, 2)\n+    FIELD(DEV_INSTR_WR_CONFIG_REG, ADDR_XFER_TYPE_STD_MODE_FLD, 12, 2)\n+    FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV1_FLD, 9, 3)\n+    FIELD(DEV_INSTR_WR_CONFIG_REG, WEL_DIS_FLD, 8, 1)\n+    FIELD(DEV_INSTR_WR_CONFIG_REG, WR_OPCODE_FLD, 0, 8)\n+REG32(DEV_DELAY_REG, 0xc)\n+    FIELD(DEV_DELAY_REG, D_NSS_FLD, 24, 8)\n+    FIELD(DEV_DELAY_REG, D_BTWN_FLD, 16, 8)\n+    FIELD(DEV_DELAY_REG, D_AFTER_FLD, 8, 8)\n+    FIELD(DEV_DELAY_REG, D_INIT_FLD, 0, 8)\n+REG32(RD_DATA_CAPTURE_REG, 0x10)\n+    FIELD(RD_DATA_CAPTURE_REG, RD_DATA_RESV3_FLD, 20, 12)\n+    FIELD(RD_DATA_CAPTURE_REG, DDR_READ_DELAY_FLD, 16, 4)\n+    FIELD(RD_DATA_CAPTURE_REG, RD_DATA_RESV2_FLD, 9, 7)\n+    FIELD(RD_DATA_CAPTURE_REG, DQS_ENABLE_FLD, 8, 1)\n+    FIELD(RD_DATA_CAPTURE_REG, RD_DATA_RESV1_FLD, 6, 2)\n+    FIELD(RD_DATA_CAPTURE_REG, SAMPLE_EDGE_SEL_FLD, 5, 1)\n+    FIELD(RD_DATA_CAPTURE_REG, DELAY_FLD, 1, 4)\n+    FIELD(RD_DATA_CAPTURE_REG, BYPASS_FLD, 0, 1)\n+REG32(DEV_SIZE_CONFIG_REG, 0x14)\n+    FIELD(DEV_SIZE_CONFIG_REG, DEV_SIZE_RESV_FLD, 29, 3)\n+    FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS3_FLD, 27, 2)\n+    FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS2_FLD, 25, 2)\n+    FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS1_FLD, 23, 2)\n+    FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS0_FLD, 21, 2)\n+    FIELD(DEV_SIZE_CONFIG_REG, BYTES_PER_SUBSECTOR_FLD, 16, 5)\n+    FIELD(DEV_SIZE_CONFIG_REG, BYTES_PER_DEVICE_PAGE_FLD, 4, 12)\n+    FIELD(DEV_SIZE_CONFIG_REG, NUM_ADDR_BYTES_FLD, 0, 4)\n+REG32(SRAM_PARTITION_CFG_REG, 0x18)\n+    FIELD(SRAM_PARTITION_CFG_REG, SRAM_PARTITION_RESV_FLD, 8, 24)\n+    FIELD(SRAM_PARTITION_CFG_REG, ADDR_FLD, 0, 8)\n+REG32(IND_AHB_ADDR_TRIGGER_REG, 0x1c)\n+REG32(DMA_PERIPH_CONFIG_REG, 0x20)\n+    FIELD(DMA_PERIPH_CONFIG_REG, DMA_PERIPH_RESV2_FLD, 12, 20)\n+    FIELD(DMA_PERIPH_CONFIG_REG, NUM_BURST_REQ_BYTES_FLD, 8, 4)\n+    FIELD(DMA_PERIPH_CONFIG_REG, DMA_PERIPH_RESV1_FLD, 4, 4)\n+    FIELD(DMA_PERIPH_CONFIG_REG, NUM_SINGLE_REQ_BYTES_FLD, 0, 4)\n+REG32(REMAP_ADDR_REG, 0x24)\n+REG32(MODE_BIT_CONFIG_REG, 0x28)\n+    FIELD(MODE_BIT_CONFIG_REG, RX_CRC_DATA_LOW_FLD, 24, 8)\n+    FIELD(MODE_BIT_CONFIG_REG, RX_CRC_DATA_UP_FLD, 16, 8)\n+    FIELD(MODE_BIT_CONFIG_REG, CRC_OUT_ENABLE_FLD, 15, 1)\n+    FIELD(MODE_BIT_CONFIG_REG, MODE_BIT_RESV1_FLD, 11, 4)\n+    FIELD(MODE_BIT_CONFIG_REG, CHUNK_SIZE_FLD, 8, 3)\n+    FIELD(MODE_BIT_CONFIG_REG, MODE_FLD, 0, 8)\n+REG32(SRAM_FILL_REG, 0x2c)\n+    FIELD(SRAM_FILL_REG, SRAM_FILL_INDAC_WRITE_FLD, 16, 16)\n+    FIELD(SRAM_FILL_REG, SRAM_FILL_INDAC_READ_FLD, 0, 16)\n+REG32(TX_THRESH_REG, 0x30)\n+    FIELD(TX_THRESH_REG, TX_THRESH_RESV_FLD, 5, 27)\n+    FIELD(TX_THRESH_REG, LEVEL_FLD, 0, 5)\n+REG32(RX_THRESH_REG, 0x34)\n+    FIELD(RX_THRESH_REG, RX_THRESH_RESV_FLD, 5, 27)\n+    FIELD(RX_THRESH_REG, LEVEL_FLD, 0, 5)\n+REG32(WRITE_COMPLETION_CTRL_REG, 0x38)\n+    FIELD(WRITE_COMPLETION_CTRL_REG, POLL_REP_DELAY_FLD, 24, 8)\n+    FIELD(WRITE_COMPLETION_CTRL_REG, POLL_COUNT_FLD, 16, 8)\n+    FIELD(WRITE_COMPLETION_CTRL_REG, ENABLE_POLLING_EXP_FLD, 15, 1)\n+    FIELD(WRITE_COMPLETION_CTRL_REG, DISABLE_POLLING_FLD, 14, 1)\n+    FIELD(WRITE_COMPLETION_CTRL_REG, POLLING_POLARITY_FLD, 13, 1)\n+    FIELD(WRITE_COMPLETION_CTRL_REG, WR_COMP_CTRL_RESV1_FLD, 12, 1)\n+    FIELD(WRITE_COMPLETION_CTRL_REG, POLLING_ADDR_EN_FLD, 11, 1)\n+    FIELD(WRITE_COMPLETION_CTRL_REG, POLLING_BIT_INDEX_FLD, 8, 3)\n+    FIELD(WRITE_COMPLETION_CTRL_REG, OPCODE_FLD, 0, 8)\n+REG32(NO_OF_POLLS_BEF_EXP_REG, 0x3c)\n+REG32(IRQ_STATUS_REG, 0x40)\n+    FIELD(IRQ_STATUS_REG, IRQ_STAT_RESV_FLD, 20, 12)\n+    FIELD(IRQ_STATUS_REG, ECC_FAIL_FLD, 19, 1)\n+    FIELD(IRQ_STATUS_REG, TX_CRC_CHUNK_BRK_FLD, 18, 1)\n+    FIELD(IRQ_STATUS_REG, RX_CRC_DATA_VAL_FLD, 17, 1)\n+    FIELD(IRQ_STATUS_REG, RX_CRC_DATA_ERR_FLD, 16, 1)\n+    FIELD(IRQ_STATUS_REG, IRQ_STAT_RESV1_FLD, 15, 1)\n+    FIELD(IRQ_STATUS_REG, STIG_REQ_INT_FLD, 14, 1)\n+    FIELD(IRQ_STATUS_REG, POLL_EXP_INT_FLD, 13, 1)\n+    FIELD(IRQ_STATUS_REG, INDRD_SRAM_FULL_FLD, 12, 1)\n+    FIELD(IRQ_STATUS_REG, RX_FIFO_FULL_FLD, 11, 1)\n+    FIELD(IRQ_STATUS_REG, RX_FIFO_NOT_EMPTY_FLD, 10, 1)\n+    FIELD(IRQ_STATUS_REG, TX_FIFO_FULL_FLD, 9, 1)\n+    FIELD(IRQ_STATUS_REG, TX_FIFO_NOT_FULL_FLD, 8, 1)\n+    FIELD(IRQ_STATUS_REG, RECV_OVERFLOW_FLD, 7, 1)\n+    FIELD(IRQ_STATUS_REG, INDIRECT_XFER_LEVEL_BREACH_FLD, 6, 1)\n+    FIELD(IRQ_STATUS_REG, ILLEGAL_ACCESS_DET_FLD, 5, 1)\n+    FIELD(IRQ_STATUS_REG, PROT_WR_ATTEMPT_FLD, 4, 1)\n+    FIELD(IRQ_STATUS_REG, INDIRECT_TRANSFER_REJECT_FLD, 3, 1)\n+    FIELD(IRQ_STATUS_REG, INDIRECT_OP_DONE_FLD, 2, 1)\n+    FIELD(IRQ_STATUS_REG, UNDERFLOW_DET_FLD, 1, 1)\n+    FIELD(IRQ_STATUS_REG, MODE_M_FAIL_FLD, 0, 1)\n+REG32(IRQ_MASK_REG, 0x44)\n+    FIELD(IRQ_MASK_REG, IRQ_MASK_RESV_FLD, 20, 12)\n+    FIELD(IRQ_MASK_REG, ECC_FAIL_MASK_FLD, 19, 1)\n+    FIELD(IRQ_MASK_REG, TX_CRC_CHUNK_BRK_MASK_FLD, 18, 1)\n+    FIELD(IRQ_MASK_REG, RX_CRC_DATA_VAL_MASK_FLD, 17, 1)\n+    FIELD(IRQ_MASK_REG, RX_CRC_DATA_ERR_MASK_FLD, 16, 1)\n+    FIELD(IRQ_MASK_REG, IRQ_MASK_RESV1_FLD, 15, 1)\n+    FIELD(IRQ_MASK_REG, STIG_REQ_MASK_FLD, 14, 1)\n+    FIELD(IRQ_MASK_REG, POLL_EXP_INT_MASK_FLD, 13, 1)\n+    FIELD(IRQ_MASK_REG, INDRD_SRAM_FULL_MASK_FLD, 12, 1)\n+    FIELD(IRQ_MASK_REG, RX_FIFO_FULL_MASK_FLD, 11, 1)\n+    FIELD(IRQ_MASK_REG, RX_FIFO_NOT_EMPTY_MASK_FLD, 10, 1)\n+    FIELD(IRQ_MASK_REG, TX_FIFO_FULL_MASK_FLD, 9, 1)\n+    FIELD(IRQ_MASK_REG, TX_FIFO_NOT_FULL_MASK_FLD, 8, 1)\n+    FIELD(IRQ_MASK_REG, RECV_OVERFLOW_MASK_FLD, 7, 1)\n+    FIELD(IRQ_MASK_REG, INDIRECT_XFER_LEVEL_BREACH_MASK_FLD, 6, 1)\n+    FIELD(IRQ_MASK_REG, ILLEGAL_ACCESS_DET_MASK_FLD, 5, 1)\n+    FIELD(IRQ_MASK_REG, PROT_WR_ATTEMPT_MASK_FLD, 4, 1)\n+    FIELD(IRQ_MASK_REG, INDIRECT_TRANSFER_REJECT_MASK_FLD, 3, 1)\n+    FIELD(IRQ_MASK_REG, INDIRECT_OP_DONE_MASK_FLD, 2, 1)\n+    FIELD(IRQ_MASK_REG, UNDERFLOW_DET_MASK_FLD, 1, 1)\n+    FIELD(IRQ_MASK_REG, MODE_M_FAIL_MASK_FLD, 0, 1)\n+REG32(LOWER_WR_PROT_REG, 0x50)\n+REG32(UPPER_WR_PROT_REG, 0x54)\n+REG32(WR_PROT_CTRL_REG, 0x58)\n+    FIELD(WR_PROT_CTRL_REG, WR_PROT_CTRL_RESV_FLD, 2, 30)\n+    FIELD(WR_PROT_CTRL_REG, ENB_FLD, 1, 1)\n+    FIELD(WR_PROT_CTRL_REG, INV_FLD, 0, 1)\n+REG32(INDIRECT_READ_XFER_CTRL_REG, 0x60)\n+    FIELD(INDIRECT_READ_XFER_CTRL_REG, INDIR_RD_XFER_RESV_FLD, 8, 24)\n+    FIELD(INDIRECT_READ_XFER_CTRL_REG, NUM_IND_OPS_DONE_FLD, 6, 2)\n+    FIELD(INDIRECT_READ_XFER_CTRL_REG, IND_OPS_DONE_STATUS_FLD, 5, 1)\n+    FIELD(INDIRECT_READ_XFER_CTRL_REG, RD_QUEUED_FLD, 4, 1)\n+    FIELD(INDIRECT_READ_XFER_CTRL_REG, SRAM_FULL_FLD, 3, 1)\n+    FIELD(INDIRECT_READ_XFER_CTRL_REG, RD_STATUS_FLD, 2, 1)\n+    FIELD(INDIRECT_READ_XFER_CTRL_REG, CANCEL_FLD, 1, 1)\n+    FIELD(INDIRECT_READ_XFER_CTRL_REG, START_FLD, 0, 1)\n+REG32(INDIRECT_READ_XFER_WATERMARK_REG, 0x64)\n+REG32(INDIRECT_READ_XFER_START_REG, 0x68)\n+REG32(INDIRECT_READ_XFER_NUM_BYTES_REG, 0x6c)\n+REG32(INDIRECT_WRITE_XFER_CTRL_REG, 0x70)\n+    FIELD(INDIRECT_WRITE_XFER_CTRL_REG, INDIR_WR_XFER_RESV2_FLD, 8, 24)\n+    FIELD(INDIRECT_WRITE_XFER_CTRL_REG, NUM_IND_OPS_DONE_FLD, 6, 2)\n+    FIELD(INDIRECT_WRITE_XFER_CTRL_REG, IND_OPS_DONE_STATUS_FLD, 5, 1)\n+    FIELD(INDIRECT_WRITE_XFER_CTRL_REG, WR_QUEUED_FLD, 4, 1)\n+    FIELD(INDIRECT_WRITE_XFER_CTRL_REG, INDIR_WR_XFER_RESV1_FLD, 3, 1)\n+    FIELD(INDIRECT_WRITE_XFER_CTRL_REG, WR_STATUS_FLD, 2, 1)\n+    FIELD(INDIRECT_WRITE_XFER_CTRL_REG, CANCEL_FLD, 1, 1)\n+    FIELD(INDIRECT_WRITE_XFER_CTRL_REG, START_FLD, 0, 1)\n+REG32(INDIRECT_WRITE_XFER_WATERMARK_REG, 0x74)\n+REG32(INDIRECT_WRITE_XFER_START_REG, 0x78)\n+REG32(INDIRECT_WRITE_XFER_NUM_BYTES_REG, 0x7c)\n+REG32(INDIRECT_TRIGGER_ADDR_RANGE_REG, 0x80)\n+    FIELD(INDIRECT_TRIGGER_ADDR_RANGE_REG, IND_RANGE_RESV1_FLD, 4, 28)\n+    FIELD(INDIRECT_TRIGGER_ADDR_RANGE_REG, IND_RANGE_WIDTH_FLD, 0, 4)\n+REG32(FLASH_COMMAND_CTRL_MEM_REG, 0x8c)\n+    FIELD(FLASH_COMMAND_CTRL_MEM_REG, FLASH_COMMAND_CTRL_MEM_RESV1_FLD, 29, 3)\n+    FIELD(FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_ADDR_FLD, 20, 9)\n+    FIELD(FLASH_COMMAND_CTRL_MEM_REG, FLASH_COMMAND_CTRL_MEM_RESV2_FLD, 19, 1)\n+    FIELD(FLASH_COMMAND_CTRL_MEM_REG, NB_OF_STIG_READ_BYTES_FLD, 16, 3)\n+    FIELD(FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_READ_DATA_FLD, 8, 8)\n+    FIELD(FLASH_COMMAND_CTRL_MEM_REG, FLASH_COMMAND_CTRL_MEM_RESV3_FLD, 2, 6)\n+    FIELD(FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_REQ_IN_PROGRESS_FLD, 1, 1)\n+    FIELD(FLASH_COMMAND_CTRL_MEM_REG, TRIGGER_MEM_BANK_REQ_FLD, 0, 1)\n+REG32(FLASH_CMD_CTRL_REG, 0x90)\n+    FIELD(FLASH_CMD_CTRL_REG, CMD_OPCODE_FLD, 24, 8)\n+    FIELD(FLASH_CMD_CTRL_REG, ENB_READ_DATA_FLD, 23, 1)\n+    FIELD(FLASH_CMD_CTRL_REG, NUM_RD_DATA_BYTES_FLD, 20, 3)\n+    FIELD(FLASH_CMD_CTRL_REG, ENB_COMD_ADDR_FLD, 19, 1)\n+    FIELD(FLASH_CMD_CTRL_REG, ENB_MODE_BIT_FLD, 18, 1)\n+    FIELD(FLASH_CMD_CTRL_REG, NUM_ADDR_BYTES_FLD, 16, 2)\n+    FIELD(FLASH_CMD_CTRL_REG, ENB_WRITE_DATA_FLD, 15, 1)\n+    FIELD(FLASH_CMD_CTRL_REG, NUM_WR_DATA_BYTES_FLD, 12, 3)\n+    FIELD(FLASH_CMD_CTRL_REG, NUM_DUMMY_CYCLES_FLD, 7, 5)\n+    FIELD(FLASH_CMD_CTRL_REG, FLASH_CMD_CTRL_RESV1_FLD, 3, 4)\n+    FIELD(FLASH_CMD_CTRL_REG, STIG_MEM_BANK_EN_FLD, 2, 1)\n+    FIELD(FLASH_CMD_CTRL_REG, CMD_EXEC_STATUS_FLD, 1, 1)\n+    FIELD(FLASH_CMD_CTRL_REG, CMD_EXEC_FLD, 0, 1)\n+REG32(FLASH_CMD_ADDR_REG, 0x94)\n+REG32(FLASH_RD_DATA_LOWER_REG, 0xa0)\n+REG32(FLASH_RD_DATA_UPPER_REG, 0xa4)\n+REG32(FLASH_WR_DATA_LOWER_REG, 0xa8)\n+REG32(FLASH_WR_DATA_UPPER_REG, 0xac)\n+REG32(POLLING_FLASH_STATUS_REG, 0xb0)\n+    FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_RSVD_FLD2, 21, 11)\n+    FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_NB_DUMMY, 16, 5)\n+    FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_RSVD_FLD1, 9, 7)\n+    FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_VALID_FLD, 8, 1)\n+    FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_FLD, 0, 8)\n+REG32(PHY_CONFIGURATION_REG, 0xb4)\n+    FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESYNC_FLD, 31, 1)\n+    FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESET_FLD, 30, 1)\n+    FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RX_DLL_BYPASS_FLD, 29, 1)\n+    FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESV2_FLD, 23, 6)\n+    FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_TX_DLL_DELAY_FLD, 16, 7)\n+    FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESV1_FLD, 7, 9)\n+    FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RX_DLL_DELAY_FLD, 0, 7)\n+REG32(PHY_MASTER_CONTROL_REG, 0xb8)\n+    FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_CONTROL_RESV3_FLD, 25, 7)\n+    FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_LOCK_MODE_FLD, 24, 1)\n+    FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_BYPASS_MODE_FLD, 23, 1)\n+    FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_PHASE_DETECT_SELECTOR_FLD, 20, 3)\n+    FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_CONTROL_RESV2_FLD, 19, 1)\n+    FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_NB_INDICATIONS_FLD, 16, 3)\n+    FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_CONTROL_RESV1_FLD, 7, 9)\n+    FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_INITIAL_DELAY_FLD, 0, 7)\n+REG32(DLL_OBSERVABLE_LOWER_REG, 0xbc)\n+    FIELD(DLL_OBSERVABLE_LOWER_REG,\n+          DLL_OBSERVABLE_LOWER_DLL_LOCK_INC_FLD, 24, 8)\n+    FIELD(DLL_OBSERVABLE_LOWER_REG,\n+          DLL_OBSERVABLE_LOWER_DLL_LOCK_DEC_FLD, 16, 8)\n+    FIELD(DLL_OBSERVABLE_LOWER_REG,\n+          DLL_OBSERVABLE_LOWER_LOOPBACK_LOCK_FLD, 15, 1)\n+    FIELD(DLL_OBSERVABLE_LOWER_REG,\n+          DLL_OBSERVABLE_LOWER_LOCK_VALUE_FLD, 8, 7)\n+    FIELD(DLL_OBSERVABLE_LOWER_REG,\n+          DLL_OBSERVABLE_LOWER_UNLOCK_COUNTER_FLD, 3, 5)\n+    FIELD(DLL_OBSERVABLE_LOWER_REG,\n+          DLL_OBSERVABLE_LOWER_LOCK_MODE_FLD, 1, 2)\n+    FIELD(DLL_OBSERVABLE_LOWER_REG,\n+          DLL_OBSERVABLE_LOWER_DLL_LOCK_FLD, 0, 1)\n+REG32(DLL_OBSERVABLE_UPPER_REG, 0xc0)\n+    FIELD(DLL_OBSERVABLE_UPPER_REG,\n+          DLL_OBSERVABLE_UPPER_RESV2_FLD, 23, 9)\n+    FIELD(DLL_OBSERVABLE_UPPER_REG,\n+          DLL_OBSERVABLE_UPPER_TX_DECODER_OUTPUT_FLD, 16, 7)\n+    FIELD(DLL_OBSERVABLE_UPPER_REG,\n+          DLL_OBSERVABLE_UPPER_RESV1_FLD, 7, 9)\n+    FIELD(DLL_OBSERVABLE_UPPER_REG,\n+          DLL_OBSERVABLE__UPPER_RX_DECODER_OUTPUT_FLD, 0, 7)\n+REG32(OPCODE_EXT_LOWER_REG, 0xe0)\n+    FIELD(OPCODE_EXT_LOWER_REG, EXT_READ_OPCODE_FLD, 24, 8)\n+    FIELD(OPCODE_EXT_LOWER_REG, EXT_WRITE_OPCODE_FLD, 16, 8)\n+    FIELD(OPCODE_EXT_LOWER_REG, EXT_POLL_OPCODE_FLD, 8, 8)\n+    FIELD(OPCODE_EXT_LOWER_REG, EXT_STIG_OPCODE_FLD, 0, 8)\n+REG32(OPCODE_EXT_UPPER_REG, 0xe4)\n+    FIELD(OPCODE_EXT_UPPER_REG, WEL_OPCODE_FLD, 24, 8)\n+    FIELD(OPCODE_EXT_UPPER_REG, EXT_WEL_OPCODE_FLD, 16, 8)\n+    FIELD(OPCODE_EXT_UPPER_REG, OPCODE_EXT_UPPER_RESV1_FLD, 0, 16)\n+REG32(MODULE_ID_REG, 0xfc)\n+    FIELD(MODULE_ID_REG, FIX_PATCH_FLD, 24, 8)\n+    FIELD(MODULE_ID_REG, MODULE_ID_FLD, 8, 16)\n+    FIELD(MODULE_ID_REG, MODULE_ID_RESV_FLD, 2, 6)\n+    FIELD(MODULE_ID_REG, CONF_FLD, 0, 2)\n+\n+#define RXFF_SZ 1024\n+#define TXFF_SZ 1024\n+\n+#define MAX_RX_DEC_OUT 8\n+\n+#define SZ_512MBIT (512 * 1024 * 1024)\n+#define SZ_1GBIT   (1024 * 1024 * 1024)\n+#define SZ_2GBIT   (2ULL * SZ_1GBIT)\n+#define SZ_4GBIT   (4ULL * SZ_1GBIT)\n+\n+#define IS_IND_DMA_START(op) (op->done_bytes == 0)\n+/*\n+ * Bit field size of R_INDIRECT_WRITE_XFER_CTRL_REG_NUM_IND_OPS_DONE_FLD\n+ * is 2 bits, which can record max of 3 indac operations.\n+ */\n+#define IND_OPS_DONE_MAX 3\n+\n+typedef enum {\n+    WREN = 0x6,\n+} FlashCMD;\n+\n+static unsigned int ospi_stig_addr_len(XlnxVersalOspi *s)\n+{\n+    /* Num address bytes is NUM_ADDR_BYTES_FLD + 1 */\n+    return ARRAY_FIELD_EX32(s->regs,\n+                            FLASH_CMD_CTRL_REG, NUM_ADDR_BYTES_FLD) + 1;\n+}\n+\n+static unsigned int ospi_stig_wr_data_len(XlnxVersalOspi *s)\n+{\n+    /* Num write data bytes is NUM_WR_DATA_BYTES_FLD + 1 */\n+    return ARRAY_FIELD_EX32(s->regs,\n+                            FLASH_CMD_CTRL_REG, NUM_WR_DATA_BYTES_FLD) + 1;\n+}\n+\n+static unsigned int ospi_stig_rd_data_len(XlnxVersalOspi *s)\n+{\n+    /* Num read data bytes is NUM_RD_DATA_BYTES_FLD + 1 */\n+    return ARRAY_FIELD_EX32(s->regs,\n+                            FLASH_CMD_CTRL_REG, NUM_RD_DATA_BYTES_FLD) + 1;\n+}\n+\n+/*\n+ * Status bits in R_IRQ_STATUS_REG are set when the event occurs and the\n+ * interrupt is enabled in the mask register ([1] Section 2.3.17)\n+ */\n+static void set_irq(XlnxVersalOspi *s, uint32_t set_mask)\n+{\n+    s->regs[R_IRQ_STATUS_REG] |= s->regs[R_IRQ_MASK_REG] & set_mask;\n+}\n+\n+static void ospi_update_irq_line(XlnxVersalOspi *s)\n+{\n+    qemu_set_irq(s->irq, !!(s->regs[R_IRQ_STATUS_REG] &\n+                            s->regs[R_IRQ_MASK_REG]));\n+}\n+\n+static uint8_t ospi_get_wr_opcode(XlnxVersalOspi *s)\n+{\n+    return ARRAY_FIELD_EX32(s->regs,\n+                            DEV_INSTR_WR_CONFIG_REG, WR_OPCODE_FLD);\n+}\n+\n+static uint8_t ospi_get_rd_opcode(XlnxVersalOspi *s)\n+{\n+    return ARRAY_FIELD_EX32(s->regs,\n+                            DEV_INSTR_RD_CONFIG_REG, RD_OPCODE_NON_XIP_FLD);\n+}\n+\n+static uint32_t ospi_get_num_addr_bytes(XlnxVersalOspi *s)\n+{\n+    /* Num address bytes is NUM_ADDR_BYTES_FLD + 1 */\n+    return ARRAY_FIELD_EX32(s->regs,\n+                            DEV_SIZE_CONFIG_REG, NUM_ADDR_BYTES_FLD) + 1;\n+}\n+\n+static void ospi_stig_membank_req(XlnxVersalOspi *s)\n+{\n+    int idx = ARRAY_FIELD_EX32(s->regs,\n+                               FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_ADDR_FLD);\n+\n+    ARRAY_FIELD_DP32(s->regs, FLASH_COMMAND_CTRL_MEM_REG,\n+                     MEM_BANK_READ_DATA_FLD, s->stig_membank[idx]);\n+}\n+\n+static int ospi_stig_membank_rd_bytes(XlnxVersalOspi *s)\n+{\n+    int rd_data_fld = ARRAY_FIELD_EX32(s->regs, FLASH_COMMAND_CTRL_MEM_REG,\n+                                       NB_OF_STIG_READ_BYTES_FLD);\n+    static const int sizes[6] = { 16, 32, 64, 128, 256, 512 };\n+    return (rd_data_fld < 6) ? sizes[rd_data_fld] : 0;\n+}\n+\n+static uint32_t ospi_get_page_sz(XlnxVersalOspi *s)\n+{\n+    return ARRAY_FIELD_EX32(s->regs,\n+                            DEV_SIZE_CONFIG_REG, BYTES_PER_DEVICE_PAGE_FLD);\n+}\n+\n+static bool ospi_ind_rd_watermark_enabled(XlnxVersalOspi *s)\n+{\n+    return s->regs[R_INDIRECT_READ_XFER_WATERMARK_REG];\n+}\n+\n+static void ind_op_advance(IndOp *op, unsigned int len)\n+{\n+    op->done_bytes += len;\n+    assert(op->done_bytes <= op->num_bytes);\n+    if (op->done_bytes == op->num_bytes) {\n+        op->completed = true;\n+    }\n+}\n+\n+static uint32_t ind_op_next_byte(IndOp *op)\n+{\n+    return op->flash_addr + op->done_bytes;\n+}\n+\n+static uint32_t ind_op_end_byte(IndOp *op)\n+{\n+    return op->flash_addr + op->num_bytes;\n+}\n+\n+static void ospi_ind_op_next(IndOp *op)\n+{\n+    op[0] = op[1];\n+    op[1].completed = true;\n+}\n+\n+static void ind_op_setup(IndOp *op, uint32_t flash_addr, uint32_t num_bytes)\n+{\n+    if (num_bytes & 0x3) {\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                      \"OSPI indirect op num bytes not word aligned\\n\");\n+    }\n+    op->flash_addr = flash_addr;\n+    op->num_bytes = num_bytes;\n+    op->done_bytes = 0;\n+    op->completed = false;\n+}\n+\n+static bool ospi_ind_op_completed(IndOp *op)\n+{\n+    return op->completed;\n+}\n+\n+static bool ospi_ind_op_all_completed(XlnxVersalOspi *s)\n+{\n+    return s->rd_ind_op[0].completed && s->wr_ind_op[0].completed;\n+}\n+\n+static void ospi_ind_op_cancel(IndOp *op)\n+{\n+    op[0].completed = true;\n+    op[1].completed = true;\n+}\n+\n+static bool ospi_ind_op_add(IndOp *op, Fifo8 *fifo,\n+                            uint32_t flash_addr, uint32_t num_bytes)\n+{\n+    /* Check if first indirect op has been completed */\n+    if (op->completed) {\n+        fifo8_reset(fifo);\n+        ind_op_setup(op, flash_addr, num_bytes);\n+        return false;\n+    }\n+\n+    /* Check if second indirect op has been completed */\n+    op++;\n+    if (op->completed) {\n+        ind_op_setup(op, flash_addr, num_bytes);\n+        return false;\n+    }\n+    return true;\n+}\n+\n+static void ospi_ind_op_queue_up_rd(XlnxVersalOspi *s)\n+{\n+    uint32_t num_bytes = s->regs[R_INDIRECT_READ_XFER_NUM_BYTES_REG];\n+    uint32_t flash_addr = s->regs[R_INDIRECT_READ_XFER_START_REG];\n+    bool failed;\n+\n+    failed = ospi_ind_op_add(s->rd_ind_op, &s->rx_sram, flash_addr, num_bytes);\n+    /* If two already queued set rd reject interrupt */\n+    if (failed) {\n+        set_irq(s, R_IRQ_STATUS_REG_INDIRECT_TRANSFER_REJECT_FLD_MASK);\n+    }\n+}\n+\n+static void ospi_ind_op_queue_up_wr(XlnxVersalOspi *s)\n+{\n+    uint32_t num_bytes = s->regs[R_INDIRECT_WRITE_XFER_NUM_BYTES_REG];\n+    uint32_t flash_addr = s->regs[R_INDIRECT_WRITE_XFER_START_REG];\n+    bool failed;\n+\n+    failed = ospi_ind_op_add(s->wr_ind_op, &s->tx_sram, flash_addr, num_bytes);\n+    /* If two already queued set rd reject interrupt */\n+    if (failed) {\n+        set_irq(s, R_IRQ_STATUS_REG_INDIRECT_TRANSFER_REJECT_FLD_MASK);\n+    }\n+}\n+\n+static uint64_t flash_sz(XlnxVersalOspi *s, unsigned int cs)\n+{\n+    /* Flash sizes in MB */\n+    static const uint64_t sizes[4] = { SZ_512MBIT / 8, SZ_1GBIT / 8,\n+                                       SZ_2GBIT / 8, SZ_4GBIT / 8 };\n+    uint32_t v = s->regs[R_DEV_SIZE_CONFIG_REG];\n+\n+    v >>= cs * R_DEV_SIZE_CONFIG_REG_MEM_SIZE_ON_CS0_FLD_LENGTH;\n+    return sizes[FIELD_EX32(v, DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS0_FLD)];\n+}\n+\n+static unsigned int ospi_get_block_sz(XlnxVersalOspi *s)\n+{\n+    unsigned int block_fld = ARRAY_FIELD_EX32(s->regs,\n+                                              DEV_SIZE_CONFIG_REG,\n+                                              BYTES_PER_SUBSECTOR_FLD);\n+    return 1 << block_fld;\n+}\n+\n+static unsigned int flash_blocks(XlnxVersalOspi *s, unsigned int cs)\n+{\n+    unsigned int b_sz = ospi_get_block_sz(s);\n+    unsigned int f_sz = flash_sz(s, cs);\n+\n+    return f_sz / b_sz;\n+}\n+\n+static int ospi_ahb_decoder_cs(XlnxVersalOspi *s, hwaddr addr)\n+{\n+    uint64_t end_addr = 0;\n+    int cs;\n+\n+    for (cs = 0; cs < s->num_cs; cs++) {\n+        end_addr += flash_sz(s, cs);\n+        if (addr < end_addr) {\n+            break;\n+        }\n+    }\n+\n+    if (cs == s->num_cs) {\n+        /* Address is out of range */\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                      \"OSPI flash address does not fit in configuration\\n\");\n+        return -1;\n+    }\n+    return cs;\n+}\n+\n+static void ospi_ahb_decoder_enable_cs(XlnxVersalOspi *s, hwaddr addr)\n+{\n+    int cs = ospi_ahb_decoder_cs(s, addr);\n+\n+    if (cs >= 0) {\n+        for (int i = 0; i < s->num_cs; i++) {\n+            qemu_set_irq(s->cs_lines[i], cs != i);\n+        }\n+    }\n+}\n+\n+static unsigned int single_cs(XlnxVersalOspi *s)\n+{\n+    unsigned int field = ARRAY_FIELD_EX32(s->regs,\n+                                          CONFIG_REG, PERIPH_CS_LINES_FLD);\n+\n+    /*\n+     * Below one liner is a trick that finds the rightmost zero and makes sure\n+     * all other bits are turned to 1. It is a variant of the 'Isolate the\n+     * rightmost 0-bit' trick found below at the time of writing:\n+     *\n+     * https://emre.me/computer-science/bit-manipulation-tricks/\n+     *\n+     * 4'bXXX0 -> 4'b1110\n+     * 4'bXX01 -> 4'b1101\n+     * 4'bX011 -> 4'b1011\n+     * 4'b0111 -> 4'b0111\n+     * 4'b1111 -> 4'b1111\n+     */\n+    return (field | ~(field + 1)) & 0xf;\n+}\n+\n+static void ospi_update_cs_lines(XlnxVersalOspi *s)\n+{\n+    unsigned int all_cs;\n+    int i;\n+\n+    if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, PERIPH_SEL_DEC_FLD)) {\n+        all_cs = ARRAY_FIELD_EX32(s->regs, CONFIG_REG, PERIPH_CS_LINES_FLD);\n+    } else {\n+        all_cs = single_cs(s);\n+    }\n+\n+    for (i = 0; i < s->num_cs; i++) {\n+        bool cs = (all_cs >> i) & 1;\n+\n+        qemu_set_irq(s->cs_lines[i], cs);\n+    }\n+}\n+\n+static void ospi_dac_cs(XlnxVersalOspi *s, hwaddr addr)\n+{\n+    if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENABLE_AHB_DECODER_FLD)) {\n+        ospi_ahb_decoder_enable_cs(s, addr);\n+    } else {\n+        ospi_update_cs_lines(s);\n+    }\n+}\n+\n+static void ospi_disable_cs(XlnxVersalOspi *s)\n+{\n+    int i;\n+\n+    for (i = 0; i < s->num_cs; i++) {\n+        qemu_set_irq(s->cs_lines[i], 1);\n+    }\n+}\n+\n+static void ospi_flush_txfifo(XlnxVersalOspi *s)\n+{\n+    while (!fifo8_is_empty(&s->tx_fifo)) {\n+        uint32_t tx_rx = fifo8_pop(&s->tx_fifo);\n+\n+        tx_rx = ssi_transfer(s->spi, tx_rx);\n+        fifo8_push(&s->rx_fifo, tx_rx);\n+    }\n+}\n+\n+static void ospi_tx_fifo_push_address_raw(XlnxVersalOspi *s,\n+                                          uint32_t flash_addr,\n+                                          unsigned int addr_bytes)\n+{\n+    /* Push write address */\n+    if (addr_bytes == 4) {\n+        fifo8_push(&s->tx_fifo, flash_addr >> 24);\n+    }\n+    if (addr_bytes >= 3) {\n+        fifo8_push(&s->tx_fifo, flash_addr >> 16);\n+    }\n+    if (addr_bytes >= 2) {\n+        fifo8_push(&s->tx_fifo, flash_addr >> 8);\n+    }\n+    fifo8_push(&s->tx_fifo, flash_addr);\n+}\n+\n+static void ospi_tx_fifo_push_address(XlnxVersalOspi *s, uint32_t flash_addr)\n+{\n+    /* Push write address */\n+    int addr_bytes = ospi_get_num_addr_bytes(s);\n+\n+    ospi_tx_fifo_push_address_raw(s, flash_addr, addr_bytes);\n+}\n+\n+static void ospi_tx_fifo_push_stig_addr(XlnxVersalOspi *s)\n+{\n+    uint32_t flash_addr = s->regs[R_FLASH_CMD_ADDR_REG];\n+    unsigned int addr_bytes = ospi_stig_addr_len(s);\n+\n+    ospi_tx_fifo_push_address_raw(s, flash_addr, addr_bytes);\n+}\n+\n+static void ospi_tx_fifo_push_rd_op_addr(XlnxVersalOspi *s, uint32_t flash_addr)\n+{\n+    uint8_t inst_code = ospi_get_rd_opcode(s);\n+\n+    fifo8_reset(&s->tx_fifo);\n+\n+    /* Push read opcode */\n+    fifo8_push(&s->tx_fifo, inst_code);\n+\n+    /* Push read address */\n+    ospi_tx_fifo_push_address(s, flash_addr);\n+}\n+\n+static void ospi_tx_fifo_push_stig_wr_data(XlnxVersalOspi *s)\n+{\n+    uint64_t data = s->regs[R_FLASH_WR_DATA_LOWER_REG];\n+    int wr_data_len = ospi_stig_wr_data_len(s);\n+    int i;\n+\n+    data |= (uint64_t) s->regs[R_FLASH_WR_DATA_UPPER_REG] << 32;\n+    for (i = 0; i < wr_data_len; i++) {\n+        int shift = i * 8;\n+        fifo8_push(&s->tx_fifo, data >> shift);\n+    }\n+}\n+\n+static void ospi_tx_fifo_push_stig_rd_data(XlnxVersalOspi *s)\n+{\n+    int rd_data_len;\n+    int i;\n+\n+    if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, STIG_MEM_BANK_EN_FLD)) {\n+        rd_data_len = ospi_stig_membank_rd_bytes(s);\n+    } else {\n+        rd_data_len = ospi_stig_rd_data_len(s);\n+    }\n+\n+    /* transmit second part (data) */\n+    for (i = 0; i < rd_data_len; ++i) {\n+        fifo8_push(&s->tx_fifo, 0);\n+    }\n+}\n+\n+static void ospi_rx_fifo_pop_stig_rd_data(XlnxVersalOspi *s)\n+{\n+    int size = ospi_stig_rd_data_len(s);\n+    uint8_t bytes[8] = {};\n+    int i;\n+\n+    size = MIN(fifo8_num_used(&s->rx_fifo), size);\n+\n+    assert(size <= 8);\n+\n+    for (i = 0; i < size; i++) {\n+        bytes[i] = fifo8_pop(&s->rx_fifo);\n+    }\n+\n+    s->regs[R_FLASH_RD_DATA_LOWER_REG] = ldl_le_p(bytes);\n+    s->regs[R_FLASH_RD_DATA_UPPER_REG] = ldl_le_p(bytes + 4);\n+}\n+\n+static void ospi_ind_read(XlnxVersalOspi *s, uint32_t flash_addr, uint32_t len)\n+{\n+    int i;\n+\n+    /* Create first section of read cmd */\n+    ospi_tx_fifo_push_rd_op_addr(s, flash_addr);\n+\n+    /* transmit first part */\n+    ospi_update_cs_lines(s);\n+    ospi_flush_txfifo(s);\n+\n+    fifo8_reset(&s->rx_fifo);\n+\n+    /* transmit second part (data) */\n+    for (i = 0; i < len; ++i) {\n+        fifo8_push(&s->tx_fifo, 0);\n+    }\n+    ospi_flush_txfifo(s);\n+\n+    for (i = 0; i < len; ++i) {\n+        fifo8_push(&s->rx_sram, fifo8_pop(&s->rx_fifo));\n+    }\n+\n+    /* done */\n+    ospi_disable_cs(s);\n+}\n+\n+static unsigned int ospi_dma_burst_size(XlnxVersalOspi *s)\n+{\n+    return 1 << ARRAY_FIELD_EX32(s->regs,\n+                                 DMA_PERIPH_CONFIG_REG,\n+                                 NUM_BURST_REQ_BYTES_FLD);\n+}\n+\n+static unsigned int ospi_dma_single_size(XlnxVersalOspi *s)\n+{\n+    return 1 << ARRAY_FIELD_EX32(s->regs,\n+                                 DMA_PERIPH_CONFIG_REG,\n+                                 NUM_SINGLE_REQ_BYTES_FLD);\n+}\n+\n+static void ind_rd_inc_num_done(XlnxVersalOspi *s)\n+{\n+    unsigned int done = ARRAY_FIELD_EX32(s->regs,\n+                                         INDIRECT_READ_XFER_CTRL_REG,\n+                                         NUM_IND_OPS_DONE_FLD);\n+    if (done < IND_OPS_DONE_MAX) {\n+        done++;\n+    }\n+    done &= 0x3;\n+    ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG,\n+                     NUM_IND_OPS_DONE_FLD, done);\n+}\n+\n+static void ospi_ind_rd_completed(XlnxVersalOspi *s)\n+{\n+    ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG,\n+                     IND_OPS_DONE_STATUS_FLD, 1);\n+\n+    ind_rd_inc_num_done(s);\n+    ospi_ind_op_next(s->rd_ind_op);\n+    if (ospi_ind_op_all_completed(s)) {\n+        set_irq(s, R_IRQ_STATUS_REG_INDIRECT_OP_DONE_FLD_MASK);\n+    }\n+}\n+\n+static void ospi_dma_read(XlnxVersalOspi *s)\n+{\n+    IndOp *op = s->rd_ind_op;\n+    uint32_t dma_len = op->num_bytes;\n+    uint32_t burst_sz = ospi_dma_burst_size(s);\n+    uint32_t single_sz = ospi_dma_single_size(s);\n+    uint32_t ind_trig_range;\n+    uint32_t remainder;\n+    XlnxCSUDMAClass *xcdc = XLNX_CSU_DMA_GET_CLASS(s->dma_src);\n+\n+    ind_trig_range = (1 << ARRAY_FIELD_EX32(s->regs,\n+                                            INDIRECT_TRIGGER_ADDR_RANGE_REG,\n+                                            IND_RANGE_WIDTH_FLD));\n+    remainder = dma_len % burst_sz;\n+    remainder = remainder % single_sz;\n+    if (burst_sz > ind_trig_range || single_sz > ind_trig_range ||\n+        remainder != 0) {\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                      \"OSPI DMA burst size / single size config error\\n\");\n+    }\n+\n+    s->src_dma_inprog = true;\n+    if (xcdc->read(s->dma_src, 0, dma_len) != MEMTX_OK) {\n+        qemu_log_mask(LOG_GUEST_ERROR, \"OSPI DMA configuration error\\n\");\n+    }\n+    s->src_dma_inprog = false;\n+}\n+\n+static void ospi_do_ind_read(XlnxVersalOspi *s)\n+{\n+    IndOp *op = s->rd_ind_op;\n+    uint32_t next_b;\n+    uint32_t end_b;\n+    uint32_t len;\n+    bool start_dma = IS_IND_DMA_START(op) && !s->src_dma_inprog;\n+\n+    /* Continue to read flash until we run out of space in sram */\n+    while (!ospi_ind_op_completed(op) &&\n+           !fifo8_is_full(&s->rx_sram)) {\n+        /* Read reqested number of bytes, max bytes limited to size of sram */\n+        next_b = ind_op_next_byte(op);\n+        end_b = next_b + fifo8_num_free(&s->rx_sram);\n+        end_b = MIN(end_b, ind_op_end_byte(op));\n+\n+        len = end_b - next_b;\n+        ospi_ind_read(s, next_b, len);\n+        ind_op_advance(op, len);\n+\n+        if (ospi_ind_rd_watermark_enabled(s)) {\n+            ARRAY_FIELD_DP32(s->regs, IRQ_STATUS_REG,\n+                             INDIRECT_XFER_LEVEL_BREACH_FLD, 1);\n+            set_irq(s,\n+                    R_IRQ_STATUS_REG_INDIRECT_XFER_LEVEL_BREACH_FLD_MASK);\n+        }\n+\n+        if (!s->src_dma_inprog &&\n+            ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DMA_IF_FLD)) {\n+            ospi_dma_read(s);\n+        }\n+    }\n+\n+    /* Set sram full */\n+    if (fifo8_num_used(&s->rx_sram) == RXFF_SZ) {\n+        ARRAY_FIELD_DP32(s->regs,\n+                         INDIRECT_READ_XFER_CTRL_REG, SRAM_FULL_FLD, 1);\n+        set_irq(s, R_IRQ_STATUS_REG_INDRD_SRAM_FULL_FLD_MASK);\n+    }\n+\n+    /* Signal completion if done, unless inside recursion via ospi_dma_read */\n+    if (!ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DMA_IF_FLD) || start_dma) {\n+        if (ospi_ind_op_completed(op)) {\n+            ospi_ind_rd_completed(s);\n+        }\n+    }\n+}\n+\n+/* Transmit write enable instruction */\n+static void ospi_transmit_wel(XlnxVersalOspi *s, bool ahb_decoder_cs,\n+                              hwaddr addr)\n+{\n+    fifo8_reset(&s->tx_fifo);\n+    fifo8_push(&s->tx_fifo, WREN);\n+\n+    if (ahb_decoder_cs) {\n+        ospi_ahb_decoder_enable_cs(s, addr);\n+    } else {\n+        ospi_update_cs_lines(s);\n+    }\n+\n+    ospi_flush_txfifo(s);\n+    ospi_disable_cs(s);\n+\n+    fifo8_reset(&s->rx_fifo);\n+}\n+\n+static void ospi_ind_write(XlnxVersalOspi *s, uint32_t flash_addr, uint32_t len)\n+{\n+    bool ahb_decoder_cs = false;\n+    uint8_t inst_code;\n+    int i;\n+\n+    assert(fifo8_num_used(&s->tx_sram) >= len);\n+\n+    if (!ARRAY_FIELD_EX32(s->regs, DEV_INSTR_WR_CONFIG_REG, WEL_DIS_FLD)) {\n+        ospi_transmit_wel(s, ahb_decoder_cs, 0);\n+    }\n+\n+    /* reset fifos */\n+    fifo8_reset(&s->tx_fifo);\n+    fifo8_reset(&s->rx_fifo);\n+\n+    /* Push write opcode */\n+    inst_code = ospi_get_wr_opcode(s);\n+    fifo8_push(&s->tx_fifo, inst_code);\n+\n+    /* Push write address */\n+    ospi_tx_fifo_push_address(s, flash_addr);\n+\n+    /* data */\n+    for (i = 0; i < len; i++) {\n+        fifo8_push(&s->tx_fifo, fifo8_pop(&s->tx_sram));\n+    }\n+\n+    /* transmit */\n+    ospi_update_cs_lines(s);\n+    ospi_flush_txfifo(s);\n+\n+    /* done */\n+    ospi_disable_cs(s);\n+    fifo8_reset(&s->rx_fifo);\n+}\n+\n+static void ind_wr_inc_num_done(XlnxVersalOspi *s)\n+{\n+    unsigned int done = ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG,\n+                                         NUM_IND_OPS_DONE_FLD);\n+    if (done < IND_OPS_DONE_MAX) {\n+        done++;\n+    }\n+    done &= 0x3;\n+    ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG,\n+                     NUM_IND_OPS_DONE_FLD, done);\n+}\n+\n+static void ospi_ind_wr_completed(XlnxVersalOspi *s)\n+{\n+    ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG,\n+                     IND_OPS_DONE_STATUS_FLD, 1);\n+    ind_wr_inc_num_done(s);\n+    ospi_ind_op_next(s->wr_ind_op);\n+    /* Set indirect op done interrupt if enabled */\n+    if (ospi_ind_op_all_completed(s)) {\n+        set_irq(s, R_IRQ_STATUS_REG_INDIRECT_OP_DONE_FLD_MASK);\n+    }\n+}\n+\n+static void ospi_do_indirect_write(XlnxVersalOspi *s)\n+{\n+    uint32_t write_watermark = s->regs[R_INDIRECT_WRITE_XFER_WATERMARK_REG];\n+    uint32_t pagesz = ospi_get_page_sz(s);\n+    uint32_t page_mask = ~(pagesz - 1);\n+    IndOp *op = s->wr_ind_op;\n+    uint32_t next_b;\n+    uint32_t end_b;\n+    uint32_t len;\n+\n+    /* Write out tx_fifo in maximum page sz chunks */\n+    while (!ospi_ind_op_completed(op) && fifo8_num_used(&s->tx_sram) > 0) {\n+        next_b = ind_op_next_byte(op);\n+        end_b = next_b +  MIN(fifo8_num_used(&s->tx_sram), pagesz);\n+\n+        /* Dont cross page boundary */\n+        if ((end_b & page_mask) > next_b) {\n+            end_b &= page_mask;\n+        }\n+\n+        len = end_b - next_b;\n+        len = MIN(len, op->num_bytes - op->done_bytes);\n+        ospi_ind_write(s, next_b, len);\n+        ind_op_advance(op, len);\n+    }\n+\n+    /*\n+     * Always set indirect transfer level breached interrupt if enabled\n+     * (write watermark > 0) since the tx_sram always will be emptied\n+     */\n+    if (write_watermark > 0) {\n+        set_irq(s, R_IRQ_STATUS_REG_INDIRECT_XFER_LEVEL_BREACH_FLD_MASK);\n+    }\n+\n+    /* Signal completions if done */\n+    if (ospi_ind_op_completed(op)) {\n+        ospi_ind_wr_completed(s);\n+    }\n+}\n+\n+static void ospi_stig_fill_membank(XlnxVersalOspi *s)\n+{\n+    int num_rd_bytes = ospi_stig_membank_rd_bytes(s);\n+    int idx = num_rd_bytes - 8; /* first of last 8 */\n+    int i;\n+\n+    for (i = 0; i < num_rd_bytes; i++) {\n+        s->stig_membank[i] = fifo8_pop(&s->rx_fifo);\n+    }\n+\n+    g_assert((idx + 4) < ARRAY_SIZE(s->stig_membank));\n+\n+    /* Fill in lower upper regs */\n+    s->regs[R_FLASH_RD_DATA_LOWER_REG] = ldl_le_p(&s->stig_membank[idx]);\n+    s->regs[R_FLASH_RD_DATA_UPPER_REG] = ldl_le_p(&s->stig_membank[idx + 4]);\n+}\n+\n+static void ospi_stig_cmd_exec(XlnxVersalOspi *s)\n+{\n+    uint8_t inst_code;\n+\n+    /* Reset fifos */\n+    fifo8_reset(&s->tx_fifo);\n+    fifo8_reset(&s->rx_fifo);\n+\n+    /* Push write opcode */\n+    inst_code = ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, CMD_OPCODE_FLD);\n+    fifo8_push(&s->tx_fifo, inst_code);\n+\n+    /* Push address if enabled */\n+    if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, ENB_COMD_ADDR_FLD)) {\n+        ospi_tx_fifo_push_stig_addr(s);\n+    }\n+\n+    /* Enable cs */\n+    ospi_update_cs_lines(s);\n+\n+    /* Data */\n+    if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, ENB_WRITE_DATA_FLD)) {\n+        ospi_tx_fifo_push_stig_wr_data(s);\n+    } else if (ARRAY_FIELD_EX32(s->regs,\n+                                FLASH_CMD_CTRL_REG, ENB_READ_DATA_FLD)) {\n+        /* transmit first part */\n+        ospi_flush_txfifo(s);\n+        fifo8_reset(&s->rx_fifo);\n+        ospi_tx_fifo_push_stig_rd_data(s);\n+    }\n+\n+    /* Transmit */\n+    ospi_flush_txfifo(s);\n+    ospi_disable_cs(s);\n+\n+    if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, ENB_READ_DATA_FLD)) {\n+        if (ARRAY_FIELD_EX32(s->regs,\n+                             FLASH_CMD_CTRL_REG, STIG_MEM_BANK_EN_FLD)) {\n+            ospi_stig_fill_membank(s);\n+        } else {\n+            ospi_rx_fifo_pop_stig_rd_data(s);\n+        }\n+    }\n+}\n+\n+static uint32_t ospi_block_address(XlnxVersalOspi *s, unsigned int block)\n+{\n+    unsigned int block_sz = ospi_get_block_sz(s);\n+    unsigned int cs = 0;\n+    uint32_t addr = 0;\n+\n+    while (cs < s->num_cs && block >= flash_blocks(s, cs)) {\n+        block -= flash_blocks(s, 0);\n+        addr += flash_sz(s, cs);\n+    }\n+    addr += block * block_sz;\n+    return addr;\n+}\n+\n+static uint32_t ospi_get_wr_prot_addr_low(XlnxVersalOspi *s)\n+{\n+    unsigned int block = s->regs[R_LOWER_WR_PROT_REG];\n+\n+    return ospi_block_address(s, block);\n+}\n+\n+static uint32_t ospi_get_wr_prot_addr_upper(XlnxVersalOspi *s)\n+{\n+    unsigned int block = s->regs[R_UPPER_WR_PROT_REG];\n+\n+    /* Get address of first block out of defined range */\n+    return ospi_block_address(s, block + 1);\n+}\n+\n+static bool ospi_is_write_protected(XlnxVersalOspi *s, hwaddr addr)\n+{\n+    uint32_t wr_prot_addr_upper = ospi_get_wr_prot_addr_upper(s);\n+    uint32_t wr_prot_addr_low = ospi_get_wr_prot_addr_low(s);\n+    bool in_range = false;\n+\n+    if (addr >= wr_prot_addr_low && addr < wr_prot_addr_upper) {\n+        in_range = true;\n+    }\n+\n+    if (ARRAY_FIELD_EX32(s->regs, WR_PROT_CTRL_REG, INV_FLD)) {\n+        in_range = !in_range;\n+    }\n+    return in_range;\n+}\n+\n+static uint64_t ospi_rx_sram_read(XlnxVersalOspi *s, unsigned int size)\n+{\n+    uint8_t bytes[8] = {};\n+    int i;\n+\n+    if (size < 4 && fifo8_num_used(&s->rx_sram) >= 4) {\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                      \"OSPI only last read of internal \"\n+                      \"sram is allowed to be < 32 bits\\n\");\n+    }\n+\n+    size = MIN(fifo8_num_used(&s->rx_sram), size);\n+\n+    assert(size <= 8);\n+\n+    for (i = 0; i < size; i++) {\n+        bytes[i] = fifo8_pop(&s->rx_sram);\n+    }\n+\n+    return ldq_le_p(bytes);\n+}\n+\n+static void ospi_tx_sram_write(XlnxVersalOspi *s, uint64_t value,\n+                               unsigned int size)\n+{\n+    int i;\n+    for (i = 0; i < size && !fifo8_is_full(&s->tx_sram); i++) {\n+        fifo8_push(&s->tx_sram, value >> 8 * i);\n+    }\n+}\n+\n+static uint64_t ospi_do_dac_read(void *opaque, hwaddr addr, unsigned int size)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);\n+    uint8_t bytes[8] = {};\n+    int i;\n+\n+    /* Create first section of read cmd */\n+    ospi_tx_fifo_push_rd_op_addr(s, (uint32_t) addr);\n+\n+    /* Enable cs and transmit first part */\n+    ospi_dac_cs(s, addr);\n+    ospi_flush_txfifo(s);\n+\n+    fifo8_reset(&s->rx_fifo);\n+\n+    /* transmit second part (data) */\n+    for (i = 0; i < size; ++i) {\n+        fifo8_push(&s->tx_fifo, 0);\n+    }\n+    ospi_flush_txfifo(s);\n+\n+    /* fill in result */\n+    size = MIN(fifo8_num_used(&s->rx_fifo), size);\n+\n+    assert(size <= 8);\n+\n+    for (i = 0; i < size; i++) {\n+        bytes[i] = fifo8_pop(&s->rx_fifo);\n+    }\n+\n+    /* done */\n+    ospi_disable_cs(s);\n+\n+    return ldq_le_p(bytes);\n+}\n+\n+static void ospi_do_dac_write(void *opaque,\n+                              hwaddr addr,\n+                              uint64_t value,\n+                              unsigned int size)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);\n+    bool ahb_decoder_cs = ARRAY_FIELD_EX32(s->regs, CONFIG_REG,\n+                                           ENABLE_AHB_DECODER_FLD);\n+    uint8_t inst_code;\n+    unsigned int i;\n+\n+    if (!ARRAY_FIELD_EX32(s->regs, DEV_INSTR_WR_CONFIG_REG, WEL_DIS_FLD)) {\n+        ospi_transmit_wel(s, ahb_decoder_cs, addr);\n+    }\n+\n+    /* reset fifos */\n+    fifo8_reset(&s->tx_fifo);\n+    fifo8_reset(&s->rx_fifo);\n+\n+    /* Push write opcode */\n+    inst_code = ospi_get_wr_opcode(s);\n+    fifo8_push(&s->tx_fifo, inst_code);\n+\n+    /* Push write address */\n+    ospi_tx_fifo_push_address(s, addr);\n+\n+    /* data */\n+    for (i = 0; i < size; i++) {\n+        fifo8_push(&s->tx_fifo, value >> 8 * i);\n+    }\n+\n+    /* Enable cs and transmit */\n+    ospi_dac_cs(s, addr);\n+    ospi_flush_txfifo(s);\n+    ospi_disable_cs(s);\n+\n+    fifo8_reset(&s->rx_fifo);\n+}\n+\n+static void flash_cmd_ctrl_mem_reg_post_write(RegisterInfo *reg,\n+                                              uint64_t val)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);\n+    if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD)) {\n+        if (ARRAY_FIELD_EX32(s->regs,\n+                             FLASH_COMMAND_CTRL_MEM_REG,\n+                             TRIGGER_MEM_BANK_REQ_FLD)) {\n+            ospi_stig_membank_req(s);\n+            ARRAY_FIELD_DP32(s->regs, FLASH_COMMAND_CTRL_MEM_REG,\n+                             TRIGGER_MEM_BANK_REQ_FLD, 0);\n+        }\n+    }\n+}\n+\n+static void flash_cmd_ctrl_reg_post_write(RegisterInfo *reg, uint64_t val)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);\n+\n+    if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD) &&\n+        ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, CMD_EXEC_FLD)) {\n+        ospi_stig_cmd_exec(s);\n+        set_irq(s, R_IRQ_STATUS_REG_STIG_REQ_INT_FLD_MASK);\n+        ARRAY_FIELD_DP32(s->regs, FLASH_CMD_CTRL_REG, CMD_EXEC_FLD, 0);\n+    }\n+}\n+\n+static uint64_t ind_wr_dec_num_done(XlnxVersalOspi *s, uint64_t val)\n+{\n+    unsigned int done = ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG,\n+                                         NUM_IND_OPS_DONE_FLD);\n+    done--;\n+    done &= 0x3;\n+    val = FIELD_DP32(val, INDIRECT_WRITE_XFER_CTRL_REG,\n+                     NUM_IND_OPS_DONE_FLD, done);\n+    return val;\n+}\n+\n+static bool ind_wr_clearing_op_done(XlnxVersalOspi *s, uint64_t new_val)\n+{\n+    bool set_in_reg = ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG,\n+                                       IND_OPS_DONE_STATUS_FLD);\n+    bool set_in_new_val = FIELD_EX32(new_val, INDIRECT_WRITE_XFER_CTRL_REG,\n+                                     IND_OPS_DONE_STATUS_FLD);\n+    /* return true if clearing bit */\n+    return set_in_reg && !set_in_new_val;\n+}\n+\n+static uint64_t ind_wr_xfer_ctrl_reg_pre_write(RegisterInfo *reg,\n+                                               uint64_t val)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);\n+\n+    if (ind_wr_clearing_op_done(s, val)) {\n+        val = ind_wr_dec_num_done(s, val);\n+    }\n+    return val;\n+}\n+\n+static void ind_wr_xfer_ctrl_reg_post_write(RegisterInfo *reg, uint64_t val)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);\n+\n+    if (s->ind_write_disabled) {\n+        return;\n+    }\n+\n+    if (ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, START_FLD)) {\n+        ospi_ind_op_queue_up_wr(s);\n+        ospi_do_indirect_write(s);\n+        ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, START_FLD, 0);\n+    }\n+\n+    if (ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, CANCEL_FLD)) {\n+        ospi_ind_op_cancel(s->wr_ind_op);\n+        fifo8_reset(&s->tx_sram);\n+        ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, CANCEL_FLD, 0);\n+    }\n+}\n+\n+static uint64_t ind_wr_xfer_ctrl_reg_post_read(RegisterInfo *reg,\n+                                               uint64_t val)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);\n+    IndOp *op = s->wr_ind_op;\n+\n+    /* Check if ind ops is ongoing */\n+    if (!ospi_ind_op_completed(&op[0])) {\n+        /* Check if two ind ops are queued */\n+        if (!ospi_ind_op_completed(&op[1])) {\n+            val = FIELD_DP32(val, INDIRECT_WRITE_XFER_CTRL_REG,\n+                             WR_QUEUED_FLD, 1);\n+        }\n+        val = FIELD_DP32(val, INDIRECT_WRITE_XFER_CTRL_REG, WR_STATUS_FLD, 1);\n+    }\n+    return val;\n+}\n+\n+static uint64_t ind_rd_dec_num_done(XlnxVersalOspi *s, uint64_t val)\n+{\n+    unsigned int done = ARRAY_FIELD_EX32(s->regs, INDIRECT_READ_XFER_CTRL_REG,\n+                                         NUM_IND_OPS_DONE_FLD);\n+    done--;\n+    done &= 0x3;\n+    val = FIELD_DP32(val, INDIRECT_READ_XFER_CTRL_REG,\n+                     NUM_IND_OPS_DONE_FLD, done);\n+    return val;\n+}\n+\n+static uint64_t ind_rd_xfer_ctrl_reg_pre_write(RegisterInfo *reg,\n+                                               uint64_t val)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);\n+\n+    if (FIELD_EX32(val, INDIRECT_READ_XFER_CTRL_REG,\n+                   IND_OPS_DONE_STATUS_FLD)) {\n+        val = ind_rd_dec_num_done(s, val);\n+        val &= ~R_INDIRECT_READ_XFER_CTRL_REG_IND_OPS_DONE_STATUS_FLD_MASK;\n+    }\n+    return val;\n+}\n+\n+static void ind_rd_xfer_ctrl_reg_post_write(RegisterInfo *reg, uint64_t val)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);\n+\n+    if (ARRAY_FIELD_EX32(s->regs, INDIRECT_READ_XFER_CTRL_REG, START_FLD)) {\n+        ospi_ind_op_queue_up_rd(s);\n+        ospi_do_ind_read(s);\n+        ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG, START_FLD, 0);\n+    }\n+\n+    if (ARRAY_FIELD_EX32(s->regs, INDIRECT_READ_XFER_CTRL_REG, CANCEL_FLD)) {\n+        ospi_ind_op_cancel(s->rd_ind_op);\n+        fifo8_reset(&s->rx_sram);\n+        ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG, CANCEL_FLD, 0);\n+    }\n+}\n+\n+static uint64_t ind_rd_xfer_ctrl_reg_post_read(RegisterInfo *reg,\n+                                               uint64_t val)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);\n+    IndOp *op = s->rd_ind_op;\n+\n+    /* Check if ind ops is ongoing */\n+    if (!ospi_ind_op_completed(&op[0])) {\n+        /* Check if two ind ops are queued */\n+        if (!ospi_ind_op_completed(&op[1])) {\n+            val = FIELD_DP32(val, INDIRECT_READ_XFER_CTRL_REG,\n+                             RD_QUEUED_FLD, 1);\n+        }\n+        val = FIELD_DP32(val, INDIRECT_READ_XFER_CTRL_REG, RD_STATUS_FLD, 1);\n+    }\n+    return val;\n+}\n+\n+static uint64_t sram_fill_reg_post_read(RegisterInfo *reg, uint64_t val)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);\n+    val = ((fifo8_num_used(&s->tx_sram) & 0xFFFF) << 16) |\n+          (fifo8_num_used(&s->rx_sram) & 0xFFFF);\n+    return val;\n+}\n+\n+static uint64_t dll_obs_upper_reg_post_read(RegisterInfo *reg, uint64_t val)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);\n+    uint32_t rx_dec_out;\n+\n+    rx_dec_out = FIELD_EX32(val, DLL_OBSERVABLE_UPPER_REG,\n+                            DLL_OBSERVABLE__UPPER_RX_DECODER_OUTPUT_FLD);\n+\n+    if (rx_dec_out < MAX_RX_DEC_OUT) {\n+        ARRAY_FIELD_DP32(s->regs, DLL_OBSERVABLE_UPPER_REG,\n+                         DLL_OBSERVABLE__UPPER_RX_DECODER_OUTPUT_FLD,\n+                         rx_dec_out + 1);\n+    }\n+\n+    return val;\n+}\n+\n+\n+static void xlnx_versal_ospi_reset(DeviceState *dev)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(dev);\n+    unsigned int i;\n+\n+    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {\n+        register_reset(&s->regs_info[i]);\n+    }\n+\n+    fifo8_reset(&s->rx_fifo);\n+    fifo8_reset(&s->tx_fifo);\n+    fifo8_reset(&s->rx_sram);\n+    fifo8_reset(&s->tx_sram);\n+\n+    s->rd_ind_op[0].completed = true;\n+    s->rd_ind_op[1].completed = true;\n+    s->wr_ind_op[0].completed = true;\n+    s->wr_ind_op[1].completed = true;\n+    ARRAY_FIELD_DP32(s->regs, DLL_OBSERVABLE_LOWER_REG,\n+                     DLL_OBSERVABLE_LOWER_DLL_LOCK_FLD, 1);\n+    ARRAY_FIELD_DP32(s->regs, DLL_OBSERVABLE_LOWER_REG,\n+                     DLL_OBSERVABLE_LOWER_LOOPBACK_LOCK_FLD, 1);\n+}\n+\n+static RegisterAccessInfo ospi_regs_info[] = {\n+    {   .name = \"CONFIG_REG\",\n+        .addr = A_CONFIG_REG,\n+        .reset = 0x80780081,\n+        .ro = 0x9c000000,\n+    },{ .name = \"DEV_INSTR_RD_CONFIG_REG\",\n+        .addr = A_DEV_INSTR_RD_CONFIG_REG,\n+        .reset = 0x3,\n+        .ro = 0xe0ecc800,\n+    },{ .name = \"DEV_INSTR_WR_CONFIG_REG\",\n+        .addr = A_DEV_INSTR_WR_CONFIG_REG,\n+        .reset = 0x2,\n+        .ro = 0xe0fcce00,\n+    },{ .name = \"DEV_DELAY_REG\",\n+        .addr = A_DEV_DELAY_REG,\n+    },{ .name = \"RD_DATA_CAPTURE_REG\",\n+        .addr = A_RD_DATA_CAPTURE_REG,\n+        .reset = 0x1,\n+        .ro = 0xfff0fec0,\n+    },{ .name = \"DEV_SIZE_CONFIG_REG\",\n+        .addr = A_DEV_SIZE_CONFIG_REG,\n+        .reset = 0x101002,\n+        .ro = 0xe0000000,\n+    },{ .name = \"SRAM_PARTITION_CFG_REG\",\n+        .addr = A_SRAM_PARTITION_CFG_REG,\n+        .reset = 0x80,\n+        .ro = 0xffffff00,\n+    },{ .name = \"IND_AHB_ADDR_TRIGGER_REG\",\n+        .addr = A_IND_AHB_ADDR_TRIGGER_REG,\n+    },{ .name = \"DMA_PERIPH_CONFIG_REG\",\n+        .addr = A_DMA_PERIPH_CONFIG_REG,\n+        .ro = 0xfffff0f0,\n+    },{ .name = \"REMAP_ADDR_REG\",\n+        .addr = A_REMAP_ADDR_REG,\n+    },{ .name = \"MODE_BIT_CONFIG_REG\",\n+        .addr = A_MODE_BIT_CONFIG_REG,\n+        .reset = 0x200,\n+        .ro = 0xffff7800,\n+    },{ .name = \"SRAM_FILL_REG\",\n+        .addr = A_SRAM_FILL_REG,\n+        .ro = 0xffffffff,\n+        .post_read = sram_fill_reg_post_read,\n+    },{ .name = \"TX_THRESH_REG\",\n+        .addr = A_TX_THRESH_REG,\n+        .reset = 0x1,\n+        .ro = 0xffffffe0,\n+    },{ .name = \"RX_THRESH_REG\",\n+        .addr = A_RX_THRESH_REG,\n+        .reset = 0x1,\n+        .ro = 0xffffffe0,\n+    },{ .name = \"WRITE_COMPLETION_CTRL_REG\",\n+        .addr = A_WRITE_COMPLETION_CTRL_REG,\n+        .reset = 0x10005,\n+        .ro = 0x1800,\n+    },{ .name = \"NO_OF_POLLS_BEF_EXP_REG\",\n+        .addr = A_NO_OF_POLLS_BEF_EXP_REG,\n+        .reset = 0xffffffff,\n+    },{ .name = \"IRQ_STATUS_REG\",\n+        .addr = A_IRQ_STATUS_REG,\n+        .ro = 0xfff08000,\n+        .w1c = 0xf7fff,\n+    },{ .name = \"IRQ_MASK_REG\",\n+        .addr = A_IRQ_MASK_REG,\n+        .ro = 0xfff08000,\n+    },{ .name = \"LOWER_WR_PROT_REG\",\n+        .addr = A_LOWER_WR_PROT_REG,\n+    },{ .name = \"UPPER_WR_PROT_REG\",\n+        .addr = A_UPPER_WR_PROT_REG,\n+    },{ .name = \"WR_PROT_CTRL_REG\",\n+        .addr = A_WR_PROT_CTRL_REG,\n+        .ro = 0xfffffffc,\n+    },{ .name = \"INDIRECT_READ_XFER_CTRL_REG\",\n+        .addr = A_INDIRECT_READ_XFER_CTRL_REG,\n+        .ro = 0xffffffd4,\n+        .w1c = 0x08,\n+        .pre_write = ind_rd_xfer_ctrl_reg_pre_write,\n+        .post_write = ind_rd_xfer_ctrl_reg_post_write,\n+        .post_read = ind_rd_xfer_ctrl_reg_post_read,\n+    },{ .name = \"INDIRECT_READ_XFER_WATERMARK_REG\",\n+        .addr = A_INDIRECT_READ_XFER_WATERMARK_REG,\n+    },{ .name = \"INDIRECT_READ_XFER_START_REG\",\n+        .addr = A_INDIRECT_READ_XFER_START_REG,\n+    },{ .name = \"INDIRECT_READ_XFER_NUM_BYTES_REG\",\n+        .addr = A_INDIRECT_READ_XFER_NUM_BYTES_REG,\n+    },{ .name = \"INDIRECT_WRITE_XFER_CTRL_REG\",\n+        .addr = A_INDIRECT_WRITE_XFER_CTRL_REG,\n+        .ro = 0xffffffdc,\n+        .w1c = 0x20,\n+        .pre_write = ind_wr_xfer_ctrl_reg_pre_write,\n+        .post_write = ind_wr_xfer_ctrl_reg_post_write,\n+        .post_read = ind_wr_xfer_ctrl_reg_post_read,\n+    },{ .name = \"INDIRECT_WRITE_XFER_WATERMARK_REG\",\n+        .addr = A_INDIRECT_WRITE_XFER_WATERMARK_REG,\n+        .reset = 0xffffffff,\n+    },{ .name = \"INDIRECT_WRITE_XFER_START_REG\",\n+        .addr = A_INDIRECT_WRITE_XFER_START_REG,\n+    },{ .name = \"INDIRECT_WRITE_XFER_NUM_BYTES_REG\",\n+        .addr = A_INDIRECT_WRITE_XFER_NUM_BYTES_REG,\n+    },{ .name = \"INDIRECT_TRIGGER_ADDR_RANGE_REG\",\n+        .addr = A_INDIRECT_TRIGGER_ADDR_RANGE_REG,\n+        .reset = 0x4,\n+        .ro = 0xfffffff0,\n+    },{ .name = \"FLASH_COMMAND_CTRL_MEM_REG\",\n+        .addr = A_FLASH_COMMAND_CTRL_MEM_REG,\n+        .ro = 0xe008fffe,\n+        .post_write = flash_cmd_ctrl_mem_reg_post_write,\n+    },{ .name = \"FLASH_CMD_CTRL_REG\",\n+        .addr = A_FLASH_CMD_CTRL_REG,\n+        .ro = 0x7a,\n+        .post_write = flash_cmd_ctrl_reg_post_write,\n+    },{ .name = \"FLASH_CMD_ADDR_REG\",\n+        .addr = A_FLASH_CMD_ADDR_REG,\n+    },{ .name = \"FLASH_RD_DATA_LOWER_REG\",\n+        .addr = A_FLASH_RD_DATA_LOWER_REG,\n+        .ro = 0xffffffff,\n+    },{ .name = \"FLASH_RD_DATA_UPPER_REG\",\n+        .addr = A_FLASH_RD_DATA_UPPER_REG,\n+        .ro = 0xffffffff,\n+    },{ .name = \"FLASH_WR_DATA_LOWER_REG\",\n+        .addr = A_FLASH_WR_DATA_LOWER_REG,\n+    },{ .name = \"FLASH_WR_DATA_UPPER_REG\",\n+        .addr = A_FLASH_WR_DATA_UPPER_REG,\n+    },{ .name = \"POLLING_FLASH_STATUS_REG\",\n+        .addr = A_POLLING_FLASH_STATUS_REG,\n+        .ro = 0xfff0ffff,\n+    },{ .name = \"PHY_CONFIGURATION_REG\",\n+        .addr = A_PHY_CONFIGURATION_REG,\n+        .reset = 0x40000000,\n+        .ro = 0x1f80ff80,\n+    },{ .name = \"PHY_MASTER_CONTROL_REG\",\n+        .addr = A_PHY_MASTER_CONTROL_REG,\n+        .reset = 0x800000,\n+        .ro = 0xfe08ff80,\n+    },{ .name = \"DLL_OBSERVABLE_LOWER_REG\",\n+        .addr = A_DLL_OBSERVABLE_LOWER_REG,\n+        .ro = 0xffffffff,\n+    },{ .name = \"DLL_OBSERVABLE_UPPER_REG\",\n+        .addr = A_DLL_OBSERVABLE_UPPER_REG,\n+        .ro = 0xffffffff,\n+        .post_read = dll_obs_upper_reg_post_read,\n+    },{ .name = \"OPCODE_EXT_LOWER_REG\",\n+        .addr = A_OPCODE_EXT_LOWER_REG,\n+        .reset = 0x13edfa00,\n+    },{ .name = \"OPCODE_EXT_UPPER_REG\",\n+        .addr = A_OPCODE_EXT_UPPER_REG,\n+        .reset = 0x6f90000,\n+        .ro = 0xffff,\n+    },{ .name = \"MODULE_ID_REG\",\n+        .addr = A_MODULE_ID_REG,\n+        .reset = 0x300,\n+        .ro = 0xffffffff,\n+    }\n+};\n+\n+/* Return dev-obj from reg-region created by register_init_block32 */\n+static XlnxVersalOspi *xilinx_ospi_of_mr(void *mr_accessor)\n+{\n+    RegisterInfoArray *reg_array = mr_accessor;\n+    Object *dev;\n+\n+    dev = reg_array->mem.owner;\n+    assert(dev);\n+\n+    return XILINX_VERSAL_OSPI(dev);\n+}\n+\n+static void ospi_write(void *opaque, hwaddr addr, uint64_t value,\n+        unsigned int size)\n+{\n+    XlnxVersalOspi *s = xilinx_ospi_of_mr(opaque);\n+\n+    register_write_memory(opaque, addr, value, size);\n+    ospi_update_irq_line(s);\n+}\n+\n+static const MemoryRegionOps ospi_ops = {\n+    .read = register_read_memory,\n+    .write = ospi_write,\n+    .endianness = DEVICE_LITTLE_ENDIAN,\n+    .valid = {\n+        .min_access_size = 4,\n+        .max_access_size = 4,\n+    },\n+};\n+\n+static uint64_t ospi_indac_read(void *opaque, unsigned int size)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);\n+    uint64_t ret = ospi_rx_sram_read(s, size);\n+\n+    if (!ospi_ind_op_completed(s->rd_ind_op)) {\n+        ospi_do_ind_read(s);\n+    }\n+    return ret;\n+}\n+\n+static void ospi_indac_write(void *opaque, uint64_t value, unsigned int size)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);\n+\n+    g_assert(!s->ind_write_disabled);\n+\n+    if (!ospi_ind_op_completed(s->wr_ind_op)) {\n+        ospi_tx_sram_write(s, value, size);\n+        ospi_do_indirect_write(s);\n+    } else {\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+            \"OSPI wr into indac area while no ongoing indac wr\\n\");\n+    }\n+}\n+\n+static bool is_inside_indac_range(XlnxVersalOspi *s, hwaddr addr)\n+{\n+    uint32_t range_start;\n+    uint32_t range_end;\n+\n+    if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DMA_IF_FLD)) {\n+        return true;\n+    }\n+\n+    range_start = s->regs[R_IND_AHB_ADDR_TRIGGER_REG];\n+    range_end = range_start +\n+                (1 << ARRAY_FIELD_EX32(s->regs,\n+                                       INDIRECT_TRIGGER_ADDR_RANGE_REG,\n+                                       IND_RANGE_WIDTH_FLD));\n+\n+    addr += s->regs[R_IND_AHB_ADDR_TRIGGER_REG] & 0xF0000000;\n+\n+    return addr >= range_start && addr < range_end;\n+}\n+\n+static bool ospi_is_indac_active(XlnxVersalOspi *s)\n+{\n+    /*\n+     * When dac and indac cannot be active at the same time,\n+     * return true when dac is disabled.\n+     */\n+    return s->dac_with_indac || !s->dac_enable;\n+}\n+\n+static uint64_t ospi_dac_read(void *opaque, hwaddr addr, unsigned int size)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);\n+\n+    if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD)) {\n+        if (ospi_is_indac_active(s) &&\n+            is_inside_indac_range(s, addr)) {\n+            return ospi_indac_read(s, size);\n+        }\n+        if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DIR_ACC_CTLR_FLD)\n+            && s->dac_enable) {\n+            if (ARRAY_FIELD_EX32(s->regs,\n+                                 CONFIG_REG, ENB_AHB_ADDR_REMAP_FLD)) {\n+                addr += s->regs[R_REMAP_ADDR_REG];\n+            }\n+            return ospi_do_dac_read(opaque, addr, size);\n+        } else {\n+            qemu_log_mask(LOG_GUEST_ERROR, \"OSPI AHB rd while DAC disabled\\n\");\n+        }\n+    } else {\n+        qemu_log_mask(LOG_GUEST_ERROR, \"OSPI AHB rd while OSPI disabled\\n\");\n+    }\n+\n+    return 0;\n+}\n+\n+static void ospi_dac_write(void *opaque, hwaddr addr, uint64_t value,\n+                           unsigned int size)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);\n+\n+    if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD)) {\n+        if (ospi_is_indac_active(s) &&\n+            !s->ind_write_disabled &&\n+            is_inside_indac_range(s, addr)) {\n+            return ospi_indac_write(s, value, size);\n+        }\n+        if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DIR_ACC_CTLR_FLD) &&\n+            s->dac_enable) {\n+            if (ARRAY_FIELD_EX32(s->regs,\n+                                 CONFIG_REG, ENB_AHB_ADDR_REMAP_FLD)) {\n+                addr += s->regs[R_REMAP_ADDR_REG];\n+            }\n+            /* Check if addr is write protected */\n+            if (ARRAY_FIELD_EX32(s->regs, WR_PROT_CTRL_REG, ENB_FLD) &&\n+                ospi_is_write_protected(s, addr)) {\n+                set_irq(s, R_IRQ_STATUS_REG_PROT_WR_ATTEMPT_FLD_MASK);\n+                ospi_update_irq_line(s);\n+                qemu_log_mask(LOG_GUEST_ERROR,\n+                              \"OSPI writing into write protected area\\n\");\n+                return;\n+            }\n+            ospi_do_dac_write(opaque, addr, value, size);\n+        } else {\n+            qemu_log_mask(LOG_GUEST_ERROR, \"OSPI AHB wr while DAC disabled\\n\");\n+        }\n+    } else {\n+        qemu_log_mask(LOG_GUEST_ERROR, \"OSPI AHB wr while OSPI disabled\\n\");\n+    }\n+}\n+\n+static const MemoryRegionOps ospi_dac_ops = {\n+    .read = ospi_dac_read,\n+    .write = ospi_dac_write,\n+    .endianness = DEVICE_LITTLE_ENDIAN,\n+    .valid = {\n+        .min_access_size = 4,\n+        .max_access_size = 4,\n+    },\n+};\n+\n+static void ospi_update_dac_status(void *opaque, int n, int level)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);\n+\n+    s->dac_enable = level;\n+}\n+\n+static void xlnx_versal_ospi_realize(DeviceState *dev, Error **errp)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(dev);\n+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);\n+\n+    s->num_cs = 4;\n+    s->spi = ssi_create_bus(dev, \"spi0\");\n+    s->cs_lines = g_new0(qemu_irq, s->num_cs);\n+    for (int i = 0; i < s->num_cs; ++i) {\n+        sysbus_init_irq(sbd, &s->cs_lines[i]);\n+    }\n+\n+    fifo8_create(&s->rx_fifo, RXFF_SZ);\n+    fifo8_create(&s->tx_fifo, TXFF_SZ);\n+    fifo8_create(&s->rx_sram, RXFF_SZ);\n+    fifo8_create(&s->tx_sram, TXFF_SZ);\n+}\n+\n+static void xlnx_versal_ospi_init(Object *obj)\n+{\n+    XlnxVersalOspi *s = XILINX_VERSAL_OSPI(obj);\n+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);\n+    DeviceState *dev = DEVICE(obj);\n+    RegisterInfoArray *reg_array;\n+\n+    memory_region_init(&s->iomem, obj, TYPE_XILINX_VERSAL_OSPI,\n+                       XILINX_VERSAL_OSPI_R_MAX * 4);\n+    reg_array =\n+        register_init_block32(DEVICE(obj), ospi_regs_info,\n+                              ARRAY_SIZE(ospi_regs_info),\n+                              s->regs_info, s->regs,\n+                              &ospi_ops,\n+                              XILINX_VERSAL_OSPI_ERR_DEBUG,\n+                              XILINX_VERSAL_OSPI_R_MAX * 4);\n+    memory_region_add_subregion(&s->iomem, 0x0, &reg_array->mem);\n+    sysbus_init_mmio(sbd, &s->iomem);\n+\n+    memory_region_init_io(&s->iomem_dac, obj, &ospi_dac_ops, s,\n+                          TYPE_XILINX_VERSAL_OSPI \"-dac\", 0x20000000);\n+    sysbus_init_mmio(sbd, &s->iomem_dac);\n+\n+    sysbus_init_irq(sbd, &s->irq);\n+\n+    object_property_add_link(obj, \"dma-src\", TYPE_XLNX_CSU_DMA,\n+                             (Object **)&s->dma_src,\n+                             object_property_allow_set_link,\n+                             OBJ_PROP_LINK_STRONG);\n+\n+    qdev_init_gpio_in_named(dev, ospi_update_dac_status, \"ospi-mux-sel\", 1);\n+}\n+\n+static const VMStateDescription vmstate_ind_op = {\n+    .name = \"OSPIIndOp\",\n+    .version_id = 1,\n+    .minimum_version_id = 1,\n+    .fields = (VMStateField[]) {\n+        VMSTATE_UINT32(flash_addr, IndOp),\n+        VMSTATE_UINT32(num_bytes, IndOp),\n+        VMSTATE_UINT32(done_bytes, IndOp),\n+        VMSTATE_BOOL(completed, IndOp),\n+        VMSTATE_END_OF_LIST()\n+    }\n+};\n+\n+static const VMStateDescription vmstate_xlnx_versal_ospi = {\n+    .name = TYPE_XILINX_VERSAL_OSPI,\n+    .version_id = 1,\n+    .minimum_version_id = 1,\n+    .minimum_version_id_old = 1,\n+    .fields = (VMStateField[]) {\n+        VMSTATE_FIFO8(rx_fifo, XlnxVersalOspi),\n+        VMSTATE_FIFO8(tx_fifo, XlnxVersalOspi),\n+        VMSTATE_FIFO8(rx_sram, XlnxVersalOspi),\n+        VMSTATE_FIFO8(tx_sram, XlnxVersalOspi),\n+        VMSTATE_BOOL(ind_write_disabled, XlnxVersalOspi),\n+        VMSTATE_BOOL(dac_with_indac, XlnxVersalOspi),\n+        VMSTATE_BOOL(dac_enable, XlnxVersalOspi),\n+        VMSTATE_BOOL(src_dma_inprog, XlnxVersalOspi),\n+        VMSTATE_STRUCT_ARRAY(rd_ind_op, XlnxVersalOspi, 2, 1,\n+                             vmstate_ind_op, IndOp),\n+        VMSTATE_STRUCT_ARRAY(wr_ind_op, XlnxVersalOspi, 2, 1,\n+                             vmstate_ind_op, IndOp),\n+        VMSTATE_UINT32_ARRAY(regs, XlnxVersalOspi, XILINX_VERSAL_OSPI_R_MAX),\n+        VMSTATE_UINT8_ARRAY(stig_membank, XlnxVersalOspi, 512),\n+        VMSTATE_END_OF_LIST(),\n+    }\n+};\n+\n+static Property xlnx_versal_ospi_properties[] = {\n+    DEFINE_PROP_BOOL(\"dac-with-indac\", XlnxVersalOspi, dac_with_indac, false),\n+    DEFINE_PROP_BOOL(\"indac-write-disabled\", XlnxVersalOspi,\n+                     ind_write_disabled, false),\n+    DEFINE_PROP_END_OF_LIST(),\n+};\n+\n+static void xlnx_versal_ospi_class_init(ObjectClass *klass, void *data)\n+{\n+    DeviceClass *dc = DEVICE_CLASS(klass);\n+\n+    dc->reset = xlnx_versal_ospi_reset;\n+    dc->realize = xlnx_versal_ospi_realize;\n+    dc->vmsd = &vmstate_xlnx_versal_ospi;\n+    device_class_set_props(dc, xlnx_versal_ospi_properties);\n+}\n+\n+static const TypeInfo xlnx_versal_ospi_info = {\n+    .name          = TYPE_XILINX_VERSAL_OSPI,\n+    .parent        = TYPE_SYS_BUS_DEVICE,\n+    .instance_size = sizeof(XlnxVersalOspi),\n+    .class_init    = xlnx_versal_ospi_class_init,\n+    .instance_init = xlnx_versal_ospi_init,\n+};\n+\n+static void xlnx_versal_ospi_register_types(void)\n+{\n+    type_register_static(&xlnx_versal_ospi_info);\n+}\n+\n+type_init(xlnx_versal_ospi_register_types)\ndiff --git a/hw/ssi/meson.build b/hw/ssi/meson.build\nindex 3d6bc82ab1f..0ded9cd092d 100644\n--- a/hw/ssi/meson.build\n+++ b/hw/ssi/meson.build\n@@ -7,5 +7,6 @@ softmmu_ss.add(when: 'CONFIG_SSI', if_true: files('ssi.c'))\n softmmu_ss.add(when: 'CONFIG_STM32F2XX_SPI', if_true: files('stm32f2xx_spi.c'))\n softmmu_ss.add(when: 'CONFIG_XILINX_SPI', if_true: files('xilinx_spi.c'))\n softmmu_ss.add(when: 'CONFIG_XILINX_SPIPS', if_true: files('xilinx_spips.c'))\n+softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-ospi.c'))\n softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_spi.c'))\n softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_spi.c'))\n",
    "prefixes": [
        "PULL",
        "10/32"
    ]
}