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

fpga manager: Adding FPGA Manager support for Xilinx zynqmp

This patch adds FPGA Manager support for the Xilinx
ZynqMP chip.

Signed-off-by: Nava kishore Manne <nava.manne@xilinx.com>
Reviewed-by: Moritz Fischer <mdf@kernel.org>
Acked-by: Alan Tull <atull@kernel.org>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>

authored by

Nava kishore Manne and committed by
Michal Simek
c09f7471 9b087962

+169
+9
drivers/fpga/Kconfig
··· 204 204 205 205 To compile this as a module, choose M here. 206 206 207 + config FPGA_MGR_ZYNQMP_FPGA 208 + tristate "Xilinx ZynqMP FPGA" 209 + depends on ARCH_ZYNQMP || COMPILE_TEST 210 + help 211 + FPGA manager driver support for Xilinx ZynqMP FPGAs. 212 + This driver uses the processor configuration port(PCAP) 213 + to configure the programmable logic(PL) through PS 214 + on ZynqMP SoC. 215 + 207 216 endif # FPGA
+1
drivers/fpga/Makefile
··· 17 17 obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o 18 18 obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o 19 19 obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o 20 + obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA) += zynqmp-fpga.o 20 21 obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o 21 22 obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o 22 23
+159
drivers/fpga/zynqmp-fpga.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Copyright (C) 2019 Xilinx, Inc. 4 + */ 5 + 6 + #include <linux/dma-mapping.h> 7 + #include <linux/fpga/fpga-mgr.h> 8 + #include <linux/io.h> 9 + #include <linux/kernel.h> 10 + #include <linux/module.h> 11 + #include <linux/of_address.h> 12 + #include <linux/string.h> 13 + #include <linux/firmware/xlnx-zynqmp.h> 14 + 15 + /* Constant Definitions */ 16 + #define IXR_FPGA_DONE_MASK BIT(3) 17 + 18 + /** 19 + * struct zynqmp_fpga_priv - Private data structure 20 + * @dev: Device data structure 21 + * @flags: flags which is used to identify the bitfile type 22 + */ 23 + struct zynqmp_fpga_priv { 24 + struct device *dev; 25 + u32 flags; 26 + }; 27 + 28 + static int zynqmp_fpga_ops_write_init(struct fpga_manager *mgr, 29 + struct fpga_image_info *info, 30 + const char *buf, size_t size) 31 + { 32 + struct zynqmp_fpga_priv *priv; 33 + 34 + priv = mgr->priv; 35 + priv->flags = info->flags; 36 + 37 + return 0; 38 + } 39 + 40 + static int zynqmp_fpga_ops_write(struct fpga_manager *mgr, 41 + const char *buf, size_t size) 42 + { 43 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 44 + struct zynqmp_fpga_priv *priv; 45 + dma_addr_t dma_addr; 46 + u32 eemi_flags = 0; 47 + char *kbuf; 48 + int ret; 49 + 50 + if (!eemi_ops || !eemi_ops->fpga_load) 51 + return -ENXIO; 52 + 53 + priv = mgr->priv; 54 + 55 + kbuf = dma_alloc_coherent(priv->dev, size, &dma_addr, GFP_KERNEL); 56 + if (!kbuf) 57 + return -ENOMEM; 58 + 59 + memcpy(kbuf, buf, size); 60 + 61 + wmb(); /* ensure all writes are done before initiate FW call */ 62 + 63 + if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG) 64 + eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL; 65 + 66 + ret = eemi_ops->fpga_load(dma_addr, size, eemi_flags); 67 + 68 + dma_free_coherent(priv->dev, size, kbuf, dma_addr); 69 + 70 + return ret; 71 + } 72 + 73 + static int zynqmp_fpga_ops_write_complete(struct fpga_manager *mgr, 74 + struct fpga_image_info *info) 75 + { 76 + return 0; 77 + } 78 + 79 + static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr) 80 + { 81 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 82 + u32 status; 83 + 84 + if (!eemi_ops || !eemi_ops->fpga_get_status) 85 + return FPGA_MGR_STATE_UNKNOWN; 86 + 87 + eemi_ops->fpga_get_status(&status); 88 + if (status & IXR_FPGA_DONE_MASK) 89 + return FPGA_MGR_STATE_OPERATING; 90 + 91 + return FPGA_MGR_STATE_UNKNOWN; 92 + } 93 + 94 + static const struct fpga_manager_ops zynqmp_fpga_ops = { 95 + .state = zynqmp_fpga_ops_state, 96 + .write_init = zynqmp_fpga_ops_write_init, 97 + .write = zynqmp_fpga_ops_write, 98 + .write_complete = zynqmp_fpga_ops_write_complete, 99 + }; 100 + 101 + static int zynqmp_fpga_probe(struct platform_device *pdev) 102 + { 103 + struct device *dev = &pdev->dev; 104 + struct zynqmp_fpga_priv *priv; 105 + struct fpga_manager *mgr; 106 + int ret; 107 + 108 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 109 + if (!priv) 110 + return -ENOMEM; 111 + 112 + priv->dev = dev; 113 + 114 + mgr = devm_fpga_mgr_create(dev, "Xilinx ZynqMP FPGA Manager", 115 + &zynqmp_fpga_ops, priv); 116 + if (!mgr) 117 + return -ENOMEM; 118 + 119 + platform_set_drvdata(pdev, mgr); 120 + 121 + ret = fpga_mgr_register(mgr); 122 + if (ret) { 123 + dev_err(dev, "unable to register FPGA manager"); 124 + return ret; 125 + } 126 + 127 + return 0; 128 + } 129 + 130 + static int zynqmp_fpga_remove(struct platform_device *pdev) 131 + { 132 + struct fpga_manager *mgr = platform_get_drvdata(pdev); 133 + 134 + fpga_mgr_unregister(mgr); 135 + 136 + return 0; 137 + } 138 + 139 + static const struct of_device_id zynqmp_fpga_of_match[] = { 140 + { .compatible = "xlnx,zynqmp-pcap-fpga", }, 141 + {}, 142 + }; 143 + 144 + MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match); 145 + 146 + static struct platform_driver zynqmp_fpga_driver = { 147 + .probe = zynqmp_fpga_probe, 148 + .remove = zynqmp_fpga_remove, 149 + .driver = { 150 + .name = "zynqmp_fpga_manager", 151 + .of_match_table = of_match_ptr(zynqmp_fpga_of_match), 152 + }, 153 + }; 154 + 155 + module_platform_driver(zynqmp_fpga_driver); 156 + 157 + MODULE_AUTHOR("Nava kishore Manne <navam@xilinx.com>"); 158 + MODULE_DESCRIPTION("Xilinx ZynqMp FPGA Manager"); 159 + MODULE_LICENSE("GPL");