xref: /linux/drivers/fpga/zynqmp-fpga.c (revision 5e21a3ecad1500e35b46701e7f3f232e15d78e69)
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  	struct zynqmp_fpga_priv *priv;
44  	dma_addr_t dma_addr;
45  	u32 eemi_flags = 0;
46  	char *kbuf;
47  	int ret;
48  
49  	priv = mgr->priv;
50  
51  	kbuf = dma_alloc_coherent(priv->dev, size, &dma_addr, GFP_KERNEL);
52  	if (!kbuf)
53  		return -ENOMEM;
54  
55  	memcpy(kbuf, buf, size);
56  
57  	wmb(); /* ensure all writes are done before initiate FW call */
58  
59  	if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG)
60  		eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL;
61  
62  	ret = zynqmp_pm_fpga_load(dma_addr, size, eemi_flags);
63  
64  	dma_free_coherent(priv->dev, size, kbuf, dma_addr);
65  
66  	return ret;
67  }
68  
69  static int zynqmp_fpga_ops_write_complete(struct fpga_manager *mgr,
70  					  struct fpga_image_info *info)
71  {
72  	return 0;
73  }
74  
75  static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr)
76  {
77  	u32 status = 0;
78  
79  	zynqmp_pm_fpga_get_status(&status);
80  	if (status & IXR_FPGA_DONE_MASK)
81  		return FPGA_MGR_STATE_OPERATING;
82  
83  	return FPGA_MGR_STATE_UNKNOWN;
84  }
85  
86  static const struct fpga_manager_ops zynqmp_fpga_ops = {
87  	.state = zynqmp_fpga_ops_state,
88  	.write_init = zynqmp_fpga_ops_write_init,
89  	.write = zynqmp_fpga_ops_write,
90  	.write_complete = zynqmp_fpga_ops_write_complete,
91  };
92  
93  static int zynqmp_fpga_probe(struct platform_device *pdev)
94  {
95  	struct device *dev = &pdev->dev;
96  	struct zynqmp_fpga_priv *priv;
97  	struct fpga_manager *mgr;
98  
99  	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
100  	if (!priv)
101  		return -ENOMEM;
102  
103  	priv->dev = dev;
104  
105  	mgr = devm_fpga_mgr_create(dev, "Xilinx ZynqMP FPGA Manager",
106  				   &zynqmp_fpga_ops, priv);
107  	if (!mgr)
108  		return -ENOMEM;
109  
110  	return devm_fpga_mgr_register(dev, mgr);
111  }
112  
113  static const struct of_device_id zynqmp_fpga_of_match[] = {
114  	{ .compatible = "xlnx,zynqmp-pcap-fpga", },
115  	{},
116  };
117  
118  MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match);
119  
120  static struct platform_driver zynqmp_fpga_driver = {
121  	.probe = zynqmp_fpga_probe,
122  	.driver = {
123  		.name = "zynqmp_fpga_manager",
124  		.of_match_table = of_match_ptr(zynqmp_fpga_of_match),
125  	},
126  };
127  
128  module_platform_driver(zynqmp_fpga_driver);
129  
130  MODULE_AUTHOR("Nava kishore Manne <navam@xilinx.com>");
131  MODULE_DESCRIPTION("Xilinx ZynqMp FPGA Manager");
132  MODULE_LICENSE("GPL");
133