1
2
3
4
5
6#include <linux/clk.h>
7#include <linux/dma-mapping.h>
8#include <linux/fpga/fpga-mgr.h>
9#include <linux/io.h>
10#include <linux/kernel.h>
11#include <linux/module.h>
12#include <linux/of_address.h>
13#include <linux/string.h>
14#include <linux/seq_file.h>
15#include <linux/firmware/xlnx-zynqmp.h>
16
17
18#define IXR_FPGA_DONE_MASK 0X00000008U
19#define IXR_FPGA_ENCRYPTION_EN 0x00000008U
20
21#define READ_DMA_SIZE 0x200
22#define DUMMY_FRAMES_SIZE 0x64
23#define PCAP_READ_CLKFREQ 25000000
24
25
26#define IXR_FPGA_ERR_CRC_ERR BIT(0)
27#define IXR_FPGA_ERR_SECURITY_ERR BIT(16)
28
29
30#define IXR_FPGA_END_OF_STARTUP BIT(4)
31#define IXR_FPGA_GST_CFG_B BIT(5)
32#define IXR_FPGA_INIT_B_INTERNAL BIT(11)
33#define IXR_FPGA_DONE_INTERNAL_SIGNAL BIT(13)
34
35#define IXR_FPGA_CONFIG_STAT_OFFSET 7U
36#define IXR_FPGA_READ_CONFIG_TYPE 0U
37
38static bool readback_type;
39module_param(readback_type, bool, 0644);
40MODULE_PARM_DESC(readback_type,
41 "readback_type 0-configuration register read "
42 "1- configuration data read (default: 0)");
43
44static const struct zynqmp_eemi_ops *eemi_ops;
45
46
47
48
49
50
51struct zynqmp_configreg {
52 char *reg;
53 u32 offset;
54};
55
56static struct zynqmp_configreg cfgreg[] = {
57 {.reg = "CRC", .offset = 0},
58 {.reg = "FAR", .offset = 1},
59 {.reg = "FDRI", .offset = 2},
60 {.reg = "FDRO", .offset = 3},
61 {.reg = "CMD", .offset = 4},
62 {.reg = "CTRL0", .offset = 5},
63 {.reg = "MASK", .offset = 6},
64 {.reg = "STAT", .offset = 7},
65 {.reg = "LOUT", .offset = 8},
66 {.reg = "COR0", .offset = 9},
67 {.reg = "MFWR", .offset = 10},
68 {.reg = "CBC", .offset = 11},
69 {.reg = "IDCODE", .offset = 12},
70 {.reg = "AXSS", .offset = 13},
71 {.reg = "COR1", .offset = 14},
72 {.reg = "WBSTR", .offset = 16},
73 {.reg = "TIMER", .offset = 17},
74 {.reg = "BOOTSTS", .offset = 22},
75 {.reg = "CTRL1", .offset = 24},
76 {}
77};
78
79
80
81
82
83
84
85
86
87struct zynqmp_fpga_priv {
88 struct device *dev;
89 struct mutex lock;
90 struct clk *clk;
91 char *key;
92 u32 flags;
93 u32 size;
94};
95
96static int zynqmp_fpga_ops_write_init(struct fpga_manager *mgr,
97 struct fpga_image_info *info,
98 const char *buf, size_t size)
99{
100 struct zynqmp_fpga_priv *priv;
101
102 priv = mgr->priv;
103 priv->flags = info->flags;
104 priv->key = info->key;
105
106 return 0;
107}
108
109static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
110 const char *buf, size_t size)
111{
112 struct zynqmp_fpga_priv *priv;
113 char *kbuf;
114 size_t dma_size;
115 dma_addr_t dma_addr;
116 int ret;
117
118 if (!eemi_ops->fpga_load)
119 return -ENXIO;
120
121 priv = mgr->priv;
122 priv->size = size;
123
124 if (!mutex_trylock(&priv->lock))
125 return -EBUSY;
126
127 ret = clk_enable(priv->clk);
128 if (ret)
129 goto err_unlock;
130
131 if (priv->flags & IXR_FPGA_ENCRYPTION_EN)
132 dma_size = size + ENCRYPTED_KEY_LEN;
133 else
134 dma_size = size;
135
136 kbuf = dma_alloc_coherent(priv->dev, dma_size, &dma_addr, GFP_KERNEL);
137 if (!kbuf) {
138 ret = -ENOMEM;
139 goto disable_clk;
140 }
141
142 memcpy(kbuf, buf, size);
143
144 if (priv->flags & IXR_FPGA_ENCRYPTION_EN)
145 memcpy(kbuf + size, priv->key, ENCRYPTED_KEY_LEN);
146
147 wmb();
148
149 if (priv->flags & IXR_FPGA_ENCRYPTION_EN)
150 ret = eemi_ops->fpga_load(dma_addr, dma_addr + size,
151 priv->flags);
152 else
153 ret = eemi_ops->fpga_load(dma_addr, size, priv->flags);
154
155 dma_free_coherent(priv->dev, dma_size, kbuf, dma_addr);
156disable_clk:
157 clk_disable(priv->clk);
158err_unlock:
159 mutex_unlock(&priv->lock);
160 return ret;
161}
162
163static int zynqmp_fpga_ops_write_complete(struct fpga_manager *mgr,
164 struct fpga_image_info *info)
165{
166 return 0;
167}
168
169static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr)
170{
171 u32 status;
172
173 if (!eemi_ops->fpga_get_status)
174 return FPGA_MGR_STATE_UNKNOWN;
175
176 eemi_ops->fpga_get_status(&status);
177 if (status & IXR_FPGA_DONE_MASK)
178 return FPGA_MGR_STATE_OPERATING;
179
180 return FPGA_MGR_STATE_UNKNOWN;
181}
182
183static u64 zynqmp_fpga_ops_status(struct fpga_manager *mgr)
184{
185 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
186 unsigned int *buf, reg_val;
187 dma_addr_t dma_addr;
188 u64 status = 0;
189 int ret;
190
191 if (IS_ERR_OR_NULL(eemi_ops) || !eemi_ops->fpga_read)
192 return FPGA_MGR_STATUS_FIRMWARE_REQ_ERR;
193
194 buf = dma_zalloc_coherent(mgr->dev.parent, READ_DMA_SIZE,
195 &dma_addr, GFP_KERNEL);
196 if (!buf)
197 return FPGA_MGR_STATUS_FIRMWARE_REQ_ERR;
198
199 ret = eemi_ops->fpga_read(IXR_FPGA_CONFIG_STAT_OFFSET, dma_addr,
200 IXR_FPGA_READ_CONFIG_TYPE, ®_val);
201 if (ret) {
202 status = FPGA_MGR_STATUS_FIRMWARE_REQ_ERR;
203 goto free_dmabuf;
204 }
205
206 if (reg_val & IXR_FPGA_ERR_CRC_ERR)
207 status |= FPGA_MGR_STATUS_CRC_ERR;
208 if (reg_val & IXR_FPGA_ERR_SECURITY_ERR)
209 status |= FPGA_MGR_STATUS_SECURITY_ERR;
210 if (!(reg_val & IXR_FPGA_INIT_B_INTERNAL))
211 status |= FPGA_MGR_STATUS_DEVICE_INIT_ERR;
212 if (!(reg_val & IXR_FPGA_DONE_INTERNAL_SIGNAL))
213 status |= FPGA_MGR_STATUS_SIGNAL_ERR;
214 if (!(reg_val & IXR_FPGA_GST_CFG_B))
215 status |= FPGA_MGR_STATUS_HIGH_Z_STATE_ERR;
216 if (!(reg_val & IXR_FPGA_END_OF_STARTUP))
217 status |= FPGA_MGR_STATUS_EOS_ERR;
218
219free_dmabuf:
220 dma_free_coherent(mgr->dev.parent, READ_DMA_SIZE, buf, dma_addr);
221
222 return status;
223}
224
225static int zynqmp_fpga_read_cfgreg(struct fpga_manager *mgr,
226 struct seq_file *s)
227{
228 struct zynqmp_fpga_priv *priv = mgr->priv;
229 int ret, val;
230 unsigned int *buf;
231 dma_addr_t dma_addr;
232 struct zynqmp_configreg *p = cfgreg;
233
234 ret = clk_enable(priv->clk);
235 if (ret)
236 return ret;
237
238 buf = dma_zalloc_coherent(mgr->dev.parent, READ_DMA_SIZE,
239 &dma_addr, GFP_KERNEL);
240 if (!buf) {
241 ret = -ENOMEM;
242 goto disable_clk;
243 }
244
245 seq_puts(s, "zynqMP FPGA Configuration register contents are\n");
246
247 while (p->reg) {
248 ret = eemi_ops->fpga_read(p->offset, dma_addr, readback_type,
249 &val);
250 if (ret)
251 goto free_dmabuf;
252 seq_printf(s, "%s --> \t %x \t\r\n", p->reg, val);
253 p++;
254 }
255
256free_dmabuf:
257 dma_free_coherent(mgr->dev.parent, READ_DMA_SIZE, buf,
258 dma_addr);
259disable_clk:
260 clk_disable(priv->clk);
261
262 return ret;
263}
264
265static int zynqmp_fpga_read_cfgdata(struct fpga_manager *mgr,
266 struct seq_file *s)
267{
268 struct zynqmp_fpga_priv *priv;
269 int ret, data_offset;
270 unsigned int *buf;
271 dma_addr_t dma_addr;
272 size_t size;
273 int clk_rate;
274
275 priv = mgr->priv;
276 size = priv->size + READ_DMA_SIZE + DUMMY_FRAMES_SIZE;
277
278
279
280
281
282
283 clk_rate = clk_get_rate(priv->clk);
284 clk_unprepare(priv->clk);
285 ret = clk_set_rate(priv->clk, PCAP_READ_CLKFREQ);
286 if (ret) {
287 dev_err(&mgr->dev, "Unable to reduce the PCAP freq %d\n", ret);
288 goto prepare_clk;
289 }
290 ret = clk_prepare_enable(priv->clk);
291 if (ret) {
292 dev_err(&mgr->dev, "Cannot enable clock.\n");
293 goto restore_pcap_clk;
294 }
295
296 buf = dma_zalloc_coherent(mgr->dev.parent, size, &dma_addr,
297 GFP_KERNEL);
298 if (!buf) {
299 ret = -ENOMEM;
300 goto disable_clk;
301 }
302
303 seq_puts(s, "zynqMP FPGA Configuration data contents are\n");
304 ret = eemi_ops->fpga_read((priv->size + DUMMY_FRAMES_SIZE) / 4,
305 dma_addr, readback_type, &data_offset);
306 if (ret)
307 goto free_dmabuf;
308
309 seq_write(s, &buf[data_offset], priv->size);
310
311free_dmabuf:
312 dma_free_coherent(mgr->dev.parent, size, buf, dma_addr);
313disable_clk:
314 clk_disable_unprepare(priv->clk);
315restore_pcap_clk:
316 clk_set_rate(priv->clk, clk_rate);
317prepare_clk:
318 clk_prepare(priv->clk);
319
320 return ret;
321}
322
323static int zynqmp_fpga_ops_read(struct fpga_manager *mgr, struct seq_file *s)
324{
325 struct zynqmp_fpga_priv *priv = mgr->priv;
326 int ret;
327
328 if (!eemi_ops->fpga_read)
329 return -ENXIO;
330
331 if (!mutex_trylock(&priv->lock))
332 return -EBUSY;
333
334 if (readback_type)
335 ret = zynqmp_fpga_read_cfgdata(mgr, s);
336 else
337 ret = zynqmp_fpga_read_cfgreg(mgr, s);
338
339 mutex_unlock(&priv->lock);
340 return ret;
341}
342
343static const struct fpga_manager_ops zynqmp_fpga_ops = {
344 .state = zynqmp_fpga_ops_state,
345 .status = zynqmp_fpga_ops_status,
346 .write_init = zynqmp_fpga_ops_write_init,
347 .write = zynqmp_fpga_ops_write,
348 .write_complete = zynqmp_fpga_ops_write_complete,
349 .read = zynqmp_fpga_ops_read,
350};
351
352static int zynqmp_fpga_probe(struct platform_device *pdev)
353{
354 struct device *dev = &pdev->dev;
355 struct zynqmp_fpga_priv *priv;
356 int err, ret;
357 struct fpga_manager *mgr;
358
359 eemi_ops = zynqmp_pm_get_eemi_ops();
360 if (IS_ERR(eemi_ops))
361 return PTR_ERR(eemi_ops);
362
363 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
364 if (!priv)
365 return -ENOMEM;
366
367 priv->dev = dev;
368 mutex_init(&priv->lock);
369 ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44));
370 if (ret < 0)
371 dev_err(dev, "no usable DMA configuration");
372
373 mgr = fpga_mgr_create(dev, "Xilinx ZynqMP FPGA Manager",
374 &zynqmp_fpga_ops, priv);
375 if (!mgr)
376 return -ENOMEM;
377
378 platform_set_drvdata(pdev, mgr);
379
380 priv->clk = devm_clk_get(dev, "ref_clk");
381 if (IS_ERR(priv->clk)) {
382 ret = PTR_ERR(priv->clk);
383 dev_err(dev, "failed to to get pcp ref_clk (%d)\n", ret);
384 return ret;
385 }
386
387 ret = clk_prepare(priv->clk);
388 if (ret) {
389 dev_err(dev, "Cannot enable clock.\n");
390 return ret;
391 }
392
393 err = fpga_mgr_register(mgr);
394 if (err) {
395 dev_err(dev, "unable to register FPGA manager");
396 fpga_mgr_free(mgr);
397 clk_unprepare(priv->clk);
398 return err;
399 }
400
401 return 0;
402}
403
404static int zynqmp_fpga_remove(struct platform_device *pdev)
405{
406 struct zynqmp_fpga_priv *priv;
407 struct fpga_manager *mgr;
408
409 mgr = platform_get_drvdata(pdev);
410 priv = mgr->priv;
411
412 fpga_mgr_unregister(mgr);
413 clk_unprepare(priv->clk);
414
415 return 0;
416}
417
418static const struct of_device_id zynqmp_fpga_of_match[] = {
419 { .compatible = "xlnx,zynqmp-pcap-fpga", },
420 {},
421};
422
423MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match);
424
425static struct platform_driver zynqmp_fpga_driver = {
426 .probe = zynqmp_fpga_probe,
427 .remove = zynqmp_fpga_remove,
428 .driver = {
429 .name = "zynqmp_fpga_manager",
430 .of_match_table = of_match_ptr(zynqmp_fpga_of_match),
431 },
432};
433
434module_platform_driver(zynqmp_fpga_driver);
435
436MODULE_AUTHOR("Nava kishore Manne <navam@xilinx.com>");
437MODULE_DESCRIPTION("Xilinx ZynqMp FPGA Manager");
438MODULE_LICENSE("GPL");
439