From patchwork Fri Dec 15 11:47:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thangaraj Samynathan X-Patchwork-Id: 179214 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:3b04:b0:fb:cd0c:d3e with SMTP id c4csp9211430dys; Fri, 15 Dec 2023 03:51:46 -0800 (PST) X-Google-Smtp-Source: AGHT+IGPly/yF2dHA6RzlFFyyOYY+VokECUlgwRstqf76oMf4AFqpa8K7+wMhFKbiVocU6kXyxqs X-Received: by 2002:a17:902:f684:b0:1d3:62a9:6aad with SMTP id l4-20020a170902f68400b001d362a96aadmr2749545plg.57.1702641105682; Fri, 15 Dec 2023 03:51:45 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1702641105; cv=none; d=google.com; s=arc-20160816; b=XwsurTbDiaA9r5Djlp82dTNdT+8E+5EIK5qZBl1+22mAlkxtldjQ1j2/9DkUpubbYf dZVDhAAYwtM5Cfr8NtEB6+rT0I3kJn1D5Ms1mhDimJghN2VFdZZvyFM7kVEcgfOgxGi5 ppNVDLy2f+rkqNof/GHqap0SxN9vfyLH8vnK9ajvHULhuyAlmz6Vaa+5ZwgvyJel741z E7Diq09fCgjT9sgo7Ux+PNY64Pamic+aDcSUfwX0iyHt+fOun4uxmrgdruFAJamExQJT f5OD0RwZy13pPbJ5c3DtiILA1Rm8mUb72qO49v+MhM+FgMpQn0+FkrBmT/glMJCKoh4g fl3w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=JABh52HmM7Pf7EmjwJaKpdfZud0HqNcVQku+lBm1H6E=; fh=cGbkLwFjdUmwzsSfH4uGElh042qw4yrimp50Fdi/yLk=; b=suR/PN7kt5KQLp0kBJrdUDjeAHgFESEPugZFTbpgzZM32SxzmWfrp9dZaBREEOi013 sHWcnW/3+urB4o2Ih1qrr9Ga3LGVOK4udYoUVuBWt5HMGJKDzG1EJuZSON8ft14yNup1 sSiegHdccssHrY0sinGjW4OuhFr/sd04Q81kOn9PdYcJNhZtvSkf9Fw7Mp1JVqyWyo+y GkuAmw961m2Nn4ke958eCU+4DvoRqjh1JoTxAQGZr8eYShMYJDU+IAZYYE1yy48zYpoN pZgi4AdoXFPWuFiuxqOPK9Ps8XpV8oPHnhZGcHhZu7tZLhV0apZ+pBO7kdf3Q+RfitNL Xr/Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@microchip.com header.s=mchp header.b=F16odioc; spf=pass (google.com: domain of linux-kernel+bounces-869-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.48.161 as permitted sender) smtp.mailfrom="linux-kernel+bounces-869-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=QUARANTINE sp=REJECT dis=NONE) header.from=microchip.com Received: from sy.mirrors.kernel.org (sy.mirrors.kernel.org. [147.75.48.161]) by mx.google.com with ESMTPS id v16-20020a17090331d000b001d3485656cbsi4922420ple.160.2023.12.15.03.51.45 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Dec 2023 03:51:45 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-869-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.48.161 as permitted sender) client-ip=147.75.48.161; Authentication-Results: mx.google.com; dkim=pass header.i=@microchip.com header.s=mchp header.b=F16odioc; spf=pass (google.com: domain of linux-kernel+bounces-869-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.48.161 as permitted sender) smtp.mailfrom="linux-kernel+bounces-869-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=QUARANTINE sp=REJECT dis=NONE) header.from=microchip.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sy.mirrors.kernel.org (Postfix) with ESMTPS id EC6C6B21823 for ; Fri, 15 Dec 2023 11:51:19 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id AFBE32D02B; Fri, 15 Dec 2023 11:50:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="F16odioc" X-Original-To: linux-kernel@vger.kernel.org Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1CB57250F9; Fri, 15 Dec 2023 11:50:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1702641027; x=1734177027; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=pCX1ECWz6AH7SgM0njcfU2IlPtMHstb/aOqlR8RvaxI=; b=F16odiocSUAwHiJD7amPueu/uvI3AHNopX/hd9u7hDZkxnaiLr3XG48C 2E9ZD8UcGiSfdNJMYDnzIESZ37TxG1LELj1JCMSG1PRrLPcqOwu2/9rrT aI4/HYYe1OdENK2YUfKe5H138KZ2Ct9PebEUZWXZSc6OPSQSiQWiHHtAs LYB7xGN5Gz0DRfhLrmUwm8ZIoNoYJCtunK8sQgEEW2KMzXnq0220U3MkD v0LVHvrxNOauqLlvy5hclw1mc6gjgRPjGd8m2P94Kw9bNrAnPKwMLkC46 ZRuBK3rQYAdhF9KI0dSH4Wntkk+9cjqOAxym4nuApEMFdSRZUnLT6T9uW A==; X-CSE-ConnectionGUID: LGva2yzVSgmRfFnu4BtIaw== X-CSE-MsgGUID: 9y+XknkMQqqkC0QqYskCKg== X-ThreatScanner-Verdict: Negative X-IronPort-AV: E=Sophos;i="6.04,278,1695711600"; d="scan'208";a="14317229" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa1.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 15 Dec 2023 04:50:20 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Fri, 15 Dec 2023 04:50:04 -0700 Received: from che-dk-ungapp03lx.microchip.com (10.10.85.11) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.35 via Frontend Transport; Fri, 15 Dec 2023 04:50:01 -0700 From: Thangaraj Samynathan To: CC: , , , , , , Subject: [PATCH SPI for-next 1/3] spi: mchp-pci1xxxx: Add support for DMA in SPI Date: Fri, 15 Dec 2023 17:17:46 +0530 Message-ID: <20231215114748.152319-2-thangaraj.s@microchip.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231215114748.152319-1-thangaraj.s@microchip.com> References: <20231215114748.152319-1-thangaraj.s@microchip.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1785348599825544254 X-GMAIL-MSGID: 1785348599825544254 In PCI1xxxx C0, support for DMA in PCIe endpoint is added to enhance the SPI performance. With this support, the performance is improved from 6Mbps to 17Mbps with 20Mhz clock. - DMA Supports two Channels, 0 and 1 - SPI Instance 0 uses chan 0 and SPI Instance 1 uses chan 1 - DMA can be used only if SPI is mapped to PF0 in the multi function endpoint and the MSI interrupt is supported - MSI interrupt of one of the SPI instance is assigned to the DMA and both channels 0 and 1 share the same irq, the MSI address and MSI Data of the irq is obtained and stored in DMA registers to generate interrupt Signed-off-by: Thangaraj Samynathan --- drivers/spi/spi-pci1xxxx.c | 135 +++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/drivers/spi/spi-pci1xxxx.c b/drivers/spi/spi-pci1xxxx.c index 5b2d3e4e21b7..95b1255e62cd 100644 --- a/drivers/spi/spi-pci1xxxx.c +++ b/drivers/spi/spi-pci1xxxx.c @@ -5,7 +5,12 @@ // Kumaravel Thiagarajan +#include +#include +#include #include +#include +#include #include #include #include @@ -32,8 +37,33 @@ #define SPI_MST_CTL_MODE_SEL (BIT(2)) #define SPI_MST_CTL_GO (BIT(0)) +#define SPI_SYSTEM_ADDR_BASE (0x2000) #define SPI_MST1_ADDR_BASE (0x800) +#define DEV_REV_REG (SPI_SYSTEM_ADDR_BASE + 0x00) +#define SPI_SYSLOCK_REG (SPI_SYSTEM_ADDR_BASE + 0xA0) +#define SPI_CONFIG_PERI_ENABLE_REG (SPI_SYSTEM_ADDR_BASE + 0x108) + +#define SPI_PERI_ENBLE_PF_MASK (GENMASK(17, 16)) +#define DEV_REV_MASK (GENMASK(7, 0)) + +#define SPI_SYSLOCK BIT(4) + +/* DMA Related Registers */ +#define SPI_DMA_ADDR_BASE (0x1000) +#define SPI_DMA_GLOBAL_WR_ENGINE_EN (SPI_DMA_ADDR_BASE + 0x0C) +#define SPI_DMA_GLOBAL_RD_ENGINE_EN (SPI_DMA_ADDR_BASE + 0x2C) +#define SPI_DMA_INTR_IMWR_WDONE_LOW (SPI_DMA_ADDR_BASE + 0x60) +#define SPI_DMA_INTR_IMWR_WDONE_HIGH (SPI_DMA_ADDR_BASE + 0x64) +#define SPI_DMA_INTR_IMWR_WABORT_LOW (SPI_DMA_ADDR_BASE + 0x68) +#define SPI_DMA_INTR_IMWR_WABORT_HIGH (SPI_DMA_ADDR_BASE + 0x6C) +#define SPI_DMA_INTR_WR_IMWR_DATA (SPI_DMA_ADDR_BASE + 0x70) +#define SPI_DMA_INTR_IMWR_RDONE_LOW (SPI_DMA_ADDR_BASE + 0xCC) +#define SPI_DMA_INTR_IMWR_RDONE_HIGH (SPI_DMA_ADDR_BASE + 0xD0) +#define SPI_DMA_INTR_IMWR_RABORT_LOW (SPI_DMA_ADDR_BASE + 0xD4) +#define SPI_DMA_INTR_IMWR_RABORT_HIGH (SPI_DMA_ADDR_BASE + 0xD8) +#define SPI_DMA_INTR_RD_IMWR_DATA (SPI_DMA_ADDR_BASE + 0xDC) + /* x refers to SPI Host Controller HW instance id in the below macros - 0 or 1 */ #define SPI_MST_CMD_BUF_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x00) @@ -50,6 +80,8 @@ #define SPI_MAX_DATA_LEN 320 #define PCI1XXXX_SPI_TIMEOUT (msecs_to_jiffies(100)) +#define SYSLOCK_RETRY_CNT (1000) +#define SPI_DMA_ENGINE_EN (0x1) #define SPI_INTR BIT(8) #define SPI_FORCE_CE BIT(4) @@ -76,7 +108,10 @@ struct pci1xxxx_spi_internal { struct pci1xxxx_spi { struct pci_dev *dev; u8 total_hw_instances; + u8 dev_rev; void __iomem *reg_base; + void __iomem *dma_offset_bar; + bool can_dma; struct pci1xxxx_spi_internal *spi_int[] __counted_by(total_hw_instances); }; @@ -106,6 +141,102 @@ static const struct pci_device_id pci1xxxx_spi_pci_id_table[] = { MODULE_DEVICE_TABLE(pci, pci1xxxx_spi_pci_id_table); +static int pci1xxxx_set_sys_lock(struct pci1xxxx_spi *par) +{ + writel(SPI_SYSLOCK, par->reg_base + SPI_SYSLOCK_REG); + return readl(par->reg_base + SPI_SYSLOCK_REG); +} + +static int pci1xxxx_acquire_sys_lock(struct pci1xxxx_spi *par) +{ + u32 regval; + + return readx_poll_timeout(pci1xxxx_set_sys_lock, par, regval, + (regval & SPI_SYSLOCK), 100, + SYSLOCK_RETRY_CNT * 100); +} + +static void pci1xxxx_release_sys_lock(struct pci1xxxx_spi *par) +{ + writel(0x0, par->reg_base + SPI_SYSLOCK_REG); +} + +static int pci1xxxx_check_spi_can_dma(struct pci1xxxx_spi *spi_bus, int irq) +{ + struct pci_dev *pdev = spi_bus->dev; + u32 pf_num; + u32 regval; + int ret; + + /* + * DEV REV Registers is a system register, HW Syslock bit + * should be acquired before accessing the register + */ + ret = pci1xxxx_acquire_sys_lock(spi_bus); + if (ret) + return ret; + + regval = readl(spi_bus->reg_base + DEV_REV_REG); + spi_bus->dev_rev = regval & DEV_REV_MASK; + if (spi_bus->dev_rev >= 0xC0) { + regval = readl(spi_bus->reg_base + + SPI_CONFIG_PERI_ENABLE_REG); + pf_num = regval & SPI_PERI_ENBLE_PF_MASK; + } + + pci1xxxx_release_sys_lock(spi_bus); + + /* + * DMA is supported only from C0 and SPI can use DMA only if + * it is mapped to PF0 + */ + if (spi_bus->dev_rev < 0xC0 || pf_num) + return -EOPNOTSUPP; + + /* + * DMA Supported only with MSI Interrupts + * One of the SPI instance's MSI vector address and data + * is used for DMA Interrupt + */ + if (!irq_get_msi_desc(irq)) + return -EOPNOTSUPP; + + spi_bus->dma_offset_bar = pcim_iomap(pdev, 2, pci_resource_len(pdev, 2)); + if (!spi_bus->dma_offset_bar) + return -EOPNOTSUPP; + + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) + return -EOPNOTSUPP; + + return 0; +} + +static int pci1xxxx_spi_dma_init(struct pci1xxxx_spi *spi_bus, int irq) +{ + struct msi_msg msi; + int ret; + + ret = pci1xxxx_check_spi_can_dma(spi_bus, irq); + if (ret) + return ret; + + get_cached_msi_msg(irq, &msi); + writel(SPI_DMA_ENGINE_EN, spi_bus->dma_offset_bar + SPI_DMA_GLOBAL_WR_ENGINE_EN); + writel(SPI_DMA_ENGINE_EN, spi_bus->dma_offset_bar + SPI_DMA_GLOBAL_RD_ENGINE_EN); + writel(msi.address_hi, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_WDONE_HIGH); + writel(msi.address_hi, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_WABORT_HIGH); + writel(msi.address_hi, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_RDONE_HIGH); + writel(msi.address_hi, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_RABORT_HIGH); + writel(msi.address_lo, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_WDONE_LOW); + writel(msi.address_lo, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_WABORT_LOW); + writel(msi.address_lo, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_RDONE_LOW); + writel(msi.address_lo, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_RABORT_LOW); + writel(msi.data, spi_bus->dma_offset_bar + SPI_DMA_INTR_WR_IMWR_DATA); + writel(msi.data, spi_bus->dma_offset_bar + SPI_DMA_INTR_RD_IMWR_DATA); + spi_bus->can_dma = true; + return 0; +} + static void pci1xxxx_spi_set_cs(struct spi_device *spi, bool enable) { struct pci1xxxx_spi_internal *p = spi_controller_get_devdata(spi->controller); @@ -324,6 +455,10 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id * goto error; } + ret = pci1xxxx_spi_dma_init(spi_bus, spi_sub_ptr->irq); + if (ret && ret != -EOPNOTSUPP) + return ret; + /* This register is only applicable for 1st instance */ regval = readl(spi_bus->reg_base + SPI_PCI_CTRL_REG_OFFSET(0)); if (!only_sec_inst) From patchwork Fri Dec 15 11:47:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thangaraj Samynathan X-Patchwork-Id: 179212 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:3b04:b0:fb:cd0c:d3e with SMTP id c4csp9211342dys; Fri, 15 Dec 2023 03:51:32 -0800 (PST) X-Google-Smtp-Source: AGHT+IG3LOfJxu0TtKbplpKUqKJubkbQMQcIn5IDAN21RAimeFTw1hn3eyUIhRPt5YJETCiGVsD4 X-Received: by 2002:a05:620a:1207:b0:77e:fba3:a21e with SMTP id u7-20020a05620a120700b0077efba3a21emr13695240qkj.120.1702641092109; Fri, 15 Dec 2023 03:51:32 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1702641092; cv=none; d=google.com; s=arc-20160816; b=kJKCFCKEv5LlBMd9Oq04i7tS4Q6dSV7ImCDhN2se3IkSIsbCDXf9IK9oGEWudkvEuR 8JGPA5AvwSk/BL9t/0U9GPYAvGRh/j+Aj9IibP3CDw1RCaK3C/GrcqDJtOdmItWdta8Z 3yAylKBMxH0yXHP5+5aJTUVB+El3IyNIxyRTfYp+1H0TPJyu2hNHfdHUf+VrqMfMU8Rt 063BXira+ZTTlxBETkPqLfHZO8QbMtCrj1v1dX1pRTLvCZjhlMoWN2Qo9zKNYzrIEsLL syqcQcp3dvGJWXRYGzbLq+pjhZ+EbQzjc6c7y1dtqUKwwKut87D9eVZGAXrN9Ul0402R gnwA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=m8eY1Ce46OLz0EWjxIxEFLRcvtTecGh7PfViBxK8Eqs=; fh=cGbkLwFjdUmwzsSfH4uGElh042qw4yrimp50Fdi/yLk=; b=LgCE3CnINMe9XJvyDR9TpRlXgvFKI4rcO47rGy2vE5gFVc/vC268XvVVNC28IKvVu+ Y9tBa6nIML0NxcQuV/97j7b23pIVWOLulvJyOIOyUcSCyB4+bOg0WaIYYTqCpX/UT16A 4bVbzteqn7Mc4aMrlh2+i9drIW7GcM8Q61jqfw1KciRSGm8j9Llgrj6GBKJKKk39RIQy vWi1KrgYkMtE70h2PRVmuNFFgPglVqk1j5Ti1ad0+AneeI8J9yCfVaV9WpDkxgXUGULH 6jDtl6uz4OUR86nt5q+FWIbHp4c82x7XsFU31VU3UYsc6dxHIXE2UGmVyITD3a9Ib6np k+aQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@microchip.com header.s=mchp header.b=N0rqGd8P; spf=pass (google.com: domain of linux-kernel+bounces-870-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-870-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=QUARANTINE sp=REJECT dis=NONE) header.from=microchip.com Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [2604:1380:45d1:ec00::1]) by mx.google.com with ESMTPS id w14-20020a05620a444e00b0077f05d46542si18935727qkp.58.2023.12.15.03.51.32 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Dec 2023 03:51:32 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-870-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) client-ip=2604:1380:45d1:ec00::1; Authentication-Results: mx.google.com; dkim=pass header.i=@microchip.com header.s=mchp header.b=N0rqGd8P; spf=pass (google.com: domain of linux-kernel+bounces-870-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-870-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=QUARANTINE sp=REJECT dis=NONE) header.from=microchip.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id D18521C2323E for ; Fri, 15 Dec 2023 11:51:31 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 9E4AC2D791; Fri, 15 Dec 2023 11:50:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="N0rqGd8P" X-Original-To: linux-kernel@vger.kernel.org Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2884925555; Fri, 15 Dec 2023 11:50:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1702641028; x=1734177028; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=1/ShOR4SuOYUD1NdG9lT57dZhG0qlGrCznKgFAREjDs=; b=N0rqGd8P9N+vxj3Bf4UNalNBEQqkvJQLRwchQujnrwwJeZGExwO5QxoA 2ri6dObPVR+GzHo2AJ0OZfPlxv196AnxbMIuoXGMJb8GSXm5yWsLsi4uC mot/3cgkBd0Ys43hMqMGvN/IV0V1uWU9zRi9bIi6pNCx+7hOn7f9byjX8 LQ4rtJ5vAUClki3mJ9VtbBhOD9mBqr0g5DgZ8pDxzy2HM6Qj7V5Pi8bVn xFLz874Y80EtEDb3kb+HJ5k+tknhtl93hvwnuheYLnUpvyVXf9y1RqNAu +Ym639/NaUHR1Pgsty+DZ1d04pKx/CCBNQ4nDVe0pRJd0WNxuVcn/mdni Q==; X-CSE-ConnectionGUID: LGva2yzVSgmRfFnu4BtIaw== X-CSE-MsgGUID: qhWTRBLBTy295LdSunusew== X-ThreatScanner-Verdict: Negative X-IronPort-AV: E=Sophos;i="6.04,278,1695711600"; d="scan'208";a="14317230" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa1.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 15 Dec 2023 04:50:20 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Fri, 15 Dec 2023 04:50:08 -0700 Received: from che-dk-ungapp03lx.microchip.com (10.10.85.11) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.35 via Frontend Transport; Fri, 15 Dec 2023 04:50:06 -0700 From: Thangaraj Samynathan To: CC: , , , , , , Subject: [PATCH SPI for-next 2/3] spi: mchp-pci1xxxx: DMA Read support for copying data into SPI Buf Date: Fri, 15 Dec 2023 17:17:47 +0530 Message-ID: <20231215114748.152319-3-thangaraj.s@microchip.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231215114748.152319-1-thangaraj.s@microchip.com> References: <20231215114748.152319-1-thangaraj.s@microchip.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1785348585806341605 X-GMAIL-MSGID: 1785348585806341605 pci1xxxx_spi_transfer_with_dma is registered as transfer_one callback when DMA can be supported. This function adds DMA read operation which copies the data from host cpu buffer to SPI Tx Buffer. On DMA Read Completion interrupt, SPI transaction is initiated in isr. Helper functions pci1xxxx_spi_setup, pci1xxxx_spi_setup_dma_read and pci1xxxx_start_spi_xfer are added for starting spi transfer, setting up spi and dma read operation. In the existing implementation, codes are replaced with helper wherever applicable. Signed-off-by: Thangaraj Samynathan --- drivers/spi/spi-pci1xxxx.c | 225 +++++++++++++++++++++++++++++++++---- 1 file changed, 204 insertions(+), 21 deletions(-) diff --git a/drivers/spi/spi-pci1xxxx.c b/drivers/spi/spi-pci1xxxx.c index 95b1255e62cd..824885ada9b6 100644 --- a/drivers/spi/spi-pci1xxxx.c +++ b/drivers/spi/spi-pci1xxxx.c @@ -5,6 +5,7 @@ // Kumaravel Thiagarajan +#include #include #include #include @@ -12,6 +13,7 @@ #include #include #include +#include #include #include @@ -37,6 +39,7 @@ #define SPI_MST_CTL_MODE_SEL (BIT(2)) #define SPI_MST_CTL_GO (BIT(0)) +#define SPI_PERI_ADDR_BASE (0x160000) #define SPI_SYSTEM_ADDR_BASE (0x2000) #define SPI_MST1_ADDR_BASE (0x800) @@ -48,22 +51,49 @@ #define DEV_REV_MASK (GENMASK(7, 0)) #define SPI_SYSLOCK BIT(4) +#define SPI0 (0) +#define SPI1 (1) /* DMA Related Registers */ #define SPI_DMA_ADDR_BASE (0x1000) #define SPI_DMA_GLOBAL_WR_ENGINE_EN (SPI_DMA_ADDR_BASE + 0x0C) #define SPI_DMA_GLOBAL_RD_ENGINE_EN (SPI_DMA_ADDR_BASE + 0x2C) +#define SPI_DMA_RD_DOORBELL_REG (SPI_DMA_ADDR_BASE + 0x30) #define SPI_DMA_INTR_IMWR_WDONE_LOW (SPI_DMA_ADDR_BASE + 0x60) #define SPI_DMA_INTR_IMWR_WDONE_HIGH (SPI_DMA_ADDR_BASE + 0x64) #define SPI_DMA_INTR_IMWR_WABORT_LOW (SPI_DMA_ADDR_BASE + 0x68) #define SPI_DMA_INTR_IMWR_WABORT_HIGH (SPI_DMA_ADDR_BASE + 0x6C) #define SPI_DMA_INTR_WR_IMWR_DATA (SPI_DMA_ADDR_BASE + 0x70) +#define SPI_DMA_INTR_RD_STS (SPI_DMA_ADDR_BASE + 0xA0) +#define SPI_DMA_RD_INT_MASK (SPI_DMA_ADDR_BASE + 0xA8) +#define SPI_DMA_INTR_RD_CLR (SPI_DMA_ADDR_BASE + 0xAC) +#define SPI_DMA_ERR_RD_STS (SPI_DMA_ADDR_BASE + 0xB8) #define SPI_DMA_INTR_IMWR_RDONE_LOW (SPI_DMA_ADDR_BASE + 0xCC) #define SPI_DMA_INTR_IMWR_RDONE_HIGH (SPI_DMA_ADDR_BASE + 0xD0) #define SPI_DMA_INTR_IMWR_RABORT_LOW (SPI_DMA_ADDR_BASE + 0xD4) #define SPI_DMA_INTR_IMWR_RABORT_HIGH (SPI_DMA_ADDR_BASE + 0xD8) #define SPI_DMA_INTR_RD_IMWR_DATA (SPI_DMA_ADDR_BASE + 0xDC) +#define SPI_DMA_CH0_RD_BASE (SPI_DMA_ADDR_BASE + 0x300) +#define SPI_DMA_CH1_RD_BASE (SPI_DMA_ADDR_BASE + 0x500) + +#define SPI_DMA_CH_CTL1_OFFSET (0x00) +#define SPI_DMA_CH_XFER_LEN_OFFSET (0x08) +#define SPI_DMA_CH_SAR_LO_OFFSET (0x0C) +#define SPI_DMA_CH_SAR_HI_OFFSET (0x10) +#define SPI_DMA_CH_DAR_LO_OFFSET (0x14) +#define SPI_DMA_CH_DAR_HI_OFFSET (0x18) + +#define SPI_DMA_CH0_DONE_INT BIT(0) +#define SPI_DMA_CH1_DONE_INT BIT(1) +#define SPI_DMA_CH0_ABORT_INT BIT(16) +#define SPI_DMA_CH1_ABORT_INT BIT(17) +#define SPI_DMA_DONE_INT_MASK (SPI_DMA_CH0_DONE_INT | SPI_DMA_CH1_DONE_INT) +#define SPI_DMA_ABORT_INT_MASK (SPI_DMA_CH0_ABORT_INT | SPI_DMA_CH1_ABORT_INT) +#define DMA_CH_CONTROL_LIE BIT(3) +#define DMA_CH_CONTROL_RIE BIT(4) +#define DMA_INTR_EN (DMA_CH_CONTROL_RIE | DMA_CH_CONTROL_LIE) + /* x refers to SPI Host Controller HW instance id in the below macros - 0 or 1 */ #define SPI_MST_CMD_BUF_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x00) @@ -82,6 +112,7 @@ #define PCI1XXXX_SPI_TIMEOUT (msecs_to_jiffies(100)) #define SYSLOCK_RETRY_CNT (1000) #define SPI_DMA_ENGINE_EN (0x1) +#define SPI_DMA_ENGINE_DIS (0x0) #define SPI_INTR BIT(8) #define SPI_FORCE_CE BIT(4) @@ -95,6 +126,7 @@ struct pci1xxxx_spi_internal { u8 hw_inst; bool spi_xfer_in_progress; + bool dma_aborted_rd; int irq; struct completion spi_xfer_done; struct spi_controller *spi_host; @@ -111,6 +143,8 @@ struct pci1xxxx_spi { u8 dev_rev; void __iomem *reg_base; void __iomem *dma_offset_bar; + /* lock to safely access the DMA registers in isr */ + spinlock_t dma_reg_lock; bool can_dma; struct pci1xxxx_spi_internal *spi_int[] __counted_by(total_hw_instances); }; @@ -220,6 +254,7 @@ static int pci1xxxx_spi_dma_init(struct pci1xxxx_spi *spi_bus, int irq) if (ret) return ret; + spin_lock_init(&spi_bus->dma_reg_lock); get_cached_msi_msg(irq, &msi); writel(SPI_DMA_ENGINE_EN, spi_bus->dma_offset_bar + SPI_DMA_GLOBAL_WR_ENGINE_EN); writel(SPI_DMA_ENGINE_EN, spi_bus->dma_offset_bar + SPI_DMA_GLOBAL_RD_ENGINE_EN); @@ -277,6 +312,53 @@ static u8 pci1xxxx_get_clock_div(u32 hz) return val; } +static void pci1xxxx_spi_setup_dma_read(struct pci1xxxx_spi_internal *p, + dma_addr_t dma_addr, u32 len) +{ + void *base; + + if (!p->hw_inst) + base = p->parent->dma_offset_bar + SPI_DMA_CH0_RD_BASE; + else + base = p->parent->dma_offset_bar + SPI_DMA_CH1_RD_BASE; + + writel(DMA_INTR_EN, base + SPI_DMA_CH_CTL1_OFFSET); + writel(len, base + SPI_DMA_CH_XFER_LEN_OFFSET); + writel(lower_32_bits(dma_addr), base + SPI_DMA_CH_SAR_LO_OFFSET); + writel(upper_32_bits(dma_addr), base + SPI_DMA_CH_SAR_HI_OFFSET); + /* Updated SPI Command Registers */ + writel(lower_32_bits(SPI_PERI_ADDR_BASE + SPI_MST_CMD_BUF_OFFSET(p->hw_inst)), + base + SPI_DMA_CH_DAR_LO_OFFSET); + writel(upper_32_bits(SPI_PERI_ADDR_BASE + SPI_MST_CMD_BUF_OFFSET(p->hw_inst)), + base + SPI_DMA_CH_DAR_HI_OFFSET); +} + +static void pci1xxxx_spi_setup(struct pci1xxxx_spi *par, u8 hw_inst, u32 mode, + u8 clkdiv, u32 len) +{ + u32 regval; + + regval = readl(par->reg_base + SPI_MST_CTL_REG_OFFSET(hw_inst)); + regval &= ~(SPI_MST_CTL_MODE_SEL | SPI_MST_CTL_CMD_LEN_MASK | + SPI_MST_CTL_SPEED_MASK); + + if (mode == SPI_MODE_3) + regval |= SPI_MST_CTL_MODE_SEL; + + regval |= FIELD_PREP(SPI_MST_CTL_CMD_LEN_MASK, len); + regval |= FIELD_PREP(SPI_MST_CTL_SPEED_MASK, clkdiv); + writel(regval, par->reg_base + SPI_MST_CTL_REG_OFFSET(hw_inst)); +} + +static void pci1xxxx_start_spi_xfer(struct pci1xxxx_spi_internal *p, u8 hw_inst) +{ + u32 regval; + + regval = readl(p->parent->reg_base + SPI_MST_CTL_REG_OFFSET(hw_inst)); + regval |= SPI_MST_CTL_GO; + writel(regval, p->parent->reg_base + SPI_MST_CTL_REG_OFFSET(hw_inst)); +} + static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr, struct spi_device *spi, struct spi_transfer *xfer) { @@ -317,26 +399,8 @@ static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr, memcpy_toio(par->reg_base + SPI_MST_CMD_BUF_OFFSET(p->hw_inst), &tx_buf[bytes_transfered], len); bytes_transfered += len; - regval = readl(par->reg_base + - SPI_MST_CTL_REG_OFFSET(p->hw_inst)); - regval &= ~(SPI_MST_CTL_MODE_SEL | SPI_MST_CTL_CMD_LEN_MASK | - SPI_MST_CTL_SPEED_MASK); - - if (mode == SPI_MODE_3) - regval |= SPI_MST_CTL_MODE_SEL; - else - regval &= ~SPI_MST_CTL_MODE_SEL; - - regval |= (clkdiv << 5); - regval &= ~SPI_MST_CTL_CMD_LEN_MASK; - regval |= (len << 8); - writel(regval, par->reg_base + - SPI_MST_CTL_REG_OFFSET(p->hw_inst)); - regval = readl(par->reg_base + - SPI_MST_CTL_REG_OFFSET(p->hw_inst)); - regval |= SPI_MST_CTL_GO; - writel(regval, par->reg_base + - SPI_MST_CTL_REG_OFFSET(p->hw_inst)); + pci1xxxx_spi_setup(par, p->hw_inst, spi->mode, clkdiv, len); + pci1xxxx_start_spi_xfer(p, p->hw_inst); /* Wait for DMA_TERM interrupt */ result = wait_for_completion_timeout(&p->spi_xfer_done, @@ -356,10 +420,105 @@ static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr, return 0; } +static int pci1xxxx_spi_transfer_with_dma(struct spi_controller *spi_ctlr, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct pci1xxxx_spi_internal *p = spi_controller_get_devdata(spi_ctlr); + struct pci1xxxx_spi *par = p->parent; + struct device *dev = &par->dev->dev; + dma_addr_t tx_dma_addr = 0; + u64 bytes_transfered = 0; + u64 bytes_recvd = 0; + int loop_count; + int ret = 0; + u32 regval; + u8 *rx_buf; + u8 clkdiv; + u32 len; + u32 i; + + p->spi_xfer_in_progress = true; + clkdiv = pci1xxxx_get_clock_div(xfer->speed_hz); + rx_buf = xfer->rx_buf; + regval = readl(par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst)); + writel(regval, par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst)); + + if (!xfer->tx_buf) { + ret = -EINVAL; + goto error; + } + + tx_dma_addr = dma_map_single(dev, (void *)xfer->tx_buf, xfer->len, DMA_TO_DEVICE); + if (dma_mapping_error(NULL, tx_dma_addr)) { + tx_dma_addr = 0; + ret = -ENOMEM; + goto error; + } + + loop_count = DIV_ROUND_UP(xfer->len, SPI_MAX_DATA_LEN); + len = SPI_MAX_DATA_LEN; + pci1xxxx_spi_setup(par, p->hw_inst, spi->mode, clkdiv, len); + for (i = 0; i < loop_count; i++) { + if ((i == loop_count - 1) && (xfer->len % SPI_MAX_DATA_LEN != 0)) { + len = xfer->len % SPI_MAX_DATA_LEN; + pci1xxxx_spi_setup(par, p->hw_inst, spi->mode, clkdiv, len); + } + + pci1xxxx_spi_setup_dma_read(p, (tx_dma_addr + bytes_transfered), len); + + writel(p->hw_inst, par->dma_offset_bar + SPI_DMA_RD_DOORBELL_REG); + + reinit_completion(&p->spi_xfer_done); + /* Wait for DMA_TERM interrupt */ + ret = wait_for_completion_timeout(&p->spi_xfer_done, PCI1XXXX_SPI_TIMEOUT); + if (!ret) { + ret = -ETIMEDOUT; + if (p->dma_aborted_rd) { + writel(SPI_DMA_ENGINE_DIS, + par->dma_offset_bar + SPI_DMA_GLOBAL_RD_ENGINE_EN); + + /* + * DMA ENGINE reset takes time if any TLP + * completeion in progress, should wait + * till DMA Engine reset is completed. + */ + ret = readl_poll_timeout(par->dma_offset_bar + + SPI_DMA_GLOBAL_RD_ENGINE_EN, regval, + (regval == 0x0), 0, USEC_PER_MSEC); + if (ret) { + ret = -ECANCELED; + goto error; + } + writel(SPI_DMA_ENGINE_EN, + par->dma_offset_bar + SPI_DMA_GLOBAL_RD_ENGINE_EN); + p->dma_aborted_rd = false; + ret = -ECANCELED; + } + goto error; + } + bytes_transfered += len; + if (rx_buf) { + memcpy_fromio(&rx_buf[bytes_recvd], par->reg_base + + SPI_MST_RSP_BUF_OFFSET(p->hw_inst), len); + bytes_recvd += len; + } + ret = 0; + } + +error: + p->spi_xfer_in_progress = false; + if (tx_dma_addr) + dma_unmap_single(dev, tx_dma_addr, xfer->len, DMA_TO_DEVICE); + + return ret; +} + static irqreturn_t pci1xxxx_spi_isr(int irq, void *dev) { struct pci1xxxx_spi_internal *p = dev; irqreturn_t spi_int_fired = IRQ_NONE; + unsigned long flags; u32 regval; /* Clear the SPI GO_BIT Interrupt */ @@ -372,6 +531,26 @@ static irqreturn_t pci1xxxx_spi_isr(int irq, void *dev) writel(regval, p->parent->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst)); + if (!p->parent->can_dma) + return spi_int_fired; + + spin_lock_irqsave(&p->parent->dma_reg_lock, flags); + /* Clear the DMA RD INT and start spi xfer*/ + regval = readl(p->parent->dma_offset_bar + SPI_DMA_INTR_RD_STS); + if (regval & SPI_DMA_DONE_INT_MASK) { + if (regval & SPI_DMA_CH0_DONE_INT) + pci1xxxx_start_spi_xfer(p, SPI0); + if (regval & SPI_DMA_CH1_DONE_INT) + pci1xxxx_start_spi_xfer(p, SPI1); + spi_int_fired = IRQ_HANDLED; + } + if (regval & SPI_DMA_ABORT_INT_MASK) { + p->dma_aborted_rd = true; + spi_int_fired = IRQ_HANDLED; + } + writel(regval, p->parent->dma_offset_bar + SPI_DMA_INTR_RD_CLR); + spin_unlock_irqrestore(&p->parent->dma_reg_lock, flags); + return spi_int_fired; } @@ -495,7 +674,11 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id * spi_host->num_chipselect = SPI_CHIP_SEL_COUNT; spi_host->mode_bits = SPI_MODE_0 | SPI_MODE_3 | SPI_RX_DUAL | SPI_TX_DUAL | SPI_LOOP; - spi_host->transfer_one = pci1xxxx_spi_transfer_one; + if (spi_bus->can_dma) + spi_host->transfer_one = pci1xxxx_spi_transfer_with_dma; + else + spi_host->transfer_one = pci1xxxx_spi_transfer_one; + spi_host->set_cs = pci1xxxx_spi_set_cs; spi_host->bits_per_word_mask = SPI_BPW_MASK(8); spi_host->max_speed_hz = PCI1XXXX_SPI_MAX_CLOCK_HZ; From patchwork Fri Dec 15 11:47:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thangaraj Samynathan X-Patchwork-Id: 179213 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:3b04:b0:fb:cd0c:d3e with SMTP id c4csp9211379dys; Fri, 15 Dec 2023 03:51:39 -0800 (PST) X-Google-Smtp-Source: AGHT+IFyAQkc5f3qV18d2q4L3fXd32J6zJfV4N4lihiCUx3q7BaWm0KVRfbNS8cM1URxGGpIBrUd X-Received: by 2002:a17:907:9708:b0:a1d:9831:1da with SMTP id jg8-20020a170907970800b00a1d983101damr7474321ejc.91.1702641099570; Fri, 15 Dec 2023 03:51:39 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1702641099; cv=none; d=google.com; s=arc-20160816; b=kSIEZVGTiU127bW/e5gbg9gnKJZ4wGpkLCzShlUWm7snJrVg/Q7KXU7FtOak03d2vS vP1Glg1Ilvq0epHImIIrQN6sPRIoprEIQhH6BIAYOvF5wLxSReIk4gBBzUn79zy71lqr VZwkcYrGzqRJpL6Q9HPKHFZ7+fZo67ytiiMZGbtvxTak87MyLa+FEWNcrWRfggvphxGa zNMlMQCU7aK7SD2ux4aa9KQfj6wD0Fgg1ObUcatMYKp1uuIEeuAJ+SPL0PGQhb9oEaNG msIkXoSyrlNjC2NGmPQPWRDK0vVrxYKwzTTiVe/t/mcau4LAbaJ8iPmmZjwUPzRdGTJ3 Amvw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=i3P02RSqyKJ1LGpPvSud6sf7ziXsa40InRkeNAr4Gp8=; fh=cGbkLwFjdUmwzsSfH4uGElh042qw4yrimp50Fdi/yLk=; b=FZ4oOkNNlOtT7dCWoXZqreo176ugZmx7q53BrI8GREEw/+X+7NMPdqIkE2K+Z1e9VF KKxWNqJFDgQtNxcouUwAUqkjMuV7VLkLFSCbHEljmxer1cPH5iS9t/HkXdB3uxZKtw6g o7Ur7HAK7lsahJeAjetZypeWQyKKMTGVMLR3U/PME/g36WV7ZrV150hgci/ioMB0hVZz Ouw5JJxjrpgEps1/mQdKu1M+yQrOBpmEEw8X6FFKNWS37xlV6CqfBrR1yFaguOGUUuy9 mkBluAD87DsEE/V+mKW0k804b2ogDmXFw73TSM5L/7//OqH2mnblTqUps0pIqEfcA2Z6 1Aiw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@microchip.com header.s=mchp header.b=hlWVnDA6; spf=pass (google.com: domain of linux-kernel+bounces-871-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.80.249 as permitted sender) smtp.mailfrom="linux-kernel+bounces-871-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=QUARANTINE sp=REJECT dis=NONE) header.from=microchip.com Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [147.75.80.249]) by mx.google.com with ESMTPS id j14-20020a170906050e00b00a1fb2be9d79si797976eja.1011.2023.12.15.03.51.39 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Dec 2023 03:51:39 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-871-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.80.249 as permitted sender) client-ip=147.75.80.249; Authentication-Results: mx.google.com; dkim=pass header.i=@microchip.com header.s=mchp header.b=hlWVnDA6; spf=pass (google.com: domain of linux-kernel+bounces-871-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.80.249 as permitted sender) smtp.mailfrom="linux-kernel+bounces-871-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=QUARANTINE sp=REJECT dis=NONE) header.from=microchip.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id 0BBBA1F225C9 for ; Fri, 15 Dec 2023 11:51:39 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 434C42D7AF; Fri, 15 Dec 2023 11:50:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="hlWVnDA6" X-Original-To: linux-kernel@vger.kernel.org Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2AC232556B; Fri, 15 Dec 2023 11:50:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1702641029; x=1734177029; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=+c81t6P+VrINi52C/mrkf7kTMz9CCpU+nj9sKXqCplI=; b=hlWVnDA67ouRf7ETxRCJZ2wnIQoMPbzgIoK/CjYa4ZincobVA4YKemCI Me8phZapwCqB/G/j46xN4zfDYimbMmrq+Tmqf+hBth8ztdje2/kJM15qA oJ7EqtzPSDEd5FXS5CUatS/MqMDnJiPjsCLdyz+V1RtvgQW9IWNNcico4 y5mtW/biaYqC3/e8rdR+x9iFEk5biR95n2nA+eDvF6NxdUpvquIBClB13 tmH+8LnQAYn/42TYa1R+y9+6BHiUMsn/5tyrL7SsucS3kkKE3b/WzM/0M /Ze+Yg7Vl1I8ePnBdeqicrHIx3X5nfCUq1mv8VAlhEAhBdRP+X7rUIb6I g==; X-CSE-ConnectionGUID: LGva2yzVSgmRfFnu4BtIaw== X-CSE-MsgGUID: +5RO2q1pS+ydHvkV8he07w== X-ThreatScanner-Verdict: Negative X-IronPort-AV: E=Sophos;i="6.04,278,1695711600"; d="scan'208";a="14317231" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa1.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 15 Dec 2023 04:50:20 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Fri, 15 Dec 2023 04:50:14 -0700 Received: from che-dk-ungapp03lx.microchip.com (10.10.85.11) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.35 via Frontend Transport; Fri, 15 Dec 2023 04:50:11 -0700 From: Thangaraj Samynathan To: CC: , , , , , , Subject: [PATCH SPI for-next 3/3] spi: mchp-pci1xxxx: DMA Write Support for copying data from SPI Buf Date: Fri, 15 Dec 2023 17:17:48 +0530 Message-ID: <20231215114748.152319-4-thangaraj.s@microchip.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231215114748.152319-1-thangaraj.s@microchip.com> References: <20231215114748.152319-1-thangaraj.s@microchip.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1785348593509677845 X-GMAIL-MSGID: 1785348593509677845 DMA Write setup is done in pci1xxxx_spi_transfer_with_dma, before initiating the transaction. Once the SPI transaction complete interrupt is received, doorbell is written to initiate DMA Write. DMA Write operation copies the data from SPI RX buffer to CPU buffer. Signed-off-by: Thangaraj Samynathan --- drivers/spi/spi-pci1xxxx.c | 93 +++++++++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-pci1xxxx.c b/drivers/spi/spi-pci1xxxx.c index 824885ada9b6..5dcb63c367b9 100644 --- a/drivers/spi/spi-pci1xxxx.c +++ b/drivers/spi/spi-pci1xxxx.c @@ -57,8 +57,13 @@ /* DMA Related Registers */ #define SPI_DMA_ADDR_BASE (0x1000) #define SPI_DMA_GLOBAL_WR_ENGINE_EN (SPI_DMA_ADDR_BASE + 0x0C) +#define SPI_DMA_WR_DOORBELL_REG (SPI_DMA_ADDR_BASE + 0x10) #define SPI_DMA_GLOBAL_RD_ENGINE_EN (SPI_DMA_ADDR_BASE + 0x2C) #define SPI_DMA_RD_DOORBELL_REG (SPI_DMA_ADDR_BASE + 0x30) +#define SPI_DMA_INTR_WR_STS (SPI_DMA_ADDR_BASE + 0x4C) +#define SPI_DMA_WR_INT_MASK (SPI_DMA_ADDR_BASE + 0x54) +#define SPI_DMA_INTR_WR_CLR (SPI_DMA_ADDR_BASE + 0x58) +#define SPI_DMA_ERR_WR_STS (SPI_DMA_ADDR_BASE + 0x5C) #define SPI_DMA_INTR_IMWR_WDONE_LOW (SPI_DMA_ADDR_BASE + 0x60) #define SPI_DMA_INTR_IMWR_WDONE_HIGH (SPI_DMA_ADDR_BASE + 0x64) #define SPI_DMA_INTR_IMWR_WABORT_LOW (SPI_DMA_ADDR_BASE + 0x68) @@ -74,7 +79,9 @@ #define SPI_DMA_INTR_IMWR_RABORT_HIGH (SPI_DMA_ADDR_BASE + 0xD8) #define SPI_DMA_INTR_RD_IMWR_DATA (SPI_DMA_ADDR_BASE + 0xDC) +#define SPI_DMA_CH0_WR_BASE (SPI_DMA_ADDR_BASE + 0x200) #define SPI_DMA_CH0_RD_BASE (SPI_DMA_ADDR_BASE + 0x300) +#define SPI_DMA_CH1_WR_BASE (SPI_DMA_ADDR_BASE + 0x400) #define SPI_DMA_CH1_RD_BASE (SPI_DMA_ADDR_BASE + 0x500) #define SPI_DMA_CH_CTL1_OFFSET (0x00) @@ -126,7 +133,9 @@ struct pci1xxxx_spi_internal { u8 hw_inst; bool spi_xfer_in_progress; + void *rx_buf; bool dma_aborted_rd; + bool dma_aborted_wr; int irq; struct completion spi_xfer_done; struct spi_controller *spi_host; @@ -333,6 +342,26 @@ static void pci1xxxx_spi_setup_dma_read(struct pci1xxxx_spi_internal *p, base + SPI_DMA_CH_DAR_HI_OFFSET); } +static void pci1xxxx_spi_setup_dma_write(struct pci1xxxx_spi_internal *p, + dma_addr_t dma_addr, u32 len) +{ + void *base; + + if (!p->hw_inst) + base = p->parent->dma_offset_bar + SPI_DMA_CH0_WR_BASE; + else + base = p->parent->dma_offset_bar + SPI_DMA_CH1_WR_BASE; + + writel(DMA_INTR_EN, base + SPI_DMA_CH_CTL1_OFFSET); + writel(len, base + SPI_DMA_CH_XFER_LEN_OFFSET); + writel(lower_32_bits(dma_addr), base + SPI_DMA_CH_DAR_LO_OFFSET); + writel(upper_32_bits(dma_addr), base + SPI_DMA_CH_DAR_HI_OFFSET); + writel(lower_32_bits(SPI_PERI_ADDR_BASE + SPI_MST_RSP_BUF_OFFSET(p->hw_inst)), + base + SPI_DMA_CH_SAR_LO_OFFSET); + writel(upper_32_bits(SPI_PERI_ADDR_BASE + SPI_MST_RSP_BUF_OFFSET(p->hw_inst)), + base + SPI_DMA_CH_SAR_HI_OFFSET); +} + static void pci1xxxx_spi_setup(struct pci1xxxx_spi *par, u8 hw_inst, u32 mode, u8 clkdiv, u32 len) { @@ -427,9 +456,9 @@ static int pci1xxxx_spi_transfer_with_dma(struct spi_controller *spi_ctlr, struct pci1xxxx_spi_internal *p = spi_controller_get_devdata(spi_ctlr); struct pci1xxxx_spi *par = p->parent; struct device *dev = &par->dev->dev; + dma_addr_t rx_dma_addr = 0; dma_addr_t tx_dma_addr = 0; u64 bytes_transfered = 0; - u64 bytes_recvd = 0; int loop_count; int ret = 0; u32 regval; @@ -439,6 +468,7 @@ static int pci1xxxx_spi_transfer_with_dma(struct spi_controller *spi_ctlr, u32 i; p->spi_xfer_in_progress = true; + p->rx_buf = xfer->rx_buf; clkdiv = pci1xxxx_get_clock_div(xfer->speed_hz); rx_buf = xfer->rx_buf; regval = readl(par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst)); @@ -456,6 +486,15 @@ static int pci1xxxx_spi_transfer_with_dma(struct spi_controller *spi_ctlr, goto error; } + if (xfer->rx_buf) { + rx_dma_addr = dma_map_single(dev, (void *)xfer->rx_buf, xfer->len, DMA_FROM_DEVICE); + if (dma_mapping_error(NULL, rx_dma_addr)) { + rx_dma_addr = 0; + ret = -ENOMEM; + goto error; + } + } + loop_count = DIV_ROUND_UP(xfer->len, SPI_MAX_DATA_LEN); len = SPI_MAX_DATA_LEN; pci1xxxx_spi_setup(par, p->hw_inst, spi->mode, clkdiv, len); @@ -466,6 +505,8 @@ static int pci1xxxx_spi_transfer_with_dma(struct spi_controller *spi_ctlr, } pci1xxxx_spi_setup_dma_read(p, (tx_dma_addr + bytes_transfered), len); + if (rx_dma_addr) + pci1xxxx_spi_setup_dma_write(p, (rx_dma_addr + bytes_transfered), len); writel(p->hw_inst, par->dma_offset_bar + SPI_DMA_RD_DOORBELL_REG); @@ -495,14 +536,31 @@ static int pci1xxxx_spi_transfer_with_dma(struct spi_controller *spi_ctlr, p->dma_aborted_rd = false; ret = -ECANCELED; } + if (p->dma_aborted_wr) { + writel(SPI_DMA_ENGINE_DIS, + par->dma_offset_bar + SPI_DMA_GLOBAL_WR_ENGINE_EN); + + /* + * DMA ENGINE reset takes time if any TLP + * completeion in progress, should wait + * till DMA Engine reset is completed. + */ + ret = readl_poll_timeout(par->dma_offset_bar + + SPI_DMA_GLOBAL_WR_ENGINE_EN, regval, + (regval == 0x0), 0, USEC_PER_MSEC); + if (ret) { + ret = -ECANCELED; + goto error; + } + + writel(SPI_DMA_ENGINE_EN, + par->dma_offset_bar + SPI_DMA_GLOBAL_WR_ENGINE_EN); + p->dma_aborted_wr = false; + ret = -ECANCELED; + } goto error; } bytes_transfered += len; - if (rx_buf) { - memcpy_fromio(&rx_buf[bytes_recvd], par->reg_base + - SPI_MST_RSP_BUF_OFFSET(p->hw_inst), len); - bytes_recvd += len; - } ret = 0; } @@ -510,6 +568,8 @@ static int pci1xxxx_spi_transfer_with_dma(struct spi_controller *spi_ctlr, p->spi_xfer_in_progress = false; if (tx_dma_addr) dma_unmap_single(dev, tx_dma_addr, xfer->len, DMA_TO_DEVICE); + if (rx_dma_addr) + dma_unmap_single(dev, rx_dma_addr, xfer->len, DMA_FROM_DEVICE); return ret; } @@ -525,7 +585,11 @@ static irqreturn_t pci1xxxx_spi_isr(int irq, void *dev) regval = readl(p->parent->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst)); if (regval & SPI_INTR) { /* Clear xfer_done */ - complete(&p->spi_xfer_done); + if (p->parent->can_dma && p->rx_buf) + writel(p->hw_inst, p->parent->dma_offset_bar + + SPI_DMA_WR_DOORBELL_REG); + else + complete(&p->parent->spi_int[p->hw_inst]->spi_xfer_done); spi_int_fired = IRQ_HANDLED; } @@ -549,6 +613,21 @@ static irqreturn_t pci1xxxx_spi_isr(int irq, void *dev) spi_int_fired = IRQ_HANDLED; } writel(regval, p->parent->dma_offset_bar + SPI_DMA_INTR_RD_CLR); + + /* Clear the DMA WR INT */ + regval = readl(p->parent->dma_offset_bar + SPI_DMA_INTR_WR_STS); + if (regval & SPI_DMA_DONE_INT_MASK) { + if (regval & SPI_DMA_CH0_DONE_INT) + complete(&p->parent->spi_int[SPI0]->spi_xfer_done); + if (regval & SPI_DMA_CH1_DONE_INT) + complete(&p->parent->spi_int[SPI1]->spi_xfer_done); + spi_int_fired = IRQ_HANDLED; + } + if (regval & SPI_DMA_ABORT_INT_MASK) { + p->dma_aborted_wr = true; + spi_int_fired = IRQ_HANDLED; + } + writel(regval, p->parent->dma_offset_bar + SPI_DMA_INTR_WR_CLR); spin_unlock_irqrestore(&p->parent->dma_reg_lock, flags); return spi_int_fired;