Browse Source

antminer: Support for setting BM1382/4 clock by frequency MHz

Luke Dashjr 10 years ago
parent
commit
78f44d2324
4 changed files with 113 additions and 14 deletions
  1. 52 14
      driver-antminer.c
  2. 1 0
      driver-icarus.h
  3. 57 0
      util.c
  4. 3 0
      util.h

+ 52 - 14
driver-antminer.c

@@ -41,6 +41,22 @@ BFG_REGISTER_DRIVER(antminer_drv)
 static
 const struct bfg_set_device_definition antminer_set_device_funcs[];
 
+static const char *bm1382_chips[] = {
+	"BM1382",
+	"BM1384",
+	NULL
+};
+
+static bool antminer_chip_has_bm1382_freq_register(const char * const prodstr)
+{
+	for (const char **chipname = bm1382_chips; chipname; ++chipname) {
+		if (strstr(prodstr, *chipname)) {
+			return true;
+		}
+	}
+	return false;
+}
+
 static
 bool antminer_detect_one(const char *devpath)
 {
@@ -57,6 +73,8 @@ bool antminer_detect_one(const char *devpath)
 		.do_icarus_timing = true,
 		.read_size = 5,
 		.reopen_mode = IRM_NEVER,
+		
+		.has_bm1382_freq_register = antminer_chip_has_bm1382_freq_register(detectone_meta_info.product),
 	};
 	
 	struct cgpu_info * const dev = icarus_detect_custom(devpath, drv, info);
@@ -128,26 +146,35 @@ char *antminer_get_clock(struct cgpu_info *cgpu, char *replybuf)
 static
 const char *antminer_set_clock(struct cgpu_info * const cgpu, const char * const optname, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const out_success)
 {
+	struct ICARUS_INFO * const info = cgpu->device_data;
+	
 	if (!setting || !*setting)
 		return "missing clock setting";
 	
-	// For now we only allow hex values that use BITMAINtech's lookup table
-	// This means values should be prefixed with an x so that later we can
-	// accept and distinguish decimal values
-	if (setting[0] != 'x')
+	uint8_t reg_data[2];
+	
+	if (setting[0] == 'x')
 	{
-		sprintf(replybuf, "invalid clock: '%s' data must be prefixed with an x", setting);
-		return replybuf;
+		// remove leading character
+		const char * const hex_setting = &setting[1];
+		
+		if (!hex2bin(reg_data, hex_setting, sizeof(reg_data)))
+		{
+			sprintf(replybuf, "invalid clock: '%s' data must be a hexadecimal value", hex_setting);
+			return replybuf;
+		}
 	}
-	
-	//remove leading character
-	const char * const hex_setting = &setting[1];
-
-	uint8_t reg_data[4] = {0};
-	
-	if (!hex2bin(reg_data, hex_setting, strlen(hex_setting) / 2))
+	else
+	if (info->has_bm1382_freq_register)
 	{
-		sprintf(replybuf, "invalid clock: '%s' data must be a hexadecimal value", hex_setting);
+		const double mhz = atof(setting);
+		if (!bm1382_freq_to_reg_data(reg_data, mhz)) {
+			return "invalid clock";
+		}
+	}
+	else
+	{
+		sprintf(replybuf, "invalid clock: '%s' data must be prefixed with an x", setting);
 		return replybuf;
 	}
 	
@@ -224,6 +251,16 @@ invalid_voltage:
 	return NULL;
 }
 
+static
+const char *antminer_set_chip(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct ICARUS_INFO * const info = proc->device_data;
+	
+	info->has_bm1382_freq_register = antminer_chip_has_bm1382_freq_register(newvalue);
+	
+	return NULL;
+}
+
 static
 void antminer_flash_led(const struct cgpu_info *antminer)
 {
@@ -255,6 +292,7 @@ bool antminer_identify(struct cgpu_info *antminer)
 
 static
 const struct bfg_set_device_definition antminer_set_device_funcs[] = {
+	{"chip", antminer_set_chip, "chip unit is based on (BM1380, BM1382, etc)"},
 	{"baud"         , icarus_set_baud         , "serial baud rate"},
 	{"work_division", icarus_set_work_division, "number of pieces work is split into"},
 	{"reopen"       , icarus_set_reopen       , "how often to reopen device: never, timeout, cycle, (or now for a one-shot reopen)"},

+ 1 - 0
driver-icarus.h

@@ -129,6 +129,7 @@ struct ICARUS_INFO {
 	// Custom driver functions
 	bool (*detect_init_func)(const char *devpath, int fd, struct ICARUS_INFO *);
 	bool (*job_start_func)(struct thr_info *);
+	bool has_bm1382_freq_register;
 	
 #ifdef USE_DUALMINER
 #ifdef USE_SCRYPT

+ 57 - 0
util.c

@@ -15,6 +15,7 @@
 
 #include "config.h"
 
+#include <float.h>
 #include <math.h>
 #include <stdbool.h>
 #include <stdint.h>
@@ -4045,6 +4046,62 @@ void run_cmd(const char *cmd)
 }
 
 
+#if defined(USE_BITMAIN) || defined(USE_ICARUS)
+bool bm1382_freq_to_reg_data(uint8_t * const out_reg_data, float mhz)
+{
+	// We add 1 so fractions don't interfere with near-integer settings
+	++mhz;
+	
+	if (mhz < 100)
+		return false;
+	float best_delta = FLT_MAX;
+	unsigned best_dc = 0;
+	unsigned try_list[4], *tlp = try_list;
+	if (mhz >= 200) {
+		if (mhz >= 403.125) {
+			*(tlp++) = 0x0101;
+			*(tlp++) = 0x0205;
+		} else {
+			*(tlp++) = 0x0202;
+		}
+		*(tlp++) = 0x0406;
+	} else {
+		*(tlp++) = 0x0403;
+	}
+	*(tlp++) = 0x0807;
+	for (unsigned *tli = try_list; tli < tlp; ++tli) {
+		const float d = *tli >> 8;
+		const float df = 25. / d;
+		unsigned n = mhz / df;
+		// NOTE: 0x3f here is 0x3e in the final register
+		if (n > 0x3f) {
+			n = 0x3f;
+		}
+		const float delta = mhz - (n * df);
+		if (delta < best_delta) {
+			best_delta = delta;
+			best_dc = *tli;
+			if (delta == 0) {
+				break;
+			}
+		}
+	}
+	if (!best_dc)
+		return false;
+	const float d = best_dc >> 8;
+	const float df = 25. / d;
+	const unsigned di = best_dc & 0xff;
+	unsigned n = (mhz / df) - 1;
+	if (n > 0x3e) {
+		n = 0x3e;
+	}
+	const uint16_t reg_num = (n << 7) | di;
+	pk_u16be(out_reg_data, 0, reg_num);
+	return true;
+}
+#endif
+
+
 uint8_t crc5usb(unsigned char *ptr, uint8_t len)
 {
     uint8_t i, j, k;

+ 3 - 0
util.h

@@ -830,6 +830,9 @@ extern char *trimmed_strdup(const char *);
 extern void run_cmd(const char *cmd);
 
 
+extern bool bm1382_freq_to_reg_data(uint8_t *out_reg_data, float mhz);
+
+
 extern uint8_t crc5usb(unsigned char *ptr, uint8_t len);
 extern void bfg_init_checksums(void);
 extern uint8_t crc8ccitt(const void *, size_t);