jtag: cap the clock by device max_tck_khz at autoinit (phase B)
- fpga_target gains max_tck_khz (registry key), the max safe JTAG TCK for a part/board (0 = unspecified) - jtag_autoinit, after identifying the chain, resolves the clock: if the requested JTAG_TCK_FREQ_KHZ exceeds the smallest device max, it clamps it and re-opens the probe once (stored probe id) to apply, then re-scans; within-cap / unset just report the cap - autoinit body extracted into autoinit_run() so it can re-run after the re-tune; fpga_list shows maxtck Validated on the IGLOO2/FlashPro (req 500 -> clamp 200 -> reopen -> still detected; within-cap and unset paths don't reopen). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1474,7 +1474,13 @@ const char *cmd_autoinit_help[] = {
|
||||
"explanations line two",
|
||||
""
|
||||
};
|
||||
static int cmd_autoinit(script_ctx *ctx, char *line)
|
||||
/* Id of the currently open probe (drv<<8|probe), -1 if none. Lets
|
||||
* jtag_autoinit re-open the same probe to apply a clock re-tune. */
|
||||
static int g_probe_id = -1;
|
||||
|
||||
/* Scan the chain and auto-load matching BSDLs. Returns the number of
|
||||
* BSDLs loaded (>= 0), or a negative JTAG_CORE_* error. */
|
||||
static int autoinit_run(script_ctx *ctx)
|
||||
{
|
||||
jtag_core *jc;
|
||||
int number_of_devices, dev_nb;
|
||||
@@ -1588,9 +1594,86 @@ static int cmd_autoinit(script_ctx *ctx, char *line)
|
||||
return JTAG_CORE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
return loaded_bsdl;
|
||||
}
|
||||
|
||||
/* Smallest device-declared max TCK (kHz) over the matched chain devices,
|
||||
* or 0 if none of them declare one. */
|
||||
static int chain_max_tck_khz(jtag_core *jc)
|
||||
{
|
||||
int i, n, cap = 0;
|
||||
const fpga_target *t;
|
||||
|
||||
n = jtagcore_get_number_of_devices(jc);
|
||||
for (i = 0; i < n; i++) {
|
||||
t = fpga_lookup_by_idcode(jtagcore_get_dev_id(jc, i));
|
||||
if (t && t->max_tck_khz > 0 && (cap == 0 || t->max_tck_khz < cap))
|
||||
cap = t->max_tck_khz;
|
||||
}
|
||||
return cap;
|
||||
}
|
||||
|
||||
static int cmd_autoinit(script_ctx *ctx, char *line)
|
||||
{
|
||||
jtag_core *jc;
|
||||
int loaded, cap, req;
|
||||
|
||||
(void)line;
|
||||
jc = (jtag_core *)ctx->app_ctx;
|
||||
|
||||
loaded = autoinit_run(ctx);
|
||||
if (loaded < 0)
|
||||
return loaded;
|
||||
|
||||
// Phase B: resolve the JTAG clock against the devices now identified.
|
||||
// The registry can cap the TCK for a part/board; if the requested
|
||||
// clock exceeds that, clamp it and re-open the probe so it takes
|
||||
// effect (the chain is then re-scanned at the safe clock).
|
||||
cap = chain_max_tck_khz(jc);
|
||||
req = jtagcore_getEnvVarValue(jc, "JTAG_TCK_FREQ_KHZ");
|
||||
if (cap > 0)
|
||||
{
|
||||
if (req > 0 && req > cap)
|
||||
{
|
||||
char buf[24];
|
||||
snprintf(buf, sizeof(buf), "%d", cap);
|
||||
ctx->script_printf(ctx, MSG_WARNING,
|
||||
"JTAG clock %d kHz exceeds the device max %d kHz; clamping.\n", req, cap);
|
||||
setEnvVarDat((envvar_entry *)ctx->env, "JTAG_TCK_FREQ_KHZ", buf);
|
||||
setEnvVarDat((envvar_entry *)ctx->env, "PROBE_FTDI_TCK_FREQ_KHZ", buf);
|
||||
if (g_probe_id >= 0)
|
||||
{
|
||||
ctx->script_printf(ctx, MSG_INFO_0,
|
||||
"Re-opening at %d kHz and re-scanning.\n", cap);
|
||||
if (jtagcore_select_and_open_probe(jc, g_probe_id) == JTAG_CORE_NO_ERROR)
|
||||
{
|
||||
loaded = autoinit_run(ctx);
|
||||
if (loaded < 0)
|
||||
return loaded;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->script_printf(ctx, MSG_ERROR,
|
||||
"Re-open failed; the clock will apply on the next jtag_open.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->script_printf(ctx, MSG_WARNING,
|
||||
"Reopen the probe (jtag_close / jtag_open) to apply the clamped clock.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->script_printf(ctx, MSG_INFO_0,
|
||||
"Device max JTAG clock: %d kHz%s.\n", cap,
|
||||
(req > 0) ? "" : " (set JTAG_TCK_FREQ_KHZ to control the clock)");
|
||||
}
|
||||
}
|
||||
|
||||
// Expose the count to scripts via last_data_value, but report success
|
||||
// (a non-zero return is treated as an error code by the engine).
|
||||
ctx->last_data_value = loaded_bsdl;
|
||||
ctx->last_data_value = loaded;
|
||||
return JTAG_CORE_NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -1885,6 +1968,7 @@ static int cmd_open_probe(script_ctx *ctx, char *line)
|
||||
}
|
||||
else
|
||||
{
|
||||
g_probe_id = id;
|
||||
ctx->script_printf(ctx, MSG_INFO_0, "Probe Ok !\n");
|
||||
return JTAG_CORE_NO_ERROR;
|
||||
}
|
||||
@@ -1921,6 +2005,7 @@ static int cmd_close_probe(script_ctx *ctx, char *line)
|
||||
// chain looks probe-less until the next jtag_open.
|
||||
jc->io_functions.drv_DeInit(jc);
|
||||
memset(&jc->io_functions, 0, sizeof(jc->io_functions));
|
||||
g_probe_id = -1;
|
||||
ctx->script_printf(ctx, MSG_INFO_0, "Probe released.\n");
|
||||
}
|
||||
else
|
||||
@@ -2909,10 +2994,10 @@ static int cmd_fpga_list(script_ctx *ctx, char *line)
|
||||
i, t->idcode, t->idcode_mask,
|
||||
t->name, fpga_family_name(t->family));
|
||||
ctx->script_printf(ctx, MSG_NONE,
|
||||
" bsdl=%s ir=%d proxy=%s caveats=0x%x\n",
|
||||
" bsdl=%s ir=%d proxy=%s caveats=0x%x maxtck=%dkHz\n",
|
||||
t->bsdl_filename, t->ir_length,
|
||||
t->proxy_bitstream ? t->proxy_bitstream : "(none yet)",
|
||||
t->caveats);
|
||||
t->caveats, t->max_tck_khz);
|
||||
}
|
||||
return JTAG_CORE_NO_ERROR;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user