ddrio.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. #define _XOPEN_SOURCE 500
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <stdbool.h>
  5. #include <string.h>
  6. #include <unistd.h>
  7. #include <getopt.h>
  8. #include <pcilib.h>
  9. #include <pcilib/bar.h>
  10. #include <pcilib/kmem.h>
  11. #include "hf-interface.h"
  12. /* this should actually come from the distributed pcitool sources */
  13. #include "pciDriver.h"
  14. #ifndef NDEBUG
  15. #define WR32(addr, value) *(uint32_t *) (bar + (addr)) = (value);\
  16. printf ("WR32N %4x <- %x\n", (addr), (value));
  17. #define WR32_sleep(addr, value) *(uint32_t *) (bar + (addr)) = (value); usleep (1000);\
  18. printf ("WR32S %4x <- %x\n", (addr), (value));
  19. #define WR64(addr, value) *(uint64_t *) (bar + (addr)) = (value);\
  20. printf ("WR64N %4x <- %x\n", (addr), (value));
  21. #define WR64_sleep(addr, value) *(uint64_t *) (bar + (addr)) = (value); usleep (1000);\
  22. printf ("WR64S %4x <- %x\n", (addr), (value));
  23. #else
  24. #define WR32(addr, value) *(uint32_t *) (bar + (addr)) = (value);
  25. #define WR32_sleep(addr, value) *(uint32_t *) (bar + (addr)) = (value); usleep (1000);
  26. #define WR64(addr, value) *(uint64_t *) (bar + (addr)) = (value);
  27. #define WR64_sleep(addr, value) *(uint64_t *) (bar + (addr)) = (value); usleep (1000);
  28. #endif
  29. #define RD32(addr) (*(uint32_t *) (bar + (addr)))
  30. #define RD64(addr) (*(uint64_t *) (bar + (addr)))
  31. #define KMEM_USE_RING PCILIB_KMEM_USE(PCILIB_KMEM_USE_USER, 1)
  32. #define KMEM_DEFAULT_FLAGS PCILIB_KMEM_FLAG_HARDWARE | \
  33. PCILIB_KMEM_FLAG_PERSISTENT | \
  34. PCILIB_KMEM_FLAG_EXCLUSIVE
  35. typedef struct {
  36. const char *input;
  37. const char *output;
  38. bool keep;
  39. bool verbose;
  40. size_t size;
  41. enum {
  42. COPY_UINT64 = 0,
  43. COPY_MEMCPY,
  44. } copy;
  45. } Options;
  46. static void
  47. usage (void)
  48. {
  49. printf ("Usage: ddr [OPTION] [FILE]\n"
  50. "Options:\n"
  51. " -h, --help Show this help message and exit\n"
  52. " -v, --verbose Be more verbose\n"
  53. " -k, --keep-data Keep data and don't reset DMA\n"
  54. " -o, --output Output filename\n"
  55. " -i, --input Input filename\n"
  56. " -s, --size Size of data (leave if reading supplied input)\n"
  57. " -c, --copy Copy method, either `memcpy' or `64'\n");
  58. }
  59. static void
  60. parse_options (int argc, char *const *argv, Options *opts)
  61. {
  62. enum {
  63. OPT_HELP = 'h',
  64. OPT_VERBOSE = 'v',
  65. OPT_KEEP = 'k',
  66. OPT_INPUT = 'i',
  67. OPT_OUTPUT = 'o',
  68. OPT_SIZE = 's',
  69. OPT_COPY = 'c',
  70. };
  71. static struct option long_options[] = {
  72. { "help", no_argument, 0, OPT_HELP },
  73. { "verbose", no_argument, 0, OPT_VERBOSE },
  74. { "keep", no_argument, 0, OPT_KEEP },
  75. { "input", required_argument, 0, OPT_INPUT },
  76. { "output", required_argument, 0, OPT_OUTPUT },
  77. { "size", required_argument, 0, OPT_SIZE },
  78. { "copy", required_argument, 0, OPT_COPY },
  79. { 0, 0, 0, 0 },
  80. };
  81. int ret;
  82. int index;
  83. if (argc == 1) {
  84. usage ();
  85. exit (0);
  86. }
  87. memset (opts, 0, sizeof (Options));
  88. while ((ret = getopt_long (argc, argv, "i:o:s:c:khv", long_options, &index)) != -1) {
  89. switch (ret) {
  90. case OPT_HELP:
  91. usage ();
  92. exit (0);
  93. case OPT_VERBOSE:
  94. opts->verbose = true;
  95. break;
  96. case OPT_KEEP:
  97. opts->keep = true;
  98. break;
  99. case OPT_INPUT:
  100. opts->input = optarg;
  101. break;
  102. case OPT_OUTPUT:
  103. opts->output = optarg;
  104. break;
  105. case OPT_SIZE:
  106. opts->size = (size_t) atol (optarg);
  107. break;
  108. case OPT_COPY:
  109. if (!strcmp (optarg, "memcpy"))
  110. opts->copy = COPY_MEMCPY;
  111. else if (!strcmp (optarg, "64"))
  112. opts->copy = COPY_UINT64;
  113. default:
  114. break;
  115. }
  116. }
  117. }
  118. static void
  119. reset_ddr_data (pcilib_t *pci, volatile void *bar, Options *opts)
  120. {
  121. /* reset DMA */
  122. WR32_sleep (HF_REG_BASE, HF_BASE_RESET);
  123. WR32_sleep (HF_REG_BASE, 0);
  124. /* reset DDR and FIFOs */
  125. WR32_sleep (HF_REG_CONTROL,
  126. HF_CONTROL_RESET |
  127. HF_CONTROL_SOFT_RESET |
  128. HF_CONTROL_SOURCE_RX_FIFO);
  129. /* write only in DDR mode, disable read */
  130. WR32_sleep (HF_REG_CONTROL,
  131. HF_CONTROL_SOURCE_RX_FIFO);
  132. }
  133. static void
  134. copy_data (volatile void *bar, char *data, size_t size, Options *opts)
  135. {
  136. if (opts->verbose)
  137. printf ("Writing %zu bytes\n", size);
  138. switch (opts->copy) {
  139. case COPY_MEMCPY:
  140. memcpy (bar + 0x9400, data, size);
  141. break;
  142. case COPY_UINT64:
  143. {
  144. uint64_t *src = (uint64_t *) data;
  145. uint64_t *dst = (uint64_t *) (bar + 0x9400);
  146. int remaining;
  147. for (size_t i = 0; i < size / 8; i++)
  148. dst[0] = src[i];
  149. remaining = size % 8;
  150. for (int i = 0; i < remaining; i++)
  151. ((uint8_t *) bar + 0x9400)[0] = data[size - 1 - i];
  152. }
  153. break;
  154. default:
  155. break;
  156. }
  157. }
  158. static void
  159. write_to_ddr (pcilib_t *pci, volatile void *bar, Options *opts)
  160. {
  161. FILE *fp;
  162. char *data;
  163. size_t size;
  164. size_t read_size;
  165. if ((fp = fopen (opts->input, "rb")) == NULL) {
  166. fprintf (stderr, "Could not open `%s'\n", opts->input);
  167. return;
  168. }
  169. if (opts->size == 0) {
  170. fseek (fp, 0, SEEK_END);
  171. size = (size_t) ftell (fp);
  172. rewind (fp);
  173. opts->size = size;
  174. }
  175. else
  176. size = opts->size;
  177. data = malloc (size);
  178. read_size = fread (data, 1, size, fp);
  179. if (read_size != size) {
  180. fprintf (stderr, "Could only read %zu/%zu bytes, expect inconsistencies\n",
  181. read_size, size);
  182. }
  183. copy_data (bar, data, size, opts);
  184. if (size >= 4096 && size % 4096) {
  185. size_t remaining = 4096 - size % 4096;
  186. memset (data, 0, remaining);
  187. copy_data (bar, data, remaining, opts);
  188. }
  189. free (data);
  190. fclose (fp);
  191. }
  192. static void
  193. read_from_ddr (pcilib_t *pci, volatile void *bar, Options *opts)
  194. {
  195. FILE *fp;
  196. pcilib_kmem_handle_t *kmem_data;
  197. pcilib_kmem_handle_t *kmem_desc;
  198. uintptr_t bus_addr_data;
  199. uintptr_t bus_addr_desc;
  200. volatile uint32_t *data;
  201. volatile uint32_t *desc;
  202. uint32_t hardware_ptr;
  203. size_t size;
  204. int started = 0;
  205. const size_t mem_size = 4096;
  206. const int flag_index = 2;
  207. if (opts->size == 0) {
  208. fprintf (stderr, "Read size is zero, not going to read\n");
  209. return;
  210. }
  211. if ((fp = fopen (opts->output, "wb")) == NULL) {
  212. fprintf (stderr, "Could not open `%s'\n", opts->output);
  213. return;
  214. }
  215. size = opts->size;
  216. kmem_data = pcilib_alloc_kernel_memory (pci, PCILIB_KMEM_TYPE_CONSISTENT, 1, mem_size, mem_size, PCILIB_KMEM_USE_DMA_PAGES, KMEM_DEFAULT_FLAGS);
  217. kmem_desc = pcilib_alloc_kernel_memory (pci, PCILIB_KMEM_TYPE_CONSISTENT, 1, 128, 4096, KMEM_USE_RING, KMEM_DEFAULT_FLAGS);
  218. data = (uint32_t *) pcilib_kmem_get_block_ua (pci, kmem_data, 0);
  219. desc = (uint32_t *) pcilib_kmem_get_block_ua (pci, kmem_desc, 0);
  220. bus_addr_data = pcilib_kmem_get_block_ba (pci, kmem_data, 0);
  221. bus_addr_desc = pcilib_kmem_get_block_ba (pci, kmem_desc, 0);
  222. memset (data, 0xf0, mem_size);
  223. hardware_ptr = 0;
  224. /* enable multi-read from DDR */
  225. WR32_sleep (HF_REG_CONTROL,
  226. HF_CONTROL_ENABLE_READ |
  227. HF_CONTROL_ENABLE_MULTI_READ |
  228. HF_CONTROL_SOURCE_RX_FIFO);
  229. WR32_sleep (HF_REG_CONTROL,
  230. HF_CONTROL_ENABLE_READ |
  231. HF_CONTROL_SOURCE_RX_FIFO);
  232. /* DMA config */
  233. WR32_sleep (HF_REG_NUM_PACKETS, 0x20);
  234. WR32_sleep (HF_REG_PACKET_LENGTH, 0x20);
  235. WR32_sleep (HF_REG_UPDATE_THRESHOLD, 1);
  236. WR64_sleep (HF_REG_UPDATE_ADDRESS, bus_addr_desc);
  237. WR32_sleep (HF_REG_TIMER_THRESHOLD, 0x20000);
  238. desc[flag_index] = 0;
  239. while (size >= mem_size) {
  240. desc[flag_index] = 0;
  241. /* set write addr */
  242. WR64 (HF_REG_DESCRIPTOR_ADDRESS, bus_addr_data);
  243. /* start DMA */
  244. if (!started) {
  245. WR32_sleep (HF_REG_DMA, HF_DMA_START);
  246. started = 1;
  247. }
  248. do {
  249. hardware_ptr = desc[flag_index];
  250. }
  251. while (hardware_ptr != (bus_addr_data & 0xFFFFFFFF));
  252. fwrite (data, 1, mem_size, fp);
  253. size -= mem_size;
  254. }
  255. memset (data, 0xf0, mem_size);
  256. if (size > 0) {
  257. desc[flag_index] = 0;
  258. if (opts->verbose)
  259. printf ("Read remaining %zu bytes\n", size);
  260. WR64_sleep (HF_REG_DESCRIPTOR_ADDRESS, bus_addr_data);
  261. do {
  262. hardware_ptr = desc[flag_index];
  263. }
  264. while (hardware_ptr != (bus_addr_data & 0xFFFFFFFF));
  265. fwrite (data, 1, size, fp);
  266. }
  267. if (opts->verbose)
  268. printf ("Descriptor: update_pattern=%x empty=%x last_address=%lx\n", desc[0], 1 & desc[1], desc[2] | (((uint64_t) desc[3]) << 32));
  269. WR32_sleep (HF_REG_DMA, HF_DMA_STOP);
  270. fclose (fp);
  271. pcilib_free_kernel_memory (pci, kmem_data, KMEM_DEFAULT_FLAGS);
  272. pcilib_free_kernel_memory (pci, kmem_desc, KMEM_DEFAULT_FLAGS);
  273. }
  274. int
  275. main (int argc, char const* argv[])
  276. {
  277. static const char *DEVICE = "/dev/fpga0";
  278. Options opts;
  279. pcilib_t *pci;
  280. volatile void *bar;
  281. parse_options (argc, (char *const *) argv, &opts);
  282. pci = pcilib_open (DEVICE, "pci");
  283. if (pci == NULL) {
  284. fprintf (stderr, "Could not open `%s'", DEVICE);
  285. return 1;
  286. }
  287. pcilib_map_bar (pci, PCILIB_BAR0);
  288. bar = pcilib_resolve_bar_address (pci, PCILIB_BAR0, 0);
  289. /* reset dbg tx */
  290. WR32_sleep (HF_REG_DEBUG_REQUESTER_RESET, 1);
  291. WR32_sleep (HF_REG_DEBUG_REQUESTER_RESET, 0);
  292. WR32_sleep (HF_REG_DEBUG_COMPLETER_RESET, 1);
  293. WR32_sleep (HF_REG_DEBUG_COMPLETER_RESET, 0);
  294. /* configure interconnect */
  295. WR32_sleep (HF_REG_INTERCONNECT,
  296. HF_INTERCONNECT_MASTER_DMA |
  297. HF_INTERCONNECT_DDR_TO_DMA |
  298. HF_INTERCONNECT_DDR_FROM_64);
  299. if (opts.input != NULL) {
  300. if (!opts.keep) {
  301. if (opts.verbose)
  302. printf ("Reset DDR and data\n");
  303. reset_ddr_data (pci, bar, &opts);
  304. }
  305. write_to_ddr (pci, bar, &opts);
  306. }
  307. if (opts.output != NULL)
  308. read_from_ddr (pci, bar, &opts);
  309. pcilib_unmap_bar (pci, PCILIB_BAR0, (void *) bar);
  310. pcilib_close (pci);
  311. }