DFS for FS control 2

This commit is contained in:
Steven Dan
2026-06-18 21:59:46 +08:00
parent aca7163c0a
commit ffda68d54a
2 changed files with 38 additions and 10 deletions

View File

@@ -24,8 +24,9 @@
#if C1_DFS_EN
/* Default low-power divider for tile[1] core clock when idle.
* The register is programmed with (value - 1); result = 600 MHz / N.
* 40 -> ~15 MHz (ds1-proven start point). Sweep lower via SET_TILE1_DIV. */
* Per AN02022 (xcore.ai Clock Frequency Control): the per-tile divider XCDIV is
* programmed with (divide - 1), i.e. tile_clk = SystemFrequency / N.
* 40 -> ~15 MHz (ds1-proven start point). Sweep lower via SET_TILE1_DIV (HID 0xB6). */
#ifndef C1_TILE1_LP_XCORE_DIV_DEFAULT
#define C1_TILE1_LP_XCORE_DIV_DEFAULT 40
#endif

View File

@@ -25,27 +25,54 @@ static timer c1_tile1_tmr;
static unsigned c1_tile1_grace_target = 0;
static int c1_tile1_grace_armed = 0;
/* ---- clock primitives (mirror ds1 enable_tile1_core_divider / up / down) ---- */
/* ---- clock primitives (AN02022 "xcore.ai Clock Frequency Control") ----
*
* We throttle tile[1] ONLY, using the per-tile xcore clock divider
* (XS1_PSWITCH_PLL_CLK_DIVIDER_NUM, field XCDIV). Per AN02022:
*
* tile_clk = SystemFrequency / (XCDIV + 1) (register value = divide - 1)
*
* and "Setting the tile clock divider does not take effect until the tile
* allows the divider to be used, which is achieved by calling
* setps(XS1_PS_XCORE_CTRL0, 0x10)" (XCORE_CTRL0 bit 4).
*
* Scope note (why NOT the AN's "Low power configurations" bypass): that mode
* bypasses the System PLL (XS1_SSWITCH_PLL_CTL_NUM, BYPASS bit) to drop
* PLL_AVDD power to ~0 — but the System PLL is the single node-level PLL
* shared by BOTH tiles, so bypass would also slow tile[0] (USB/I2S/EQ lose
* 600 MHz). It is intentionally NOT used here. The cross-tile PSWITCH writes
* below target tile[1] explicitly and are safe to issue from tile[0], where
* the power state machine (c1_tile1_power_tick) runs. */
/* Local to tile[1]: uses per-core setps/getps. */
/* Program the per-tile divider. `divide` is the desired ratio (>=1). */
static void c1_tile1_set_xcdiv(unsigned divide)
{
if (divide == 0) divide = 1; /* XCDIV = divide - 1; 0 would mean /1 */
write_pswitch_reg(get_tile_id(tile[1]), XS1_PSWITCH_PLL_CLK_DIVIDER_NUM, divide - 1);
}
/* One-time enable. MUST run LOCALLY on tile[1] (uses per-core setps/getps).
* Enables the tile's local divider output so the XCDIV value takes effect. */
void c1_tile1_clk_enable(void)
{
/* Program divider = 1 (full speed), then enable the divider output path
* via XCORE_CTRL0 bit 4. */
write_pswitch_reg(get_tile_id(tile[1]), XS1_PSWITCH_PLL_CLK_DIVIDER_NUM, 1 - 1);
/* XCDIV = 0 (full speed) first, then enable the divider output (bit 4).
* Only set bit 4, preserving the other XCORE_CTRL0 bits — safer than the
* AN's literal setps(...,0x10) which overwrites the whole register. */
c1_tile1_set_xcdiv(1);
unsigned val = getps(XS1_PS_XCORE_CTRL0);
setps(XS1_PS_XCORE_CTRL0, val | (1u << 4));
}
/* Restore tile[1] to full speed: XCDIV = 0 => divide by 1 => 600 MHz. */
void c1_tile1_clock_up(void)
{
write_pswitch_reg(get_tile_id(tile[1]), XS1_PSWITCH_PLL_CLK_DIVIDER_NUM, 1 - 1); /* /1 => 600 MHz */
c1_tile1_set_xcdiv(1);
}
/* Throttle tile[1] core clock to SystemFrequency / div. */
void c1_tile1_clock_down(unsigned div)
{
if (div == 0) div = 1;
write_pswitch_reg(get_tile_id(tile[1]), XS1_PSWITCH_PLL_CLK_DIVIDER_NUM, div - 1);
c1_tile1_set_xcdiv(div);
}
/* ---- policy tick ----