From nobody Tue Feb 10 01:16:28 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 150952076967530.466662895898935; Wed, 1 Nov 2017 00:19:29 -0700 (PDT) Received: from localhost ([::1]:48701 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9nJ5-0007YB-5j for importer@patchew.org; Wed, 01 Nov 2017 03:19:23 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54481) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9nGw-0006DK-A4 for qemu-devel@nongnu.org; Wed, 01 Nov 2017 03:17:13 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e9nGt-0001U1-FG for qemu-devel@nongnu.org; Wed, 01 Nov 2017 03:17:10 -0400 Received: from mail-lf0-x242.google.com ([2a00:1450:4010:c07::242]:52019) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1e9nGt-0001Tl-4C for qemu-devel@nongnu.org; Wed, 01 Nov 2017 03:17:07 -0400 Received: by mail-lf0-x242.google.com with SMTP id r129so1470800lff.8 for ; Wed, 01 Nov 2017 00:17:07 -0700 (PDT) Received: from localhost.localdomain (c83-254-152-225.bredband.comhem.se. [83.254.152.225]) by smtp.gmail.com with ESMTPSA id c132sm562371lfe.37.2017.11.01.00.17.04 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 01 Nov 2017 00:17:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=LLPSYFC4X6giAbTrrYQFJJs+vZkinyiqhd7d2s3gTmE=; b=ihenHRlF7/0+JhUSV6aCEWOOvwtpurDQDZ0B6Fxq+MSQ2iSlBPG/Ey/y14OhFbtHKt 2Kot6I1rE3c2eZJVGLe0GzhAyQA53X1HnJMIXqICM3xqm/E1RaJkiJ+nVXKZ/x8u+DH6 wmj0AxNTjwj8eGQfaLob8N4ICBfTxe73XW4ZgwhlviNjzfKch0GQ++3OjPXE10iscNto n6NkkptRzLw2zK+Lhdy2DCJw2TXhvbdf4+vIakYpXdCl3VXjzA3nz1XrfZBe4T9daBW6 OWEzwguaVdEM6xiWebCWEYTns9hLCcX+CR4H4TJlVNYPj+UEF519Al3sd7d8OrieJZuf dAAw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=LLPSYFC4X6giAbTrrYQFJJs+vZkinyiqhd7d2s3gTmE=; b=UenowhWVwTkK1sKEcxw40LCLxNhp3wWhf+Tq+OVOzxqpPgtDW9vzKGBVEtraaNO12o n0Tt2Uw4QSPPqpe5n0P3Nd6Ho8rRxA5TVRAxlOlvH/jJJyzm0nGME/LM4rUr2Okw83oA IQATRfmpLE4L6AmHcZhOGSOgoEv8+i4reuAy6ozFpixLjm0j9MSHyzSYQHHHZ0m2Z3bw GL4hGx8TYezV5GAnYvDwD3jD/XiZTcLEFLnFDVvI/FckoDnvbWYreuRBZ3ufMn2z4l3K avpp330l6eu2WB6XVsePvFOTx/UYhlpyNkMQlSpuz2ace9/SOOFNa7XUFsQnPGQl2X63 AkIQ== X-Gm-Message-State: AMCzsaVI3zHxnp8r9qbRLRftS6iZtlb1+go03bIQVabl3ZBmVu8AosKi 5xGMZ+r2e7jHlaGUpeLEG91Wow== X-Google-Smtp-Source: ABhQp+SAnmMC3J94baa4nx7paB3fTgaldfErR11Xvk+T2VPWk396kPeBDRgXSr/ASS7zrNuQNSp08w== X-Received: by 10.46.89.147 with SMTP id g19mr1973760ljf.26.1509520625533; Wed, 01 Nov 2017 00:17:05 -0700 (PDT) From: Francisco Iglesias To: qemu-devel@nongnu.org Date: Wed, 1 Nov 2017 08:16:46 +0100 Message-Id: <20171101071652.19375-8-frasse.iglesias@gmail.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20171101071652.19375-1-frasse.iglesias@gmail.com> References: <20171101071652.19375-1-frasse.iglesias@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4010:c07::242 Subject: [Qemu-devel] [PATCH v6 07/13] xilinx_spips: Add support for RX discard and RX drain X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: edgari@xilinx.com, alistai@xilinx.com, francisco.iglesias@feimtech.se, mar.krzeminski@gmail.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Add support for the RX discard and RX drain functionality. Also transmit one byte per dummy cycle (to the flash memories) with commands that require these. Signed-off-by: Francisco Iglesias --- hw/ssi/xilinx_spips.c | 167 +++++++++++++++++++++++++++++++++++++-= ---- include/hw/ssi/xilinx_spips.h | 6 ++ 2 files changed, 155 insertions(+), 18 deletions(-) diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 7accf5d..8634810 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -30,6 +30,7 @@ #include "qemu/bitops.h" #include "hw/ssi/xilinx_spips.h" #include "qapi/error.h" +#include "hw/register.h" #include "migration/blocker.h" =20 #ifndef XILINX_SPIPS_ERR_DEBUG @@ -100,6 +101,14 @@ #define LQSPI_CFG_DUMMY_SHIFT 8 #define LQSPI_CFG_INST_CODE 0xFF =20 +#define R_CMND (0xc0 / 4) + #define R_CMND_RXFIFO_DRAIN (1 << 19) + FIELD(CMND, PARTIAL_BYTE_LEN, 16, 3) +#define R_CMND_EXT_ADD (1 << 15) + FIELD(CMND, RX_DISCARD, 8, 7) + FIELD(CMND, DUMMY_CYCLES, 2, 6) +#define R_CMND_DMA_EN (1 << 1) +#define R_CMND_PUSH_WAIT (1 << 0) #define R_LQSPI_STS (0xA4 / 4) #define LQSPI_STS_WR_RECVD (1 << 1) =20 @@ -116,7 +125,8 @@ #define LQSPI_ADDRESS_BITS 24 =20 #define SNOOP_CHECKING 0xFF -#define SNOOP_NONE 0xFE +#define SNOOP_ADDR 0xF0 +#define SNOOP_NONE 0xEE #define SNOOP_STRIPING 0 =20 static inline int num_effective_busses(XilinxSPIPS *s) @@ -146,9 +156,14 @@ static void xilinx_spips_update_cs_lines(XilinxSPIPS *= s) if (xilinx_spips_cs_is_set(s, i, field) && !found) { DB_PRINT_L(0, "selecting slave %d\n", i); qemu_set_irq(s->cs_lines[cs_to_set], 0); + if (s->cs_lines_state[cs_to_set]) { + s->cs_lines_state[cs_to_set] =3D false; + s->rx_discard =3D ARRAY_FIELD_EX32(s->regs, CMND, RX_D= ISCARD); + } } else { DB_PRINT_L(0, "deselecting slave %d\n", i); qemu_set_irq(s->cs_lines[cs_to_set], 1); + s->cs_lines_state[cs_to_set] =3D true; } } if (xilinx_spips_cs_is_set(s, i, field)) { @@ -157,6 +172,10 @@ static void xilinx_spips_update_cs_lines(XilinxSPIPS *= s) } if (!found) { s->snoop_state =3D SNOOP_CHECKING; + s->cmd_dummies =3D 0; + s->link_state =3D 1; + s->link_state_next =3D 1; + s->link_state_next_when =3D 0; DB_PRINT_L(1, "moving to snoop check state\n"); } } @@ -203,7 +222,11 @@ static void xilinx_spips_reset(DeviceState *d) /* FIXME: move magic number definition somewhere sensible */ s->regs[R_MOD_ID] =3D 0x01090106; s->regs[R_LQSPI_CFG] =3D R_LQSPI_CFG_RESET; + s->link_state =3D 1; + s->link_state_next =3D 1; + s->link_state_next_when =3D 0; s->snoop_state =3D SNOOP_CHECKING; + s->cmd_dummies =3D 0; xilinx_spips_update_ixr(s); xilinx_spips_update_cs_lines(s); } @@ -238,14 +261,69 @@ static inline void stripe8(uint8_t *x, int num, bool = dir) memcpy(x, r, sizeof(uint8_t) * num); } =20 +static int xilinx_spips_num_dummies(XilinxQSPIPS *qs, uint8_t command) +{ + if (!qs) { + /* The SPI device is not a QSPI device */ + return -1; + } + + switch (command) { /* check for dummies */ + case READ: /* no dummy bytes/cycles */ + case PP: + case DPP: + case QPP: + case READ_4: + case PP_4: + case QPP_4: + return 0; + case FAST_READ: + case DOR: + case QOR: + case DOR_4: + case QOR_4: + return 1; + case DIOR: + case FAST_READ_4: + case DIOR_4: + return 2; + case QIOR: + case QIOR_4: + return 5; + default: + return -1; + } +} + +static inline uint8_t get_addr_length(XilinxSPIPS *s, uint8_t cmd) +{ + switch (cmd) { + case PP_4: + case QPP_4: + case READ_4: + case QIOR_4: + case FAST_READ_4: + case DOR_4: + case QOR_4: + case DIOR_4: + return 4; + default: + return (s->regs[R_CMND] & R_CMND_EXT_ADD) ? 4 : 3; + } +} + static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) { int debug_level =3D 0; + XilinxQSPIPS *q =3D (XilinxQSPIPS *) object_dynamic_cast(OBJECT(s), + TYPE_XILINX_QSP= IPS); =20 for (;;) { int i; uint8_t tx =3D 0; uint8_t tx_rx[num_effective_busses(s)]; + uint8_t dummy_cycles =3D 0; + uint8_t addr_length; =20 if (fifo8_is_empty(&s->tx_fifo)) { if (!(s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE)) { @@ -258,54 +336,102 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) tx_rx[i] =3D fifo8_pop(&s->tx_fifo); } stripe8(tx_rx, num_effective_busses(s), false); - } else { + } else if (s->snoop_state >=3D SNOOP_ADDR) { tx =3D fifo8_pop(&s->tx_fifo); for (i =3D 0; i < num_effective_busses(s); ++i) { tx_rx[i] =3D tx; } + } else { + /* Extract a dummy byte and generate dummy cycles according to= the + * link state */ + tx =3D fifo8_pop(&s->tx_fifo); + dummy_cycles =3D 8 / s->link_state; } =20 for (i =3D 0; i < num_effective_busses(s); ++i) { int bus =3D num_effective_busses(s) - 1 - i; - DB_PRINT_L(debug_level, "tx =3D %02x\n", tx_rx[i]); - tx_rx[i] =3D ssi_transfer(s->spi[bus], (uint32_t)tx_rx[i]); - DB_PRINT_L(debug_level, "rx =3D %02x\n", tx_rx[i]); + if (dummy_cycles) { + int d; + for (d =3D 0; d < dummy_cycles; ++d) { + tx_rx[0] =3D ssi_transfer(s->spi[bus], (uint32_t)tx_rx= [0]); + } + } else { + DB_PRINT_L(debug_level, "tx =3D %02x\n", tx_rx[i]); + tx_rx[i] =3D ssi_transfer(s->spi[bus], (uint32_t)tx_rx[i]); + DB_PRINT_L(debug_level, "rx =3D %02x\n", tx_rx[i]); + } } =20 - if (fifo8_is_full(&s->rx_fifo)) { + if (s->regs[R_CMND] & R_CMND_RXFIFO_DRAIN) { + DB_PRINT_L(debug_level, "dircarding drained rx byte\n"); + /* Do nothing */ + } else if (s->rx_discard) { + DB_PRINT_L(debug_level, "dircarding discarded rx byte\n"); + s->rx_discard -=3D 8 / s->link_state; + } else if (fifo8_is_full(&s->rx_fifo)) { s->regs[R_INTR_STATUS] |=3D IXR_RX_FIFO_OVERFLOW; DB_PRINT_L(0, "rx FIFO overflow"); } else if (s->snoop_state =3D=3D SNOOP_STRIPING) { stripe8(tx_rx, num_effective_busses(s), true); for (i =3D 0; i < num_effective_busses(s); ++i) { fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[i]); + DB_PRINT_L(debug_level, "pushing striped rx byte\n"); } } else { + DB_PRINT_L(debug_level, "pushing unstriped rx byte\n"); fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[0]); } =20 + if (s->link_state_next_when) { + s->link_state_next_when--; + if (!s->link_state_next_when) { + s->link_state =3D s->link_state_next; + } + } + DB_PRINT_L(debug_level, "initial snoop state: %x\n", (unsigned)s->snoop_state); switch (s->snoop_state) { case (SNOOP_CHECKING): - switch (tx) { /* new instruction code */ - case READ: /* 3 address bytes, no dummy bytes/cycles */ - case PP: + /* Store the count of dummy bytes in the txfifo */ + s->cmd_dummies =3D xilinx_spips_num_dummies(q, tx); + addr_length =3D get_addr_length(s, tx); + if (s->cmd_dummies < 0) { + s->snoop_state =3D SNOOP_NONE; + } else { + s->snoop_state =3D SNOOP_ADDR + addr_length - 1; + } + switch (tx) { case DPP: - case QPP: - s->snoop_state =3D 3; - break; - case FAST_READ: /* 3 address bytes, 1 dummy byte */ case DOR: + case DOR_4: + s->link_state_next =3D 2; + s->link_state_next_when =3D addr_length + s->cmd_dummies; + break; + case QPP: + case QPP_4: case QOR: - case DIOR: /* FIXME: these vary between vendor - set to spansi= on */ - s->snoop_state =3D 4; + case QOR_4: + s->link_state_next =3D 4; + s->link_state_next_when =3D addr_length + s->cmd_dummies; + break; + case DIOR: + case DIOR_4: + s->link_state =3D 2; break; - case QIOR: /* 3 address bytes, 2 dummy bytes */ - s->snoop_state =3D 6; + case QIOR: + case QIOR_4: + s->link_state =3D 4; break; - default: + } + break; + case (SNOOP_ADDR): + /* Address has been transmitted, transmit dummy cycles now if + * needed */ + if (s->cmd_dummies < 0) { s->snoop_state =3D SNOOP_NONE; + } else { + s->snoop_state =3D s->cmd_dummies; } break; case (SNOOP_STRIPING): @@ -483,6 +609,7 @@ static void xilinx_qspips_write(void *opaque, hwaddr ad= dr, uint64_t value, unsigned size) { XilinxQSPIPS *q =3D XILINX_QSPIPS(opaque); + XilinxSPIPS *s =3D XILINX_SPIPS(opaque); =20 xilinx_spips_write(opaque, addr, value, size); addr >>=3D 2; @@ -490,6 +617,9 @@ static void xilinx_qspips_write(void *opaque, hwaddr ad= dr, if (addr =3D=3D R_LQSPI_CFG) { xilinx_qspips_invalidate_mmio_ptr(q); } + if (s->regs[R_CMND] & R_CMND_RXFIFO_DRAIN) { + fifo8_reset(&s->rx_fifo); + } } =20 static const MemoryRegionOps qspips_ops =3D { @@ -632,6 +762,7 @@ static void xilinx_spips_realize(DeviceState *dev, Erro= r **errp) } =20 s->cs_lines =3D g_new0(qemu_irq, s->num_cs * s->num_busses); + s->cs_lines_state =3D g_new0(bool, s->num_cs * s->num_busses); for (i =3D 0, cs =3D s->cs_lines; i < s->num_busses; ++i, cs +=3D s->n= um_cs) { ssi_auto_connect_slaves(DEVICE(s), cs, s->spi[i]); } diff --git a/include/hw/ssi/xilinx_spips.h b/include/hw/ssi/xilinx_spips.h index 7f9e2fc..bac90a5 100644 --- a/include/hw/ssi/xilinx_spips.h +++ b/include/hw/ssi/xilinx_spips.h @@ -61,13 +61,19 @@ struct XilinxSPIPS { uint8_t num_busses; =20 uint8_t snoop_state; + int cmd_dummies; + uint8_t link_state; + uint8_t link_state_next; + uint8_t link_state_next_when; qemu_irq *cs_lines; + bool *cs_lines_state; SSIBus **spi; =20 Fifo8 rx_fifo; Fifo8 tx_fifo; =20 uint8_t num_txrx_bytes; + uint32_t rx_discard; =20 uint32_t regs[XLNX_SPIPS_R_MAX]; }; --=20 2.9.3