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