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