Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

spi: mchp-pci1xxxx: Add support for DMA in SPI

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 <thangaraj.s@microchip.com>
Link: https://lore.kernel.org/r/20240207080621.30742-2-thangaraj.s@microchip.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Thangaraj Samynathan and committed by
Mark Brown
3e7cfd6a abb4b46c

+145
+145
drivers/spi/spi-pci1xxxx.c
··· 5 5 // Kumaravel Thiagarajan <Kumaravel.Thiagarajan@microchip.com> 6 6 7 7 8 + #include <linux/dma-mapping.h> 9 + #include <linux/iopoll.h> 10 + #include <linux/irq.h> 8 11 #include <linux/module.h> 12 + #include <linux/msi.h> 13 + #include <linux/pci_regs.h> 9 14 #include <linux/pci.h> 10 15 #include <linux/spi/spi.h> 11 16 #include <linux/delay.h> ··· 37 32 #define SPI_MST_CTL_MODE_SEL (BIT(2)) 38 33 #define SPI_MST_CTL_GO (BIT(0)) 39 34 35 + #define SPI_SYSTEM_ADDR_BASE (0x2000) 40 36 #define SPI_MST1_ADDR_BASE (0x800) 37 + 38 + #define DEV_REV_REG (SPI_SYSTEM_ADDR_BASE + 0x00) 39 + #define SPI_SYSLOCK_REG (SPI_SYSTEM_ADDR_BASE + 0xA0) 40 + #define SPI_CONFIG_PERI_ENABLE_REG (SPI_SYSTEM_ADDR_BASE + 0x108) 41 + 42 + #define SPI_PERI_ENBLE_PF_MASK (GENMASK(17, 16)) 43 + #define DEV_REV_MASK (GENMASK(7, 0)) 44 + 45 + #define SPI_SYSLOCK BIT(4) 46 + 47 + /* DMA Related Registers */ 48 + #define SPI_DMA_ADDR_BASE (0x1000) 49 + #define SPI_DMA_GLOBAL_WR_ENGINE_EN (SPI_DMA_ADDR_BASE + 0x0C) 50 + #define SPI_DMA_GLOBAL_RD_ENGINE_EN (SPI_DMA_ADDR_BASE + 0x2C) 51 + #define SPI_DMA_INTR_IMWR_WDONE_LOW (SPI_DMA_ADDR_BASE + 0x60) 52 + #define SPI_DMA_INTR_IMWR_WDONE_HIGH (SPI_DMA_ADDR_BASE + 0x64) 53 + #define SPI_DMA_INTR_IMWR_WABORT_LOW (SPI_DMA_ADDR_BASE + 0x68) 54 + #define SPI_DMA_INTR_IMWR_WABORT_HIGH (SPI_DMA_ADDR_BASE + 0x6C) 55 + #define SPI_DMA_INTR_WR_IMWR_DATA (SPI_DMA_ADDR_BASE + 0x70) 56 + #define SPI_DMA_INTR_IMWR_RDONE_LOW (SPI_DMA_ADDR_BASE + 0xCC) 57 + #define SPI_DMA_INTR_IMWR_RDONE_HIGH (SPI_DMA_ADDR_BASE + 0xD0) 58 + #define SPI_DMA_INTR_IMWR_RABORT_LOW (SPI_DMA_ADDR_BASE + 0xD4) 59 + #define SPI_DMA_INTR_IMWR_RABORT_HIGH (SPI_DMA_ADDR_BASE + 0xD8) 60 + #define SPI_DMA_INTR_RD_IMWR_DATA (SPI_DMA_ADDR_BASE + 0xDC) 41 61 42 62 /* x refers to SPI Host Controller HW instance id in the below macros - 0 or 1 */ 43 63 ··· 80 50 #define SPI_MAX_DATA_LEN 320 81 51 82 52 #define PCI1XXXX_SPI_TIMEOUT (msecs_to_jiffies(100)) 53 + #define SYSLOCK_RETRY_CNT (1000) 54 + #define SPI_DMA_ENGINE_EN (0x1) 83 55 84 56 #define SPI_INTR BIT(8) 85 57 #define SPI_FORCE_CE BIT(4) ··· 108 76 struct pci1xxxx_spi { 109 77 struct pci_dev *dev; 110 78 u8 total_hw_instances; 79 + u8 dev_rev; 111 80 void __iomem *reg_base; 81 + void __iomem *dma_offset_bar; 82 + bool can_dma; 112 83 struct pci1xxxx_spi_internal *spi_int[] __counted_by(total_hw_instances); 113 84 }; 114 85 ··· 140 105 }; 141 106 142 107 MODULE_DEVICE_TABLE(pci, pci1xxxx_spi_pci_id_table); 108 + 109 + static int pci1xxxx_set_sys_lock(struct pci1xxxx_spi *par) 110 + { 111 + writel(SPI_SYSLOCK, par->reg_base + SPI_SYSLOCK_REG); 112 + return readl(par->reg_base + SPI_SYSLOCK_REG); 113 + } 114 + 115 + static int pci1xxxx_acquire_sys_lock(struct pci1xxxx_spi *par) 116 + { 117 + u32 regval; 118 + 119 + return readx_poll_timeout(pci1xxxx_set_sys_lock, par, regval, 120 + (regval & SPI_SYSLOCK), 100, 121 + SYSLOCK_RETRY_CNT * 100); 122 + } 123 + 124 + static void pci1xxxx_release_sys_lock(struct pci1xxxx_spi *par) 125 + { 126 + writel(0x0, par->reg_base + SPI_SYSLOCK_REG); 127 + } 128 + 129 + static int pci1xxxx_check_spi_can_dma(struct pci1xxxx_spi *spi_bus, int irq) 130 + { 131 + struct pci_dev *pdev = spi_bus->dev; 132 + u32 pf_num; 133 + u32 regval; 134 + int ret; 135 + 136 + /* 137 + * DEV REV Registers is a system register, HW Syslock bit 138 + * should be acquired before accessing the register 139 + */ 140 + ret = pci1xxxx_acquire_sys_lock(spi_bus); 141 + if (ret) { 142 + dev_err(&pdev->dev, "Error failed to acquire syslock\n"); 143 + return ret; 144 + } 145 + 146 + regval = readl(spi_bus->reg_base + DEV_REV_REG); 147 + spi_bus->dev_rev = regval & DEV_REV_MASK; 148 + if (spi_bus->dev_rev >= 0xC0) { 149 + regval = readl(spi_bus->reg_base + 150 + SPI_CONFIG_PERI_ENABLE_REG); 151 + pf_num = regval & SPI_PERI_ENBLE_PF_MASK; 152 + } 153 + 154 + pci1xxxx_release_sys_lock(spi_bus); 155 + 156 + /* 157 + * DMA is supported only from C0 and SPI can use DMA only if 158 + * it is mapped to PF0 159 + */ 160 + if (spi_bus->dev_rev < 0xC0 || pf_num) 161 + return -EOPNOTSUPP; 162 + 163 + /* 164 + * DMA Supported only with MSI Interrupts 165 + * One of the SPI instance's MSI vector address and data 166 + * is used for DMA Interrupt 167 + */ 168 + if (!irq_get_msi_desc(irq)) { 169 + dev_warn(&pdev->dev, "Error MSI Interrupt not supported, will operate in PIO mode\n"); 170 + return -EOPNOTSUPP; 171 + } 172 + 173 + spi_bus->dma_offset_bar = pcim_iomap(pdev, 2, pci_resource_len(pdev, 2)); 174 + if (!spi_bus->dma_offset_bar) { 175 + dev_warn(&pdev->dev, "Error failed to map dma bar, will operate in PIO mode\n"); 176 + return -EOPNOTSUPP; 177 + } 178 + 179 + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) { 180 + dev_warn(&pdev->dev, "Error failed to set DMA mask, will operate in PIO mode\n"); 181 + pcim_iounmap(pdev, spi_bus->dma_offset_bar); 182 + spi_bus->dma_offset_bar = NULL; 183 + return -EOPNOTSUPP; 184 + } 185 + 186 + return 0; 187 + } 188 + 189 + static int pci1xxxx_spi_dma_init(struct pci1xxxx_spi *spi_bus, int irq) 190 + { 191 + struct msi_msg msi; 192 + int ret; 193 + 194 + ret = pci1xxxx_check_spi_can_dma(spi_bus, irq); 195 + if (ret) 196 + return ret; 197 + 198 + get_cached_msi_msg(irq, &msi); 199 + writel(SPI_DMA_ENGINE_EN, spi_bus->dma_offset_bar + SPI_DMA_GLOBAL_WR_ENGINE_EN); 200 + writel(SPI_DMA_ENGINE_EN, spi_bus->dma_offset_bar + SPI_DMA_GLOBAL_RD_ENGINE_EN); 201 + writel(msi.address_hi, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_WDONE_HIGH); 202 + writel(msi.address_hi, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_WABORT_HIGH); 203 + writel(msi.address_hi, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_RDONE_HIGH); 204 + writel(msi.address_hi, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_RABORT_HIGH); 205 + writel(msi.address_lo, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_WDONE_LOW); 206 + writel(msi.address_lo, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_WABORT_LOW); 207 + writel(msi.address_lo, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_RDONE_LOW); 208 + writel(msi.address_lo, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_RABORT_LOW); 209 + writel(msi.data, spi_bus->dma_offset_bar + SPI_DMA_INTR_WR_IMWR_DATA); 210 + writel(msi.data, spi_bus->dma_offset_bar + SPI_DMA_INTR_RD_IMWR_DATA); 211 + spi_bus->can_dma = true; 212 + return 0; 213 + } 143 214 144 215 static void pci1xxxx_spi_set_cs(struct spi_device *spi, bool enable) 145 216 { ··· 464 323 ret = -ENODEV; 465 324 goto error; 466 325 } 326 + 327 + ret = pci1xxxx_spi_dma_init(spi_bus, spi_sub_ptr->irq); 328 + if (ret && ret != -EOPNOTSUPP) 329 + return ret; 467 330 468 331 /* This register is only applicable for 1st instance */ 469 332 regval = readl(spi_bus->reg_base + SPI_PCI_CTRL_REG_OFFSET(0));