driver-cairnsmore.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. * Copyright 2012 Luke Dashjr
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License as published by the Free
  6. * Software Foundation; either version 3 of the License, or (at your option)
  7. * any later version. See COPYING for more details.
  8. */
  9. #include "dynclock.h"
  10. #include "fpgautils.h"
  11. #include "icarus-common.h"
  12. #include "miner.h"
  13. #define CAIRNSMORE1_IO_SPEED 115200
  14. // This is a general ballpark
  15. #define CAIRNSMORE1_HASH_TIME 0.0000000024484
  16. #define CAIRNSMORE1_MINIMUM_CLOCK 5
  17. #define CAIRNSMORE1_DEFAULT_CLOCK 200
  18. #define CAIRNSMORE1_MAXIMUM_CLOCK 200
  19. struct device_api cairnsmore_api;
  20. static bool cairnsmore_detect_one(const char *devpath)
  21. {
  22. struct ICARUS_INFO *info = calloc(1, sizeof(struct ICARUS_INFO));
  23. if (unlikely(!info))
  24. quit(1, "Failed to malloc ICARUS_INFO");
  25. info->baud = CAIRNSMORE1_IO_SPEED;
  26. info->work_division = 2;
  27. info->fpga_count = 2;
  28. info->quirk_reopen = false;
  29. info->Hs = CAIRNSMORE1_HASH_TIME;
  30. info->timing_mode = MODE_LONG;
  31. info->do_icarus_timing = true;
  32. if (!icarus_detect_custom(devpath, &cairnsmore_api, info)) {
  33. free(info);
  34. return false;
  35. }
  36. return true;
  37. }
  38. static int cairnsmore_detect_auto(void)
  39. {
  40. return
  41. serial_autodetect_udev (cairnsmore_detect_one, "*Cairnsmore1*") ?:
  42. serial_autodetect_devserial(cairnsmore_detect_one, "Cairnsmore1") ?:
  43. serial_autodetect_ftdi (cairnsmore_detect_one, "Cairnsmore1", NULL) ?:
  44. 0;
  45. }
  46. static void cairnsmore_detect()
  47. {
  48. // Actual serial detection is handled by Icarus driver
  49. serial_detect_auto_byname(cairnsmore_api.dname, cairnsmore_detect_one, cairnsmore_detect_auto);
  50. }
  51. static bool cairnsmore_send_cmd(int fd, uint8_t cmd, uint8_t data)
  52. {
  53. unsigned char pkt[64] =
  54. "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  55. "vdi\xb7"
  56. "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  57. "BFG0" "\xff\xff\xff\xff" "\0\0\0\0";
  58. pkt[32] = 0xda ^ cmd ^ data;
  59. pkt[33] = data;
  60. pkt[34] = cmd;
  61. return write(fd, pkt, sizeof(pkt)) == sizeof(pkt);
  62. }
  63. bool cairnsmore_supports_dynclock(int fd)
  64. {
  65. unsigned char pkts[64] =
  66. "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
  67. "\xe6\x3c\0\xb7" // Set frequency multiplier to 60 (150 Mhz)
  68. "\0\0\0\0\0\0\0\0\0\0\0\0" "BFG0"
  69. "\x8b\xdb\x05\x1a" "\xff\xff\xff\xff" "\x00\x00\x1e\xfd";
  70. if (write(fd, pkts, sizeof(pkts) != sizeof(pkts)))
  71. return false;
  72. uint32_t nonce = 0;
  73. {
  74. struct timeval tv_finish;
  75. struct thr_info dummy = {
  76. .work_restart = false,
  77. .work_restart_fd = -1,
  78. };
  79. icarus_gets((unsigned char*)&nonce, fd, &tv_finish, &dummy, 1);
  80. }
  81. switch (nonce) {
  82. case 0x000b1b5e:
  83. // Hashed the command, so it's not supported
  84. return false;
  85. case 0:
  86. return true;
  87. default:
  88. applog(LOG_DEBUG, "cairnsmore_supports_dynclock got unexpected nonce %08x", nonce);
  89. return false;
  90. }
  91. }
  92. static bool cairnsmore_change_clock_func(struct thr_info *thr, int bestM)
  93. {
  94. struct cgpu_info *cm1 = thr->cgpu;
  95. struct ICARUS_INFO *info = cm1->cgpu_data;
  96. if (unlikely(!cairnsmore_send_cmd(cm1->device_fd, 0, bestM)))
  97. return false;
  98. char repr[0x10];
  99. sprintf(repr, "%s %u", cm1->api->name, cm1->device_id);
  100. dclk_msg_freqchange(repr, 2.5 * (double)info->dclk.freqM, 2.5 * (double)bestM, NULL);
  101. info->dclk.freqM = bestM;
  102. return true;
  103. }
  104. static bool cairnsmore_init(struct thr_info *thr)
  105. {
  106. struct cgpu_info *cm1 = thr->cgpu;
  107. struct ICARUS_INFO *info = cm1->cgpu_data;
  108. if (cairnsmore_supports_dynclock(cm1->device_fd)) {
  109. info->dclk_change_clock_func = cairnsmore_change_clock_func;
  110. dclk_prepare(&info->dclk);
  111. info->dclk.freqMaxM = CAIRNSMORE1_MAXIMUM_CLOCK / 2.5;
  112. info->dclk.freqM =
  113. info->dclk.freqMDefault = CAIRNSMORE1_DEFAULT_CLOCK / 2.5;
  114. cairnsmore_send_cmd(cm1->device_fd, 0, info->dclk.freqM);
  115. applog(LOG_WARNING, "%s %u: Frequency set to %u Mhz (range: %u-%u)",
  116. cm1->api->name, cm1->device_id,
  117. CAIRNSMORE1_DEFAULT_CLOCK, CAIRNSMORE1_MINIMUM_CLOCK, CAIRNSMORE1_MAXIMUM_CLOCK
  118. );
  119. } else {
  120. // Test failures corrupt the hash state, so next scanhash is a firstrun
  121. struct icarus_state *state = thr->cgpu_data;
  122. state->firstrun = true;
  123. }
  124. return true;
  125. }
  126. void convert_icarus_to_cairnsmore(struct cgpu_info *cm1)
  127. {
  128. struct ICARUS_INFO *info = cm1->cgpu_data;
  129. info->Hs = CAIRNSMORE1_HASH_TIME;
  130. info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
  131. info->timing_mode = MODE_LONG;
  132. info->do_icarus_timing = true;
  133. cm1->api = &cairnsmore_api;
  134. renumber_cgpu(cm1);
  135. cairnsmore_init(cm1->thr[0]);
  136. }
  137. static struct api_data *cairnsmore_api_extra_device_status(struct cgpu_info *cm1)
  138. {
  139. struct ICARUS_INFO *info = cm1->cgpu_data;
  140. struct api_data*root = NULL;
  141. if (info->dclk.freqM) {
  142. double frequency = 2.5 * info->dclk.freqM;
  143. root = api_add_freq(root, "Frequency", &frequency, true);
  144. }
  145. return root;
  146. }
  147. extern struct device_api icarus_api;
  148. __attribute__((constructor(1000)))
  149. static void cairnsmore_api_init()
  150. {
  151. cairnsmore_api = icarus_api;
  152. cairnsmore_api.dname = "cairnsmore";
  153. cairnsmore_api.name = "ECM";
  154. cairnsmore_api.api_detect = cairnsmore_detect;
  155. cairnsmore_api.thread_init = cairnsmore_init;
  156. cairnsmore_api.get_api_extra_device_status = cairnsmore_api_extra_device_status;
  157. }