1 // Copyright 2017-2019 VMware, Inc.
2 // SPDX-License-Identifier: BSD-2-Clause
3 //
4 // The BSD-2 license (the License) set forth below applies to all parts of the
5 // Cascade project. You may not use this file except in compliance with the
6 // License.
7 //
8 // BSD-2 License
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are met:
12 //
13 // 1. Redistributions of source code must retain the above copyright notice, this
14 // list of conditions and the following disclaimer.
15 //
16 // 2. Redistributions in binary form must reproduce the above copyright notice,
17 // this list of conditions and the following disclaimer in the documentation
18 // and/or other materials provided with the distribution.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND
21 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 // MIT License
32 //
33 // Copyright (c) 2018 Nicolás Hasbún
34 //
35 // Permission is hereby granted, free of charge, to any person obtaining a copy
36 // of this software and associated documentation files (the "Software"), to deal
37 // in the Software without restriction, including without limitation the rights
38 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
39 // copies of the Software, and to permit persons to whom the Software is
40 // furnished to do so, subject to the following conditions:
41 //
42 // The above copyright notice and this permission notice shall be included in all
43 // copies or substantial portions of the Software.
44 //
45 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
46 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
47 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
49 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
50 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
51 // SOFTWARE.
52
53 #include "target/core/avmm/de10/de10_config.h"
54
55 #include <cstdio>
56 #include <cstdlib>
57 #include <cstring>
58 #include <stdint.h>
59 #include <fcntl.h>
60 #include <sys/mman.h>
61 #include <unistd.h>
62 #include "target/core/avmm/de10/hps.h"
63 #include "target/core/avmm/de10/socal.h"
64
65 // Useful macros
66 #define BIT(x,n) (((x) >> (n)) & 1)
67 #define INSERT_BITS(original, mask, value, num) (original & (~mask)) | (value << num)
68
69 #define FPGA_MANAGER_ADD (0xff706000) // FPGA MANAGER MAIN REGISTER ADDRESS
70 #define STAT_OFFSET (0x000)
71 #define CTRL_OFFSET (0x004)
72 #define GPIO_INTSTATUS (0x840)
73
74 #define FPGA_MANAGER_DATA_ADD (0xffb90000) // FPGA MANAGER DATA REGISTER ADDRESS
75
76 using namespace std;
77
78 namespace cascade::avmm {
79
run(const string & path)80 void De10Config::run(const string& path) {
81 fd_ = open("/dev/mem", (O_RDWR|O_SYNC));
82
83 const size_t largobytes = 1;
84 virtualbase_ = mmap(NULL, largobytes,
85 (PROT_READ|PROT_WRITE), MAP_SHARED, fd_, FPGA_MANAGER_ADD);
86 config_routine(path.c_str());
87
88 close(fd_);
89 }
90
config_routine(const char * path)91 void De10Config::config_routine(const char* path) {
92 report_status(); // Check registers... could be accessed using "status" argument.
93 set_ctrl_en(1); // Activate control by HPS.
94 fpga_off(); // Reset State for fpga.
95 while(1) if(fpga_state() == 0x1) break;
96
97 set_cdratio(); // Set corresponding cdratio (check fpga manager docs).
98 fpga_on(); // Should be on config state.
99 while(1) if(fpga_state() == 0x2) break;
100
101 set_axicfgen(1); // Activate AXI configuration data transfers.
102 config_fpga(path); // Load rbf config file to fpga manager data register.
103 while(1) if(fpga_state() == 0x4) break;
104
105 set_axicfgen(0); // Turn off AXI configuration data transfers..
106 set_ctrl_en(0); // Disable control by HPS (so JTAG can load new fpga configs).
107 report_status(); // Should report "User mode".
108 }
109
report_status()110 void De10Config::report_status() {
111 uint8_t status = alt_read_byte(static_cast<uint8_t*>(virtualbase_) + STAT_OFFSET);
112 uint8_t mode_mask = 0b111;
113 uint8_t msel_mask = 0b11111 << 3;
114
115 uint8_t mode = status & mode_mask;
116 uint8_t msel = (status & msel_mask) >> 3;
117
118 uint16_t control_reg = alt_read_hword(static_cast<uint8_t*>(virtualbase_) + CTRL_OFFSET);
119 uint16_t cfgwdth_mask = (0b1 << 9);
120 uint16_t cdratio_mask = (0b11 << 6);
121
122 uint8_t cfgwdth = (control_reg & cfgwdth_mask) >> 9;
123 uint8_t cdratio = (control_reg & cdratio_mask) >> 6;
124 uint8_t axicfgen = BIT(control_reg, 8);
125 uint8_t ctrl_en = BIT(control_reg, 0);
126 uint8_t nconfigpull = BIT(control_reg, 2);
127
128 uint16_t gpio_intstatus_reg = alt_read_hword(static_cast<uint8_t*>(virtualbase_) + GPIO_INTSTATUS);
129 uint8_t cd = BIT(gpio_intstatus_reg, 1); // configuration done register
130 }
131
fpga_state()132 uint8_t De10Config::fpga_state() {
133 uint8_t status = alt_read_byte(static_cast<uint8_t*>(virtualbase_) + STAT_OFFSET);
134 uint8_t mode_mask = 0b111;
135 uint8_t mode = status & mode_mask;
136 return mode;
137 }
138
set_cdratio()139 void De10Config::set_cdratio() {
140 uint16_t control_reg = alt_read_hword(static_cast<uint8_t*>(virtualbase_) + CTRL_OFFSET);
141 uint16_t cdratio_mask = (0b11 << 6);
142 uint8_t cdratio = 0x3;
143
144 control_reg = INSERT_BITS(control_reg, cdratio_mask, cdratio, 6);
145 alt_write_hword(static_cast<uint8_t*>(virtualbase_) + CTRL_OFFSET, control_reg);
146 }
147
config_fpga(const char * path)148 void De10Config::config_fpga(const char* path) {
149 // Memory map the fpga data register
150 void * data_mmap = mmap(NULL, 4,
151 (PROT_READ|PROT_WRITE), MAP_SHARED, fd_, FPGA_MANAGER_DATA_ADD);
152
153 // Open rbf file.
154 int rbf = open(path, (O_RDONLY|O_SYNC));
155 if (rbf < 0) {
156 // Some error happened...
157 //printf("\n%s\n\n", Error opening file. Check for an appropiate fpga_config_file.rbf file.");
158 exit(-1);
159 }
160
161 // Set buffer to read rbf files and copy to fpga manager data register.
162 uint8_t * data_buffer = (uint8_t*)malloc(sizeof(uint8_t) * 4);
163 memset(data_buffer, 0, 4); // set initial data to 0.
164
165 // Loop to read rbf and write to fpga data address.
166 // We advancse every 4 bytes (32 bits).
167
168 bool run_while = true;
169 //printf("%s\n", "Loading rbf file.");
170
171 while(run_while) {
172 ssize_t read_result = read(rbf, data_buffer, 4);
173 if (read_result < 4) {
174 //printf("%s\n", "EOF reached.");
175 run_while = false;
176 }
177
178 // Follow format expected by fpga manager.
179 uint32_t format_data = *(data_buffer) << 0;
180 format_data = format_data | *(data_buffer + 1) << 8;
181 format_data = format_data | *(data_buffer + 2) << 16;
182 format_data = format_data | *(data_buffer + 3) << 24;
183
184 alt_write_word(data_mmap, format_data);
185 memset(data_buffer, 0, 4); // reset data to 0.
186 }
187
188 close(rbf);
189 }
190
set_axicfgen(uint8_t value)191 void De10Config::set_axicfgen(uint8_t value) {
192 uint16_t control_reg = alt_read_hword(static_cast<uint8_t*>(virtualbase_) + CTRL_OFFSET);
193 uint16_t axicfgen_mask = 1 << 8;
194 uint8_t axicfgen = value & 1; // binary values
195
196 control_reg = INSERT_BITS(control_reg, axicfgen_mask, axicfgen, 8);
197
198 alt_write_hword(static_cast<uint8_t*>(virtualbase_) + CTRL_OFFSET, control_reg);
199 }
200
set_ctrl_en(uint8_t value)201 void De10Config::set_ctrl_en(uint8_t value) {
202 uint16_t control_reg = alt_read_hword(static_cast<uint8_t*>(virtualbase_) + CTRL_OFFSET);
203 uint16_t ctrl_en_mask = 1 << 0;
204 uint8_t ctrl_en = value & 1; // binary values
205
206 control_reg = INSERT_BITS(control_reg, ctrl_en_mask, ctrl_en, 0);
207
208 alt_write_hword(static_cast<uint8_t*>(virtualbase_) + CTRL_OFFSET, control_reg);
209 }
210
set_nconfigpull(uint8_t value)211 void De10Config::set_nconfigpull(uint8_t value) {
212 uint16_t control_reg = alt_read_hword(static_cast<uint8_t*>(virtualbase_) + CTRL_OFFSET);
213 uint16_t nconfigpull_mask = 1 << 2;
214 uint8_t nconfigpull = value & 1; // binary values
215
216 control_reg = INSERT_BITS(control_reg, nconfigpull_mask, nconfigpull, 2);
217
218 alt_write_hword(static_cast<uint8_t*>(virtualbase_) + CTRL_OFFSET, control_reg);
219 }
220
fpga_off()221 void De10Config::fpga_off() {
222 set_nconfigpull(1);
223 }
224
fpga_on()225 void De10Config::fpga_on() {
226 set_nconfigpull(0);
227 }
228
229 } // namespace cascade::avmm
230