blob: fbdbe8fe9890e19e6454ce19b3ca103cb6d088d2 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2014 Brian Swetland
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#include <platform/fpga.h>
25#include <trace.h>
26#include <reg.h>
27#include <err.h>
28#include <platform.h>
29#include <kernel/thread.h>
30
31#define LOCAL_TRACE 0
32#define FPGA_TIMEOUT 1000
33
34#define DEVCFG_CTRL 0xF8007000
35#define PCFG_PROG_B (1 << 30)
36#define PCFG_POR_CNT_4K (1 << 29)
37#define PCAP_PR (1 << 27) // 0 = ICAP CFG, 1 = PCAP CFG
38#define PCAP_MODE (1 << 26) // 1 = Enable PCAP Interface
39#define DEVCFG_LOCK 0xF8007004
40#define DEVCFG_CFG 0xF8007008
41#define DEVCFG_INT_STS 0xF800700C
42#define DMA_DONE_INT (1 << 13)
43#define PSS_CFG_RESET_B (1 << 5) // 1 = PL in reset state
44#define PCFG_DONE_INT (1 << 2) // 1 = PL successfully programmed
45#define PCFG_INIT_PE_INT (1 << 1)
46#define PCFG_INIT_NE_INT (1 << 0)
47#define DEVCFG_INT_MASK 0xF8007010
48#define DEVCFG_STATUS 0xF8007014
49#define PCFG_INIT (1 << 4) // 1 = ready for bitstream
50#define DEVCFG_DMA_SRC_ADDR 0xF8007018
51#define DEVCFG_DMA_DST_ADDR 0xF800701C
52#define DEVCFG_DMA_SRC_LEN 0xF8007020 // words
53#define DEVCFG_DMA_DST_LEN 0xF8007024 // words
54#define DEVCFG_SW_ID 0xF8007030
55#define DEVCFG_MCTRL 0xF8007080
56#define PCFG_POR_B (1 << 8) // 1 = PL is powered on
57#define INT_PCAP_LPBK (1 << 4) // 1 = Loopback Enabled
58
59// Per Zynq TRM, 6.4.4
60// 1. wait for PCFG_INIT==1
61// 2. disable loopback
62// 3. set DEVCFG CTRL PCAP_PR and PCAP_MODE
63// 4. set dma src, dst, srclen, dstlen (in that specific order)
64// 5. wait for PCFG_DONE_INT==1
65
66status_t zynq_program_fpga(paddr_t physaddr, size_t length) {
67 LTRACEF("phys 0x%lx, len 0x%zx\n", physaddr, length);
68
69 lk_bigtime_t bt = current_time_hires();
70
71 /* length is in words */
72 length /= 4;
73
74 lk_time_t t;
75
76 t = current_time();
77 while(!(readl(DEVCFG_STATUS) & PCFG_INIT)) {
78 if (current_time() - t > FPGA_TIMEOUT) {
79 TRACEF("timeout waiting for PCFG_INIT\n");
80 return ERR_TIMED_OUT;
81 }
82 }
83 writel(readl(DEVCFG_MCTRL) & (~INT_PCAP_LPBK), DEVCFG_MCTRL);
84 writel(readl(DEVCFG_CTRL) | PCAP_PR | PCAP_MODE, DEVCFG_CTRL);
85 writel(0xffffffff, DEVCFG_INT_STS);
86 writel(physaddr, DEVCFG_DMA_SRC_ADDR);
87 writel(0xFFFFFFFF, DEVCFG_DMA_DST_ADDR);
88 writel(length, DEVCFG_DMA_SRC_LEN);
89 writel(length, DEVCFG_DMA_DST_LEN);
90
91 t = current_time();
92 uint32_t sts = 0;
93 for (;;) {
94 sts = readl(DEVCFG_INT_STS);
95#if LOCAL_TRACE
96 static uint32_t last = 0;
97 if (last != sts) {
98 printf("dsts 0x%x\n", sts);
99 }
100 last = sts;
101#endif
102 if (sts & PCFG_DONE_INT)
103 break;
104
105 if (current_time() - t > FPGA_TIMEOUT) {
106 TRACEF("timeout waiting for PCFG_DONE_INT, DEVCFG_INT_STS is 0x%x\n", sts);
107 return ERR_TIMED_OUT;
108 }
109 }
110
111 bt = current_time_hires() - bt;
112 LTRACEF("fpga program took %llu usecs\n", bt);
113
114 return NO_ERROR;
115}
116
117bool zync_fpga_config_done(void) {
118 return (0 != (readl(DEVCFG_INT_STS) & PCFG_DONE_INT));
119}
120
121void zynq_reset_fpga(void) {
122 writel(readl(DEVCFG_CTRL) & (~PCFG_PROG_B), DEVCFG_CTRL);
123 writel(readl(DEVCFG_CTRL) | PCFG_PROG_B, DEVCFG_CTRL);
124}
125