From ffda68d54ad6832251b139b49a94d9b794b6cdbe Mon Sep 17 00:00:00 2001 From: Steven Dan Date: Thu, 18 Jun 2026 21:59:46 +0800 Subject: [PATCH] DFS for FS control 2 --- .../src/extensions/tile1_clk.h | 5 ++- .../src/extensions/tile1_clk.xc | 43 +++++++++++++++---- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/tile1_clk.h b/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/tile1_clk.h index 7c2ec10..6e4a1ab 100644 --- a/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/tile1_clk.h +++ b/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/tile1_clk.h @@ -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 diff --git a/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/tile1_clk.xc b/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/tile1_clk.xc index 2011b04..bbc69a4 100644 --- a/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/tile1_clk.xc +++ b/sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/tile1_clk.xc @@ -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 ----