All of lore.kernel.org
 help / color / mirror / Atom feed
From: Chalapathi V <chalapathi.v@linux.ibm.com>
To: qemu-devel@nongnu.org
Cc: qemu-ppc@nongnu.org, fbarrat@linux.ibm.com, npiggin@gmail.com,
	clg@kaod.org, calebs@us.ibm.com, chalapathi.v@ibm.com,
	chalapathi.v@linux.ibm.com, saif.abrar@linux.vnet.ibm.com
Subject: [PATCH v1 1/5] hw/ppc: SPI responder model
Date: Wed,  7 Feb 2024 10:08:29 -0600	[thread overview]
Message-ID: <20240207160833.3437779-2-chalapathi.v@linux.ibm.com> (raw)
In-Reply-To: <20240207160833.3437779-1-chalapathi.v@linux.ibm.com>

Serial pheripheral interface provides full-duplex synchronous serial
communication between single controller and multiple responder devices.
One SPI Controller is implemented and supported on a SPI Bus, there is
no support for multiple controllers on the SPI bus.

The current implemetation assumes that single responder is connected to
bus, hence chip_select is not modelled.

Signed-off-by: Chalapathi V <chalapathi.v@linux.ibm.com>
---
 include/hw/ppc/pnv_spi_responder.h | 109 +++++++++++++++++++
 hw/ppc/pnv_spi_responder.c         | 166 +++++++++++++++++++++++++++++
 hw/ppc/meson.build                 |   1 +
 3 files changed, 276 insertions(+)
 create mode 100644 include/hw/ppc/pnv_spi_responder.h
 create mode 100644 hw/ppc/pnv_spi_responder.c

diff --git a/include/hw/ppc/pnv_spi_responder.h b/include/hw/ppc/pnv_spi_responder.h
new file mode 100644
index 0000000000..1cf7279aad
--- /dev/null
+++ b/include/hw/ppc/pnv_spi_responder.h
@@ -0,0 +1,109 @@
+/*
+ * QEMU SPI Responder.
+ *
+ * Copyright (c) 2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * SPI provides full-duplex synchronous serial communication between single
+ * controller and multiple responder devices. One SPI Controller is
+ * implemented and supported on a SPI Bus, there is no support for multiple
+ * controllers on the SPI bus.
+ *
+ * The current implementation assumes that single responder is connected to
+ * bus, hence chip_select is not modelled.
+ */
+
+#ifndef PPC_PNV_SPI_RESPONDER_H
+#define PPC_PNV_SPI_RESPONDER_H
+
+#include "hw/qdev-core.h"
+#include "qom/object.h"
+#include "qemu/log.h"
+
+#define TYPE_PNV_SPI_RESPONDER "spi-responder"
+OBJECT_DECLARE_TYPE(PnvSpiResponder, PnvSpiResponderClass,
+                    PNV_SPI_RESPONDER)
+
+typedef struct xfer_buffer xfer_buffer;
+
+struct PnvSpiResponderClass {
+    DeviceClass parent_class;
+
+    /*
+     * These methods are from controller to responder and implemented
+     * by all responders.
+     * Connect_controller/disconnect_controller methods are called by
+     * controller to initiate/stop the SPI transfer.
+     */
+    void (*connect_controller)(PnvSpiResponder *responder, const char *port);
+    void (*disconnect_controller)(PnvSpiResponder *responder);
+    /*
+     * SPI transfer consists of a number of consecutive calls to the request
+     * method.
+     * The parameter first is true on first call of the transfer and last is on
+     * the final call of the transfer. Parameter bits and payload defines the
+     * number of bits and data payload sent by controller.
+     * Responder returns the response payload.
+     */
+    xfer_buffer *(*request)(PnvSpiResponder *responder, int first, int last,
+                    int bits, xfer_buffer *payload);
+};
+
+struct PnvSpiResponder {
+    DeviceState parent_obj;
+};
+
+#define TYPE_SPI_BUS "spi-bus"
+OBJECT_DECLARE_SIMPLE_TYPE(SpiBus, SPI_BUS)
+
+struct SpiBus {
+    BusState parent_obj;
+};
+
+/*
+ * spi_realize_and_unref: realize and unref an SPI responder
+ * @dev: SPI responder to realize
+ * @bus: SPI bus to put it on
+ * @errp: error pointer
+ */
+bool spi_realize_and_unref(DeviceState *dev, SpiBus *bus, Error **errp);
+
+/*
+ * spi_create_responder: create a SPI responder.
+ * @bus: SPI bus to put it on
+ * @name: name of the responder object.
+ * call spi_realize_and_unref() after creating the responder.
+ */
+
+PnvSpiResponder *spi_create_responder(SpiBus *bus, const char *name);
+
+/* xfer_buffer */
+typedef struct xfer_buffer {
+
+    uint32_t    len;
+    uint8_t    *data;
+
+} xfer_buffer;
+
+/*
+ * xfer_buffer_read_ptr: Increment the payload length and return the pointer
+ * to the data at offset
+ */
+uint8_t *xfer_buffer_write_ptr(xfer_buffer *payload, uint32_t offset,
+                uint32_t length);
+/* xfer_buffer_read_ptr: Return the pointer to the data at offset */
+void xfer_buffer_read_ptr(xfer_buffer *payload, uint8_t **read_buf,
+                uint32_t offset, uint32_t length);
+/* xfer_buffer_new: Allocate memory and return the pointer */
+xfer_buffer *xfer_buffer_new(void);
+/* xfer_buffer_free: free the payload */
+void xfer_buffer_free(xfer_buffer *payload);
+
+/* Controller interface */
+SpiBus *spi_create_bus(DeviceState *parent, const char *name);
+xfer_buffer *spi_request(SpiBus *bus, int first, int last, int bits,
+                xfer_buffer *payload);
+bool spi_connect_controller(SpiBus *bus, const char *port);
+bool spi_disconnect_controller(SpiBus *bus);
+#endif /* PPC_PNV_SPI_SEEPROM_H */
diff --git a/hw/ppc/pnv_spi_responder.c b/hw/ppc/pnv_spi_responder.c
new file mode 100644
index 0000000000..c3bc659b1b
--- /dev/null
+++ b/hw/ppc/pnv_spi_responder.c
@@ -0,0 +1,166 @@
+/*
+ * QEMU PowerPC SPI Responder
+ *
+ * Copyright (c) 2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/ppc/pnv_spi_responder.h"
+#include "qapi/error.h"
+
+static const TypeInfo spi_bus_info = {
+    .name = TYPE_SPI_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(SpiBus),
+};
+
+SpiBus *spi_create_bus(DeviceState *parent, const char *name)
+{
+    BusState *bus;
+    bus = qbus_new(TYPE_SPI_BUS, parent, name);
+    return SPI_BUS(bus);
+}
+
+/* xfer_buffer_methods */
+xfer_buffer *xfer_buffer_new(void)
+{
+    xfer_buffer *payload = g_malloc0(sizeof(*payload));
+    payload->data = g_malloc0(payload->len * sizeof(uint8_t));
+    return payload;
+}
+
+void xfer_buffer_free(xfer_buffer *payload)
+{
+    free(payload->data);
+    payload->data = NULL;
+    free(payload);
+}
+
+uint8_t *xfer_buffer_write_ptr(xfer_buffer *payload, uint32_t offset,
+                            uint32_t length)
+{
+    if (payload->len < (offset + length)) {
+        payload->len = offset + length;
+        payload->data = g_realloc(payload->data,
+                        payload->len * sizeof(uint8_t));
+    }
+    return &payload->data[offset];
+}
+
+void xfer_buffer_read_ptr(xfer_buffer *payload, uint8_t **read_buf,
+                uint32_t offset, uint32_t length)
+{
+    static uint32_t prev_len;
+    uint32_t offset_org = offset;
+    if (offset > payload->len) {
+        if (length < payload->len) {
+            offset = payload->len - length;
+        } else {
+            offset = 0;
+            length = payload->len;
+        }
+        qemu_log_mask(LOG_GUEST_ERROR, "Read offset(%d) exceeds buffer "
+                        "length(%d), altered offset to %d and length to %d to "
+                        "read within buffer\n", offset_org, payload->len,
+                        offset, length);
+    } else if ((offset + length) > payload->len) {
+        qemu_log_mask(LOG_GUEST_ERROR, "Read length(%d) bytes from offset (%d)"
+                        ", exceeds buffer length(%d)\n", length, offset,
+                        payload->len);
+        length = payload->len - offset;
+    }
+
+    if ((prev_len != length) || (*read_buf == NULL)) {
+        *read_buf = g_realloc(*read_buf, length * sizeof(uint8_t));
+        prev_len = length;
+    }
+    *read_buf = &payload->data[offset];
+}
+
+/* Controller interface methods */
+bool spi_connect_controller(SpiBus *bus, const char *port)
+{
+    BusState *b = BUS(bus);
+    BusChild *kid;
+    QTAILQ_FOREACH(kid, &b->children, sibling) {
+        PnvSpiResponder *r = PNV_SPI_RESPONDER(kid->child);
+        PnvSpiResponderClass *rc = PNV_SPI_RESPONDER_GET_CLASS(r);
+        rc->connect_controller(r, port);
+        return true;
+    }
+    return false;
+}
+bool spi_disconnect_controller(SpiBus *bus)
+{
+    BusState *b = BUS(bus);
+    BusChild *kid;
+    QTAILQ_FOREACH(kid, &b->children, sibling) {
+        PnvSpiResponder *r = PNV_SPI_RESPONDER(kid->child);
+        PnvSpiResponderClass *rc = PNV_SPI_RESPONDER_GET_CLASS(r);
+        rc->disconnect_controller(r);
+        return true;
+    }
+    return false;
+}
+
+xfer_buffer *spi_request(SpiBus *bus,
+                int first, int last, int bits, xfer_buffer *payload)
+{
+    BusState *b = BUS(bus);
+    BusChild *kid;
+    xfer_buffer *rsp_payload = NULL;
+    uint8_t *buf = NULL;
+
+    QTAILQ_FOREACH(kid, &b->children, sibling) {
+        PnvSpiResponder *r = PNV_SPI_RESPONDER(kid->child);
+        PnvSpiResponderClass *rc = PNV_SPI_RESPONDER_GET_CLASS(r);
+        rsp_payload = rc->request(r, first, last, bits, payload);
+        return rsp_payload;
+    }
+    if (rsp_payload == NULL) {
+        rsp_payload = xfer_buffer_new();
+    }
+    buf = xfer_buffer_write_ptr(rsp_payload, 0, payload->len);
+    memset(buf, 0, payload->len);
+    return rsp_payload;
+}
+
+/* create and realise spi responder device */
+bool spi_realize_and_unref(DeviceState *dev, SpiBus *bus, Error **errp)
+{
+    return qdev_realize_and_unref(dev, &bus->parent_obj, errp);
+}
+
+PnvSpiResponder *spi_create_responder(SpiBus *bus, const char *name)
+{
+    DeviceState *dev = qdev_new(name);
+
+    spi_realize_and_unref(dev, bus, &error_fatal);
+    return PNV_SPI_RESPONDER(dev);
+}
+
+static void pnv_spi_responder_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc = "PowerNV SPI RESPONDER";
+}
+
+static const TypeInfo pnv_spi_responder_info = {
+    .name          = TYPE_PNV_SPI_RESPONDER,
+    .parent        = TYPE_DEVICE,
+    .instance_size = sizeof(PnvSpiResponder),
+    .class_init    = pnv_spi_responder_class_init,
+    .abstract      = true,
+    .class_size    = sizeof(PnvSpiResponderClass),
+};
+
+static void pnv_spi_responder_register_types(void)
+{
+    type_register_static(&pnv_spi_responder_info);
+    type_register_static(&spi_bus_info);
+}
+
+type_init(pnv_spi_responder_register_types);
diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build
index eba3406e7f..9bfd5a5613 100644
--- a/hw/ppc/meson.build
+++ b/hw/ppc/meson.build
@@ -53,6 +53,7 @@ ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files(
   'pnv_bmc.c',
   'pnv_homer.c',
   'pnv_pnor.c',
+  'pnv_spi_responder.c',
 ))
 # PowerPC 4xx boards
 ppc_ss.add(when: 'CONFIG_PPC405', if_true: files(
-- 
2.31.1



  reply	other threads:[~2024-02-07 16:10 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-02-07 16:08 [PATCH v1 0/5] hw/ppc: SPI model Chalapathi V
2024-02-07 16:08 ` Chalapathi V [this message]
2024-03-08 16:00   ` [PATCH v1 1/5] hw/ppc: SPI responder model Stefan Berger
2024-02-07 16:08 ` [PATCH v1 2/5] hw/ppc: SPI controller model - registers implementation Chalapathi V
2024-03-07 18:54   ` Stefan Berger
2024-03-07 19:11     ` Stefan Berger
2024-03-08 15:17     ` Stefan Berger
2024-02-07 16:08 ` [PATCH v1 3/5] hw/ppc: SPI controller model - sequencer and shifter Chalapathi V
2024-03-08 19:36   ` Stefan Berger
2024-02-07 16:08 ` [PATCH v1 4/5] hw/ppc: SPI SEEPROM model Chalapathi V
2024-03-08 15:14   ` Stefan Berger
2024-02-07 16:08 ` [PATCH v1 5/5] hw/ppc: SPI controller wiring to P10 chip and create seeprom device Chalapathi V
2024-03-01 16:17 ` [PATCH v1 0/5] hw/ppc: SPI model Chalapathi V
2024-03-01 16:36   ` Cédric Le Goater
2024-03-01 18:33     ` Chalapathi V

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240207160833.3437779-2-chalapathi.v@linux.ibm.com \
    --to=chalapathi.v@linux.ibm.com \
    --cc=calebs@us.ibm.com \
    --cc=chalapathi.v@ibm.com \
    --cc=clg@kaod.org \
    --cc=fbarrat@linux.ibm.com \
    --cc=npiggin@gmail.com \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-ppc@nongnu.org \
    --cc=saif.abrar@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.