1c09f7471SNava kishore Manne // SPDX-License-Identifier: GPL-2.0+
2c09f7471SNava kishore Manne /*
3c09f7471SNava kishore Manne * Copyright (C) 2019 Xilinx, Inc.
4c09f7471SNava kishore Manne */
5c09f7471SNava kishore Manne
6c09f7471SNava kishore Manne #include <linux/dma-mapping.h>
7c09f7471SNava kishore Manne #include <linux/fpga/fpga-mgr.h>
8c09f7471SNava kishore Manne #include <linux/io.h>
9c09f7471SNava kishore Manne #include <linux/kernel.h>
10c09f7471SNava kishore Manne #include <linux/module.h>
11c09f7471SNava kishore Manne #include <linux/of_address.h>
12c09f7471SNava kishore Manne #include <linux/string.h>
13c09f7471SNava kishore Manne #include <linux/firmware/xlnx-zynqmp.h>
14c09f7471SNava kishore Manne
15c09f7471SNava kishore Manne /* Constant Definitions */
16c09f7471SNava kishore Manne #define IXR_FPGA_DONE_MASK BIT(3)
17c09f7471SNava kishore Manne
18c09f7471SNava kishore Manne /**
19c09f7471SNava kishore Manne * struct zynqmp_fpga_priv - Private data structure
20c09f7471SNava kishore Manne * @dev: Device data structure
21c09f7471SNava kishore Manne * @flags: flags which is used to identify the bitfile type
22c09f7471SNava kishore Manne */
23c09f7471SNava kishore Manne struct zynqmp_fpga_priv {
24c09f7471SNava kishore Manne struct device *dev;
25c09f7471SNava kishore Manne u32 flags;
26c09f7471SNava kishore Manne };
27c09f7471SNava kishore Manne
zynqmp_fpga_ops_write_init(struct fpga_manager * mgr,struct fpga_image_info * info,const char * buf,size_t size)28c09f7471SNava kishore Manne static int zynqmp_fpga_ops_write_init(struct fpga_manager *mgr,
29c09f7471SNava kishore Manne struct fpga_image_info *info,
30c09f7471SNava kishore Manne const char *buf, size_t size)
31c09f7471SNava kishore Manne {
32c09f7471SNava kishore Manne struct zynqmp_fpga_priv *priv;
33c09f7471SNava kishore Manne
34c09f7471SNava kishore Manne priv = mgr->priv;
35c09f7471SNava kishore Manne priv->flags = info->flags;
36c09f7471SNava kishore Manne
37c09f7471SNava kishore Manne return 0;
38c09f7471SNava kishore Manne }
39c09f7471SNava kishore Manne
zynqmp_fpga_ops_write(struct fpga_manager * mgr,const char * buf,size_t size)40c09f7471SNava kishore Manne static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
41c09f7471SNava kishore Manne const char *buf, size_t size)
42c09f7471SNava kishore Manne {
43c09f7471SNava kishore Manne struct zynqmp_fpga_priv *priv;
44c09f7471SNava kishore Manne dma_addr_t dma_addr;
45c09f7471SNava kishore Manne u32 eemi_flags = 0;
46c09f7471SNava kishore Manne char *kbuf;
47c09f7471SNava kishore Manne int ret;
48c09f7471SNava kishore Manne
49c09f7471SNava kishore Manne priv = mgr->priv;
50c09f7471SNava kishore Manne
51c09f7471SNava kishore Manne kbuf = dma_alloc_coherent(priv->dev, size, &dma_addr, GFP_KERNEL);
52c09f7471SNava kishore Manne if (!kbuf)
53c09f7471SNava kishore Manne return -ENOMEM;
54c09f7471SNava kishore Manne
55c09f7471SNava kishore Manne memcpy(kbuf, buf, size);
56c09f7471SNava kishore Manne
57c09f7471SNava kishore Manne wmb(); /* ensure all writes are done before initiate FW call */
58c09f7471SNava kishore Manne
59c09f7471SNava kishore Manne if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG)
60c09f7471SNava kishore Manne eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL;
61c09f7471SNava kishore Manne
624db8180fSRajan Vaja ret = zynqmp_pm_fpga_load(dma_addr, size, eemi_flags);
63c09f7471SNava kishore Manne
64c09f7471SNava kishore Manne dma_free_coherent(priv->dev, size, kbuf, dma_addr);
65c09f7471SNava kishore Manne
66c09f7471SNava kishore Manne return ret;
67c09f7471SNava kishore Manne }
68c09f7471SNava kishore Manne
zynqmp_fpga_ops_state(struct fpga_manager * mgr)69c09f7471SNava kishore Manne static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr)
70c09f7471SNava kishore Manne {
714db8180fSRajan Vaja u32 status = 0;
72c09f7471SNava kishore Manne
734db8180fSRajan Vaja zynqmp_pm_fpga_get_status(&status);
74c09f7471SNava kishore Manne if (status & IXR_FPGA_DONE_MASK)
75c09f7471SNava kishore Manne return FPGA_MGR_STATE_OPERATING;
76c09f7471SNava kishore Manne
77c09f7471SNava kishore Manne return FPGA_MGR_STATE_UNKNOWN;
78c09f7471SNava kishore Manne }
79c09f7471SNava kishore Manne
status_show(struct device * dev,struct device_attribute * attr,char * buf)80*995a3bb7SNava kishore Manne static ssize_t status_show(struct device *dev,
81*995a3bb7SNava kishore Manne struct device_attribute *attr, char *buf)
82*995a3bb7SNava kishore Manne {
83*995a3bb7SNava kishore Manne u32 status;
84*995a3bb7SNava kishore Manne int ret;
85*995a3bb7SNava kishore Manne
86*995a3bb7SNava kishore Manne ret = zynqmp_pm_fpga_get_config_status(&status);
87*995a3bb7SNava kishore Manne if (ret)
88*995a3bb7SNava kishore Manne return ret;
89*995a3bb7SNava kishore Manne
90*995a3bb7SNava kishore Manne return sysfs_emit(buf, "0x%x\n", status);
91*995a3bb7SNava kishore Manne }
92*995a3bb7SNava kishore Manne static DEVICE_ATTR_RO(status);
93*995a3bb7SNava kishore Manne
94*995a3bb7SNava kishore Manne static struct attribute *zynqmp_fpga_attrs[] = {
95*995a3bb7SNava kishore Manne &dev_attr_status.attr,
96*995a3bb7SNava kishore Manne NULL,
97*995a3bb7SNava kishore Manne };
98*995a3bb7SNava kishore Manne ATTRIBUTE_GROUPS(zynqmp_fpga);
99*995a3bb7SNava kishore Manne
100c09f7471SNava kishore Manne static const struct fpga_manager_ops zynqmp_fpga_ops = {
101c09f7471SNava kishore Manne .state = zynqmp_fpga_ops_state,
102c09f7471SNava kishore Manne .write_init = zynqmp_fpga_ops_write_init,
103c09f7471SNava kishore Manne .write = zynqmp_fpga_ops_write,
104c09f7471SNava kishore Manne };
105c09f7471SNava kishore Manne
zynqmp_fpga_probe(struct platform_device * pdev)106c09f7471SNava kishore Manne static int zynqmp_fpga_probe(struct platform_device *pdev)
107c09f7471SNava kishore Manne {
108c09f7471SNava kishore Manne struct device *dev = &pdev->dev;
109c09f7471SNava kishore Manne struct zynqmp_fpga_priv *priv;
110c09f7471SNava kishore Manne struct fpga_manager *mgr;
111c09f7471SNava kishore Manne
112c09f7471SNava kishore Manne priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
113c09f7471SNava kishore Manne if (!priv)
114c09f7471SNava kishore Manne return -ENOMEM;
115c09f7471SNava kishore Manne
116c09f7471SNava kishore Manne priv->dev = dev;
117c09f7471SNava kishore Manne
1184ba0b2c2SRuss Weight mgr = devm_fpga_mgr_register(dev, "Xilinx ZynqMP FPGA Manager",
119c09f7471SNava kishore Manne &zynqmp_fpga_ops, priv);
1204ba0b2c2SRuss Weight return PTR_ERR_OR_ZERO(mgr);
121c09f7471SNava kishore Manne }
122c09f7471SNava kishore Manne
1236f125e87SMoritz Fischer #ifdef CONFIG_OF
124c09f7471SNava kishore Manne static const struct of_device_id zynqmp_fpga_of_match[] = {
125c09f7471SNava kishore Manne { .compatible = "xlnx,zynqmp-pcap-fpga", },
126c09f7471SNava kishore Manne {},
127c09f7471SNava kishore Manne };
128c09f7471SNava kishore Manne MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match);
1296f125e87SMoritz Fischer #endif
130c09f7471SNava kishore Manne
131c09f7471SNava kishore Manne static struct platform_driver zynqmp_fpga_driver = {
132c09f7471SNava kishore Manne .probe = zynqmp_fpga_probe,
133c09f7471SNava kishore Manne .driver = {
134c09f7471SNava kishore Manne .name = "zynqmp_fpga_manager",
135c09f7471SNava kishore Manne .of_match_table = of_match_ptr(zynqmp_fpga_of_match),
136*995a3bb7SNava kishore Manne .dev_groups = zynqmp_fpga_groups,
137c09f7471SNava kishore Manne },
138c09f7471SNava kishore Manne };
139c09f7471SNava kishore Manne
140c09f7471SNava kishore Manne module_platform_driver(zynqmp_fpga_driver);
141c09f7471SNava kishore Manne
142c09f7471SNava kishore Manne MODULE_AUTHOR("Nava kishore Manne <navam@xilinx.com>");
143c09f7471SNava kishore Manne MODULE_DESCRIPTION("Xilinx ZynqMp FPGA Manager");
144c09f7471SNava kishore Manne MODULE_LICENSE("GPL");
145