1 /**
2 * Copyright (C) 2012-2014 Analog Devices, Inc.
3 *
4 * Licensed under the GPL-2.
5 *
6 **/
7 #include <stdio.h>
8
9 #include <gtk/gtk.h>
10 #include <gtkdatabox.h>
11 #include <glib.h>
12 #include <gtkdatabox_grid.h>
13 #include <gtkdatabox_points.h>
14 #include <gtkdatabox_lines.h>
15 #include <math.h>
16 #include <stdint.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <stdbool.h>
20 #include <stdlib.h>
21 #include <sys/stat.h>
22 #include <string.h>
23 #include <unistd.h>
24
25 #include "../datatypes.h"
26 #include "../osc.h"
27 #include "../iio_widget.h"
28 #include "../osc_plugin.h"
29 #include "../config.h"
30 #include "../libini2.h"
31
32 #define THIS_DRIVER "Partial Reconfiguration"
33
34 #define ARRAY_SIZE(x) (!sizeof(x) ?: sizeof(x) / sizeof((x)[0]))
35
36 #define PHY_DEVICE "ad9361-phy"
37 #define DEVICE_NAME_ADC "cf-ad9361-lpc"
38 #define DEVICE_NAME_DAC "cf-ad9361-dds-core-lpc"
39
40 #define PR_STATUS_ADDR 0x800000B8
41 #define PR_CONTROL_ADDR 0x800000BC
42
43 #define PR_LOGIC_DEFAULT_ID 0xA0
44 #define PR_LOGIC_BIST_ID 0xA1
45 #define PR_LOGIC_QPSK_ID 0xA2
46
47 #define IS_PARTIAL_BITSTREAM_FILEPATH "/sys/bus/platform/devices/f8007000.devcfg/is_partial_bitstream"
48 #define XDEVCFG_FILEPATH "/dev/xdevcfg"
49
50 #define BUF_SIZE 0x00300000
51 static char buf_pr[BUF_SIZE];
52 static int fd_devcfg = 0;
53 static int fd_is_partial = 0;
54 static char *config_file_path;
55
56 static struct iio_context *ctx;
57 static struct iio_device *phy, *adc, *dac;
58 static bool context_is_local;
59
60 enum regmaps {
61 ADC_REGMAP,
62 DAC_REGMAP,
63 };
64
65 static GtkWidget *reconf_chooser;
66 static GtkWidget *reconf_path_text;
67 static GtkWidget *regmap_select;
68 static GtkWidget *pr_stat_text;
69 static GtkWidget *pr_conf_text;
70 static GtkWidget *reg_read;
71 static GtkWidget *reg_write;
72
73 static gint this_page;
74 static GtkWidget *pr_config_panel;
75 static gboolean plugin_detached;
76
77 static const char * pr_config_driver_attribs[] = {
78 "config_file",
79 "adc_active",
80 };
81
entry_set_hex_int(GtkWidget * entry,unsigned data)82 static void entry_set_hex_int(GtkWidget *entry, unsigned data)
83 {
84 gchar *buf;
85
86 g_return_if_fail(GTK_ENTRY(entry));
87
88 buf = g_strdup_printf("0x%.8x", data);
89 gtk_entry_set_text(GTK_ENTRY(entry), buf);
90 g_free(buf);
91 }
92
93 /*
94 * Update the PR buffer with the specified bin
95 */
updatePR(const char * pr_bin_path)96 static const char * updatePR(const char * pr_bin_path) {
97
98 ssize_t status = 0;
99 int ret, fd;
100
101 fd = open(pr_bin_path, O_RDONLY);
102 if(fd < 0) {
103 return "Could not open file!";
104 } else {
105 status = read(fd, buf_pr, BUF_SIZE);
106 if(status < 0) {
107 close(fd);
108 return "Could not read file!";
109 }
110 close(fd);
111 }
112
113 /* set is_partial_bitfile device attribute */
114 fd_is_partial = open(IS_PARTIAL_BITSTREAM_FILEPATH, O_RDWR);
115 if (fd_is_partial < 0) {
116 return "Could not open "IS_PARTIAL_BITSTREAM_FILEPATH;
117 } else {
118 ret = write(fd_is_partial, "1", 2);
119 close(fd_is_partial);
120 }
121 if (ret != 2)
122 return "Could not write to "IS_PARTIAL_BITSTREAM_FILEPATH;
123
124 /* write partial bitfile to devcfg device */
125 fd_devcfg = open(XDEVCFG_FILEPATH, O_RDWR);
126 if(fd_devcfg < 0) {
127 return "Could not open "XDEVCFG_FILEPATH;
128 } else {
129 ret = write(fd_devcfg, buf_pr, BUF_SIZE);
130 sleep(1);
131 close(fd_devcfg);
132 }
133 if (ret != BUF_SIZE)
134 return "Could not write to "XDEVCFG_FILEPATH;
135
136 return NULL;
137 }
138
writeReg(char * device,uint32_t address,uint32_t data)139 static void writeReg(char* device, uint32_t address, uint32_t data) {
140 struct iio_device *dev;
141
142 if (!device) {
143 perror("writeReg() - device is NULL");
144 }
145
146 dev = iio_context_find_device(ctx, device);
147
148 if (!dev) {
149 perror("writeReg() - Unable to find device!");
150 return;
151 }
152 /* register write */
153 iio_device_reg_write(dev, address, data);
154 }
155
readReg(char * device,uint32_t address,uint32_t * data)156 static void readReg(char* device, uint32_t address, uint32_t* data) {
157 struct iio_device *dev;
158
159 if (!device) {
160 perror("readReg() - device is NULL");
161 }
162
163 dev = iio_context_find_device(ctx, device);
164
165 if (!dev) {
166 perror("readReg() - Unable to find device!");
167 return;
168 }
169 /* register read */
170 iio_device_reg_read(dev, address, data);
171 }
172
getPrId()173 static int getPrId() {
174
175 uint32_t data = 0;
176
177 /* read the current status register */
178 readReg(DEVICE_NAME_ADC, PR_STATUS_ADDR, &data);
179
180 return (data & 0xFF);
181 }
182
pr_config_file_apply(const char * filename)183 static void pr_config_file_apply(const char *filename)
184 {
185 GtkTextBuffer *buffer;
186 gchar *msg_error = NULL;
187 const gchar *ret_msg = NULL;
188
189 if (!context_is_local) {
190 msg_error = g_strdup_printf("Partial Reconfiguration is not supported in remote mode");
191 } else if(!filename) {
192 msg_error = g_strdup_printf("No file selected");
193 } else if (!g_str_has_suffix(filename, ".bin")) {
194 msg_error = g_strdup_printf("The selected file is not a .bin file");
195 } else {
196 ret_msg = updatePR(filename);
197 if (ret_msg)
198 msg_error = g_strdup_printf("%s", ret_msg);
199 }
200
201 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(reconf_path_text));
202 if (!msg_error) {
203 gtk_text_buffer_set_text(buffer, filename, -1);
204 } else {
205 gtk_text_buffer_set_text(buffer, msg_error, -1);
206 }
207
208 if (msg_error)
209 g_free(msg_error);
210 }
211
reconfig_file_set_cb(GtkFileChooser * chooser,gpointer data)212 static void reconfig_file_set_cb (GtkFileChooser *chooser, gpointer data)
213 {
214 if (config_file_path)
215 g_free(config_file_path);
216 config_file_path = gtk_file_chooser_get_filename(chooser);
217
218 pr_config_file_apply(config_file_path);
219 }
220
device_changed_cb(GtkComboBox * button,gpointer data)221 static void device_changed_cb(GtkComboBox *button, gpointer data)
222 {
223 gtk_entry_set_text(GTK_ENTRY(pr_stat_text), "");
224 gtk_entry_set_text(GTK_ENTRY(pr_conf_text), "");
225 }
226
reg_read_clicked_cb(GtkButton * button,gpointer data)227 static void reg_read_clicked_cb(GtkButton *button, gpointer data)
228 {
229 uint32_t stat_reg, ctrl_reg;
230 gchar *device;
231 gchar *active_device;
232
233 active_device = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(regmap_select));
234 if (!active_device)
235 return;
236 if (!strcmp(active_device, "ADC"))
237 device = DEVICE_NAME_ADC;
238 else if (!strcmp(active_device, "DAC"))
239 device = DEVICE_NAME_DAC;
240 else {
241 printf("Unknown device selection\n");
242 g_free(active_device);
243 return;
244 }
245 g_free(active_device);
246
247 readReg(device, PR_STATUS_ADDR, &stat_reg);
248 readReg(device, PR_CONTROL_ADDR, &ctrl_reg);
249
250 entry_set_hex_int(pr_stat_text, stat_reg);
251 entry_set_hex_int(pr_conf_text, ctrl_reg);
252 }
253
reg_write_clicked_cb(GtkButton * button,gpointer data)254 static void reg_write_clicked_cb(GtkButton *button, gpointer data)
255 {
256 uint32_t reg_data;
257 const char *buf;
258 gchar *device;
259 gchar *active_device;
260 int ret;
261
262 active_device = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(regmap_select));
263 if (!active_device)
264 return;
265 if (!strcmp(active_device, "ADC"))
266 device = DEVICE_NAME_ADC;
267 else if (!strcmp(active_device, "DAC"))
268 device = DEVICE_NAME_DAC;
269 else {
270 printf("Unknown device selection\n");
271 g_free(active_device);
272 return;
273 }
274 g_free(active_device);
275
276 buf = gtk_entry_get_text(GTK_ENTRY(pr_conf_text));
277
278 ret = sscanf(buf, "0x%x", ®_data);
279 if (ret != 1)
280 ret = sscanf(buf, "%d", ®_data);
281
282 if (ret != 1)
283 reg_data = 0;
284
285 entry_set_hex_int(pr_conf_text, reg_data);
286 writeReg(device, PR_CONTROL_ADDR, reg_data);
287 }
288
pr_config_handle_driver(struct osc_plugin * plugin,const char * attrib,const char * value)289 static int pr_config_handle_driver(struct osc_plugin *plugin, const char *attrib, const char *value)
290 {
291 if (MATCH_ATTRIB("config_file")) {
292 pr_config_file_apply(value);
293 } else if (MATCH_ATTRIB("adc_active")) {
294 gtk_combo_box_set_active(GTK_COMBO_BOX(regmap_select),
295 atoi(value) ? ADC_REGMAP : DAC_REGMAP);
296 } else {
297 return -EINVAL;
298 }
299
300 return 0;
301 }
302
pr_config_handle(struct osc_plugin * plugin,int line,const char * attrib,const char * value)303 static int pr_config_handle(struct osc_plugin *plugin, int line, const char *attrib, const char *value)
304 {
305 return osc_plugin_default_handle(ctx, line, attrib, value,
306 pr_config_handle_driver, NULL);
307 }
308
load_profile(struct osc_plugin * plugin,const char * ini_fn)309 static void load_profile(struct osc_plugin *plugin, const char *ini_fn)
310 {
311 unsigned int i;
312
313 for (i = 0; i < ARRAY_SIZE(pr_config_driver_attribs); i++) {
314 char *value = read_token_from_ini(ini_fn, THIS_DRIVER,
315 pr_config_driver_attribs[i]);
316 if (value) {
317 pr_config_handle_driver(NULL,
318 pr_config_driver_attribs[i], value);
319 free(value);
320 }
321 }
322 }
323
pr_config_init(struct osc_plugin * plugin,GtkWidget * notebook,const char * ini_fn)324 static GtkWidget * pr_config_init(struct osc_plugin *plugin, GtkWidget *notebook, const char *ini_fn)
325 {
326 GtkBuilder *builder;
327
328 builder = gtk_builder_new();
329
330 if (osc_load_glade_file(builder, "pr_config") < 0) {
331 osc_destroy_context(ctx);
332 return NULL;
333 }
334
335 pr_config_panel = GTK_WIDGET(gtk_builder_get_object(builder, "pr_config_panel"));
336 reconf_chooser = GTK_WIDGET(gtk_builder_get_object(builder, "filechooserbutton_reconf"));
337 reconf_path_text = GTK_WIDGET(gtk_builder_get_object(builder, "textview_reconf_file_path"));
338 regmap_select = GTK_WIDGET(gtk_builder_get_object(builder, "comboboxtext_regmap_select"));
339 pr_stat_text = GTK_WIDGET(gtk_builder_get_object(builder, "entry_pr_stat"));
340 pr_conf_text = GTK_WIDGET(gtk_builder_get_object(builder, "entry_pr_ctrl"));
341 reg_read = GTK_WIDGET(gtk_builder_get_object(builder, "button_regs_read"));
342 reg_write = GTK_WIDGET(gtk_builder_get_object(builder, "button_regs_write"));
343
344 if (ini_fn)
345 load_profile(NULL, ini_fn);
346
347 g_signal_connect(reconf_chooser, "file-set",
348 G_CALLBACK(reconfig_file_set_cb), NULL);
349 g_signal_connect(regmap_select, "changed",
350 G_CALLBACK(device_changed_cb), NULL);
351 g_signal_connect(reg_read, "clicked",
352 G_CALLBACK(reg_read_clicked_cb), NULL);
353 g_signal_connect(reg_write, "clicked",
354 G_CALLBACK(reg_write_clicked_cb), NULL);
355
356 gtk_combo_box_set_active(GTK_COMBO_BOX(regmap_select), ADC_REGMAP);
357
358 return pr_config_panel;
359 }
360
update_active_page(struct osc_plugin * plugin,gint active_page,gboolean is_detached)361 static void update_active_page(struct osc_plugin *plugin, gint active_page, gboolean is_detached)
362 {
363 this_page = active_page;
364 plugin_detached = is_detached;
365 }
366
pr_config_get_preferred_size(const struct osc_plugin * plugin,int * width,int * height)367 static void pr_config_get_preferred_size(const struct osc_plugin *plugin, int *width, int *height)
368 {
369 if (width)
370 *width = 640;
371 if (height)
372 *height = 480;
373 }
374
save_widgets_to_ini(FILE * f)375 static void save_widgets_to_ini(FILE *f)
376 {
377 fprintf(f, "config_file = %s\n"
378 "adc_active = %i\n",
379 config_file_path,
380 gtk_combo_box_get_active(GTK_COMBO_BOX(regmap_select)) == ADC_REGMAP);
381 }
382
save_profile(const struct osc_plugin * plugin,const char * ini_fn)383 static void save_profile(const struct osc_plugin *plugin, const char *ini_fn)
384 {
385 FILE *f = fopen(ini_fn, "a");
386 if (f) {
387 save_widgets_to_ini(f);
388 fclose(f);
389 }
390 }
391
context_destroy(struct osc_plugin * plugin,const char * ini_fn)392 static void context_destroy(struct osc_plugin *plugin, const char *ini_fn)
393 {
394 save_profile(NULL, ini_fn);
395 osc_destroy_context(ctx);
396 }
397
398 struct osc_plugin plugin;
399
pr_config_identify(const struct osc_plugin * plugin)400 static bool pr_config_identify(const struct osc_plugin *plugin)
401 {
402 /* Use the OSC's IIO context just to detect the devices */
403 struct iio_context *osc_ctx = get_context_from_osc();
404
405 if (!iio_context_find_device(osc_ctx, PHY_DEVICE) ||
406 !iio_context_find_device(osc_ctx, DEVICE_NAME_ADC) ||
407 !iio_context_find_device(osc_ctx, DEVICE_NAME_DAC))
408 return false;
409
410 ctx = osc_create_context();
411 phy = iio_context_find_device(ctx, PHY_DEVICE);
412 adc = iio_context_find_device(ctx, DEVICE_NAME_ADC);
413 dac = iio_context_find_device(ctx, DEVICE_NAME_DAC);
414
415 context_is_local = !strncmp(iio_context_get_name(ctx), "local", strlen("local"));
416
417 int id;
418 bool init = true;
419
420 if (!phy || !adc || !dac) {
421 init = false;
422 } else {
423 id = getPrId();
424 if ((id != PR_LOGIC_DEFAULT_ID) &&
425 (id != PR_LOGIC_BIST_ID) &&
426 (id != PR_LOGIC_QPSK_ID))
427 init = false;
428 }
429 if (phy && !iio_device_get_debug_attrs_count(phy))
430 init = false;
431 if (!init)
432 osc_destroy_context(ctx);
433
434 return init;
435 }
436
437 struct osc_plugin plugin = {
438 .name = THIS_DRIVER,
439 .identify = pr_config_identify,
440 .init = pr_config_init,
441 .update_active_page = update_active_page,
442 .get_preferred_size = pr_config_get_preferred_size,
443 .handle_item = pr_config_handle,
444 .save_profile = save_profile,
445 .load_profile = load_profile,
446 .destroy = context_destroy,
447 };
448