From nobody Mon Nov 25 10:32:28 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=linux.ibm.com ARC-Seal: i=1; a=rsa-sha256; t=1715795010; cv=none; d=zohomail.com; s=zohoarc; b=KoCmQDGune3AMnPpRTKYqgrNX8da557Da+r5lYy5K4fa9hZ5sR7pgHzZPO64oJxgHIYSfDzpgJMHQfvXEQ7jHC5Z9OWj7jsyhMbvghB2RKnZLgEBZFAiN2ug4yFsx/v7UjcDSygMY4HBxTdboHFf3viyaFhP8DoKN/0yJECSbrY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1715795010; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=fDdEqKsebMY4IH8RYCXUBnrZSxSEEs+/CxArXdXZMk4=; b=CQBjulG/xzCtEnHE49K/i25LsnPlfudUnRdFkhzaIYYzILII5XCCHreh/caL87QTVYgdJshS4NUBaTignIs0ZmmddPRvNjZBs51d3hmCbQs7pbTsPKMlcmN8/yfeQHh5GRrXBbCT6uBevyeFxl/B17wjOYDQ9FflLEu38I0W1eM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1715795010232644.6485136031346; Wed, 15 May 2024 10:43:30 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1s7IeE-00011j-QZ; Wed, 15 May 2024 13:42:38 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s7Ie2-00010p-3S; Wed, 15 May 2024 13:42:26 -0400 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s7Idy-0006X3-Bd; Wed, 15 May 2024 13:42:24 -0400 Received: from pps.filterd (m0360072.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 44FF6J1J025038; Wed, 15 May 2024 17:42:12 GMT Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3y4w9r8rc4-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 May 2024 17:42:12 +0000 Received: from m0360072.ppops.net (m0360072.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 44FHgBfI009810; Wed, 15 May 2024 17:42:11 GMT Received: from ppma11.dal12v.mail.ibm.com (db.9e.1632.ip4.static.sl-reverse.com [50.22.158.219]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3y4w9r8rc3-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 May 2024 17:42:11 +0000 Received: from pps.filterd (ppma11.dal12v.mail.ibm.com [127.0.0.1]) by ppma11.dal12v.mail.ibm.com (8.17.1.19/8.17.1.19) with ESMTP id 44FH2HnV005721; Wed, 15 May 2024 17:42:11 GMT Received: from smtprelay03.fra02v.mail.ibm.com ([9.218.2.224]) by ppma11.dal12v.mail.ibm.com (PPS) with ESMTPS id 3y2nq2vh1b-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 May 2024 17:42:11 +0000 Received: from smtpav02.fra02v.mail.ibm.com (smtpav02.fra02v.mail.ibm.com [10.20.54.101]) by smtprelay03.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 44FHg5mX51380674 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 15 May 2024 17:42:07 GMT Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 1EEAA2004F; Wed, 15 May 2024 17:42:05 +0000 (GMT) Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2F50520040; Wed, 15 May 2024 17:42:03 +0000 (GMT) Received: from gfwr515.rchland.ibm.com (unknown [9.10.239.103]) by smtpav02.fra02v.mail.ibm.com (Postfix) with ESMTP; Wed, 15 May 2024 17:42:03 +0000 (GMT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=fDdEqKsebMY4IH8RYCXUBnrZSxSEEs+/CxArXdXZMk4=; b=rEFLqE141cmWu3zeaQjpZrUOPBZyBpsud43LYyuETdcgcVfgImQ0fw1uz1I9vqzyq7Fv D4F/fgP7wpMpQghPcfoaSLtFwHps+5QBNY0Ofs/CKdk2E671K6LS33q8aJ0DGnAtNUAf M8q13iuE0A09KR/xiEJt20V3fLWuTfvgVus92cKRRYOiDI+fqKF21AAPB3Hok+mqf7rG G1+tj6yeAOpPGL77KQkibapwcV3lBac2j66LjeLCE3ynUDL23ubF2WkK5OsW40nk9JFU YOZa3e5FguTv13vcol+s9IlCidBZZLj3HZD7wNRh/PkwbBT9x6PPUSJ+togfV2JV9NQh Rg== From: Chalapathi V 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, dantan@us.ibm.com, milesg@linux.vnet.ibm.com Subject: [PATCH v3 1/5] ppc/pnv: Add SPI controller model Date: Wed, 15 May 2024 12:41:45 -0500 Message-Id: <20240515174149.17713-2-chalapathi.v@linux.ibm.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20240515174149.17713-1-chalapathi.v@linux.ibm.com> References: <20240515174149.17713-1-chalapathi.v@linux.ibm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: hXTaVKr0JVoY2OtumuRW6t217XNxYa9X X-Proofpoint-GUID: V75ND5DFghV-Xyzoz1kGWEWH3Sf444qD X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.650,FMLib:17.11.176.26 definitions=2024-05-15_10,2024-05-15_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 bulkscore=0 adultscore=0 impostorscore=0 spamscore=0 priorityscore=1501 lowpriorityscore=0 malwarescore=0 mlxscore=0 suspectscore=0 phishscore=0 clxscore=1015 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2405010000 definitions=main-2405150125 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=148.163.158.5; envelope-from=chalapathi.v@linux.ibm.com; helo=mx0b-001b2d01.pphosted.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, 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.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @ibm.com) X-ZM-MESSAGEID: 1715795012334100003 Content-Type: text/plain; charset="utf-8" SPI controller device model supports a connection to a single SPI responder. This provide access to SPI seeproms, TPM, flash device and an ADC controlle= r. All SPI function control is mapped into the SPI register space to enable fu= ll control by firmware. In this commit SPI configuration component is modelled which contains all SPI configuration and status registers as well as the ho= ld registers for data to be sent or having been received. An existing QEMU SSI framework is used and SSI_BUS is created. Signed-off-by: Chalapathi V --- include/hw/ppc/pnv_xscom.h | 3 + include/hw/ssi/pnv_spi.h | 44 +++++++ include/hw/ssi/pnv_spi_regs.h | 114 +++++++++++++++++ hw/ppc/pnv_spi_controller.c | 228 ++++++++++++++++++++++++++++++++++ hw/ppc/Kconfig | 1 + hw/ppc/meson.build | 1 + hw/ppc/trace-events | 6 + 7 files changed, 397 insertions(+) create mode 100644 include/hw/ssi/pnv_spi.h create mode 100644 include/hw/ssi/pnv_spi_regs.h create mode 100644 hw/ppc/pnv_spi_controller.c diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h index 6209e18492..a77b97f9b1 100644 --- a/include/hw/ppc/pnv_xscom.h +++ b/include/hw/ppc/pnv_xscom.h @@ -194,6 +194,9 @@ struct PnvXScomInterfaceClass { #define PNV10_XSCOM_PEC_PCI_BASE 0x8010800 /* index goes upwards ... */ #define PNV10_XSCOM_PEC_PCI_SIZE 0x200 =20 +#define PNV10_XSCOM_PIB_SPIC_BASE 0xc0000 +#define PNV10_XSCOM_PIB_SPIC_SIZE 0x20 + void pnv_xscom_init(PnvChip *chip, uint64_t size, hwaddr addr); int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset, uint64_t xscom_base, uint64_t xscom_size, diff --git a/include/hw/ssi/pnv_spi.h b/include/hw/ssi/pnv_spi.h new file mode 100644 index 0000000000..244ee1cfc0 --- /dev/null +++ b/include/hw/ssi/pnv_spi.h @@ -0,0 +1,44 @@ +/* + * QEMU PowerPC SPI Controller model + * + * Copyright (c) 2024, IBM Corporation. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This model Supports a connection to a single SPI responder. + * Introduced for P10 to provide access to SPI seeproms, TPM, flash device + * and an ADC controller. + */ +#include "hw/ssi/ssi.h" + +#ifndef PPC_PNV_SPI_CONTROLLER_H +#define PPC_PNV_SPI_CONTROLLER_H + +#define TYPE_PNV_SPI_CONTROLLER "pnv-spi-controller" +#define PNV_SPICONTROLLER(obj) \ + OBJECT_CHECK(PnvSpiController, (obj), TYPE_PNV_SPI_CONTROLLER) + +#define SPI_CONTROLLER_REG_SIZE 8 + +#define TYPE_PNV_SPI_BUS "pnv-spi-bus" +typedef struct PnvSpiController { + SysBusDevice parent_obj; + + SSIBus *ssi_bus; + qemu_irq *cs_line; + MemoryRegion xscom_spic_regs; + /* SPI controller object number */ + uint32_t spic_num; + + /* SPI Controller registers */ + uint64_t error_reg; + uint64_t counter_config_reg; + uint64_t config_reg1; + uint64_t clock_config_reset_control; + uint64_t memory_mapping_reg; + uint64_t transmit_data_reg; + uint64_t receive_data_reg; + uint8_t sequencer_operation_reg[SPI_CONTROLLER_REG_SIZE]; + uint64_t status_reg; +} PnvSpiController; +#endif /* PPC_PNV_SPI_CONTROLLER_H */ diff --git a/include/hw/ssi/pnv_spi_regs.h b/include/hw/ssi/pnv_spi_regs.h new file mode 100644 index 0000000000..6f613aca5e --- /dev/null +++ b/include/hw/ssi/pnv_spi_regs.h @@ -0,0 +1,114 @@ +/* + * QEMU PowerPC SPI Controller model + * + * Copyright (c) 2023, IBM Corporation. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef SPI_CONTROLLER_REGS_H +#define SPI_CONTROLLER_REGS_H + +/* Error Register */ +#define ERROR_REG 0x00 + +/* counter_config_reg */ +#define COUNTER_CONFIG_REG 0x01 +#define COUNTER_CONFIG_REG_SHIFT_COUNT_N1 PPC_BITMASK(0, 7) +#define COUNTER_CONFIG_REG_SHIFT_COUNT_N2 PPC_BITMASK(8, 15) +#define COUNTER_CONFIG_REG_COUNT_COMPARE1 PPC_BITMASK(24, 31) +#define COUNTER_CONFIG_REG_COUNT_COMPARE2 PPC_BITMASK(32, 39) +#define COUNTER_CONFIG_REG_N1_COUNT_CONTROL PPC_BITMASK(48, 51) +#define COUNTER_CONFIG_REG_N2_COUNT_CONTROL PPC_BITMASK(52, 55) + +/* config_reg */ +#define CONFIG_REG1 0x02 + +/* clock_config_reset_control_ecc_enable_reg */ +#define CLOCK_CONFIG_REG 0x03 +#define CLOCK_CONFIG_RESET_CONTROL_HARD_RESET 0x0084000000000000; +#define CLOCK_CONFIG_REG_RESET_CONTROL PPC_BITMASK(24, 27) +#define CLOCK_CONFIG_REG_ECC_CONTROL PPC_BITMASK(28, 30) + +/* memory_mapping_reg */ +#define MEMORY_MAPPING_REG 0x04 +#define MEMORY_MAPPING_REG_MMSPISM_BASE_ADDR PPC_BITMASK(0, 15) +#define MEMORY_MAPPING_REG_MMSPISM_ADDR_MASK PPC_BITMASK(16, 31) +#define MEMORY_MAPPING_REG_RDR_MATCH_VAL PPC_BITMASK(32, 47) +#define MEMORY_MAPPING_REG_RDR_MATCH_MASK PPC_BITMASK(48, 63) + +/* transmit_data_reg */ +#define TRANSMIT_DATA_REG 0x05 + +/* receive_data_reg */ +#define RECEIVE_DATA_REG 0x06 + +/* sequencer_operation_reg */ +#define SEQUENCER_OPERATION_REG 0x07 + +/* status_reg */ +#define STATUS_REG 0x08 +#define STATUS_REG_RDR_FULL PPC_BIT(0) +#define STATUS_REG_RDR_OVERRUN PPC_BIT(1) +#define STATUS_REG_RDR_UNDERRUN PPC_BIT(2) +#define STATUS_REG_TDR_FULL PPC_BIT(4) +#define STATUS_REG_TDR_OVERRUN PPC_BIT(5) +#define STATUS_REG_TDR_UNDERRUN PPC_BIT(6) +#define STATUS_REG_SEQUENCER_FSM PPC_BITMASK(8, 15) +#define STATUS_REG_SHIFTER_FSM PPC_BITMASK(16, 27) +#define STATUS_REG_SEQUENCER_INDEX PPC_BITMASK(28, 31) +#define STATUS_REG_GENERAL_SPI_STATUS PPC_BITMASK(32, 63) +#define STATUS_REG_RDR PPC_BITMASK(1, 3) +#define STATUS_REG_TDR PPC_BITMASK(5, 7) + +/* + * Shifter states + * + * These are the same values defined for the Shifter FSM field of the + * status register. It's a 12 bit field so we will represent it as three + * nibbles in the constants. + * + * These are shifter_fsm values + * + * Status reg bits 16-27 -> field bits 0-11 + * bits 0,1,2,5 unused/reserved + * bit 4 crc shift in (unused) + * bit 8 crc shift out (unused) + */ + +#define FSM_DONE 0x100 /* bit 3 */ +#define FSM_SHIFT_N2 0x020 /* bit 6 */ +#define FSM_WAIT 0x010 /* bit 7 */ +#define FSM_SHIFT_N1 0x004 /* bit 9 */ +#define FSM_START 0x002 /* bit 10 */ +#define FSM_IDLE 0x001 /* bit 11 */ + +/* + * Sequencer states + * + * These are sequencer_fsm values + * + * Status reg bits 8-15 -> field bits 0-7 + * bits 0-3 unused/reserved + * + */ +#define SEQ_STATE_INDEX_INCREMENT 0x08 /* bit 4 */ +#define SEQ_STATE_EXECUTE 0x04 /* bit 5 */ +#define SEQ_STATE_DECODE 0x02 /* bit 6 */ +#define SEQ_STATE_IDLE 0x01 /* bit 7 */ + +/* + * These are the supported sequencer operations. + * Only the upper nibble is significant because for many operations + * the lower nibble is a variable specific to the operation. + */ +#define SEQ_OP_STOP 0x00 +#define SEQ_OP_SELECT_SLAVE 0x10 +#define SEQ_OP_SHIFT_N1 0x30 +#define SEQ_OP_SHIFT_N2 0x40 +#define SEQ_OP_BRANCH_IFNEQ_RDR 0x60 +#define SEQ_OP_TRANSFER_TDR 0xC0 +#define SEQ_OP_BRANCH_IFNEQ_INC_1 0xE0 +#define SEQ_OP_BRANCH_IFNEQ_INC_2 0xF0 + +#endif diff --git a/hw/ppc/pnv_spi_controller.c b/hw/ppc/pnv_spi_controller.c new file mode 100644 index 0000000000..11b119cf0f --- /dev/null +++ b/hw/ppc/pnv_spi_controller.c @@ -0,0 +1,228 @@ +/* + * QEMU PowerPC SPI Controller model + * + * Copyright (c) 2024, IBM Corporation. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/qdev-properties.h" +#include "hw/ppc/pnv_xscom.h" +#include "hw/ssi/pnv_spi.h" +#include "hw/ssi/pnv_spi_regs.h" +#include "hw/ssi/ssi.h" +#include "hw/ppc/fdt.h" +#include +#include +#include "hw/irq.h" +#include "trace.h" + +static uint64_t pnv_spi_controller_read(void *opaque, hwaddr addr, + unsigned size) +{ + PnvSpiController *s =3D PNV_SPICONTROLLER(opaque); + uint32_t reg =3D addr >> 3; + uint64_t val =3D ~0ull; + + switch (reg) { + case ERROR_REG: + val =3D s->error_reg; + break; + case COUNTER_CONFIG_REG: + val =3D s->counter_config_reg; + break; + case CONFIG_REG1: + val =3D s->config_reg1; + break; + case CLOCK_CONFIG_REG: + val =3D s->clock_config_reset_control; + break; + case MEMORY_MAPPING_REG: + val =3D s->memory_mapping_reg; + break; + case TRANSMIT_DATA_REG: + val =3D s->transmit_data_reg; + break; + case RECEIVE_DATA_REG: + val =3D s->receive_data_reg; + trace_pnv_spi_read_RDR(val); + s->status_reg =3D SETFIELD(STATUS_REG_RDR_FULL, s->status_reg, 0); + break; + case SEQUENCER_OPERATION_REG: + val =3D 0; + for (int i =3D 0; i < SPI_CONTROLLER_REG_SIZE; i++) { + val =3D (val << 8) | s->sequencer_operation_reg[i]; + } + break; + case STATUS_REG: + val =3D s->status_reg; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "spi_controller_regs: Invalid xscom= " + "read at 0x%08x\n", reg); + } + + trace_pnv_spi_read(addr, val); + return val; +} + +static void pnv_spi_controller_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + PnvSpiController *s =3D PNV_SPICONTROLLER(opaque); + uint32_t reg =3D addr >> 3; + + trace_pnv_spi_write(addr, val); + + switch (reg) { + case ERROR_REG: + s->error_reg =3D val; + break; + case COUNTER_CONFIG_REG: + s->counter_config_reg =3D val; + break; + case CONFIG_REG1: + s->config_reg1 =3D val; + break; + case CLOCK_CONFIG_REG: + /* + * To reset the SPI controller write the sequence 0x5 0xA to + * reset_control field + */ + if (GETFIELD(CLOCK_CONFIG_REG_RESET_CONTROL, + s->clock_config_reset_control) =3D=3D 0x5)= { + if (GETFIELD(CLOCK_CONFIG_REG_RESET_CONTROL, val) =3D=3D 0xA) { + /* SPI controller reset sequence completed, resetting */ + s->clock_config_reset_control =3D + CLOCK_CONFIG_RESET_CONTROL_HARD_RESET; + } else { + s->clock_config_reset_control =3D val; + } + } else { + s->clock_config_reset_control =3D val; + } + break; + case MEMORY_MAPPING_REG: + s->memory_mapping_reg =3D val; + break; + case TRANSMIT_DATA_REG: + /* + * Writing to the transmit data register causes the transmit data + * register full status bit in the status register to be set. Wri= ting + * when the transmit data register full status bit is already set + * causes a "Resource Not Available" condition. This is not possi= ble + * in the model since writes to this register are not asynchronous= to + * the operation sequence like it would be in hardware. + */ + s->transmit_data_reg =3D val; + trace_pnv_spi_write_TDR(val); + s->status_reg =3D SETFIELD(STATUS_REG_TDR_FULL, s->status_reg, 1); + s->status_reg =3D SETFIELD(STATUS_REG_TDR_UNDERRUN, s->status_reg,= 0); + break; + case RECEIVE_DATA_REG: + s->receive_data_reg =3D val; + break; + case SEQUENCER_OPERATION_REG: + for (int i =3D 0; i < SPI_CONTROLLER_REG_SIZE; i++) { + s->sequencer_operation_reg[i] =3D (val >> (56 - i * 8)) & 0xFF; + } + break; + case STATUS_REG: + /* other fields are ignore_write */ + s->status_reg =3D SETFIELD(STATUS_REG_RDR_OVERRUN, s->status_reg, + GETFIELD(STATUS_REG_RDR, val)); + s->status_reg =3D SETFIELD(STATUS_REG_TDR_OVERRUN, s->status_reg, + GETFIELD(STATUS_REG_TDR, val)); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "spi_controller_regs: Invalid xscom= " + "write at 0x%08x\n", reg); + } + return; +} + +static const MemoryRegionOps pnv_spi_controller_xscom_ops =3D { + .read =3D pnv_spi_controller_read, + .write =3D pnv_spi_controller_write, + .valid.min_access_size =3D 8, + .valid.max_access_size =3D 8, + .impl.min_access_size =3D 8, + .impl.max_access_size =3D 8, + .endianness =3D DEVICE_BIG_ENDIAN, +}; + +static Property pnv_spi_controller_properties[] =3D { + DEFINE_PROP_UINT32("spic_num", PnvSpiController, spic_num, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pnv_spi_controller_realize(DeviceState *dev, Error **errp) +{ + PnvSpiController *s =3D PNV_SPICONTROLLER(dev); + g_autofree char *name =3D g_strdup_printf(TYPE_PNV_SPI_BUS ".%d", + s->spic_num); + s->ssi_bus =3D ssi_create_bus(dev, name); + s->cs_line =3D g_new0(qemu_irq, 1); + qdev_init_gpio_out_named(DEVICE(s), s->cs_line, "cs", 1); + + /* spi controller scoms */ + pnv_xscom_region_init(&s->xscom_spic_regs, OBJECT(s), + &pnv_spi_controller_xscom_ops, s, + "xscom-spi-controller-regs", + PNV10_XSCOM_PIB_SPIC_SIZE); +} + +static int pnv_spi_controller_dt_xscom(PnvXScomInterface *dev, void *fdt, + int offset) +{ + PnvSpiController *s =3D PNV_SPICONTROLLER(dev); + g_autofree char *name; + int s_offset; + const char compat[] =3D "ibm,power10-spi_controller"; + uint32_t spic_pcba =3D PNV10_XSCOM_PIB_SPIC_BASE + + s->spic_num * PNV10_XSCOM_PIB_SPIC_SIZE; + uint32_t reg[] =3D { + cpu_to_be32(spic_pcba), + cpu_to_be32(PNV10_XSCOM_PIB_SPIC_SIZE) + }; + name =3D g_strdup_printf("spi_controller@%x", spic_pcba); + s_offset =3D fdt_add_subnode(fdt, offset, name); + _FDT(s_offset); + + _FDT(fdt_setprop(fdt, s_offset, "reg", reg, sizeof(reg))); + _FDT(fdt_setprop(fdt, s_offset, "compatible", compat, sizeof(compat))); + _FDT((fdt_setprop_cell(fdt, s_offset, "spic_num#", s->spic_num))); + return 0; +} + +static void pnv_spi_controller_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + PnvXScomInterfaceClass *xscomc =3D PNV_XSCOM_INTERFACE_CLASS(klass); + + xscomc->dt_xscom =3D pnv_spi_controller_dt_xscom; + + dc->desc =3D "PowerNV SPI Controller"; + dc->realize =3D pnv_spi_controller_realize; + device_class_set_props(dc, pnv_spi_controller_properties); +} + +static const TypeInfo pnv_spi_controller_info =3D { + .name =3D TYPE_PNV_SPI_CONTROLLER, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(PnvSpiController), + .class_init =3D pnv_spi_controller_class_init, + .interfaces =3D (InterfaceInfo[]) { + { TYPE_PNV_XSCOM_INTERFACE }, + { } + } +}; + +static void pnv_spi_controller_register_types(void) +{ + type_register_static(&pnv_spi_controller_info); +} + +type_init(pnv_spi_controller_register_types); diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig index 78f83e78ce..6f9670b377 100644 --- a/hw/ppc/Kconfig +++ b/hw/ppc/Kconfig @@ -39,6 +39,7 @@ config POWERNV select PCI_POWERNV select PCA9552 select PCA9554 + select SSI =20 config PPC405 bool diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build index d096636ee7..68fadbae7b 100644 --- a/hw/ppc/meson.build +++ b/hw/ppc/meson.build @@ -56,6 +56,7 @@ ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files( 'pnv_pnor.c', 'pnv_nest_pervasive.c', 'pnv_n1_chiplet.c', + 'pnv_spi_controller.c', )) # PowerPC 4xx boards ppc_ss.add(when: 'CONFIG_PPC405', if_true: files( diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index bf29bbfd4b..b8e494ffc5 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -110,6 +110,12 @@ pnv_sbe_cmd_timer_stop(void) "" pnv_sbe_cmd_timer_expired(void) "" pnv_sbe_msg_recv(uint16_t cmd, uint16_t seq, uint16_t ctrl_flags) "cmd 0x%= " PRIx16 " seq %"PRIu16 " ctrl_flags 0x%" PRIx16 =20 +#pnv_spi_controller.c +pnv_spi_read(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRI= x64 +pnv_spi_write(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PR= Ix64 +pnv_spi_read_RDR(uint64_t val) "data extracted =3D 0x%" PRIx64 +pnv_spi_write_TDR(uint64_t val) "being written, data written =3D 0x%" PRIx= 64 + # ppc.c ppc_tb_adjust(uint64_t offs1, uint64_t offs2, int64_t diff, int64_t second= s) "adjusted from 0x%"PRIx64" to 0x%"PRIx64", diff %"PRId64" (%"PRId64"s)" ppc_tb_load(uint64_t tb) "tb 0x%016" PRIx64 --=20 2.39.3 From nobody Mon Nov 25 10:32:28 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=linux.ibm.com ARC-Seal: i=1; a=rsa-sha256; t=1715795053; cv=none; d=zohomail.com; s=zohoarc; b=WPzq8wZ5fTeD1kNSHiOH6vdwmcRzJVRxflzKNasPUSh3ObdVcD3hbBWA8IUOkULz2CVtgXncvPCJAEOxcJE95yiXKkhs83TRN5OyAMuSxfYFlUmV7vYviYCLkJpObvFTYRSOb/DQQp2m3W9mxmfmYtb6u29psbKXE0rzzM/NkOQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1715795053; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=t8vaAO6VLp42dzpqeuFQWY0KBaPFtXaq3/l2waaBs1I=; b=X9QButQ16WodUC8OClZ2IBdntL/ZVlZBmIgbTK0GdM/dTj2oN8DpxNS1Vy/pbMDwadDX6tPNTcjCUgxID1qSZX0qi/QajZ5U3khIv2u7pUzZErfwBSSypHSUwW68s1EhI5lsQZDhwSQZyQn75OaZIT0b4PwJUgHiZlD7oqu+i4c= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1715795053007555.3395720159591; Wed, 15 May 2024 10:44:13 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1s7IfE-0001Rq-0s; Wed, 15 May 2024 13:43:45 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s7IeP-00014T-Nd; Wed, 15 May 2024 13:42:54 -0400 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s7Ie9-0006ZG-UE; Wed, 15 May 2024 13:42:47 -0400 Received: from pps.filterd (m0356517.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 44FHapbJ024503; Wed, 15 May 2024 17:42:19 GMT Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3y51kug0a0-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 May 2024 17:42:19 +0000 Received: from m0356517.ppops.net (m0356517.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 44FHgIGf032344; Wed, 15 May 2024 17:42:18 GMT Received: from ppma23.wdc07v.mail.ibm.com (5d.69.3da9.ip4.static.sl-reverse.com [169.61.105.93]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3y51kug09x-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 May 2024 17:42:18 +0000 Received: from pps.filterd (ppma23.wdc07v.mail.ibm.com [127.0.0.1]) by ppma23.wdc07v.mail.ibm.com (8.17.1.19/8.17.1.19) with ESMTP id 44FFgTXB005986; Wed, 15 May 2024 17:42:17 GMT Received: from smtprelay02.fra02v.mail.ibm.com ([9.218.2.226]) by ppma23.wdc07v.mail.ibm.com (PPS) with ESMTPS id 3y2mgmmvyg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 May 2024 17:42:17 +0000 Received: from smtpav02.fra02v.mail.ibm.com (smtpav02.fra02v.mail.ibm.com [10.20.54.101]) by smtprelay02.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 44FHgBjk47972770 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 15 May 2024 17:42:13 GMT Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id F25B820040; Wed, 15 May 2024 17:42:10 +0000 (GMT) Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D49D320043; Wed, 15 May 2024 17:42:08 +0000 (GMT) Received: from gfwr515.rchland.ibm.com (unknown [9.10.239.103]) by smtpav02.fra02v.mail.ibm.com (Postfix) with ESMTP; Wed, 15 May 2024 17:42:08 +0000 (GMT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=t8vaAO6VLp42dzpqeuFQWY0KBaPFtXaq3/l2waaBs1I=; b=acnzSEh1lcQ5gfFeQfMFIsj9EKrHty/JLD9ZLkYxkvYwqJwqVC3JNC0nf3PMAhpMCkfB aRMcH+nUVX5gqZrk9NBYsuLWBDAkmWRFFrU42kIwG5t4o4Az8tInRyLHF5wWk8jX9Iy4 LOIrgXxZaPWofLdRyzlSVTk3GW4jBkbftZ6TgrvqFTKpZj1D2BHX3FYGZPR+FIdlX8GA xVk4/OotVZy/oE/HH1WkEcx9SrqVkCgZljQ8Cc2XaBlXpFGD6/c483tupHvOdIEa/KdX xIGGYQj7TTeRwoKpTunWbjTZZ8sJmRzIkPuvdY0mGFtZY7ipiRIBvx6wcHDYgyHMJyQ/ 2Q== From: Chalapathi V 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, dantan@us.ibm.com, milesg@linux.vnet.ibm.com Subject: [PATCH v3 2/5] ppc/pnv: Extend SPI model Date: Wed, 15 May 2024 12:41:46 -0500 Message-Id: <20240515174149.17713-3-chalapathi.v@linux.ibm.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20240515174149.17713-1-chalapathi.v@linux.ibm.com> References: <20240515174149.17713-1-chalapathi.v@linux.ibm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Proofpoint-GUID: Q7lKeZaGpar-u5NlxCYQA4WTSo-vIng3 X-Proofpoint-ORIG-GUID: _dgjoyMyVD1ibxlD91eL1Be9etckjQkW X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.650,FMLib:17.11.176.26 definitions=2024-05-15_10,2024-05-15_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 phishscore=0 bulkscore=0 lowpriorityscore=0 adultscore=0 mlxlogscore=999 malwarescore=0 clxscore=1015 impostorscore=0 mlxscore=0 priorityscore=1501 spamscore=0 suspectscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2405010000 definitions=main-2405150125 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=148.163.156.1; envelope-from=chalapathi.v@linux.ibm.com; helo=mx0a-001b2d01.pphosted.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, 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.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @ibm.com) X-ZM-MESSAGEID: 1715795054561100005 Content-Type: text/plain; charset="utf-8" In this commit SPI shift engine and sequencer logic is implemented. Shift engine performs serialization and de-serialization according to the control by the sequencer and according to the setup defined in the configuration registers. Sequencer implements the main control logic and FSM to handle data transmit and data receive control of the shift engine. Signed-off-by: Chalapathi V --- include/hw/ssi/pnv_spi.h | 28 + hw/ppc/pnv_spi_controller.c | 1074 +++++++++++++++++++++++++++++++++++ hw/ppc/trace-events | 15 + 3 files changed, 1117 insertions(+) diff --git a/include/hw/ssi/pnv_spi.h b/include/hw/ssi/pnv_spi.h index 244ee1cfc0..6e2bceab3b 100644 --- a/include/hw/ssi/pnv_spi.h +++ b/include/hw/ssi/pnv_spi.h @@ -8,6 +8,14 @@ * This model Supports a connection to a single SPI responder. * Introduced for P10 to provide access to SPI seeproms, TPM, flash device * and an ADC controller. + * + * All SPI function control is mapped into the SPI register space to enable + * full control by firmware. + * + * SPI Controller has sequencer and shift engine. The SPI shift engine + * performs serialization and de-serialization according to the control by + * the sequencer and according to the setup defined in the configuration + * registers and the SPI sequencer implements the main control logic. */ #include "hw/ssi/ssi.h" =20 @@ -29,6 +37,25 @@ typedef struct PnvSpiController { MemoryRegion xscom_spic_regs; /* SPI controller object number */ uint32_t spic_num; + uint8_t transfer_len; + uint8_t responder_select; + /* To verify if shift_n1 happens prior to shift_n2 */ + bool shift_n1_done; + /* Loop counter for branch operation opcode Ex/Fx */ + uint8_t loop_counter_1; + uint8_t loop_counter_2; + /* N1/N2_bits specifies the size of the N1/N2 segment of a frame in bi= ts.*/ + uint8_t N1_bits; + uint8_t N2_bits; + /* Number of bytes in a payload for the N1/N2 frame segment.*/ + uint8_t N1_bytes; + uint8_t N2_bytes; + /* Number of N1/N2 bytes marked for transmit */ + uint8_t N1_tx; + uint8_t N2_tx; + /* Number of N1/N2 bytes marked for receive */ + uint8_t N1_rx; + uint8_t N2_rx; =20 /* SPI Controller registers */ uint64_t error_reg; @@ -40,5 +67,6 @@ typedef struct PnvSpiController { uint64_t receive_data_reg; uint8_t sequencer_operation_reg[SPI_CONTROLLER_REG_SIZE]; uint64_t status_reg; + } PnvSpiController; #endif /* PPC_PNV_SPI_CONTROLLER_H */ diff --git a/hw/ppc/pnv_spi_controller.c b/hw/ppc/pnv_spi_controller.c index 11b119cf0f..e87f583074 100644 --- a/hw/ppc/pnv_spi_controller.c +++ b/hw/ppc/pnv_spi_controller.c @@ -19,6 +19,1072 @@ #include "hw/irq.h" #include "trace.h" =20 +/* PnvXferBuffer */ +typedef struct PnvXferBuffer { + + uint32_t len; + uint8_t *data; + +} PnvXferBuffer; + +/* pnv_spi_xfer_buffer_methods */ +static PnvXferBuffer *pnv_spi_xfer_buffer_new(void) +{ + PnvXferBuffer *payload =3D g_malloc0(sizeof(*payload)); + + return payload; +} + +static void pnv_spi_xfer_buffer_free(PnvXferBuffer *payload) +{ + free(payload->data); + free(payload); +} + +static uint8_t *pnv_spi_xfer_buffer_write_ptr(PnvXferBuffer *payload, + uint32_t offset, uint32_t length) +{ + if (payload->len < (offset + length)) { + payload->len =3D offset + length; + payload->data =3D g_realloc(payload->data, payload->len); + } + return &payload->data[offset]; +} + +static bool does_rdr_match(PnvSpiController *s) +{ + /* + * According to spec, the mask bits that are 0 are compared and the + * bits that are 1 are ignored. + */ + uint16_t rdr_match_mask =3D GETFIELD(MEMORY_MAPPING_REG_RDR_MATCH_MASK, + s->memory_mapping_reg); + uint16_t rdr_match_val =3D GETFIELD(MEMORY_MAPPING_REG_RDR_MATCH_VAL, + s->memory_mapping_reg); + + if ((~rdr_match_mask & rdr_match_val) =3D=3D ((~rdr_match_mask) & + GETFIELD(PPC_BITMASK(48, 63), s->receive_data_reg))) { + return true; + } + return false; +} + +static uint8_t get_from_offset(PnvSpiController *s, uint8_t offset) +{ + uint8_t byte; + + /* + * Offset is an index between 0 and SPI_CONTROLLER_REG_SIZE - 1 + * Check the offset before using it. + */ + if (offset < SPI_CONTROLLER_REG_SIZE) { + byte =3D (s->transmit_data_reg >> (56 - offset * 8)) & 0xFF; + } else { + /* + * Log an error and return a 0xFF since we have to assign something + * to byte before returning. + */ + qemu_log_mask(LOG_GUEST_ERROR, "Invalid offset =3D %d used to get = byte " + "from TDR\n", offset); + byte =3D 0xff; + } + return byte; +} + +static uint8_t read_from_frame(PnvSpiController *s, uint8_t *read_buf, + uint8_t nr_bytes, uint8_t ecc_count, uint8_t shift_in_coun= t) +{ + uint8_t byte; + int count =3D 0; + + while (count < nr_bytes) { + shift_in_count++; + if ((ecc_count !=3D 0) && + (shift_in_count =3D=3D (SPI_CONTROLLER_REG_SIZE + ecc_count)))= { + shift_in_count =3D 0; + } else { + byte =3D read_buf[count]; + trace_pnv_spi_shift_rx(byte, count); + s->receive_data_reg =3D (s->receive_data_reg << 8) | byte; + } + count++; + } /* end of while */ + return shift_in_count; +} + +static void spi_response(PnvSpiController *s, int bits, + PnvXferBuffer *rsp_payload) +{ + uint8_t ecc_count; + uint8_t shift_in_count; + + /* + * Processing here must handle: + * - Which bytes in the payload we should move to the RDR + * - Explicit mode counter configuration settings + * - RDR full and RDR overrun status + */ + + /* + * First check that the response payload is the exact same + * number of bytes as the request payload was + */ + if (rsp_payload->len !=3D (s->N1_bytes + s->N2_bytes)) { + qemu_log_mask(LOG_GUEST_ERROR, "Invalid response payload size in " + "bytes, expected %d, got %d\n", + (s->N1_bytes + s->N2_bytes), rsp_payload->len); + } else { + uint8_t ecc_control; + trace_pnv_spi_rx_received(rsp_payload->len); + trace_pnv_spi_log_Ncounts(s->N1_bits, s->N1_bytes, s->N1_tx, + s->N1_rx, s->N2_bits, s->N2_bytes, s->N2_tx, s->N2= _rx); + /* + * Adding an ECC count let's us know when we have found a payload = byte + * that was shifted in but cannot be loaded into RDR. Bits 29-30 = of + * clock_config_reset_control register equal to either 0b00 or 0b10 + * indicate that we are taking in data with ECC and either applying + * the ECC or discarding it. + */ + ecc_count =3D 0; + ecc_control =3D GETFIELD(PPC_BITMASK(29, 30), + s->clock_config_reset_control); + if (ecc_control =3D=3D 0 || ecc_control =3D=3D 2) { + ecc_count =3D 1; + } + /* + * Use the N1_rx and N2_rx counts to control shifting data from the + * payload into the RDR. Keep an overall count of the number of b= ytes + * shifted into RDR so we can discard every 9th byte when ECC is + * enabled. + */ + shift_in_count =3D 0; + /* Handle the N1 portion of the frame first */ + if (s->N1_rx !=3D 0) { + trace_pnv_spi_rx_read_N1frame(); + shift_in_count =3D read_from_frame(s, &rsp_payload->data[0], + s->N1_bytes, ecc_count, shift_in_count); + } + /* Handle the N2 portion of the frame */ + if (s->N2_rx !=3D 0) { + trace_pnv_spi_rx_read_N2frame(); + shift_in_count =3D read_from_frame(s, + &rsp_payload->data[s->N1_bytes], s->N2_bytes, + ecc_count, shift_in_count); + } + if ((s->N1_rx + s->N2_rx) > 0) { + /* + * Data was received so handle RDR status. + * It is easier to handle RDR_full and RDR_overrun status here + * since the RDR register's shift_byte_in method is called + * multiple times in a row. Controlling RDR status is done here + * instead of in the RDR scoped methods for that reason. + */ + if (GETFIELD(STATUS_REG_RDR_FULL, s->status_reg) =3D=3D 1) { + /* + * Data was shifted into the RDR before having been read + * causing previous data to have been overrun. + */ + s->status_reg =3D SETFIELD(STATUS_REG_RDR_OVERRUN, + s->status_reg, 1); + } else { + /* + * Set status to indicate that the received data register = is + * full. This flag is only cleared once the RDR is unloade= d. + */ + s->status_reg =3D SETFIELD(STATUS_REG_RDR_FULL, + s->status_reg, 1); + } + } + } /* end of else */ +} /* end of spi_response() */ + +static void transfer(PnvSpiController *s, PnvXferBuffer *payload) +{ + uint32_t tx; + uint32_t rx; + PnvXferBuffer *rsp_payload =3D NULL; + + rsp_payload =3D pnv_spi_xfer_buffer_new(); + for (int offset =3D 0; offset < payload->len; offset +=3D s->transfer_= len) { + tx =3D 0; + for (int i =3D 0; i < s->transfer_len; i++) { + if ((offset + i) >=3D payload->len) { + tx <<=3D 8; + } else { + tx =3D (tx << 8) | payload->data[offset + i]; + } + } + rx =3D ssi_transfer(s->ssi_bus, tx); + for (int i =3D 0; i < s->transfer_len; i++) { + if ((offset + i) >=3D payload->len) { + break; + } + *(pnv_spi_xfer_buffer_write_ptr(rsp_payload, rsp_payload->len,= 1)) =3D + (rx >> (8 * (s->transfer_len - 1) - i * 8)) & 0xFF; + } + } + if (rsp_payload !=3D NULL) { + spi_response(s, s->N1_bits, rsp_payload); + } +} + +static inline uint8_t get_seq_index(PnvSpiController *s) +{ + return GETFIELD(STATUS_REG_SEQUENCER_INDEX, s->status_reg); +} + +static inline void next_sequencer_fsm(PnvSpiController *s) +{ + uint8_t seq_index =3D get_seq_index(s); + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_INDEX, s->status_reg, + (seq_index + 1)); + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_FSM, s->status_reg, + SEQ_STATE_INDEX_INCREMENT); +} + +/* + * Calculate the N1 counters based on passed in opcode and + * internal register values. + * The method assumes that the opcode is a Shift_N1 opcode + * and doesn't test it. + * The counters returned are: + * N1 bits: Number of bits in the payload data that are significant + * to the responder. + * N1_bytes: Total count of payload bytes for the N1 (portion of the) fram= e. + * N1_tx: Total number of bytes taken from TDR for N1 + * N1_rx: Total number of bytes taken from the payload for N1 + */ +static void calculate_N1(PnvSpiController *s, uint8_t opcode) +{ + /* + * Shift_N1 opcode form: 0x3M + * Implicit mode: + * If M !=3D 0 the shift count is M bytes and M is the number of tx by= tes. + * Forced Implicit mode: + * M is the shift count but tx and rx is determined by the count contr= ol + * register fields. Note that we only check for forced Implicit mode = when + * M !=3D 0 since the mode doesn't make sense when M =3D 0. + * Explicit mode: + * If M =3D=3D 0 then shift count is number of bits defined in the + * Counter Configuration Register's shift_count_N1 field. + */ + if (GETFIELD(PPC_BITMASK8(4, 7), opcode) =3D=3D 0) { + /* Explicit mode */ + s->N1_bits =3D GETFIELD(COUNTER_CONFIG_REG_SHIFT_COUNT_N1, + s->counter_config_reg); + s->N1_bytes =3D ceil(s->N1_bits / 8); + s->N1_tx =3D 0; + s->N1_rx =3D 0; + /* If tx count control for N1 is set, load the tx value */ + if (GETFIELD(PPC_BIT(50), s->counter_config_reg) =3D=3D 1) { + s->N1_tx =3D s->N1_bytes; + } + /* If rx count control for N1 is set, load the rx value */ + if (GETFIELD(PPC_BIT(51), s->counter_config_reg) =3D=3D 1) { + s->N1_rx =3D s->N1_bytes; + } + } else { + /* Implicit mode/Forced Implicit mode, use M field from opcode */ + s->N1_bytes =3D GETFIELD(PPC_BITMASK8(4, 7), opcode); + s->N1_bits =3D s->N1_bytes * 8; + /* + * Assume that we are going to transmit the count + * (pure Implicit only) + */ + s->N1_tx =3D s->N1_bytes; + s->N1_rx =3D 0; + /* Let Forced Implicit mode have an effect on the counts */ + if (GETFIELD(PPC_BIT(49), s->counter_config_reg) =3D=3D 1) { + /* + * If Forced Implicit mode and count control doesn't + * indicate transmit then reset the tx count to 0 + */ + if (GETFIELD(PPC_BIT(50), s->counter_config_reg) =3D=3D 0) { + s->N1_tx =3D 0; + } + /* If rx count control for N1 is set, load the rx value */ + if (GETFIELD(PPC_BIT(51), s->counter_config_reg) =3D=3D 1) { + s->N1_rx =3D s->N1_bytes; + } + } + } + /* + * Enforce an upper limit on the size of N1 that is equal to the known= size + * of the shift register, 64 bits or 72 bits if ECC is enabled. + * If the size exceeds 72 bits it is a user error so log an error, + * cap the size at a max of 64 bits or 72 bits and set the sequencer F= SM + * error bit. + */ + uint8_t ecc_control =3D GETFIELD(PPC_BITMASK(29, 30), + s->clock_config_reset_control); + if (ecc_control =3D=3D 0 || ecc_control =3D=3D 2) { + if (s->N1_bytes > (SPI_CONTROLLER_REG_SIZE + 1)) { + qemu_log_mask(LOG_GUEST_ERROR, "Unsupported N1 shift size when= " + "ECC enabled, bytes =3D 0x%x, bits =3D 0x%x\n", + s->N1_bytes, s->N1_bits); + s->N1_bytes =3D SPI_CONTROLLER_REG_SIZE + 1; + s->N1_bits =3D s->N1_bytes * 8; + } + } else if (s->N1_bytes > SPI_CONTROLLER_REG_SIZE) { + qemu_log_mask(LOG_GUEST_ERROR, "Unsupported N1 shift size, " + "bytes =3D 0x%x, bits =3D 0x%x\n", + s->N1_bytes, s->N1_bits); + s->N1_bytes =3D SPI_CONTROLLER_REG_SIZE; + s->N1_bits =3D s->N1_bytes * 8; + } +} /* end of calculate_N1 */ + +/* + * Shift_N1 operation handler method + */ +static bool operation_shiftn1(PnvSpiController *s, uint8_t opcode, + PnvXferBuffer **payload, bool send_n1_alone) +{ + uint8_t n1_count; + bool stop =3D false; + + /* + * If there isn't a current payload left over from a stopped sequence + * create a new one. + */ + if (*payload =3D=3D NULL) { + *payload =3D pnv_spi_xfer_buffer_new(); + } + /* + * Use a combination of N1 counters to build the N1 portion of the + * transmit payload. + * We only care about transmit at this time since the request payload + * only represents data going out on the controller output line. + * Leave mode specific considerations in the calculate function since + * all we really care about are counters that tell use exactly how + * many bytes are in the payload and how many of those bytes to + * include from the TDR into the payload. + */ + calculate_N1(s, opcode); + trace_pnv_spi_log_Ncounts(s->N1_bits, s->N1_bytes, s->N1_tx, + s->N1_rx, s->N2_bits, s->N2_bytes, s->N2_tx, s->N2_rx); + /* + * Zero out the N2 counters here in case there is no N2 operation foll= owing + * the N1 operation in the sequencer. This keeps leftover N2 informat= ion + * from interfering with spi_response logic. + */ + s->N2_bits =3D 0; + s->N2_bytes =3D 0; + s->N2_tx =3D 0; + s->N2_rx =3D 0; + /* + * N1_bytes is the overall size of the N1 portion of the frame regardl= ess of + * whether N1 is used for tx, rx or both. Loop over the size to build= a + * payload that is N1_bytes long. + * N1_tx is the count of bytes to take from the TDR and "shift" into t= he + * frame which means append those bytes to the payload for the N1 port= ion + * of the frame. + * If N1_tx is 0 or if the count exceeds the size of the TDR append 0x= FF to + * the frame until the overall N1 count is reached. + */ + n1_count =3D 0; + while (n1_count < s->N1_bytes) { + /* + * Assuming that if N1_tx is not equal to 0 then it is the same as + * N1_bytes. + */ + if ((s->N1_tx !=3D 0) && (n1_count < SPI_CONTROLLER_REG_SIZE)) { + + if (GETFIELD(STATUS_REG_TDR_FULL, s->status_reg) =3D=3D 1) { + /* + * Note that we are only appending to the payload IF the T= DR + * is full otherwise we don't touch the payload because we= are + * going to NOT send the payload and instead tell the sequ= encer + * that called us to stop and wait for a TDR write so we h= ave + * data to load into the payload. + */ + uint8_t n1_byte =3D 0x00; + n1_byte =3D get_from_offset(s, n1_count); + trace_pnv_spi_tx_append("n1_byte", n1_byte, n1_count); + *(pnv_spi_xfer_buffer_write_ptr(*payload, (*payload)->len,= 1)) =3D + n1_byte; + } else { + /* + * We hit a shift_n1 opcode TX but the TDR is empty, tell = the + * sequencer to stop and break this loop. + */ + trace_pnv_spi_sequencer_stop_requested("Shift N1" + "set for transmit but TDR is empty"); + stop =3D true; + break; + } + } else { + /* + * Cases here: + * - we are receiving during the N1 frame segment and the RDR + * is full so we need to stop until the RDR is read + * - we are transmitting and we don't care about RDR status + * since we won't be loading RDR during the frame segment. + * - we are receiving and the RDR is empty so we allow the ope= ration + * to proceed. + */ + if ((s->N1_rx !=3D 0) && (GETFIELD(STATUS_REG_RDR_FULL, + s->status_reg) =3D=3D 1)) { + trace_pnv_spi_sequencer_stop_requested("shift N1" + "set for receive but RDR is full"); + stop =3D true; + break; + } else { + trace_pnv_spi_tx_append_FF("n1_byte"); + *(pnv_spi_xfer_buffer_write_ptr(*payload, (*payload)->len,= 1)) + =3D 0xff; + } + } + n1_count++; + } /* end of while */ + /* + * If we are not stopping due to an empty TDR and we are doing an N1 TX + * and the TDR is full we need to clear the TDR_full status. + * Do this here instead of up in the loop above so we don't log the me= ssage + * in every loop iteration. + * Ignore the send_n1_alone flag, all that does is defer the TX until = the N2 + * operation, which was found immediately after the current opcode. T= he TDR + * was unloaded and will be shifted so we have to clear the TDR_full s= tatus. + */ + if (!stop && (s->N1_tx !=3D 0) && + (GETFIELD(STATUS_REG_TDR_FULL, s->status_reg) =3D=3D 1)) { + s->status_reg =3D SETFIELD(STATUS_REG_TDR_FULL, s->status_reg, 0); + } + /* + * There are other reasons why the shifter would stop, such as a TDR e= mpty + * or RDR full condition with N1 set to receive. If we haven't stoppe= d due + * to either one of those conditions then check if the send_n1_alone f= lag is + * equal to False, indicating the next opcode is an N2 operation, AND = if + * the N2 counter reload switch (bit 0 of the N2 count control field) = is + * set. This condition requires a pacing write to "kick" off the N2 + * shift which includes the N1 shift as well when send_n1_alone is Fal= se. + */ + if (!stop && !send_n1_alone && + (GETFIELD(PPC_BIT(52), s->counter_config_reg) =3D=3D 1)) { + trace_pnv_spi_sequencer_stop_requested("N2 counter reload " + "active, stop N1 shift, TDR_underrun set to 1"); + stop =3D true; + s->status_reg =3D SETFIELD(STATUS_REG_TDR_UNDERRUN, s->status_reg,= 1); + } + /* + * If send_n1_alone is set AND we have a full TDR then this is the fir= st and + * last payload to send and we don't have an N2 frame segment to add t= o the + * payload. + */ + if (send_n1_alone && !stop) { + /* We have a TX and a full TDR or an RX and an empty RDR */ + trace_pnv_spi_tx_request("Shifting N1 frame", (*payload)->len); + transfer(s, *payload); + /* The N1 frame shift is complete so reset the N1 counters */ + s->N2_bits =3D 0; + s->N2_bytes =3D 0; + s->N2_tx =3D 0; + s->N2_rx =3D 0; + pnv_spi_xfer_buffer_free(*payload); + *payload =3D NULL; + } + return stop; +} /* end of operation_shiftn1() */ + +/* + * Calculate the N2 counters based on passed in opcode and + * internal register values. + * The method assumes that the opcode is a Shift_N2 opcode + * and doesn't test it. + * The counters returned are: + * N2 bits: Number of bits in the payload data that are significant + * to the responder. + * N2_bytes: Total count of payload bytes for the N2 frame. + * N2_tx: Total number of bytes taken from TDR for N2 + * N2_rx: Total number of bytes taken from the payload for N2 + */ +static void calculate_N2(PnvSpiController *s, uint8_t opcode) +{ + /* + * Shift_N2 opcode form: 0x4M + * Implicit mode: + * If M!=3D0 the shift count is M bytes and M is the number of rx byte= s. + * Forced Implicit mode: + * M is the shift count but tx and rx is determined by the count contr= ol + * register fields. Note that we only check for Forced Implicit mode = when + * M !=3D 0 since the mode doesn't make sense when M =3D 0. + * Explicit mode: + * If M=3D=3D0 then shift count is number of bits defined in the + * Counter Configuration Register's shift_count_N1 field. + */ + if (GETFIELD(PPC_BITMASK8(4, 7), opcode) =3D=3D 0) { + /* Explicit mode */ + s->N2_bits =3D GETFIELD(COUNTER_CONFIG_REG_SHIFT_COUNT_N2, + s->counter_config_reg); + s->N2_bytes =3D ceil(s->N2_bits / 8); + s->N2_tx =3D 0; + s->N2_rx =3D 0; + /* If tx count control for N2 is set, load the tx value */ + if (GETFIELD(PPC_BIT(54), s->counter_config_reg) =3D=3D 1) { + s->N2_tx =3D s->N2_bytes; + } + /* If rx count control for N2 is set, load the rx value */ + if (GETFIELD(PPC_BIT(55), s->counter_config_reg) =3D=3D 1) { + s->N2_rx =3D s->N2_bytes; + } + } else { + /* Implicit mode/Forced Implicit mode, use M field from opcode */ + s->N2_bytes =3D GETFIELD(PPC_BITMASK8(4, 7), opcode); + s->N2_bits =3D s->N2_bytes * 8; + /* Assume that we are going to receive the count */ + s->N2_rx =3D s->N2_bytes; + s->N2_tx =3D 0; + /* Let Forced Implicit mode have an effect on the counts */ + if (GETFIELD(PPC_BIT(53), s->counter_config_reg) =3D=3D 1) { + /* + * If Forced Implicit mode and count control doesn't + * indicate a receive then reset the rx count to 0 + */ + if (GETFIELD(PPC_BIT(55), s->counter_config_reg) =3D=3D 0) { + s->N2_rx =3D 0; + } + /* If tx count control for N2 is set, load the tx value */ + if (GETFIELD(PPC_BIT(54), s->counter_config_reg) =3D=3D 1) { + s->N2_tx =3D s->N2_bytes; + } + } + } + /* + * Enforce an upper limit on the size of N1 that is equal to the + * known size of the shift register, 64 bits or 72 bits if ECC + * is enabled. + * If the size exceeds 72 bits it is a user error so log an error, + * cap the size at a max of 64 bits or 72 bits and set the sequencer F= SM + * error bit. + */ + uint8_t ecc_control =3D GETFIELD(PPC_BITMASK(29, 30), + s->clock_config_reset_control); + if (ecc_control =3D=3D 0 || ecc_control =3D=3D 2) { + if (s->N2_bytes > (SPI_CONTROLLER_REG_SIZE + 1)) { + /* Unsupported N2 shift size when ECC enabled */ + s->N2_bytes =3D SPI_CONTROLLER_REG_SIZE + 1; + s->N2_bits =3D s->N2_bytes * 8; + } + } else if (s->N2_bytes > SPI_CONTROLLER_REG_SIZE) { + /* Unsupported N2 shift size */ + s->N2_bytes =3D SPI_CONTROLLER_REG_SIZE; + s->N2_bits =3D s->N2_bytes * 8; + } +} /* end of calculate_N2 */ + +/* + * Shift_N2 operation handler method + */ + +static bool operation_shiftn2(PnvSpiController *s, uint8_t opcode, + PnvXferBuffer **payload) +{ + uint8_t n2_count; + bool stop =3D false; + + /* + * If there isn't a current payload left over from a stopped sequence + * create a new one. + */ + if (*payload =3D=3D NULL) { + *payload =3D pnv_spi_xfer_buffer_new(); + } + /* + * Use a combination of N2 counters to build the N2 portion of the + * transmit payload. + */ + calculate_N2(s, opcode); + trace_pnv_spi_log_Ncounts(s->N1_bits, s->N1_bytes, s->N1_tx, + s->N1_rx, s->N2_bits, s->N2_bytes, s->N2_tx, s->N2_rx); + /* + * The only difference between this code and the code for shift N1 is + * that this code has to account for the possible presence of N1 trans= mit + * bytes already taken from the TDR. + * If there are bytes to be transmitted for the N2 portion of the frame + * and there are still bytes in TDR that have not been copied into the + * TX data of the payload, this code will handle transmitting those + * remaining bytes. + * If for some reason the transmit count(s) add up to more than the si= ze + * of the TDR we will just append 0xFF to the transmit payload data un= til + * the payload is N1 + N2 bytes long. + */ + n2_count =3D 0; + while (n2_count < s->N2_bytes) { + /* + * If the RDR is full and we need to RX just bail out, letting the + * code continue will end up building the payload twice in the same + * buffer since RDR full causes a sequence stop and restart. + */ + if ((s->N2_rx !=3D 0) && + (GETFIELD(STATUS_REG_RDR_FULL, s->status_reg) =3D=3D 1)) { + trace_pnv_spi_sequencer_stop_requested("shift N2 set" + "for receive but RDR is full"); + stop =3D true; + break; + } + if ((s->N2_tx !=3D 0) && ((s->N1_tx + n2_count) < + SPI_CONTROLLER_REG_SIZE)) { + /* Always append data for the N2 segment if it is set for TX */ + uint8_t n2_byte =3D 0x00; + n2_byte =3D get_from_offset(s, (s->N1_tx + n2_count)); + trace_pnv_spi_tx_append("n2_byte", n2_byte, (s->N1_tx + n2_cou= nt)); + *(pnv_spi_xfer_buffer_write_ptr(*payload, (*payload)->len, 1)) + =3D n2_byte; + } else { + /* + * Regardless of whether or not N2 is set for TX or RX, we need + * the number of bytes in the payload to match the overall len= gth + * of the operation. + */ + trace_pnv_spi_tx_append_FF("n2_byte"); + *(pnv_spi_xfer_buffer_write_ptr(*payload, (*payload)->len, 1)) + =3D 0xff; + } + n2_count++; + } /* end of while */ + if (!stop) { + /* We have a TX and a full TDR or an RX and an empty RDR */ + trace_pnv_spi_tx_request("Shifting N2 frame", (*payload)->len); + transfer(s, *payload); + /* + * If we are doing an N2 TX and the TDR is full we need to clear t= he + * TDR_full status. Do this here instead of up in the loop above s= o we + * don't log the message in every loop iteration. + */ + if ((s->N2_tx !=3D 0) && + (GETFIELD(STATUS_REG_TDR_FULL, s->status_reg) =3D=3D 1)) { + s->status_reg =3D SETFIELD(STATUS_REG_TDR_FULL, s->status_reg,= 0); + } + /* + * The N2 frame shift is complete so reset the N2 counters. + * Reset the N1 counters also in case the frame was a combination = of + * N1 and N2 segments. + */ + s->N2_bits =3D 0; + s->N2_bytes =3D 0; + s->N2_tx =3D 0; + s->N2_rx =3D 0; + s->N1_bits =3D 0; + s->N1_bytes =3D 0; + s->N1_tx =3D 0; + s->N1_rx =3D 0; + pnv_spi_xfer_buffer_free(*payload); + *payload =3D NULL; + } + return stop; +} /* end of operation_shiftn2()*/ + +static void operation_sequencer(PnvSpiController *s) +{ + /* + * Loop through each sequencer operation ID and perform the requested + * operations. + * Flag for indicating if we should send the N1 frame or wait to combi= ne + * it with a preceding N2 frame. + */ + bool send_n1_alone =3D true; + bool stop =3D false; /* Flag to stop the sequencer */ + uint8_t opcode =3D 0; + uint8_t masked_opcode =3D 0; + + /* + * PnvXferBuffer for containing the payload of the SPI frame. + * This is a static because there are cases where a sequence has to st= op + * and wait for the target application to unload the RDR. If this occ= urs + * during a sequence where N1 is not sent alone and instead combined w= ith + * N2 since the N1 tx length + the N2 tx length is less than the size = of + * the TDR. + */ + static PnvXferBuffer *payload; + + if (payload =3D=3D NULL) { + payload =3D pnv_spi_xfer_buffer_new(); + } + /* + * Clear the sequencer FSM error bit - general_SPI_status[3] + * before starting a sequence. + */ + s->status_reg =3D SETFIELD(PPC_BIT(35), s->status_reg, 0); + /* + * If the FSM is idle set the sequencer index to 0 + * (new/restarted sequence) + */ + if (GETFIELD(STATUS_REG_SEQUENCER_FSM, s->status_reg) =3D=3D + SEQ_STATE_IDLE) { + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_INDEX, + s->status_reg, 0); + } + /* + * There are only 8 possible operation IDs to iterate through though + * some operations may cause more than one frame to be sequenced. + */ + while (get_seq_index(s) < 8) { + opcode =3D s->sequencer_operation_reg[get_seq_index(s)]; + /* Set sequencer state to decode */ + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_FSM, s->status_reg, + SEQ_STATE_DECODE); + /* + * Only the upper nibble of the operation ID is needed to know what + * kind of operation is requested. + */ + masked_opcode =3D opcode & 0xF0; + switch (masked_opcode) { + /* + * Increment the operation index in each case instead of just + * once at the end in case an operation like the branch + * operation needs to change the index. + */ + case SEQ_OP_STOP: + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_FSM, + s->status_reg, SEQ_STATE_EXECUTE); + /* A stop operation in any position stops the sequencer */ + trace_pnv_spi_sequencer_op("STOP", get_seq_index(s)); + + stop =3D true; + s->status_reg =3D SETFIELD(STATUS_REG_SHIFTER_FSM, s->status_r= eg, + FSM_IDLE); + s->loop_counter_1 =3D 0; + s->loop_counter_2 =3D 0; + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_FSM, + s->status_reg, SEQ_STATE_IDLE); + break; + + case SEQ_OP_SELECT_SLAVE: + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_FSM, + s->status_reg, SEQ_STATE_EXECUTE); + trace_pnv_spi_sequencer_op("SELECT_SLAVE", get_seq_index(s)); + /* + * This device currently only supports a single responder + * connection at position 0. De-selecting a responder is fine + * and expected at the end of a sequence but selecting any + * responder other than 0 should cause an error. + */ + s->responder_select =3D opcode & 0x0F; + if (s->responder_select =3D=3D 0) { + trace_pnv_spi_shifter_done(); + qemu_set_irq(s->cs_line[0], 1); + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_INDEX, + s->status_reg, (get_seq_index(s) + 1)); + s->status_reg =3D SETFIELD(STATUS_REG_SHIFTER_FSM, + s->status_reg, FSM_DONE); + } else if (s->responder_select !=3D 1) { + qemu_log_mask(LOG_GUEST_ERROR, "Slave selection other than= 1 " + "not supported, select =3D 0x%x\n", + s->responder_select); + trace_pnv_spi_sequencer_stop_requested("invalid " + "responder select"); + s->status_reg =3D SETFIELD(STATUS_REG_SHIFTER_FSM, + s->status_reg, FSM_IDLE); + stop =3D true; + } else { + /* + * Only allow an FSM_START state when a responder is + * selected + */ + s->status_reg =3D SETFIELD(STATUS_REG_SHIFTER_FSM, + s->status_reg, FSM_START); + trace_pnv_spi_shifter_stating(); + qemu_set_irq(s->cs_line[0], 0); + /* + * A Shift_N2 operation is only valid after a Shift_N1 + * according to the spec. The spec doesn't say if that mea= ns + * immediately after or just after at any point. We will t= rack + * the occurrence of a Shift_N1 to enforce this requiremen= t in + * the most generic way possible by assuming that the rule + * applies once a valid responder select has occurred. + */ + s->shift_n1_done =3D false; + next_sequencer_fsm(s); + } + break; + + case SEQ_OP_SHIFT_N1: + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_FSM, + s->status_reg, SEQ_STATE_EXECUTE); + trace_pnv_spi_sequencer_op("SHIFT_N1", get_seq_index(s)); + /* + * Only allow a shift_n1 when the state is not IDLE or DONE. + * In either of those two cases the sequencer is not in a prop= er + * state to perform shift operations because the sequencer has: + * - processed a responder deselect (DONE) + * - processed a stop opcode (IDLE) + * - encountered an error (IDLE) + */ + if ((GETFIELD(STATUS_REG_SHIFTER_FSM, + s->status_reg) =3D=3D FSM_IDLE) || + (GETFIELD(STATUS_REG_SHIFTER_FSM, + s->status_reg) =3D=3D FSM_DONE)) { + qemu_log_mask(LOG_GUEST_ERROR, "Shift_N1 not allowed in " + "shifter state =3D 0x%llx", GETFIELD( + STATUS_REG_SHIFTER_FSM, s->status_reg)); + /* + * Set sequencer FSM error bit 3 (general_SPI_status[3]) + * in status reg. + */ + s->status_reg =3D SETFIELD(PPC_BIT(35), s->status_reg, 1); + trace_pnv_spi_sequencer_stop_requested("invalid shifter st= ate"); + stop =3D true; + } else { + /* + * Look for the special case where there is a shift_n1 set= for + * transmit and it is followed by a shift_n2 set for trans= mit + * AND the combined transmit length of the two operations = is + * less than or equal to the size of the TDR register. In = this + * case we want to use both this current shift_n1 opcode a= nd the + * following shift_n2 opcode to assemble the frame for + * transmission to the responder without requiring a refil= l of + * the TDR between the two operations. + */ + if ((s->sequencer_operation_reg[get_seq_index(s) + 1] & 0x= F0) + =3D=3D SEQ_OP_SHIFT_N2) { + send_n1_alone =3D false; + } + s->status_reg =3D SETFIELD(STATUS_REG_SHIFTER_FSM, + s->status_reg, FSM_SHIFT_N1); + stop =3D operation_shiftn1(s, opcode, &payload, send_n1_al= one); + if (stop) { + /* + * The operation code says to stop, this can occur if: + * (1) RDR is full and the N1 shift is set for receive + * (2) TDR was empty at the time of the N1 shift so we= need + * to wait for data. + * (3) Neither 1 nor 2 are occurring and we aren't sen= ding + * N1 alone and N2 counter reload is set (bit 0 of the= N2 + * counter reload field). In this case TDR_underrun w= ill + * will be set and the Payload has been loaded so it is + * ok to advance the sequencer. + */ + if (GETFIELD(STATUS_REG_TDR_UNDERRUN, s->status_reg)) { + s->shift_n1_done =3D true; + s->status_reg =3D SETFIELD(STATUS_REG_SHIFTER_FSM, + s->status_reg, + FSM_SHIFT_N2); + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_IN= DEX, + s->status_reg, (get_seq_index(s) += 1)); + } else { + /* + * This is case (1) or (2) so the sequencer needs = to + * wait and NOT go to the next sequence yet. + */ + s->status_reg =3D SETFIELD(STATUS_REG_SHIFTER_FSM, + s->status_reg, FSM_WAIT); + } + } else { + /* Ok to move on to the next index */ + s->shift_n1_done =3D true; + next_sequencer_fsm(s); + } + } + break; + + case SEQ_OP_SHIFT_N2: + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_FSM, + s->status_reg, SEQ_STATE_EXECUTE); + trace_pnv_spi_sequencer_op("SHIFT_N2", get_seq_index(s)); + if (!s->shift_n1_done) { + qemu_log_mask(LOG_GUEST_ERROR, "Shift_N2 is not allowed if= a " + "Shift_N1 is not done, shifter state =3D 0x%= llx", + GETFIELD(STATUS_REG_SHIFTER_FSM, + s->status_reg)); + /* + * In case the sequencer actually stops if an N2 shift is + * requested before any N1 shift is done. Set sequencer FSM + * error bit 3 (general_SPI_status[3]) in status reg. + */ + s->status_reg =3D SETFIELD(PPC_BIT(35), s->status_reg, 1); + trace_pnv_spi_sequencer_stop_requested("shift_n2 " + "w/no shift_n1 done"); + stop =3D true; + } else { + /* Ok to do a Shift_N2 */ + s->status_reg =3D SETFIELD(STATUS_REG_SHIFTER_FSM, + s->status_reg, FSM_SHIFT_N2); + stop =3D operation_shiftn2(s, opcode, &payload); + /* + * If the operation code says to stop set the shifter stat= e to + * wait and stop + */ + if (stop) { + s->status_reg =3D SETFIELD(STATUS_REG_SHIFTER_FSM, + s->status_reg, FSM_WAIT); + } else { + /* Ok to move on to the next index */ + next_sequencer_fsm(s); + } + } + break; + + case SEQ_OP_BRANCH_IFNEQ_RDR: + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_FSM, + s->status_reg, SEQ_STATE_EXECUTE); + trace_pnv_spi_sequencer_op("BRANCH_IFNEQ_RDR", get_seq_index(s= )); + /* + * The memory mapping register RDR match value is compared aga= inst + * the 16 rightmost bytes of the RDR (potentially with masking= ). + * Since this comparison is performed against the contents of = the + * RDR then a receive must have previously occurred otherwise + * there is no data to compare and the operation cannot be + * completed and will stop the sequencer until RDR full is set= to + * 1. + */ + if (GETFIELD(STATUS_REG_RDR_FULL, s->status_reg) =3D=3D 1) { + bool rdr_matched =3D false; + rdr_matched =3D does_rdr_match(s); + if (rdr_matched) { + trace_pnv_spi_RDR_match("success"); + /* A match occurred, increment the sequencer index. */ + next_sequencer_fsm(s); + } else { + trace_pnv_spi_RDR_match("failed"); + /* + * Branch the sequencer to the index coded into the op + * code. + */ + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_INDEX, + s->status_reg, (opcode & 0x7= )); + } + /* + * Regardless of where the branch ended up we want the + * sequencer to continue shifting so we have to clear + * RDR_full. + */ + s->status_reg =3D SETFIELD(STATUS_REG_RDR_FULL, + s->status_reg, 0); + } else { + trace_pnv_spi_sequencer_stop_requested("RDR not" + "full for 0x6x opcode"); + stop =3D true; + s->status_reg =3D SETFIELD(STATUS_REG_SHIFTER_FSM, + s->status_reg, FSM_WAIT); + } + break; + + case SEQ_OP_TRANSFER_TDR: + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_FSM, + s->status_reg, SEQ_STATE_EXECUTE); + qemu_log_mask(LOG_GUEST_ERROR, "Transfer TDR is not supported\= n"); + next_sequencer_fsm(s); + break; + + case SEQ_OP_BRANCH_IFNEQ_INC_1: + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_FSM, + s->status_reg, SEQ_STATE_EXECUTE); + trace_pnv_spi_sequencer_op("BRANCH_IFNEQ_INC_1", get_seq_index= (s)); + /* + * The spec says the loop should execute count compare + 1 tim= es. + * However we learned from engineering that we really only loop + * count_compare times, count compare =3D 0 makes this op code= a + * no-op + */ + if (s->loop_counter_1 !=3D + GETFIELD(COUNTER_CONFIG_REG_COUNT_COMPARE1, + s->counter_config_reg)) { + /* + * Next index is the lower nibble of the branch operation = ID, + * mask off all but the first three bits so we don't try to + * access beyond the sequencer_operation_reg boundary. + */ + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_INDEX, + s->status_reg, (opcode & 0x7)); + s->loop_counter_1++; + } else { + /* Continue to next index if loop counter is reached */ + next_sequencer_fsm(s); + } + break; + + case SEQ_OP_BRANCH_IFNEQ_INC_2: + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_FSM, + s->status_reg, SEQ_STATE_EXECUTE); + trace_pnv_spi_sequencer_op("BRANCH_IFNEQ_INC_2", get_seq_index= (s)); + uint8_t condition2 =3D GETFIELD(COUNTER_CONFIG_REG_COUNT_COMPA= RE2, + s->counter_config_reg); + /* + * The spec says the loop should execute count compare + 1 tim= es. + * However we learned from engineering that we really only loop + * count_compare times, count compare =3D 0 makes this op code= a + * no-op + */ + if (s->loop_counter_2 !=3D condition2) { + /* + * Next index is the lower nibble of the branch operation = ID, + * mask off all but the first three bits so we don't try to + * access beyond the sequencer_operation_reg boundary. + */ + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_INDEX, + s->status_reg, + (opcode & 0x7)); + s->loop_counter_2++; + } else { + /* Continue to next index if loop counter is reached */ + next_sequencer_fsm(s); + } + break; + + default: + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_FSM, + s->status_reg, SEQ_STATE_EXECUTE); + /* Ignore unsupported operations. */ + next_sequencer_fsm(s); + break; + } /* end of switch */ + /* + * If we used all 8 opcodes without seeing a 00 - STOP in the sequ= ence + * we need to go ahead and end things as if there was a STOP at the + * end. + */ + if (get_seq_index(s) =3D=3D 8) { + /* All 8 opcodes completed, sequencer idling */ + s->status_reg =3D SETFIELD(STATUS_REG_SHIFTER_FSM, s->status_r= eg, + FSM_IDLE); + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_INDEX, + s->status_reg, 0); + s->loop_counter_1 =3D 0; + s->loop_counter_2 =3D 0; + s->status_reg =3D SETFIELD(STATUS_REG_SEQUENCER_FSM, + s->status_reg, SEQ_STATE_IDLE); + break; + } + /* Break the loop if a stop was requested */ + if (stop) { + break; + } + } /* end of while */ + return; +} /* end of operation_sequencer() */ + +/* + * The SPIC engine and its internal sequencer can be interrupted and reset= by + * a hardware signal, the sbe_spicst_hard_reset bits from Pervasive + * Miscellaneous Register of sbe_register_bo device. + * Reset immediately aborts any SPI transaction in progress and returns the + * sequencer and state machines to idle state. + * The configuration register values are not changed. The status register = is + * not reset. The engine registers are not reset. + * The SPIC engine reset does not have any affect on the attached devices. + * Reset handling of any attached devices is beyond the scope of the engin= e. + */ +static void do_reset(DeviceState *dev) +{ + PnvSpiController *s =3D PNV_SPICONTROLLER(dev); + + trace_pnv_spi_reset(); + + /* Reset all N1 and N2 counters, and other constants */ + s->N2_bits =3D 0; + s->N2_bytes =3D 0; + s->N2_tx =3D 0; + s->N2_rx =3D 0; + s->N1_bits =3D 0; + s->N1_bytes =3D 0; + s->N1_tx =3D 0; + s->N1_rx =3D 0; + s->loop_counter_1 =3D 0; + s->loop_counter_2 =3D 0; + /* Disconnected from responder */ + qemu_set_irq(s->cs_line[0], 1); +} + static uint64_t pnv_spi_controller_read(void *opaque, hwaddr addr, unsigned size) { @@ -49,6 +1115,10 @@ static uint64_t pnv_spi_controller_read(void *opaque, = hwaddr addr, val =3D s->receive_data_reg; trace_pnv_spi_read_RDR(val); s->status_reg =3D SETFIELD(STATUS_REG_RDR_FULL, s->status_reg, 0); + if (GETFIELD(STATUS_REG_SHIFTER_FSM, s->status_reg) =3D=3D FSM_WAI= T) { + trace_pnv_spi_start_sequencer(); + operation_sequencer(s); + } break; case SEQUENCER_OPERATION_REG: val =3D 0; @@ -120,6 +1190,8 @@ static void pnv_spi_controller_write(void *opaque, hwa= ddr addr, trace_pnv_spi_write_TDR(val); s->status_reg =3D SETFIELD(STATUS_REG_TDR_FULL, s->status_reg, 1); s->status_reg =3D SETFIELD(STATUS_REG_TDR_UNDERRUN, s->status_reg,= 0); + trace_pnv_spi_start_sequencer(); + operation_sequencer(s); break; case RECEIVE_DATA_REG: s->receive_data_reg =3D val; @@ -155,6 +1227,7 @@ static const MemoryRegionOps pnv_spi_controller_xscom_= ops =3D { =20 static Property pnv_spi_controller_properties[] =3D { DEFINE_PROP_UINT32("spic_num", PnvSpiController, spic_num, 0), + DEFINE_PROP_UINT8("transfer_len", PnvSpiController, transfer_len, 4), DEFINE_PROP_END_OF_LIST(), }; =20 @@ -206,6 +1279,7 @@ static void pnv_spi_controller_class_init(ObjectClass = *klass, void *data) =20 dc->desc =3D "PowerNV SPI Controller"; dc->realize =3D pnv_spi_controller_realize; + dc->reset =3D do_reset; device_class_set_props(dc, pnv_spi_controller_properties); } =20 diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index b8e494ffc5..4b08311160 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -115,6 +115,21 @@ pnv_spi_read(uint64_t addr, uint64_t val) "addr 0x%" P= RIx64 " val 0x%" PRIx64 pnv_spi_write(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PR= Ix64 pnv_spi_read_RDR(uint64_t val) "data extracted =3D 0x%" PRIx64 pnv_spi_write_TDR(uint64_t val) "being written, data written =3D 0x%" PRIx= 64 +pnv_spi_start_sequencer(void) "" +pnv_spi_reset(void) "spic engine sequencer configuration and spi communica= tion" +pnv_spi_sequencer_op(const char* op, uint8_t index) "%s at index =3D 0x%x" +pnv_spi_shifter_stating(void) "pull CS line low" +pnv_spi_shifter_done(void) "pull the CS line high" +pnv_spi_log_Ncounts(uint8_t N1_bits, uint8_t N1_bytes, uint8_t N1_tx, uint= 8_t N1_rx, uint8_t N2_bits, uint8_t N2_bytes, uint8_t N2_tx, uint8_t N2_rx)= "N1_bits =3D %d, N1_bytes =3D %d, N1_tx =3D %d, N1_rx =3D %d, N2_bits =3D = %d, N2_bytes =3D %d, N2_tx =3D %d, N2_rx =3D %d" +pnv_spi_tx_append(const char* frame, uint8_t byte, uint8_t tdr_index) "%s = =3D 0x%2.2x to payload from TDR at index %d" +pnv_spi_tx_append_FF(const char* frame) "%s to Payload" +pnv_spi_tx_request(const char* frame, uint32_t payload_len) "%s, payload l= en =3D %d" +pnv_spi_rx_received(uint32_t payload_len) "payload len =3D %d" +pnv_spi_rx_read_N1frame(void) "" +pnv_spi_rx_read_N2frame(void) "" +pnv_spi_shift_rx(uint8_t byte, uint32_t index) "byte =3D 0x%2.2x into RDR = from payload index %d" +pnv_spi_sequencer_stop_requested(const char* reason) "due to %s" +pnv_spi_RDR_match(const char* result) "%s" =20 # ppc.c ppc_tb_adjust(uint64_t offs1, uint64_t offs2, int64_t diff, int64_t second= s) "adjusted from 0x%"PRIx64" to 0x%"PRIx64", diff %"PRId64" (%"PRId64"s)" --=20 2.39.3 From nobody Mon Nov 25 10:32:28 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=linux.ibm.com ARC-Seal: i=1; a=rsa-sha256; t=1715795017; cv=none; d=zohomail.com; s=zohoarc; b=Dnm1lMHoIS5L2wa3aOsJdEaZQk7z3dLOq4pSw4w5Y6cRWdQieuJKMgGYbZyP1LaVJslagb8SXNDHfqwhAqBtFppSaOqohQ/jNGlA28YuOINib9gI4HVyTRSPPxpxh8jHG0csOY0X23XVn8vDYyK5hCcg0QZZwGVwnMTJQccvnkQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1715795017; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=mzWizbN0oiLw3S2B0TR+0ZNFAMrMm8gzHZ0tye51ztI=; b=YhKIXJ3GiTzdrfPrQfC1C6vT1BLDf6yENr52gMw6Zm/N22ZWn6B1NRql+FO7T7B96aCxpdGyDMzd7gm8MgoBmqk/gkO9gLfqCGrWC6XOBw5d9aA+IcCBIhAqlB6iWRcRbe4cx6K2c5Y7PRzYEhEArsvuMJgQ5Cn//NrJOm/iikw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1715795017480803.9527168236345; Wed, 15 May 2024 10:43:37 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1s7Iel-00018F-7h; Wed, 15 May 2024 13:43:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s7IeE-00012s-7D; Wed, 15 May 2024 13:42:38 -0400 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s7IeB-0006YP-2B; Wed, 15 May 2024 13:42:37 -0400 Received: from pps.filterd (m0360083.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 44FH0dtN018907; Wed, 15 May 2024 17:42:23 GMT Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3y4xtvrfts-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 May 2024 17:42:23 +0000 Received: from m0360083.ppops.net (m0360083.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 44FHgNQR023562; Wed, 15 May 2024 17:42:23 GMT Received: from ppma23.wdc07v.mail.ibm.com (5d.69.3da9.ip4.static.sl-reverse.com [169.61.105.93]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3y4xtvrftp-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 May 2024 17:42:23 +0000 Received: from pps.filterd (ppma23.wdc07v.mail.ibm.com [127.0.0.1]) by ppma23.wdc07v.mail.ibm.com (8.17.1.19/8.17.1.19) with ESMTP id 44FFbI45006200; Wed, 15 May 2024 17:42:21 GMT Received: from smtprelay06.fra02v.mail.ibm.com ([9.218.2.230]) by ppma23.wdc07v.mail.ibm.com (PPS) with ESMTPS id 3y2mgmmvyr-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 May 2024 17:42:21 +0000 Received: from smtpav02.fra02v.mail.ibm.com (smtpav02.fra02v.mail.ibm.com [10.20.54.101]) by smtprelay06.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 44FHgFfs35259090 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 15 May 2024 17:42:18 GMT Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id DBD752004F; Wed, 15 May 2024 17:42:15 +0000 (GMT) Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id EB1492004E; Wed, 15 May 2024 17:42:13 +0000 (GMT) Received: from gfwr515.rchland.ibm.com (unknown [9.10.239.103]) by smtpav02.fra02v.mail.ibm.com (Postfix) with ESMTP; Wed, 15 May 2024 17:42:13 +0000 (GMT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=mzWizbN0oiLw3S2B0TR+0ZNFAMrMm8gzHZ0tye51ztI=; b=A3E8f6bdKqhZqxqhbdVr43QkzRsvt+hEVnE1P7UgE4iLajD0/NWtgJn59LSByVZQVu5Z SjIEe7cMSq71+I1gDgx0zPiZKeFHufiG8c0u420L1E7s6iJ4tj8WwRg5+1+ijQb4sQfz Jdy+ilAX37RIU7XBaElGiKyUIy/PWRHclf/Ct6C4WVkPkxgdzj4wEnMj1YGKddpwnw3H 54XKODnaYc5CplDGNLQ2W5Fuk0nVWJkxvsq4SU1j+ASpe8CR7TL0bE/JeFB3dwOVcXXe JcGJlNwAd+ISB0JCzuHVX7MuOQe0vE7xtwObidb7X/3g+eeENHrG7o46f4EdA1+ggc08 yQ== From: Chalapathi V 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, dantan@us.ibm.com, milesg@linux.vnet.ibm.com Subject: [PATCH v3 3/5] hw/block: Add Microchip's 25CSM04 to m25p80 Date: Wed, 15 May 2024 12:41:47 -0500 Message-Id: <20240515174149.17713-4-chalapathi.v@linux.ibm.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20240515174149.17713-1-chalapathi.v@linux.ibm.com> References: <20240515174149.17713-1-chalapathi.v@linux.ibm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: yoNNwqQNxE6J3R_Gk9yP5Nw97DW-oBZf X-Proofpoint-GUID: rnH9kxMXR497_DsYoiLsV1CY-b2_8gJL X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.650,FMLib:17.11.176.26 definitions=2024-05-15_10,2024-05-15_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 adultscore=0 bulkscore=0 clxscore=1015 impostorscore=0 lowpriorityscore=0 mlxscore=0 priorityscore=1501 spamscore=0 mlxlogscore=841 malwarescore=0 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2405010000 definitions=main-2405150125 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=148.163.156.1; envelope-from=chalapathi.v@linux.ibm.com; helo=mx0a-001b2d01.pphosted.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, 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.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @ibm.com) X-ZM-MESSAGEID: 1715795018514100003 Content-Type: text/plain; charset="utf-8" Add Microchip's 25CSM04 Serial EEPROM to m25p80. 25CSM04 provides 4 Mbits of Serial EEPROM utilizing the Serial Peripheral Interface (SPI) compatible bus. The device is organized as 524288 bytes of 8 bits each (512Kbyte) and is optimized for use in consumer and industrial applications where reliable and dependable nonvolatile memory storage is essential. Signed-off-by: Chalapathi V Reviewed-by: C=C3=A9dric Le Goater --- hw/block/m25p80.c | 3 +++ hw/ppc/Kconfig | 1 + 2 files changed, 4 insertions(+) diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 8dec134832..824a6c5c60 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -357,6 +357,9 @@ static const FlashPartInfo known_devices[] =3D { .sfdp_read =3D m25p80_sfdp_w25q512jv }, { INFO("w25q01jvq", 0xef4021, 0, 64 << 10, 2048, ER_4K), .sfdp_read =3D m25p80_sfdp_w25q01jvq }, + + /* Microchip */ + { INFO("25csm04", 0x29cc00, 0x100, 64 << 10, 8, 0) }, }; =20 typedef enum { diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig index 6f9670b377..a93430b734 100644 --- a/hw/ppc/Kconfig +++ b/hw/ppc/Kconfig @@ -40,6 +40,7 @@ config POWERNV select PCA9552 select PCA9554 select SSI + select SSI_M25P80 =20 config PPC405 bool --=20 2.39.3 From nobody Mon Nov 25 10:32:28 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=linux.ibm.com ARC-Seal: i=1; a=rsa-sha256; t=1715795052; cv=none; d=zohomail.com; s=zohoarc; b=gt7GVPu3TnOZloz9WQsP2NiidOj1MDuL9JuzsWaWvVb+mCYSkM5QIARaVh9jOQWh275O+S17XSEnaRe28334DNKoMLLvKG0Dd87zD9V7sdvkQMdpJEPpzpNJTeZMpny7xSbUhc73oXZZ55q16txk0Ephj5ArXTT9rBV6guEfgtE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1715795052; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=9JpHgyAWqR1K/1zTMIvfKMjnTXujnXR48Y1/i2DU7PM=; b=PV/7ykPN3qsOAy6hk3kdV7zlqlywhhP+/FVrZyKyJZc6vc+5EONvmolpIYdrAMAFYrNVkoxt2zBbKm0B/DYWW9xK6/XTGykyyY4Y2TfgEcct7OTNvXC+Uv6eFufH9UyT7e6muCPKEB6SMH00WcJbBINHW3dc5NvMetBHFIrAQ9Q= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1715795052636431.1244309197241; Wed, 15 May 2024 10:44:12 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1s7If4-0001OX-57; Wed, 15 May 2024 13:43:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s7IeI-00013s-Ov; Wed, 15 May 2024 13:42:46 -0400 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s7IeE-0006aU-9S; Wed, 15 May 2024 13:42:40 -0400 Received: from pps.filterd (m0353722.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 44FGHua0019147; Wed, 15 May 2024 17:42:27 GMT Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3y4y29rej9-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 May 2024 17:42:27 +0000 Received: from m0353722.ppops.net (m0353722.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 44FHgQwU019191; Wed, 15 May 2024 17:42:26 GMT Received: from ppma23.wdc07v.mail.ibm.com (5d.69.3da9.ip4.static.sl-reverse.com [169.61.105.93]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3y4y29rej8-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 May 2024 17:42:26 +0000 Received: from pps.filterd (ppma23.wdc07v.mail.ibm.com [127.0.0.1]) by ppma23.wdc07v.mail.ibm.com (8.17.1.19/8.17.1.19) with ESMTP id 44FF2IDC006183; Wed, 15 May 2024 17:42:26 GMT Received: from smtprelay04.fra02v.mail.ibm.com ([9.218.2.228]) by ppma23.wdc07v.mail.ibm.com (PPS) with ESMTPS id 3y2mgmmw04-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 May 2024 17:42:26 +0000 Received: from smtpav02.fra02v.mail.ibm.com (smtpav02.fra02v.mail.ibm.com [10.20.54.101]) by smtprelay04.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 44FHgKON30147188 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 15 May 2024 17:42:22 GMT Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 5CE872004B; Wed, 15 May 2024 17:42:20 +0000 (GMT) Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 776C320043; Wed, 15 May 2024 17:42:18 +0000 (GMT) Received: from gfwr515.rchland.ibm.com (unknown [9.10.239.103]) by smtpav02.fra02v.mail.ibm.com (Postfix) with ESMTP; Wed, 15 May 2024 17:42:18 +0000 (GMT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=9JpHgyAWqR1K/1zTMIvfKMjnTXujnXR48Y1/i2DU7PM=; b=e0ZNFl4+kkfE0VAjYQR11Qk1hS3r9gs0KYYB7dSJ6YxQYf/q4XTADsCgYRagEEWJvvt9 F2yR3pr0b+9VRr3bM35UyzOoZD8+3HurQZ3A6NMzyb0Ef5+7Pjr1AkNiIi413olJW0Vr 8MoMaIJvcSlneKN9spzRogDjk/zwNKP7yX1ylj6+VTZLP4kRMs0Il97YBm9e6jsqDZ20 MwviSkbQsbom/a1dPSLGHgF6d9BPD3Kq4pPdh+1hA6o84H3PGKX1x0+Qwuo+POjX8DY2 11+C7Z8UTiW77L0/kouyrjHWE1v5685QgbNGXmtVaRfGGTWSQQAP2v1KBZ/fZWVovKKy vA== From: Chalapathi V 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, dantan@us.ibm.com, milesg@linux.vnet.ibm.com Subject: [PATCH v3 4/5] hw/ppc: SPI controller wiring to P10 chip Date: Wed, 15 May 2024 12:41:48 -0500 Message-Id: <20240515174149.17713-5-chalapathi.v@linux.ibm.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20240515174149.17713-1-chalapathi.v@linux.ibm.com> References: <20240515174149.17713-1-chalapathi.v@linux.ibm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: LSVk2wWVaXNYga3QCqVSXnmRWnCX8eCQ X-Proofpoint-GUID: tr2dOtYwDX5omusT-wvcszu2dMdQl5eC X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.650,FMLib:17.11.176.26 definitions=2024-05-15_10,2024-05-15_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxlogscore=736 spamscore=0 mlxscore=0 adultscore=0 suspectscore=0 priorityscore=1501 clxscore=1015 bulkscore=0 impostorscore=0 lowpriorityscore=0 phishscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2405010000 definitions=main-2405150125 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=148.163.158.5; envelope-from=chalapathi.v@linux.ibm.com; helo=mx0b-001b2d01.pphosted.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, 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.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @ibm.com) X-ZM-MESSAGEID: 1715795054496100004 Content-Type: text/plain; charset="utf-8" In this commit, create SPI controller on p10 chip and connect cs irq. The QOM tree of spi controller and seeprom are. /machine (powernv10-machine) /chip[0] (power10_v2.0-pnv-chip) /pib_spic[2] (pnv-spi-controller) /pnv-spi-bus.2 (SSI) /xscom-spi-controller-regs[0] (memory-region) /machine (powernv10-machine) /peripheral-anon (container) /device[0] (25csm04) /WP#[0] (irq) /ssi-gpio-cs[0] (irq) (qemu) qom-get /machine/peripheral-anon /device[76] "parent_bus" "/machine/chip[0]/pib_spic[2]/pnv-spi-bus.2" Signed-off-by: Chalapathi V Reviewed-by: C=C3=A9dric Le Goater --- include/hw/ppc/pnv_chip.h | 3 +++ hw/ppc/pnv.c | 21 ++++++++++++++++++++- hw/ppc/pnv_spi_controller.c | 8 ++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/include/hw/ppc/pnv_chip.h b/include/hw/ppc/pnv_chip.h index 8589f3291e..d464858f79 100644 --- a/include/hw/ppc/pnv_chip.h +++ b/include/hw/ppc/pnv_chip.h @@ -6,6 +6,7 @@ #include "hw/ppc/pnv_core.h" #include "hw/ppc/pnv_homer.h" #include "hw/ppc/pnv_n1_chiplet.h" +#include "hw/ssi/pnv_spi.h" #include "hw/ppc/pnv_lpc.h" #include "hw/ppc/pnv_occ.h" #include "hw/ppc/pnv_psi.h" @@ -118,6 +119,8 @@ struct Pnv10Chip { PnvSBE sbe; PnvHomer homer; PnvN1Chiplet n1_chiplet; +#define PNV10_CHIP_MAX_PIB_SPIC 6 + PnvSpiController pib_spic[PNV10_CHIP_MAX_PIB_SPIC]; =20 uint32_t nr_quads; PnvQuad *quads; diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 6e3a5ccdec..6850592a85 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1829,6 +1829,11 @@ static void pnv_chip_power10_instance_init(Object *o= bj) for (i =3D 0; i < pcc->i2c_num_engines; i++) { object_initialize_child(obj, "i2c[*]", &chip10->i2c[i], TYPE_PNV_I= 2C); } + + for (i =3D 0; i < PNV10_CHIP_MAX_PIB_SPIC ; i++) { + object_initialize_child(obj, "pib_spic[*]", &chip10->pib_spic[i], + TYPE_PNV_SPI_CONTROLLER); + } } =20 static void pnv_chip_power10_quad_realize(Pnv10Chip *chip10, Error **errp) @@ -2043,7 +2048,21 @@ static void pnv_chip_power10_realize(DeviceState *de= v, Error **errp) qdev_get_gpio_in(DEVICE(&chip10->psi), PSIHB9_IRQ_SBE_I2C)); } - + /* PIB SPI Controller */ + for (i =3D 0; i < PNV10_CHIP_MAX_PIB_SPIC; i++) { + object_property_set_int(OBJECT(&chip10->pib_spic[i]), "spic_num", + i, &error_fatal); + /* pib_spic[2] connected to 25csm04 which implements 1 byte transf= er */ + object_property_set_int(OBJECT(&chip10->pib_spic[i]), "transfer_le= n", + (i =3D=3D 2) ? 1 : 4, &error_fatal); + if (!sysbus_realize(SYS_BUS_DEVICE(OBJECT + (&chip10->pib_spic[i])), errp)) { + return; + } + pnv_xscom_add_subregion(chip, PNV10_XSCOM_PIB_SPIC_BASE + + i * PNV10_XSCOM_PIB_SPIC_SIZE, + &chip10->pib_spic[i].xscom_spic_regs); + } } =20 static void pnv_rainier_i2c_init(PnvMachineState *pnv) diff --git a/hw/ppc/pnv_spi_controller.c b/hw/ppc/pnv_spi_controller.c index e87f583074..3d47e932de 100644 --- a/hw/ppc/pnv_spi_controller.c +++ b/hw/ppc/pnv_spi_controller.c @@ -1067,9 +1067,17 @@ static void operation_sequencer(PnvSpiController *s) static void do_reset(DeviceState *dev) { PnvSpiController *s =3D PNV_SPICONTROLLER(dev); + DeviceState *ssi_dev; =20 trace_pnv_spi_reset(); =20 + /* Connect cs irq */ + ssi_dev =3D ssi_get_cs(s->ssi_bus, 0); + if (ssi_dev) { + qemu_irq cs_line =3D qdev_get_gpio_in_named(ssi_dev, SSI_GPIO_CS, = 0); + qdev_connect_gpio_out_named(DEVICE(s), "cs", 0, cs_line); + } + /* Reset all N1 and N2 counters, and other constants */ s->N2_bits =3D 0; s->N2_bytes =3D 0; --=20 2.39.3 From nobody Mon Nov 25 10:32:28 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=linux.ibm.com ARC-Seal: i=1; a=rsa-sha256; t=1715795083; cv=none; d=zohomail.com; s=zohoarc; b=FCz2WCkqiXcV+aImvR2ITHo4xtJlwl8Lzl/oPE/tkBZ2QbhG3m/j3HcQ3FZ0ePYBFFEGjK/uMMAGqb+xbSETPlnFMyKpOEo6yZLFdhI4KCq90StFSYWJIfINj1/acyvWjxzEAMVHqooP3CEmGr1fd0FgrI1Mxue54aYG3nGr1Ug= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1715795083; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=QFOIIEwntNr8VDOPKVgOD5yWt8+9WtIKcxGP5ZVNdmE=; b=BWmEFBRee6Gz+BkADun3bB04A8aKynAsM1H7XErKxaqdRLjZyYReb05UWMpDBNA/uGgL2RUTvic7YSg7AhUvBtpzqqJAEqXFiogkI2vQo6cTUhR0x1zNQVcIYcDzkqZHrcK6grPLqbIYVPIomrz7rPneJeFU+VU8ME4SfpVr5zI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17157950838681018.6981454790928; Wed, 15 May 2024 10:44:43 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1s7Ifp-00024E-1s; Wed, 15 May 2024 13:44:18 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s7IeP-00014R-H3; Wed, 15 May 2024 13:42:54 -0400 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s7IeD-0006ad-Rw; Wed, 15 May 2024 13:42:45 -0400 Received: from pps.filterd (m0356517.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 44FHbFGt025156; Wed, 15 May 2024 17:42:34 GMT Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3y51kug0ae-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 May 2024 17:42:33 +0000 Received: from m0356517.ppops.net (m0356517.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 44FHgXml032475; Wed, 15 May 2024 17:42:33 GMT Received: from ppma21.wdc07v.mail.ibm.com (5b.69.3da9.ip4.static.sl-reverse.com [169.61.105.91]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3y51kug0ad-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 May 2024 17:42:33 +0000 Received: from pps.filterd (ppma21.wdc07v.mail.ibm.com [127.0.0.1]) by ppma21.wdc07v.mail.ibm.com (8.17.1.19/8.17.1.19) with ESMTP id 44FFUxIt002273; Wed, 15 May 2024 17:42:31 GMT Received: from smtprelay02.fra02v.mail.ibm.com ([9.218.2.226]) by ppma21.wdc07v.mail.ibm.com (PPS) with ESMTPS id 3y2m0pcy91-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 May 2024 17:42:31 +0000 Received: from smtpav02.fra02v.mail.ibm.com (smtpav02.fra02v.mail.ibm.com [10.20.54.101]) by smtprelay02.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 44FHgPO151970482 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 15 May 2024 17:42:27 GMT Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id AEB552004F; Wed, 15 May 2024 17:42:25 +0000 (GMT) Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C92FA20067; Wed, 15 May 2024 17:42:23 +0000 (GMT) Received: from gfwr515.rchland.ibm.com (unknown [9.10.239.103]) by smtpav02.fra02v.mail.ibm.com (Postfix) with ESMTP; Wed, 15 May 2024 17:42:23 +0000 (GMT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=QFOIIEwntNr8VDOPKVgOD5yWt8+9WtIKcxGP5ZVNdmE=; b=ZyCTIYbUiXy+39FSRgqwhq+MCzmt55JStzyJjL8DpxKCP/RzOHiEA3gZYi+wjZ0bHsNF gX0oXONSRdn3p83YaPI7IzFD962XdJWRz/a1LYYo09z8edT5m2SAjcRuZXdBkJgKrw1m Lci958x80pCZUWdDJ+rxGdRhHfVv+M4ENSauwRAx6KU0LpGzkbDV0eBS1ZXaeOqmDU4c NYKGqPFIFWs6jo5LmOMbCh4Vi2HCjiC6gW48OTLZdgjHHWSjxMne5lq+JDPgbdn5kVfW l5Ejxl5T/pDRK7/TVCULVjALM/+6jkEnfQLsZORfh7ZeUWYlOELEST0VGaS9PRw3Z6M7 4g== From: Chalapathi V 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, dantan@us.ibm.com, milesg@linux.vnet.ibm.com Subject: [PATCH v3 5/5] tests/qtest: Add pnv-spi-seeprom qtest Date: Wed, 15 May 2024 12:41:49 -0500 Message-Id: <20240515174149.17713-6-chalapathi.v@linux.ibm.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20240515174149.17713-1-chalapathi.v@linux.ibm.com> References: <20240515174149.17713-1-chalapathi.v@linux.ibm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Proofpoint-GUID: 9avthapFlrb-803NlRz9dnDNKzJgTbKH X-Proofpoint-ORIG-GUID: aJgCcfiZdR2tZIQeJf_bjkqg4uf0BUUp X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.650,FMLib:17.11.176.26 definitions=2024-05-15_10,2024-05-15_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 phishscore=0 bulkscore=0 lowpriorityscore=0 adultscore=0 mlxlogscore=521 malwarescore=0 clxscore=1015 impostorscore=0 mlxscore=0 priorityscore=1501 spamscore=0 suspectscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2405010000 definitions=main-2405150125 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=148.163.156.1; envelope-from=chalapathi.v@linux.ibm.com; helo=mx0a-001b2d01.pphosted.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, 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.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @ibm.com) X-ZM-MESSAGEID: 1715795084631100003 Content-Type: text/plain; charset="utf-8" In this commit Write a qtest pnv-spi-seeprom-test to check the SPI transactions between spi controller and seeprom device. Signed-off-by: Chalapathi V --- tests/qtest/pnv-spi-seeprom-test.c | 129 +++++++++++++++++++++++++++++ tests/qtest/meson.build | 1 + 2 files changed, 130 insertions(+) create mode 100644 tests/qtest/pnv-spi-seeprom-test.c diff --git a/tests/qtest/pnv-spi-seeprom-test.c b/tests/qtest/pnv-spi-seepr= om-test.c new file mode 100644 index 0000000000..bfa57f3234 --- /dev/null +++ b/tests/qtest/pnv-spi-seeprom-test.c @@ -0,0 +1,129 @@ +/* + * QTest testcase for PowerNV 10 Seeprom Communications + * + * Copyright (c) 2024, IBM Corporation. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qemu/bswap.h" +#include "hw/ssi/pnv_spi_regs.h" + +#define P10_XSCOM_BASE 0x000603fc00000000ull +#define SPIC2_XSCOM_BASE 0xc0040 + +/* To transmit READ opcode and address */ +#define READ_OP_TDR_DATA 0x0300010000000000 +/* + * N1 shift - tx 4 bytes (transmit opcode and address) + * N2 shift - tx and rx 8 bytes. + */ +#define READ_OP_COUNTER_CONFIG 0x2040000000002b00 +/* SEQ_OP_SELECT_RESPONDER - N1 Shift - N2 Shift * 5 - SEQ_OP_STOP */ +#define READ_OP_SEQUENCER 0x1130404040404010 + +/* To transmit WREN(Set Write Enable Latch in status0 register) opcode */ +#define WRITE_OP_WREN 0x0600000000000000 +/* To transmit WRITE opcode, address and data */ +#define WRITE_OP_TDR_DATA 0x0300010012345678 +/* N1 shift - tx 8 bytes (transmit opcode, address and data) */ +#define WRITE_OP_COUNTER_CONFIG 0x4000000000002000 +/* SEQ_OP_SELECT_RESPONDER - N1 Shift - SEQ_OP_STOP */ +#define WRITE_OP_SEQUENCER 0x1130100000000000 + +static uint64_t pnv_xscom_addr(uint32_t pcba) +{ + return P10_XSCOM_BASE | ((uint64_t) pcba << 3); +} + +static uint64_t pnv_spi_seeprom_xscom_addr(uint32_t reg) +{ + return pnv_xscom_addr(SPIC2_XSCOM_BASE + reg); +} + +static void pnv_spi_controller_xscom_write(QTestState *qts, uint32_t reg, + uint64_t val) +{ + qtest_writeq(qts, pnv_spi_seeprom_xscom_addr(reg), val); +} + +static uint64_t pnv_spi_controller_xscom_read(QTestState *qts, uint32_t re= g) +{ + return qtest_readq(qts, pnv_spi_seeprom_xscom_addr(reg)); +} + +static void spi_seeprom_transaction(QTestState *qts) +{ + /* SPI transactions to SEEPROM to read from SEEPROM image */ + pnv_spi_controller_xscom_write(qts, COUNTER_CONFIG_REG, + READ_OP_COUNTER_CONFIG); + pnv_spi_controller_xscom_write(qts, SEQUENCER_OPERATION_REG, + READ_OP_SEQUENCER); + pnv_spi_controller_xscom_write(qts, TRANSMIT_DATA_REG, READ_OP_TDR_DAT= A); + pnv_spi_controller_xscom_write(qts, TRANSMIT_DATA_REG, 0); + /* Read 5*8 bytes from SEEPROM at 0x100 */ + uint64_t rdr_val =3D pnv_spi_controller_xscom_read(qts, RECEIVE_DATA_R= EG); + printf("RDR READ =3D 0x%lx\n", rdr_val); + rdr_val =3D pnv_spi_controller_xscom_read(qts, RECEIVE_DATA_REG); + rdr_val =3D pnv_spi_controller_xscom_read(qts, RECEIVE_DATA_REG); + rdr_val =3D pnv_spi_controller_xscom_read(qts, RECEIVE_DATA_REG); + rdr_val =3D pnv_spi_controller_xscom_read(qts, RECEIVE_DATA_REG); + printf("RDR READ =3D 0x%lx\n", rdr_val); + + /* SPI transactions to SEEPROM to write to SEEPROM image */ + pnv_spi_controller_xscom_write(qts, COUNTER_CONFIG_REG, + WRITE_OP_COUNTER_CONFIG); + /* Set Write Enable Latch bit of status0 register */ + pnv_spi_controller_xscom_write(qts, SEQUENCER_OPERATION_REG, + WRITE_OP_SEQUENCER); + pnv_spi_controller_xscom_write(qts, TRANSMIT_DATA_REG, WRITE_OP_WREN); + /* write 8 bytes to SEEPROM at 0x100 */ + pnv_spi_controller_xscom_write(qts, SEQUENCER_OPERATION_REG, + WRITE_OP_SEQUENCER); + pnv_spi_controller_xscom_write(qts, TRANSMIT_DATA_REG, WRITE_OP_TDR_DA= TA); +} + +/* Find complete path of in_file in the current working directory */ +static void find_file(const char *in_file, char *in_path) +{ + g_autofree char *cwd =3D g_get_current_dir(); + char *filepath =3D g_build_filename(cwd, in_file, NULL); + if (!access(filepath, F_OK)) { + strcpy(in_path, filepath); + } else { + strcpy(in_path, ""); + printf("File %s not found within %s\n", in_file, cwd); + } +} + +static void test_spi_seeprom(void) +{ + QTestState *qts =3D NULL; + char seepromfile[500]; + find_file("sbe_measurement_seeprom.bin.ecc", seepromfile); + if (strcmp(seepromfile, "")) { + printf("Starting QEMU with seeprom file.\n"); + qts =3D qtest_initf("-m 2G -machine powernv10 -smp 2,cores=3D2," + "threads=3D1 -accel tcg,thread=3Dsingle -nograph= ic " + "-blockdev node-name=3Dpib_spic2,driver=3Dfile," + "filename=3Dsbe_measurement_seeprom.bin.ecc " + "-device 25csm04,bus=3Dpnv-spi-bus.2,cs=3D0," + "drive=3Dpib_spic2"); + } else { + printf("Starting QEMU without seeprom file.\n"); + qts =3D qtest_initf("-m 2G -machine powernv10 -smp 2,cores=3D2," + "threads=3D1 -accel tcg,thread=3Dsingle -nograph= ic" + " -device 25csm04,bus=3Dpnv-spi-bus.2,cs=3D0"); + } + spi_seeprom_transaction(qts); + qtest_quit(qts); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + qtest_add_func("spi_seeprom", test_spi_seeprom); + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 86293051dc..2fa98b2430 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -171,6 +171,7 @@ qtests_ppc64 =3D \ qtests_ppc + \ (config_all_devices.has_key('CONFIG_PSERIES') ? ['device-plug-test'] : [= ]) + \ (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-xscom-test'] : [])= + \ + (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-spi-seeprom-test']= : []) + \ (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-host-i2c-test'] : = []) + \ (config_all_devices.has_key('CONFIG_PSERIES') ? ['rtas-test'] : []) + = \ (slirp.found() ? ['pxe-test'] : []) + \ --=20 2.39.3