For BFL Monarch, I added experimental underclocking support to cgminer.
Example Usage: the following sets the clock frequency to max (1x), voltage at 580mV.
# cgminer --bflsc-volt=4 --bflsc-clock=16
Refer to BFL documentation for voltage levels, but please note I shifted the index by one; I needed '0' to mean 'do-nothing'. IE: the '16' above = 'F" in BFL docs.
As a safety precaution, cgminer will not initialize / use a Monarch unless the voltage and clock are set successfully. IE: a hotplug or power interruption will restore the voltage/clock settings to a Monarch before mining commences.
The patch below is against cgminer commit 8b425ed545d64f3007c6a7b2b70910efec65a7ea.
htt p s://github.com/ckolivas/cgminer/commit/8b425ed545d64f3007c6a7b2b70910efec65a7ea
----------------
diff --git a/cgminer.c b/cgminer.c
index 94e847e..48db62d 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -796,6 +796,16 @@ static char *set_int_1_to_10(const char *arg, int *i)
return set_int_range(arg, i, 1, 10);
}
+static char *set_int_0_to_32(const char *arg, int *i)
+{
+ return set_int_range(arg, i, 0, 32);
+}
+
+static char *set_int_0_to_16(const char *arg, int *i)
+{
+ return set_int_range(arg, i, 0, 16);
+}
+
static char __maybe_unused *set_int_0_to_4(const char *arg, int *i)
{
return set_int_range(arg, i, 0, 4);
@@ -1265,6 +1275,12 @@ static struct opt_table opt_config_table[] = {
OPT_WITH_ARG("--bflsc-overheat",
set_int_0_to_200, opt_show_intval, &opt_bflsc_overheat,
"Set overheat temperature where BFLSC devices throttle, 0 to disable"),
+ OPT_WITH_ARG("--bflsc-volt",
+ set_int_0_to_16, opt_show_intval, &opt_bflsc_volt,
+ "Set monarch voltage level (1-16), 0 to disable. BFL claims values above 7 are disabled."),
+ OPT_WITH_ARG("--bflsc-clock",
+ set_int_0_to_32, opt_show_intval, &opt_bflsc_clock,
+ "Set monarch clock speed (1-32), 0 to disable, 17-32 enable clock doubler"),
#endif
#ifdef USE_AVALON
OPT_WITH_ARG("--bitburner-voltage",
diff --git a/driver-bflsc.c b/driver-bflsc.c
index ac77d48..7dfd10c 100644
--- a/driver-bflsc.c
+++ b/driver-bflsc.c
@@ -31,6 +31,15 @@
#include "driver-bflsc.h"
int opt_bflsc_overheat = BFLSC_TEMP_OVERHEAT;
+int opt_bflsc_clock = 0;
+int opt_bflsc_volt = 0;
+
+float bflsc_voltage_map[] = {
+ 0.540, 0.550, 0.560, 0.580,
+ 0.600, 0.620, 0.630, 0.643,
+ 0.650, 0.662, 0.670, 0.680,
+ 0.700, 0.720, 0.730, 0.750
+};
static const char *blank = "";
@@ -453,6 +462,7 @@ static bool bflsc_qres(struct cgpu_info *bflsc, char *buf, size_t bufsiz, int de
static void __bflsc_initialise(struct cgpu_info *bflsc)
{
int err, interface;
+ struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data);
// TODO: does x-link bypass the other device FTDI? (I think it does)
// So no initialisation required except for the master device?
@@ -536,6 +546,7 @@ static void __bflsc_initialise(struct cgpu_info *bflsc)
if (!bflsc->cutofftemp)
bflsc->cutofftemp = opt_bflsc_overheat;
+
}
static void bflsc_initialise(struct cgpu_info *bflsc)
@@ -555,6 +566,82 @@ static void bflsc_initialise(struct cgpu_info *bflsc)
}
}
+static bool __bflsc_set_volt(struct cgpu_info *bflsc) {
+ char msg[16];
+ char recv[100];
+ int err,amount;
+ bool sent;
+ int effective_volt;
+
+ if (!opt_bflsc_volt)
+ return true;
+
+ effective_volt=opt_bflsc_volt-1;
+
+ applogsiz(LOG_WARNING, BFLSC_APPLOGSIZ,
+ "%s (%s) set volt to %0.3fV (V%XX) ",
+ bflsc->drv->dname, bflsc->device_path,
+ bflsc_voltage_map[effective_volt], effective_volt);
+
+ snprintf(msg, sizeof(msg), "V%XX\n", effective_volt);
+ err = usb_write(bflsc, msg, strlen(msg), &amount, C_SETVOLT);
+ if (err < 0 || amount < 4) {
+ bflsc_applog(bflsc, 0, C_SETVOLT, amount, err);
+ return false;
+ }
+ err = usb_read_ok_timeout(bflsc, recv, sizeof(recv)-1, &amount, SET_VOLT_TIME_MAX_MS, C_REPLYSETVOLT);
+ if (err < 0 ) {
+ bflsc_applog(bflsc, 0, C_REPLYSETVOLT, amount, err);
+ return false;
+ }
+ return true;
+}
+
+static bool __bflsc_set_clock(struct cgpu_info *bflsc) {
+ char msg[16];
+ char recv[100];
+ int err,amount;
+ bool sent;
+ char double_clock_flag;
+ int effective_clock;
+
+ if (!opt_bflsc_clock)
+ return true;
+
+ effective_clock=opt_bflsc_clock-1;
+ double_clock_flag='X';
+
+ if (effective_clock > 15) {
+ double_clock_flag='D';
+ effective_clock &= 0x0F;
+ if (effective_clock > 2) {
+ applogsiz(LOG_WARNING, BFLSC_APPLOGSIZ,
+ "Frequency too high with clock doubling enabled; reducing frequency.");
+ effective_clock=2;
+ opt_bflsc_clock=19;
+ }
+ }
+
+ applogsiz(LOG_WARNING, BFLSC_APPLOGSIZ,
+ "%s (%s) set clock to %i (F%X%c)",
+ bflsc->drv->dname, bflsc->device_path,
+ opt_bflsc_clock, effective_clock, double_clock_flag);
+
+ snprintf(msg, sizeof(msg), "F%X%c\n", effective_clock, double_clock_flag);
+ err = usb_write(bflsc, msg, strlen(msg), &amount, C_SETCLOCK);
+ if (err < 0 || amount < 4) {
+ bflsc_applog(bflsc, 0, C_SETCLOCK, amount, err);
+ return false;
+ }
+ err = usb_read_ok_timeout(bflsc, recv, sizeof(recv)-1, &amount, SET_CLOCK_TIME_MAX_MS, C_REPLYSETCLOCK);
+ if (err < 0 ) {
+ bflsc_applog(bflsc, 0, C_REPLYSETCLOCK, amount, err);
+ return false;
+ }
+ return true;
+}
+
+
static bool getinfo(struct cgpu_info *bflsc, int dev)
{
struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data);
@@ -894,6 +981,15 @@ reinit:
applog(LOG_DEBUG, "%s (%s) identified as: '%s'",
bflsc->drv->dname, bflsc->device_path, bflsc->drv->name);
+ if (sc_info->ident == IDENT_BMA) {
+ if (!__bflsc_set_volt(bflsc))
+ goto unshin;
+ cgsleep_ms(100); // let voltage stabilize
+ if (!__bflsc_set_clock(bflsc))
+ goto unshin;
+ cgsleep_ms(100); // let clock stabilize
+ }
+
if (!add_cgpu(bflsc))
goto unshin;
diff --git a/driver-bflsc.h b/driver-bflsc.h
index 4778993..50789b0 100644
--- a/driver-bflsc.h
+++ b/driver-bflsc.h
@@ -386,7 +386,13 @@ struct SaveString {
#define REINIT_TIME_MAX_MS 800
// Keep trying up to this many us
#define REINIT_TIME_MAX 3000000
+// How long do we wait for the voltage-set operation? (ms)
+#define SET_VOLT_TIME_MAX_MS 10000
+// How long do we wait for the clock-set operation? (ms)
+#define SET_CLOCK_TIME_MAX_MS 15000
int opt_bflsc_overheat;
+int opt_bflsc_clock;
+int opt_bflsc_volt;
#endif /* BFLSC_H */