{"id":1447382,"url":"http://patchwork.ozlabs.org/api/patches/1447382/?format=json","web_url":"http://patchwork.ozlabs.org/project/qemu-devel/patch/20210304144651.310037-8-alistair.francis@wdc.com/","project":{"id":14,"url":"http://patchwork.ozlabs.org/api/projects/14/?format=json","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":"<20210304144651.310037-8-alistair.francis@wdc.com>","list_archive_url":null,"date":"2021-03-04T14:46:39","name":"[PULL,v2,07/19] hw/ssi: Add SiFive SPI controller support","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"3458f8f324ffce95b6d9504071c79d9af90d151c","submitter":{"id":74007,"url":"http://patchwork.ozlabs.org/api/people/74007/?format=json","name":"Alistair Francis","email":"alistair.francis@wdc.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/qemu-devel/patch/20210304144651.310037-8-alistair.francis@wdc.com/mbox/","series":[{"id":232161,"url":"http://patchwork.ozlabs.org/api/series/232161/?format=json","web_url":"http://patchwork.ozlabs.org/project/qemu-devel/list/?series=232161","date":"2021-03-04T14:46:33","name":"[PULL,v2,01/19] target/riscv: Declare csr_ops[] with a known size","version":2,"mbox":"http://patchwork.ozlabs.org/series/232161/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/1447382/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/1447382/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":["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>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n unprotected) header.d=wdc.com header.i=@wdc.com header.a=rsa-sha256\n header.s=dkim.wdc.com header.b=VBVf30VJ;\n\tdkim-atps=neutral"],"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 ozlabs.org (Postfix) with ESMTPS id 4Drv3N3Sbgz9sSC\n\tfor <incoming@patchwork.ozlabs.org>; Fri,  5 Mar 2021 01:52:16 +1100 (AEDT)","from localhost ([::1]:39786 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 1lHpKo-0005XA-FD\n\tfor incoming@patchwork.ozlabs.org; Thu, 04 Mar 2021 09:52:14 -0500","from eggs.gnu.org ([2001:470:142:3::10]:60314)\n by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1)\n (envelope-from <prvs=690dc056c=alistair.francis@wdc.com>)\n id 1lHpH7-0001lv-V2\n for qemu-devel@nongnu.org; Thu, 04 Mar 2021 09:48:25 -0500","from esa1.hgst.iphmx.com ([68.232.141.245]:44460)\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1)\n (envelope-from <prvs=690dc056c=alistair.francis@wdc.com>)\n id 1lHpH4-0007uj-Rj\n for qemu-devel@nongnu.org; Thu, 04 Mar 2021 09:48:25 -0500","from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com)\n ([199.255.45.15])\n by ob1.hgst.iphmx.com with ESMTP; 04 Mar 2021 22:48:10 +0800","from uls-op-cesaip01.wdc.com ([10.248.3.36])\n by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 04 Mar 2021 06:29:23 -0800","from cnf008142.ad.shared (HELO alistair-risc6-laptop.hgst.com)\n ([10.86.48.109])\n by uls-op-cesaip01.wdc.com with ESMTP; 04 Mar 2021 06:48:10 -0800"],"DKIM-Signature":"v=1; a=rsa-sha256; c=simple/simple;\n d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com;\n t=1614869302; x=1646405302;\n h=from:to:cc:subject:date:message-id:in-reply-to:\n references:mime-version:content-transfer-encoding;\n bh=+lGZXaoYx3pMRxNzsM4PxWtHjJ9efR3jQix8AS/sB7g=;\n b=VBVf30VJ5LgCpneDC2ANy7nE9gGd6X4JjGwQiZBO/SUKse5jxTqR2VVT\n Un55DnDSWvsotvg78hu4ta3aQPQdByUCJjYuIWjM1Ll1nvOse+Wi7wZaM\n SdPaCqAaBV9n+cBEfNYrZ6OdIfTeHCGgv05V9v9lsyuDsVRqJeLjHDOuX\n w/SEqqA1xrvWK7srlHB9EV3lou/2X1usls2c3qCDM6yzOq/dQkrbXKzh7\n Rg/N/J+2/4L/n5V+e9XbSjGH1A5Ebf/xp6iXFmXoPtj1y6YFhc7m5S8h3\n rubBKtwj6NyyRJ6iXEs7c24g/M6FJd4ovAlb7qddUsufH5Hb3I/EQPE1i A==;","IronPort-SDR":["\n MDhPpw039h6goC0y25tWJRwythRZPzXPb00i8Ng9wi2UkahAEif39960bSLcqRcAy3TPiaIk6q\n KmwTH/qPkp9UvHAjMtpYSI2f8G4dBSpf4j13NQvYv0IkrAg6gwLxTLK/CcxJixnBkKN1CEfHdN\n tShHyjdqWBq1UfmklkU5oG/X5zVn4N4d2SiOB3XldbW+B8zXitIyv4u8PyhQJAR8n3RbDhYB25\n 7f7erkKvKUf8apP9A8p+I5XV/g2tj3e1Vy2Acbpp5MInmjsvXRJ/rvovtCzamd4MxJCSK0mbN7\n 4R4=","\n +bFldTdUIFRD28HOGJT2+TDF7ux+R0wq1NeVlF0t6hyTcuh2HDDaX2906wUOJ1Avp0HHoBoA22\n u8xZeRvfowon2tGMWRBMGXoI1X/C15MBKLaHLJ2zzhVaoo00j3W97lZ+tig8ZrneMpE5ggCl+g\n MwmRV+1z774FnyQA9cPoUe7FDHDVwzBM73fEgmHm8XojuuvqY1C/vonclxaIlkycps8I+6+ddD\n nmQMPKsFQ5nQHc2zzL8M08uBB5xm4fOoaBk3/islVk/CQY7/+OaklVhdzivYENzvb2D1/HiPkc\n krlDPxqKTSdCkObyWvX5a3C/","\n B69Vd/JDsr8qoE78AdFkfo/j1yiEjOVlMOenww4c+Jo9zcjoSDWGMLTPkaF4CanqcxGWre7pWP\n X4XpBN0DNtNs7JucVMGQmp/yWfmveOtnEZz2Z/H8euWkuYfg5OEQeT0sznCjoWfuzo9PDoHaqB\n L1UquYvpwFWscZqIqwwrKAQJeEaDrnxHekUQNzOzbcFmuyJI6odLzfwWUH1om6UZm+d34r/pmd\n Xzqu6Zvu2N5d3ieonpFHrxyUYdCM6h6+4cpzm5vzABm7xb3Lzlo5yZsMTMHEMyDy3gr/NnFRfj\n tV0="],"X-IronPort-AV":"E=Sophos;i=\"5.81,222,1610380800\"; d=\"scan'208\";a=\"271984408\"","WDCIronportException":"Internal","From":"Alistair Francis <alistair.francis@wdc.com>","To":"peter.maydell@linaro.org","Subject":"[PULL v2 07/19] hw/ssi: Add SiFive SPI controller support","Date":"Thu,  4 Mar 2021 09:46:39 -0500","Message-Id":"<20210304144651.310037-8-alistair.francis@wdc.com>","X-Mailer":"git-send-email 2.30.1","In-Reply-To":"<20210304144651.310037-1-alistair.francis@wdc.com>","References":"<20210304144651.310037-1-alistair.francis@wdc.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Received-SPF":"pass client-ip=68.232.141.245;\n envelope-from=prvs=690dc056c=alistair.francis@wdc.com;\n helo=esa1.hgst.iphmx.com","X-Spam_score_int":"-27","X-Spam_score":"-2.8","X-Spam_bar":"--","X-Spam_report":"(-2.8 / 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 RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_PASS=-0.001,\n SPF_PASS=-0.001 autolearn=ham autolearn_force=no","X-Spam_action":"no action","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.23","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>","Cc":"alistair23@gmail.com, Bin Meng <bin.meng@windriver.com>,\n Alistair Francis <alistair.francis@wdc.com>, qemu-devel@nongnu.org","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: Bin Meng <bin.meng@windriver.com>\n\nThis adds the SiFive SPI controller model for the FU540 SoC.\nThe direct memory-mapped SPI flash mode is unsupported.\n\nSigned-off-by: Bin Meng <bin.meng@windriver.com>\nReviewed-by: Alistair Francis <alistair.francis@wdc.com>\nMessage-id: 20210126060007.12904-4-bmeng.cn@gmail.com\nSigned-off-by: Alistair Francis <alistair.francis@wdc.com>\n---\n include/hw/ssi/sifive_spi.h |  47 +++++\n hw/ssi/sifive_spi.c         | 358 ++++++++++++++++++++++++++++++++++++\n hw/ssi/Kconfig              |   4 +\n hw/ssi/meson.build          |   1 +\n 4 files changed, 410 insertions(+)\n create mode 100644 include/hw/ssi/sifive_spi.h\n create mode 100644 hw/ssi/sifive_spi.c","diff":"diff --git a/include/hw/ssi/sifive_spi.h b/include/hw/ssi/sifive_spi.h\nnew file mode 100644\nindex 0000000000..47d0d6a47c\n--- /dev/null\n+++ b/include/hw/ssi/sifive_spi.h\n@@ -0,0 +1,47 @@\n+/*\n+ * QEMU model of the SiFive SPI Controller\n+ *\n+ * Copyright (c) 2021 Wind River Systems, Inc.\n+ *\n+ * Author:\n+ *   Bin Meng <bin.meng@windriver.com>\n+ *\n+ * This program is free software; you can redistribute it and/or modify it\n+ * under the terms and conditions of the GNU General Public License,\n+ * version 2 or later, as published by the Free Software Foundation.\n+ *\n+ * This program is distributed in the hope it will be useful, but WITHOUT\n+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n+ * more details.\n+ *\n+ * You should have received a copy of the GNU General Public License along with\n+ * this program.  If not, see <http://www.gnu.org/licenses/>.\n+ */\n+\n+#ifndef HW_SIFIVE_SPI_H\n+#define HW_SIFIVE_SPI_H\n+\n+#define SIFIVE_SPI_REG_NUM  (0x78 / 4)\n+\n+#define TYPE_SIFIVE_SPI \"sifive.spi\"\n+#define SIFIVE_SPI(obj) OBJECT_CHECK(SiFiveSPIState, (obj), TYPE_SIFIVE_SPI)\n+\n+typedef struct SiFiveSPIState {\n+    SysBusDevice parent_obj;\n+\n+    MemoryRegion mmio;\n+    qemu_irq irq;\n+\n+    uint32_t num_cs;\n+    qemu_irq *cs_lines;\n+\n+    SSIBus *spi;\n+\n+    Fifo8 tx_fifo;\n+    Fifo8 rx_fifo;\n+\n+    uint32_t regs[SIFIVE_SPI_REG_NUM];\n+} SiFiveSPIState;\n+\n+#endif /* HW_SIFIVE_SPI_H */\ndiff --git a/hw/ssi/sifive_spi.c b/hw/ssi/sifive_spi.c\nnew file mode 100644\nindex 0000000000..0c9ebca3c8\n--- /dev/null\n+++ b/hw/ssi/sifive_spi.c\n@@ -0,0 +1,358 @@\n+/*\n+ * QEMU model of the SiFive SPI Controller\n+ *\n+ * Copyright (c) 2021 Wind River Systems, Inc.\n+ *\n+ * Author:\n+ *   Bin Meng <bin.meng@windriver.com>\n+ *\n+ * This program is free software; you can redistribute it and/or modify it\n+ * under the terms and conditions of the GNU General Public License,\n+ * version 2 or later, as published by the Free Software Foundation.\n+ *\n+ * This program is distributed in the hope it will be useful, but WITHOUT\n+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n+ * more details.\n+ *\n+ * You should have received a copy of the GNU General Public License along with\n+ * this program.  If not, see <http://www.gnu.org/licenses/>.\n+ */\n+\n+#include \"qemu/osdep.h\"\n+#include \"hw/irq.h\"\n+#include \"hw/qdev-properties.h\"\n+#include \"hw/sysbus.h\"\n+#include \"hw/ssi/ssi.h\"\n+#include \"sysemu/sysemu.h\"\n+#include \"qemu/fifo8.h\"\n+#include \"qemu/log.h\"\n+#include \"qemu/module.h\"\n+#include \"hw/ssi/sifive_spi.h\"\n+\n+#define R_SCKDIV        (0x00 / 4)\n+#define R_SCKMODE       (0x04 / 4)\n+#define R_CSID          (0x10 / 4)\n+#define R_CSDEF         (0x14 / 4)\n+#define R_CSMODE        (0x18 / 4)\n+#define R_DELAY0        (0x28 / 4)\n+#define R_DELAY1        (0x2C / 4)\n+#define R_FMT           (0x40 / 4)\n+#define R_TXDATA        (0x48 / 4)\n+#define R_RXDATA        (0x4C / 4)\n+#define R_TXMARK        (0x50 / 4)\n+#define R_RXMARK        (0x54 / 4)\n+#define R_FCTRL         (0x60 / 4)\n+#define R_FFMT          (0x64 / 4)\n+#define R_IE            (0x70 / 4)\n+#define R_IP            (0x74 / 4)\n+\n+#define FMT_DIR         (1 << 3)\n+\n+#define TXDATA_FULL     (1 << 31)\n+#define RXDATA_EMPTY    (1 << 31)\n+\n+#define IE_TXWM         (1 << 0)\n+#define IE_RXWM         (1 << 1)\n+\n+#define IP_TXWM         (1 << 0)\n+#define IP_RXWM         (1 << 1)\n+\n+#define FIFO_CAPACITY   8\n+\n+static void sifive_spi_txfifo_reset(SiFiveSPIState *s)\n+{\n+    fifo8_reset(&s->tx_fifo);\n+\n+    s->regs[R_TXDATA] &= ~TXDATA_FULL;\n+    s->regs[R_IP] &= ~IP_TXWM;\n+}\n+\n+static void sifive_spi_rxfifo_reset(SiFiveSPIState *s)\n+{\n+    fifo8_reset(&s->rx_fifo);\n+\n+    s->regs[R_RXDATA] |= RXDATA_EMPTY;\n+    s->regs[R_IP] &= ~IP_RXWM;\n+}\n+\n+static void sifive_spi_update_cs(SiFiveSPIState *s)\n+{\n+    int i;\n+\n+    for (i = 0; i < s->num_cs; i++) {\n+        if (s->regs[R_CSDEF] & (1 << i)) {\n+            qemu_set_irq(s->cs_lines[i], !(s->regs[R_CSMODE]));\n+        }\n+    }\n+}\n+\n+static void sifive_spi_update_irq(SiFiveSPIState *s)\n+{\n+    int level;\n+\n+    if (fifo8_num_used(&s->tx_fifo) < s->regs[R_TXMARK]) {\n+        s->regs[R_IP] |= IP_TXWM;\n+    } else {\n+        s->regs[R_IP] &= ~IP_TXWM;\n+    }\n+\n+    if (fifo8_num_used(&s->rx_fifo) > s->regs[R_RXMARK]) {\n+        s->regs[R_IP] |= IP_RXWM;\n+    } else {\n+        s->regs[R_IP] &= ~IP_RXWM;\n+    }\n+\n+    level = s->regs[R_IP] & s->regs[R_IE] ? 1 : 0;\n+    qemu_set_irq(s->irq, level);\n+}\n+\n+static void sifive_spi_reset(DeviceState *d)\n+{\n+    SiFiveSPIState *s = SIFIVE_SPI(d);\n+\n+    memset(s->regs, 0, sizeof(s->regs));\n+\n+    /* The reset value is high for all implemented CS pins */\n+    s->regs[R_CSDEF] = (1 << s->num_cs) - 1;\n+\n+    /* Populate register with their default value */\n+    s->regs[R_SCKDIV] = 0x03;\n+    s->regs[R_DELAY0] = 0x1001;\n+    s->regs[R_DELAY1] = 0x01;\n+\n+    sifive_spi_txfifo_reset(s);\n+    sifive_spi_rxfifo_reset(s);\n+\n+    sifive_spi_update_cs(s);\n+    sifive_spi_update_irq(s);\n+}\n+\n+static void sifive_spi_flush_txfifo(SiFiveSPIState *s)\n+{\n+    uint8_t tx;\n+    uint8_t rx;\n+\n+    while (!fifo8_is_empty(&s->tx_fifo)) {\n+        tx = fifo8_pop(&s->tx_fifo);\n+        rx = ssi_transfer(s->spi, tx);\n+\n+        if (!fifo8_is_full(&s->rx_fifo)) {\n+            if (!(s->regs[R_FMT] & FMT_DIR)) {\n+                fifo8_push(&s->rx_fifo, rx);\n+            }\n+        }\n+    }\n+}\n+\n+static bool sifive_spi_is_bad_reg(hwaddr addr, bool allow_reserved)\n+{\n+    bool bad;\n+\n+    switch (addr) {\n+    /* reserved offsets */\n+    case 0x08:\n+    case 0x0C:\n+    case 0x1C:\n+    case 0x20:\n+    case 0x24:\n+    case 0x30:\n+    case 0x34:\n+    case 0x38:\n+    case 0x3C:\n+    case 0x44:\n+    case 0x58:\n+    case 0x5C:\n+    case 0x68:\n+    case 0x6C:\n+        bad = allow_reserved ? false : true;\n+        break;\n+    default:\n+        bad = false;\n+    }\n+\n+    if (addr >= (SIFIVE_SPI_REG_NUM << 2)) {\n+        bad = true;\n+    }\n+\n+    return bad;\n+}\n+\n+static uint64_t sifive_spi_read(void *opaque, hwaddr addr, unsigned int size)\n+{\n+    SiFiveSPIState *s = opaque;\n+    uint32_t r;\n+\n+    if (sifive_spi_is_bad_reg(addr, true)) {\n+        qemu_log_mask(LOG_GUEST_ERROR, \"%s: bad read at address 0x%\"\n+                      HWADDR_PRIx \"\\n\", __func__, addr);\n+        return 0;\n+    }\n+\n+    addr >>= 2;\n+    switch (addr) {\n+    case R_TXDATA:\n+        if (fifo8_is_full(&s->tx_fifo)) {\n+            return TXDATA_FULL;\n+        }\n+        r = 0;\n+        break;\n+\n+    case R_RXDATA:\n+        if (fifo8_is_empty(&s->rx_fifo)) {\n+            return RXDATA_EMPTY;\n+        }\n+        r = fifo8_pop(&s->rx_fifo);\n+        break;\n+\n+    default:\n+        r = s->regs[addr];\n+        break;\n+    }\n+\n+    sifive_spi_update_irq(s);\n+\n+    return r;\n+}\n+\n+static void sifive_spi_write(void *opaque, hwaddr addr,\n+                             uint64_t val64, unsigned int size)\n+{\n+    SiFiveSPIState *s = opaque;\n+    uint32_t value = val64;\n+\n+    if (sifive_spi_is_bad_reg(addr, false)) {\n+        qemu_log_mask(LOG_GUEST_ERROR, \"%s: bad write at addr=0x%\"\n+                      HWADDR_PRIx \" value=0x%x\\n\", __func__, addr, value);\n+        return;\n+    }\n+\n+    addr >>= 2;\n+    switch (addr) {\n+    case R_CSID:\n+        if (value >= s->num_cs) {\n+            qemu_log_mask(LOG_GUEST_ERROR, \"%s: invalid csid %d\\n\",\n+                          __func__, value);\n+        } else {\n+            s->regs[R_CSID] = value;\n+            sifive_spi_update_cs(s);\n+        }\n+        break;\n+\n+    case R_CSDEF:\n+        if (value >= (1 << s->num_cs)) {\n+            qemu_log_mask(LOG_GUEST_ERROR, \"%s: invalid csdef %x\\n\",\n+                          __func__, value);\n+        } else {\n+            s->regs[R_CSDEF] = value;\n+        }\n+        break;\n+\n+    case R_CSMODE:\n+        if (value > 3) {\n+            qemu_log_mask(LOG_GUEST_ERROR, \"%s: invalid csmode %x\\n\",\n+                          __func__, value);\n+        } else {\n+            s->regs[R_CSMODE] = value;\n+            sifive_spi_update_cs(s);\n+        }\n+        break;\n+\n+    case R_TXDATA:\n+        if (!fifo8_is_full(&s->tx_fifo)) {\n+            fifo8_push(&s->tx_fifo, (uint8_t)value);\n+            sifive_spi_flush_txfifo(s);\n+        }\n+        break;\n+\n+    case R_RXDATA:\n+    case R_IP:\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                      \"%s: invalid write to read-only reigster 0x%\"\n+                      HWADDR_PRIx \" with 0x%x\\n\", __func__, addr << 2, value);\n+        break;\n+\n+    case R_TXMARK:\n+    case R_RXMARK:\n+        if (value >= FIFO_CAPACITY) {\n+            qemu_log_mask(LOG_GUEST_ERROR, \"%s: invalid watermark %d\\n\",\n+                          __func__, value);\n+        } else {\n+            s->regs[addr] = value;\n+        }\n+        break;\n+\n+    case R_FCTRL:\n+    case R_FFMT:\n+        qemu_log_mask(LOG_UNIMP,\n+                      \"%s: direct-map flash interface unimplemented\\n\",\n+                      __func__);\n+        break;\n+\n+    default:\n+        s->regs[addr] = value;\n+        break;\n+    }\n+\n+    sifive_spi_update_irq(s);\n+}\n+\n+static const MemoryRegionOps sifive_spi_ops = {\n+    .read = sifive_spi_read,\n+    .write = sifive_spi_write,\n+    .endianness = DEVICE_LITTLE_ENDIAN,\n+    .valid = {\n+        .min_access_size = 4,\n+        .max_access_size = 4\n+    }\n+};\n+\n+static void sifive_spi_realize(DeviceState *dev, Error **errp)\n+{\n+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);\n+    SiFiveSPIState *s = SIFIVE_SPI(dev);\n+    int i;\n+\n+    s->spi = ssi_create_bus(dev, \"spi\");\n+    sysbus_init_irq(sbd, &s->irq);\n+\n+    s->cs_lines = g_new0(qemu_irq, s->num_cs);\n+    for (i = 0; i < s->num_cs; i++) {\n+        sysbus_init_irq(sbd, &s->cs_lines[i]);\n+    }\n+\n+    memory_region_init_io(&s->mmio, OBJECT(s), &sifive_spi_ops, s,\n+                          TYPE_SIFIVE_SPI, 0x1000);\n+    sysbus_init_mmio(sbd, &s->mmio);\n+\n+    fifo8_create(&s->tx_fifo, FIFO_CAPACITY);\n+    fifo8_create(&s->rx_fifo, FIFO_CAPACITY);\n+}\n+\n+static Property sifive_spi_properties[] = {\n+    DEFINE_PROP_UINT32(\"num-cs\", SiFiveSPIState, num_cs, 1),\n+    DEFINE_PROP_END_OF_LIST(),\n+};\n+\n+static void sifive_spi_class_init(ObjectClass *klass, void *data)\n+{\n+    DeviceClass *dc = DEVICE_CLASS(klass);\n+\n+    device_class_set_props(dc, sifive_spi_properties);\n+    dc->reset = sifive_spi_reset;\n+    dc->realize = sifive_spi_realize;\n+}\n+\n+static const TypeInfo sifive_spi_info = {\n+    .name           = TYPE_SIFIVE_SPI,\n+    .parent         = TYPE_SYS_BUS_DEVICE,\n+    .instance_size  = sizeof(SiFiveSPIState),\n+    .class_init     = sifive_spi_class_init,\n+};\n+\n+static void sifive_spi_register_types(void)\n+{\n+    type_register_static(&sifive_spi_info);\n+}\n+\n+type_init(sifive_spi_register_types)\ndiff --git a/hw/ssi/Kconfig b/hw/ssi/Kconfig\nindex 9e54a0c8dd..7d90a02181 100644\n--- a/hw/ssi/Kconfig\n+++ b/hw/ssi/Kconfig\n@@ -2,6 +2,10 @@ config PL022\n     bool\n     select SSI\n \n+config SIFIVE_SPI\n+    bool\n+    select SSI\n+\n config SSI\n     bool\n \ndiff --git a/hw/ssi/meson.build b/hw/ssi/meson.build\nindex dee00c0da6..3d6bc82ab1 100644\n--- a/hw/ssi/meson.build\n+++ b/hw/ssi/meson.build\n@@ -2,6 +2,7 @@ softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_smc.c'))\n softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-spi.c'))\n softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_fiu.c'))\n softmmu_ss.add(when: 'CONFIG_PL022', if_true: files('pl022.c'))\n+softmmu_ss.add(when: 'CONFIG_SIFIVE_SPI', if_true: files('sifive_spi.c'))\n 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","prefixes":["PULL","v2","07/19"]}