driver-neptune.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /*
  2. * Copyright 2014 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 "config.h"
  10. #include <stdint.h>
  11. #include <linux/spi/spidev.h>
  12. #include <zlib.h>
  13. #include "deviceapi.h"
  14. #include "lowl-spi.h"
  15. #include "util.h"
  16. #define NEPTUNE_SPI_SPEED 3000000
  17. #define NEPTUNE_SPI_DELAY 0
  18. #define NEPTUNE_SPI_MODE (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
  19. #define NEPTUNE_SPI_BITS 8
  20. #define NEPTUNE_MAX_CHANNEL 6
  21. #define NEPTUNE_MAX_DIES_PER_CHANNEL 4
  22. #define NEPTUNE_VERSION 0xa002
  23. BFG_REGISTER_DRIVER(neptune_drv)
  24. enum neptune_cmd {
  25. NEPTUNE_GETINFO = 0x80,
  26. };
  27. static
  28. void neptune_spi_emit_to_channel(struct spi_port * const spi, const uint8_t channel, const uint8_t datasz)
  29. {
  30. const uint8_t muxheader[2] = {0x80 | channel, datasz};
  31. spi_emit_buf(spi, muxheader, sizeof(muxheader));
  32. }
  33. void *neptune_spi_emit_cmd(struct spi_port * const spi, const uint8_t channel, const uint8_t die, const uint8_t core, const enum neptune_cmd cmd, const void * const data, const uint8_t datasz, const uint8_t responsesz)
  34. {
  35. const uint8_t cmdhdr[4] = {cmd, die, core >> 8, core & 0xff};
  36. neptune_spi_emit_to_channel(spi, channel, sizeof(cmdhdr) + datasz);
  37. spi_emit_buf(spi, cmdhdr, sizeof(cmdhdr));
  38. void * const rv = spi_emit_buf(spi, data, datasz);
  39. if (datasz < responsesz)
  40. spi_emit_nop(spi, responsesz - datasz);
  41. uint32_t crc = crc32(0, NULL, 0);
  42. crc = crc32(crc, cmdhdr, sizeof(cmdhdr));
  43. if (datasz)
  44. crc = crc32(crc, data, datasz);
  45. uint8_t crcb[4];
  46. pk_u32be(crcb, 0, crc);
  47. spi_emit_buf(spi, crcb, sizeof(crcb));
  48. return rv;
  49. }
  50. static
  51. bool neptune_detect_one(const char * const devpath)
  52. {
  53. struct cgpu_info *prev_cgpu = NULL, *cgpu;
  54. spi_init();
  55. struct spi_port * const spi = malloc(sizeof(*spi));
  56. memset(spi, 0, sizeof(*spi));
  57. spi->txrx = linux_spi_txrx;
  58. spi->repr = neptune_drv.dname;
  59. spi->logprio = LOG_ERR;
  60. spi->speed = NEPTUNE_SPI_SPEED;
  61. spi->delay = NEPTUNE_SPI_DELAY;
  62. spi->mode = NEPTUNE_SPI_MODE;
  63. spi->bits = NEPTUNE_SPI_BITS;
  64. const int fd = spi_open(spi, devpath);
  65. if (unlikely(fd == -1))
  66. {
  67. free(spi);
  68. applogr(false, LOG_DEBUG, "%s: Failed to open %s", neptune_drv.dname, devpath);
  69. }
  70. for (int channel = 0; channel < NEPTUNE_MAX_CHANNEL; ++channel)
  71. {
  72. unsigned total_cores = 0;
  73. for (int die = 0; die < NEPTUNE_MAX_DIES_PER_CHANNEL; ++die)
  74. {
  75. uint8_t *rx = neptune_spi_emit_cmd(spi, channel, die, 0, NEPTUNE_GETINFO, NULL, 0, 12);
  76. spi_txrx(spi);
  77. unsigned cores = upk_u16be(rx, 0);
  78. unsigned version = upk_u16be(rx, 2);
  79. if (version != NEPTUNE_VERSION)
  80. continue;
  81. // Read (and ignore) core status
  82. size_t bytes_to_ignore = cores / 4;
  83. neptune_spi_emit_to_channel(spi, channel, bytes_to_ignore);
  84. spi_emit_nop(spi, bytes_to_ignore);
  85. total_cores += cores;
  86. }
  87. if (!total_cores)
  88. continue;
  89. cgpu = malloc(sizeof(*cgpu));
  90. *cgpu = (struct cgpu_info){
  91. .drv = &neptune_drv,
  92. .device_path = strdup(devpath),
  93. .procs = total_cores,
  94. .threads = prev_cgpu ? 0 : 1,
  95. };
  96. if (!add_cgpu_slave(cgpu, prev_cgpu))
  97. continue;
  98. prev_cgpu = cgpu;
  99. }
  100. return prev_cgpu;
  101. }
  102. static
  103. int neptune_detect_auto(void)
  104. {
  105. if (neptune_detect_one("/dev/spidev1.0"))
  106. return 1;
  107. return 0;
  108. }
  109. static
  110. void neptune_detect(void)
  111. {
  112. generic_detect(&neptune_drv, neptune_detect_one, neptune_detect_auto, GDF_REQUIRE_DNAME | GDF_DEFAULT_NOAUTO);
  113. }
  114. struct device_drv neptune_drv = {
  115. .dname = "neptune",
  116. .name = "NEP",
  117. .drv_detect = neptune_detect,
  118. };