1 /*
2 * Copyright (c) 2014 Brian Swetland
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8
9 #include <platform/fpga.h>
10 #include <lk/trace.h>
11 #include <lk/reg.h>
12 #include <lk/err.h>
13 #include <platform.h>
14 #include <kernel/thread.h>
15
16 #define LOCAL_TRACE 0
17 #define FPGA_TIMEOUT 1000
18
19 #define DEVCFG_CTRL 0xF8007000
20 #define PCFG_PROG_B (1 << 30)
21 #define PCFG_POR_CNT_4K (1 << 29)
22 #define PCAP_PR (1 << 27) // 0 = ICAP CFG, 1 = PCAP CFG
23 #define PCAP_MODE (1 << 26) // 1 = Enable PCAP Interface
24 #define DEVCFG_LOCK 0xF8007004
25 #define DEVCFG_CFG 0xF8007008
26 #define DEVCFG_INT_STS 0xF800700C
27 #define DMA_DONE_INT (1 << 13)
28 #define PSS_CFG_RESET_B (1 << 5) // 1 = PL in reset state
29 #define PCFG_DONE_INT (1 << 2) // 1 = PL successfully programmed
30 #define PCFG_INIT_PE_INT (1 << 1)
31 #define PCFG_INIT_NE_INT (1 << 0)
32 #define DEVCFG_INT_MASK 0xF8007010
33 #define DEVCFG_STATUS 0xF8007014
34 #define PCFG_INIT (1 << 4) // 1 = ready for bitstream
35 #define DEVCFG_DMA_SRC_ADDR 0xF8007018
36 #define DEVCFG_DMA_DST_ADDR 0xF800701C
37 #define DEVCFG_DMA_SRC_LEN 0xF8007020 // words
38 #define DEVCFG_DMA_DST_LEN 0xF8007024 // words
39 #define DEVCFG_SW_ID 0xF8007030
40 #define DEVCFG_MCTRL 0xF8007080
41 #define PCFG_POR_B (1 << 8) // 1 = PL is powered on
42 #define INT_PCAP_LPBK (1 << 4) // 1 = Loopback Enabled
43
44 // Per Zynq TRM, 6.4.4
45 // 1. wait for PCFG_INIT==1
46 // 2. disable loopback
47 // 3. set DEVCFG CTRL PCAP_PR and PCAP_MODE
48 // 4. set dma src, dst, srclen, dstlen (in that specific order)
49 // 5. wait for PCFG_DONE_INT==1
50
zynq_program_fpga(paddr_t physaddr,size_t length)51 status_t zynq_program_fpga(paddr_t physaddr, size_t length) {
52 LTRACEF("phys 0x%lx, len 0x%zx\n", physaddr, length);
53
54 lk_bigtime_t bt = current_time_hires();
55
56 /* length is in words */
57 length /= 4;
58
59 lk_time_t t;
60
61 t = current_time();
62 while (!(readl(DEVCFG_STATUS) & PCFG_INIT)) {
63 if (current_time() - t > FPGA_TIMEOUT) {
64 TRACEF("timeout waiting for PCFG_INIT\n");
65 return ERR_TIMED_OUT;
66 }
67 }
68 writel(readl(DEVCFG_MCTRL) & (~INT_PCAP_LPBK), DEVCFG_MCTRL);
69 writel(readl(DEVCFG_CTRL) | PCAP_PR | PCAP_MODE, DEVCFG_CTRL);
70 writel(0xffffffff, DEVCFG_INT_STS);
71 writel(physaddr, DEVCFG_DMA_SRC_ADDR);
72 writel(0xFFFFFFFF, DEVCFG_DMA_DST_ADDR);
73 writel(length, DEVCFG_DMA_SRC_LEN);
74 writel(length, DEVCFG_DMA_DST_LEN);
75
76 t = current_time();
77 uint32_t sts = 0;
78 for (;;) {
79 sts = readl(DEVCFG_INT_STS);
80 #if LOCAL_TRACE
81 static uint32_t last = 0;
82 if (last != sts) {
83 printf("dsts 0x%x\n", sts);
84 }
85 last = sts;
86 #endif
87 if (sts & PCFG_DONE_INT)
88 break;
89
90 if (current_time() - t > FPGA_TIMEOUT) {
91 TRACEF("timeout waiting for PCFG_DONE_INT, DEVCFG_INT_STS is 0x%x\n", sts);
92 return ERR_TIMED_OUT;
93 }
94 }
95
96 bt = current_time_hires() - bt;
97 LTRACEF("fpga program took %llu usecs\n", bt);
98
99 return NO_ERROR;
100 }
101
zync_fpga_config_done(void)102 bool zync_fpga_config_done(void) {
103 return (0 != (readl(DEVCFG_INT_STS) & PCFG_DONE_INT));
104 }
105
zynq_reset_fpga(void)106 void zynq_reset_fpga(void) {
107 writel(readl(DEVCFG_CTRL) & (~PCFG_PROG_B), DEVCFG_CTRL);
108 writel(readl(DEVCFG_CTRL) | PCFG_PROG_B, DEVCFG_CTRL);
109 }
110
111