add DFS for FS control
This commit is contained in:
@@ -1 +1 @@
|
||||
xflash bin/factory/phaten_module_factory.xe --loader loader.o --upgrade 2 bin/fps_uac1/phaten_module_fps_uac1.xe --upgrade 6 ../app_usb_aud_fosi_c1_lp/bin/bypass_uac1/phaten_module_bypass_uac1.xe -o %1
|
||||
xflash bin/factory/phaten_module_factory.xe --loader loader.o --upgrade 2 bin/fps_uac1/phaten_module_fps_uac1.xe -o %1
|
||||
|
||||
@@ -1 +1 @@
|
||||
xflash --factory-version 15.3 --target-file src/core/xu316_qf60.xn --upgrade 2 bin/fps_uac1/phaten_module_fps_uac1.xe --upgrade 6 ../app_usb_aud_fosi_c1_lp/bin/bypass_uac1/phaten_module_bypass_uac1.xe -o %1
|
||||
xflash --factory-version 15.3 --target-file src/core/xu316_qf60.xn --upgrade 2 bin/fps_uac1/phaten_module_fps_uac1.xe -o %1
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "roleswitchflag.h"
|
||||
#include "xua_hid_report.h"
|
||||
#include "nau88c21.h"
|
||||
#include "tile1_clk.h"
|
||||
#if MQA_EN
|
||||
#include "MQA_XMOS.h"
|
||||
#endif
|
||||
@@ -187,6 +188,18 @@ static inline unsigned c1_mode_to_tile_mode_led_code(unsigned mode_value)
|
||||
|
||||
void switch_mode_by_c1_mode(unsigned c1_mode, unsigned force_reboot)
|
||||
{
|
||||
#if C1_DFS_EN
|
||||
/* 动态降频 / c1_no_mode_switch: FPS on/off is a runtime toggle (no reboot,
|
||||
* no role-switch flag). tile[1] clock follows via c1_tile1_power_tick().
|
||||
* c1_mode 4 = FPS (g_3d_fps=1); otherwise BYPASS (g_3d_fps=0). */
|
||||
(void)force_reboot;
|
||||
{
|
||||
unsigned fps_val = (c1_mode == 4) ? 1u : 0u;
|
||||
SET_SHARED_GLOBAL(g_3d_fps, fps_val);
|
||||
debug_printf("switch_mode_by_c1_mode: c1_mode=%d -> g_3d_fps=%d (no reboot)\n", c1_mode, fps_val);
|
||||
}
|
||||
return;
|
||||
#else
|
||||
unsigned reboot_need = 0;
|
||||
#if UAC1_MODE == 0
|
||||
switch (c1_mode)
|
||||
@@ -248,9 +261,10 @@ void switch_mode_by_c1_mode(unsigned c1_mode, unsigned force_reboot)
|
||||
if (reboot_need || force_reboot)
|
||||
{
|
||||
delay_milliseconds(200);
|
||||
device_reboot();
|
||||
while (1);
|
||||
//device_reboot();
|
||||
// while (1);
|
||||
}
|
||||
#endif /* !C1_DFS_EN: original image-swap + reboot path (factory / non-FPS) */
|
||||
}
|
||||
|
||||
#define NAU88L21_PGA_GAIN_REG_MIN_USED_VALUE 0x0 // 0x1=1, 0dB (0x0, -1dB which is not used in this design)
|
||||
@@ -439,6 +453,7 @@ uint8_t samp_support(unsigned samFreq)
|
||||
|
||||
void dac_volume(signed level, client interface i2c_master_if i2c)
|
||||
{
|
||||
|
||||
// 1dB/步: level 范围 -28 ~ 0,对应寄存器 0xcf-28=0xb3 ~ 0xcf
|
||||
|
||||
|
||||
@@ -1465,6 +1480,10 @@ void AudioHwRemote2(streaming chanend c, client interface i2c_master_if i2c, cli
|
||||
|
||||
g_last_game_mode = current_game_mode;
|
||||
|
||||
#if C1_DFS_EN
|
||||
/* 动态降频: evaluate tile[1] power state each periodic tick. */
|
||||
c1_tile1_power_tick();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1974,6 +1993,11 @@ void app_control_slave(server interface c1_led_ctrl_if i_c1_led_ctrl)
|
||||
unsigned mic_mute_switch = 1;
|
||||
c1_panel_leds_force_all_off_hw();
|
||||
|
||||
#if C1_DFS_EN
|
||||
/* 动态降频: enable tile[1] core divider output path (local setps; must run on tile[1]). */
|
||||
c1_tile1_clk_enable();
|
||||
#endif
|
||||
|
||||
unsigned eq_mode_time = 0;
|
||||
timer eq_mode_timer;
|
||||
eq_mode_timer :> eq_mode_time;
|
||||
|
||||
@@ -5,13 +5,20 @@
|
||||
#include "gpio_access.h"
|
||||
#include "xc_ptr.h"
|
||||
#include "debug_print.h"
|
||||
#include "tile1_clk.h"
|
||||
|
||||
extern unsigned g_mute_enable, g_unmute_time;
|
||||
extern unsigned g_unmute_dac_state;
|
||||
#if C1_DFS_EN
|
||||
extern unsigned g_audio_streaming; /* tile1_clk.xc: 1 while USB audio streaming */
|
||||
#endif
|
||||
unsigned long get_reference_time();
|
||||
void UserAudioStreamStart(void)
|
||||
{
|
||||
unsigned long time = get_reference_time();
|
||||
#if C1_DFS_EN
|
||||
SET_SHARED_GLOBAL(g_audio_streaming, 1);
|
||||
#endif
|
||||
SET_SHARED_GLOBAL(g_unmute_dac_state, 1);
|
||||
SET_SHARED_GLOBAL(g_unmute_time, time);
|
||||
debug_printf("UserAudioStreamStart\n");
|
||||
@@ -19,6 +26,9 @@ void UserAudioStreamStart(void)
|
||||
|
||||
void UserAudioStreamStop(void)
|
||||
{
|
||||
#if C1_DFS_EN
|
||||
SET_SHARED_GLOBAL(g_audio_streaming, 0);
|
||||
#endif
|
||||
unsigned enable_mute;
|
||||
debug_printf("UserAudioStreamStop\n");
|
||||
//SET_SHARED_GLOBAL(g_unmute_dac_state, 0);
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
void device_reboot(void);
|
||||
extern void SetRoleSwitchFlag(unsigned mode);
|
||||
extern unsigned g_3d_fps;
|
||||
#include "tile1_clk.h"
|
||||
#if C1_DFS_EN
|
||||
extern unsigned g_tile1_lp_div; /* tile1_clk.xc: tile[1] low-power divider (动态降频) */
|
||||
#endif
|
||||
#if DEBUG_MEMORY_LOG_ENABLED
|
||||
unsigned g_log_switch = 1;
|
||||
#else
|
||||
@@ -148,6 +152,9 @@ static struct {
|
||||
bool is_get_mute_switch_request; // 改动原因:添加获取静音开关请求标志,用于GET_MUTE_SWITCH (0xB2),值由MCU通过UART 0x5F返回
|
||||
bool is_get_listen_switch_request; // 改动原因:添加获取监听开关请求标志,用于GET_LISTEN_SWITCH (0xB4),直接读 g_adc_loop
|
||||
bool is_get_dnr_enable_request; // 改动原因:添加获取AI通话降噪请求标志,用于GET_DNR_ENABLE (0xB5),直接读 g_dnr_enable
|
||||
#if C1_DFS_EN
|
||||
bool is_get_tile1_div_request; // 改动原因:动态降频,获取tile1分频值请求标志,用于GET_TILE1_DIV (0xB7)
|
||||
#endif
|
||||
int32_t post_gain_db;
|
||||
} read_request = {0};
|
||||
|
||||
@@ -1534,6 +1541,26 @@ unsigned char process_send_params(uint8_t data[], uint16_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if C1_DFS_EN
|
||||
// 处理设置tile1动态降频分频值命令 (0xB6) - SET_TILE1_DIV
|
||||
// 改动原因:动态降频,主机设置tile1低功耗分频值(600MHz/N);状态机下次降频或当前已降频时生效
|
||||
if (data[1] == 0xB6) {
|
||||
uint8_t div = data[2];
|
||||
if (div == 0) div = 1; // 防止除0,最小分频1(全速)
|
||||
SET_SHARED_GLOBAL(g_tile1_lp_div, div);
|
||||
debug_printf("Received SET_TILE1_DIV (0xB6), g_tile1_lp_div=%u\n", div);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 处理获取tile1动态降频分频值命令 (0xB7) - GET_TILE1_DIV
|
||||
// 改动原因:动态降频,返回当前 g_tile1_lp_div
|
||||
if (data[1] == 0xB7) {
|
||||
debug_printf("Received get tile1 divider command (GET_TILE1_DIV) via HID 0xB7\n");
|
||||
read_request.is_get_tile1_div_request = true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 处理获取当前UAC模式命令 (0x9C) - GET_CURRENT_UAC_MODE
|
||||
// 改动原因:添加当前UAC模式查询命令,返回当前UAC模式值和名称
|
||||
if (data[1] == 0x9C) {
|
||||
@@ -3170,6 +3197,22 @@ unsigned char process_read_params(uint8_t response[]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if C1_DFS_EN
|
||||
// 处理获取tile1动态降频分频值请求 (0xB7) - GET_TILE1_DIV
|
||||
// 改动原因:动态降频,返回当前 g_tile1_lp_div(600MHz/N 的 N 值)
|
||||
if (read_request.is_get_tile1_div_request == true) {
|
||||
unsigned tile1_div;
|
||||
GET_SHARED_GLOBAL(tile1_div, g_tile1_lp_div);
|
||||
response[0] = 0x77;
|
||||
response[1] = 0xB7;
|
||||
response[2] = (uint8_t)(tile1_div & 0xFF);
|
||||
for (int i = 3; i < 63; i++) response[i] = 0x00;
|
||||
read_request.is_get_tile1_div_request = false;
|
||||
debug_printf("Building 0xB7 response (GET_TILE1_DIV), g_tile1_lp_div=%u\n", tile1_div);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (read_request.is_read_request == true) {
|
||||
#if 1 // 改动原因:fosi_c1 使用 -DUAC1=1 编译,原 #if !UAC1 导致 0x8E 读EQ参数在 HID GET_REPORT 时永不组包,eq_designer 收到全零响应
|
||||
debug_printf("Read request information:\n");
|
||||
|
||||
@@ -710,6 +710,31 @@ class EQDesigner(QMainWindow):
|
||||
|
||||
left_content_layout.addWidget(device_mode_group)
|
||||
|
||||
# 添加动态降频控制组(HID 0xB6 设置 / 0xB7 获取 tile1 低功耗分频值,仅 FPS 镜像 C1_DFS_EN 生效)
|
||||
dfs_group = QGroupBox("动态降频 (tile1分频)")
|
||||
self.ui_groups['dfs'] = dfs_group
|
||||
dfs_layout = QFormLayout(dfs_group)
|
||||
dfs_control_layout = QHBoxLayout()
|
||||
self.dfs_div_label = QLabel("分频值N:")
|
||||
self.dfs_div_spin = QSpinBox()
|
||||
self.dfs_div_spin.setRange(1, 255)
|
||||
self.dfs_div_spin.setValue(40) # 默认40,约15MHz(与固件 C1_TILE1_LP_XCORE_DIV_DEFAULT 一致)
|
||||
self.dfs_div_spin.setSuffix(" (600MHz/N)")
|
||||
dfs_control_layout.addWidget(self.dfs_div_label)
|
||||
dfs_control_layout.addWidget(self.dfs_div_spin)
|
||||
dfs_layout.addRow(dfs_control_layout)
|
||||
self.current_dfs_label = QLabel("当前分频: 未获取")
|
||||
dfs_layout.addRow("当前分频:", self.current_dfs_label)
|
||||
dfs_btn_layout = QHBoxLayout()
|
||||
self.set_dfs_btn = QPushButton("设置分频")
|
||||
self.set_dfs_btn.clicked.connect(self.on_set_tile1_div)
|
||||
self.get_dfs_btn = QPushButton("读取分频")
|
||||
self.get_dfs_btn.clicked.connect(self.on_get_tile1_div)
|
||||
dfs_btn_layout.addWidget(self.set_dfs_btn)
|
||||
dfs_btn_layout.addWidget(self.get_dfs_btn)
|
||||
dfs_layout.addRow(dfs_btn_layout)
|
||||
left_content_layout.addWidget(dfs_group)
|
||||
|
||||
# Log控制组(0x70 SET_LOG_SWITCH,0=关闭 1=开启),便于在视图菜单中显示/隐藏
|
||||
log_group = QGroupBox("Log控制")
|
||||
self.ui_groups['log_switch'] = log_group
|
||||
@@ -1073,7 +1098,8 @@ class EQDesigner(QMainWindow):
|
||||
'mute_switch': '静音开关',
|
||||
'listen_switch': '监听开关',
|
||||
'eq_enable': 'EQ使能控制',
|
||||
'firmware': '固件升级'
|
||||
'firmware': '固件升级',
|
||||
'dfs': '动态降频'
|
||||
}
|
||||
|
||||
# 为每组创建切换可见性的动作
|
||||
@@ -1109,6 +1135,8 @@ class EQDesigner(QMainWindow):
|
||||
'firmware': '固件升级'
|
||||
}
|
||||
name = group_names.get(group_key, group_key)
|
||||
if name == group_key and group_key == 'dfs':
|
||||
name = '动态降频' # 动态降频组未在上方 dict 中,补回中文名
|
||||
self.view_actions[group_key].setText(f"{'显示' if visible else '隐藏'} {name}")
|
||||
|
||||
def create_initial_filter(self):
|
||||
@@ -1260,6 +1288,58 @@ class EQDesigner(QMainWindow):
|
||||
h.close()
|
||||
|
||||
|
||||
def on_set_tile1_div(self):
|
||||
"""设置tile1动态降频分频值(发送0xB6命令)"""
|
||||
if self.device_combo.currentData() is None:
|
||||
log_message(LOG_LEVEL_ERROR, "请先选择设备", self.log_level)
|
||||
return
|
||||
div = self.dfs_div_spin.value()
|
||||
device_info = self.device_combo.currentData()
|
||||
try:
|
||||
h = hid.device()
|
||||
h.open(device_info['vendor_id'], device_info['product_id'])
|
||||
h.set_nonblocking(1)
|
||||
data = bytearray(63)
|
||||
data[0] = 0x77 # 同步头1
|
||||
data[1] = 0xB6 # 命令码 SET_TILE1_DIV
|
||||
data[2] = div & 0xFF
|
||||
log_message(LOG_LEVEL_INFO, f"设置 tile1 动态降频分频值 N={div} (约 {600.0/div:.2f} MHz)", self.log_level)
|
||||
h.write([0x01] + list(data))
|
||||
h.close()
|
||||
except Exception as e:
|
||||
log_message(LOG_LEVEL_ERROR, f"设置分频时出错: {str(e)}", self.log_level)
|
||||
|
||||
def on_get_tile1_div(self):
|
||||
"""获取tile1动态降频分频值(发送0xB7命令并读取响应)"""
|
||||
if self.device_combo.currentData() is None:
|
||||
log_message(LOG_LEVEL_ERROR, "请先选择设备", self.log_level)
|
||||
return
|
||||
device_info = self.device_combo.currentData()
|
||||
try:
|
||||
h = hid.device()
|
||||
h.open(device_info['vendor_id'], device_info['product_id'])
|
||||
h.set_nonblocking(1)
|
||||
data = bytearray(63)
|
||||
data[0] = 0x77 # 同步头1
|
||||
data[1] = 0xB7 # 命令码 GET_TILE1_DIV
|
||||
h.write([0x01] + list(data))
|
||||
import time
|
||||
time.sleep(0.05) # 等待设备响应
|
||||
reply = h.get_input_report(0x1, 64)
|
||||
h.close()
|
||||
if reply and len(reply) == 64 and reply[0] == 0x01 and reply[1] == 0x77 and reply[2] == 0xB7:
|
||||
div = reply[3]
|
||||
self.dfs_div_spin.setValue(div if div > 0 else 1)
|
||||
if div > 0:
|
||||
self.current_dfs_label.setText(f"当前分频: {div} (约 {600.0/div:.2f} MHz)")
|
||||
else:
|
||||
self.current_dfs_label.setText(f"当前分频: {div}")
|
||||
log_message(LOG_LEVEL_INFO, f"获取 tile1 分频值 N={div}", self.log_level)
|
||||
else:
|
||||
log_message(LOG_LEVEL_ERROR, f"无效的0xB7响应: {reply[:4] if reply else 'None'}", self.log_level)
|
||||
except Exception as e:
|
||||
log_message(LOG_LEVEL_ERROR, f"获取分频时出错: {str(e)}", self.log_level)
|
||||
|
||||
def update_eq_curve(self):
|
||||
"""更新EQ响应曲线"""
|
||||
try:
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
| 0xB2 | GET_MUTE_SWITCH | 获取静音开关状态 | 主机→设备 | 读取静音开关状态(0=关,1=开),设备通过串口向MCU请求后返回 |
|
||||
| 0xB3 | SET_LISTEN_SWITCH | 设置监听开关 | 主机→设备 | 设置监听开关(0=关,1=开),通过UART 0x60透传给MCU |
|
||||
| 0xB4 | GET_LISTEN_SWITCH | 获取监听开关状态 | 主机→设备 | 读取监听开关状态(0=关,1=开),直接返回 g_adc_loop 的值,不经过串口 |
|
||||
| 0xB6 | SET_TILE1_DIV | 设置tile1动态降频分频值 | 主机→设备 | 设置tile1低功耗分频值N(core clock=600MHz/N),仅FPS镜像(C1_DFS_EN)生效,tile1空闲时降频 |
|
||||
| 0xB7 | GET_TILE1_DIV | 获取tile1动态降频分频值 | 主机→设备 | 读取当前tile1低功耗分频值N(动态降频),仅FPS镜像(C1_DFS_EN)生效 |
|
||||
|
||||
### 1.3 数据包格式
|
||||
- **Report ID**: 0x01 (HID报告ID)
|
||||
@@ -981,6 +983,54 @@
|
||||
|
||||
**状态变化上报**: 当监听开关状态(g_adc_loop)发生变化时,设备会主动通过 HID 上报,数据格式与上述响应一致(0x77 0xB4 + 1 字节监听状态),与音量变化上报(0x94)方式相同,主机可通过 HID 读或中断 IN 获取。
|
||||
|
||||
### 2.35 0xB6 - SET_TILE1_DIV (设置tile1动态降频分频值)
|
||||
**功能**: 设置 tile[1] 动态降频(动态降频)的低功耗分频值 N。tile[1] core clock = 600 MHz / N。
|
||||
**方向**: 主机→设备
|
||||
**数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0xB6 | 命令码
|
||||
2 | 1 | uint8 | 分频值 N (1-255,0视为1;N=1为全速600MHz,N=40约15MHz)
|
||||
3-62 | 60 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**设备端处理**:
|
||||
- 仅在 FPS 镜像(编译宏 `C1_DFS_EN=1`,默认等于 `XMOS_FPS_EN`)生效;其它镜像(如 factory)忽略此命令。
|
||||
- 写入全局 `g_tile1_lp_div`。tile[1] 电源状态机下次进入 CLOCKED_DOWN(FPS 关闭或音频流停止、grace 超时后)时按此分频值降频;若当前已处于 CLOCKED_DOWN,则下次状态机 tick 立即按新值重写分频寄存器。
|
||||
- 全速运行(FPS 开启且音频流活跃)时不影响 tile[1] 实时时钟,仅更新待用分频值。
|
||||
|
||||
**返回值**:
|
||||
无直接返回值。如需确认,请使用 GET_TILE1_DIV (0xB7) 读取当前分频值。
|
||||
|
||||
### 2.36 0xB7 - GET_TILE1_DIV (获取tile1动态降频分频值)
|
||||
**功能**: 读取 tile[1] 动态降频当前的低功耗分频值 N。
|
||||
**方向**: 主机→设备
|
||||
**请求数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x77 | 同步头1
|
||||
1 | 1 | 0xB7 | 命令码
|
||||
2-62 | 61 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**响应数据包格式**:
|
||||
```
|
||||
字节位置 | 长度 | 内容 | 描述
|
||||
---------|------|------|------
|
||||
0 | 1 | 0x01 | Report ID
|
||||
1 | 1 | 0x77 | 同步头1
|
||||
2 | 1 | 0xB7 | 同步头2
|
||||
3 | 1 | uint8 | 当前分频值 N (1-255)
|
||||
4-62 | 59 | 0x00 | 保留字节
|
||||
```
|
||||
|
||||
**设备端处理**:
|
||||
- 仅在 FPS 镜像(`C1_DFS_EN=1`)生效,返回 `g_tile1_lp_div`。
|
||||
- 注意:返回的 N 为"待用/当前低功耗分频值",并非实时核心频率读数;tile[1] 是否实际处于降频状态取决于 FPS 开关与音频流状态(FPS 关闭或音频停止后才会真正降频)。
|
||||
|
||||
## 5. 关键特性
|
||||
|
||||
### 5.1 设备端系数计算
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "asrc_timestamp_interpolation.h"
|
||||
#include "debug_print.h"
|
||||
#include "xc_ptr.h"
|
||||
#include "tile1_clk.h"
|
||||
|
||||
#if BR_UAC2
|
||||
unsigned g_3d_fps = 2;
|
||||
@@ -68,6 +69,9 @@ extern void buffer_exchange(chanend c_data, unsigned sampsFromUsbToAudio[], unsi
|
||||
void dnr_exchange_buffer(int32_t * unsafe data);
|
||||
extern unsigned g_dnr_enable;
|
||||
extern unsigned g_adc_loop;
|
||||
#if C1_DFS_EN
|
||||
extern unsigned g_tile1_audio_ready; /* tile1_clk.xc: state-machine output */
|
||||
#endif
|
||||
#if UAC1
|
||||
#pragma unsafe arrays
|
||||
|
||||
@@ -86,13 +90,20 @@ void UserBufferManagement(unsigned sampsFromUsbToAudio[], unsigned sampsFromAudi
|
||||
|
||||
unsigned tmp = sampsFromUsbToAudio[0];
|
||||
|
||||
unsigned tile1_ready = 1; /* default (no DFS): always send to tile[1] */
|
||||
#if C1_DFS_EN
|
||||
GET_SHARED_GLOBAL(tile1_ready, g_tile1_audio_ready);
|
||||
#endif
|
||||
|
||||
if (l_3d_fps == 2)
|
||||
{
|
||||
buffer_exchange((chanend) uc_br_data, sampsFromUsbToAudio, sampsFromAudioToUsb, NUM_USB_CHAN_OUT);
|
||||
if (tile1_ready)
|
||||
buffer_exchange((chanend) uc_br_data, sampsFromUsbToAudio, sampsFromAudioToUsb, NUM_USB_CHAN_OUT);
|
||||
}
|
||||
else if (l_3d_fps == 1)
|
||||
{
|
||||
buffer_exchange((chanend)uc_br_data, sampsFromUsbToAudio, sampsFromAudioToUsb, 2);
|
||||
if (tile1_ready)
|
||||
buffer_exchange((chanend)uc_br_data, sampsFromUsbToAudio, sampsFromAudioToUsb, 2);
|
||||
}
|
||||
|
||||
if (dnr_enable)
|
||||
|
||||
@@ -11,8 +11,12 @@
|
||||
#define EP0_MAX_REQUEST_SIZE 2048
|
||||
#include "xud.h"
|
||||
#include "vendorrequests.h"
|
||||
#include "tile1_clk.h"
|
||||
|
||||
unsigned g_host_os = 0; // 1 -> Windows, 0 -> Others
|
||||
#if C1_DFS_EN
|
||||
extern unsigned g_tile1_lp_div; /* tile1_clk.xc: tile[1] low-power divider */
|
||||
#endif
|
||||
|
||||
|
||||
int VendorAudioRequests(XUD_ep ep0_out, XUD_ep ep0_in, unsigned char bRequest, unsigned char cs, unsigned char cn,
|
||||
@@ -36,6 +40,15 @@ int VendorRequests(XUD_ep ep0_out, XUD_ep ep0_in, REFERENCE_PARAM(USB_SetupPacke
|
||||
//SET_SHARED_GLOBAL(g_host_os, k);
|
||||
switch ((sp->bmRequestType.Direction << 7) | (sp->bmRequestType.Type << 5) | (sp->bmRequestType.Recipient)) {
|
||||
case USB_BMREQ_H2D_VENDOR_DEV:
|
||||
#if C1_DFS_EN
|
||||
if (sp->bRequest == 0xF0) { /* SET_TILE1_DIV: wValue = divider N */
|
||||
unsigned div = sp->wValue;
|
||||
SET_SHARED_GLOBAL(g_tile1_lp_div, div);
|
||||
/* Applied on next power tick (or immediately while CLOCKED_DOWN). */
|
||||
result = XUD_DoSetRequestStatus(ep0_in);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
result = XUD_GetBuffer(ep0_out, request_data, len);
|
||||
if (result == XUD_RES_OKAY) {
|
||||
if (a/*control_process_usb_set_request(sp.wIndex, sp.wValue, sp.wLength, request_data, i_control) == CONTROL_SUCCESS*/) {
|
||||
@@ -50,6 +63,16 @@ int VendorRequests(XUD_ep ep0_out, XUD_ep ep0_in, REFERENCE_PARAM(USB_SetupPacke
|
||||
break;
|
||||
|
||||
case USB_BMREQ_D2H_VENDOR_DEV:
|
||||
#if C1_DFS_EN
|
||||
if (sp->bRequest == 0xF1) { /* GET_TILE1_DIV -> returns current N */
|
||||
unsigned div;
|
||||
GET_SHARED_GLOBAL(div, g_tile1_lp_div);
|
||||
request_data[0] = (unsigned char)div;
|
||||
request_data[1] = (unsigned char)(div >> 8);
|
||||
result = XUD_DoGetRequest(ep0_out, ep0_in, request_data, 2, sp->wLength);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
/* application retrieval latency inside the control library call
|
||||
* XUD task defers further calls by NAKing USB transactions
|
||||
*/
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
#include <platform.h>
|
||||
|
||||
void power_down()
|
||||
{
|
||||
#if (LOW_POWER_EN == 1)
|
||||
// Give the software 10 seconds to start up, then apply power optimisations below.
|
||||
timer tmr;
|
||||
int t;
|
||||
tmr :> t;
|
||||
tmr when timerafter(t+1000000000) :> void;
|
||||
|
||||
// Reduce switch clock frequency
|
||||
// write_node_config_reg(tile[0], XS1_SSWITCH_CLK_DIVIDER_NUM, 4);
|
||||
write_node_config_reg(tile[1], XS1_SSWITCH_CLK_DIVIDER_NUM, 4);
|
||||
//
|
||||
// // Reduce core 0 clock frequency (to 9 MHz)
|
||||
// // Note, to completely disable, use:
|
||||
// // write_tile_config_reg(tile[0], XS1_PSWITCH_PLL_CLK_DIVIDER_NUM, 0x80000000);
|
||||
// write_tile_config_reg(tile[0], XS1_PSWITCH_PLL_CLK_DIVIDER_NUM, 0x00000040);
|
||||
write_tile_config_reg(tile[1], XS1_PSWITCH_PLL_CLK_DIVIDER_NUM, 0x00000040);
|
||||
|
||||
setps(XS1_PS_XCORE_CTRL0, 0x10);
|
||||
#endif
|
||||
}
|
||||
60
sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/tile1_clk.h
Normal file
60
sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/tile1_clk.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#ifndef _TILE1_CLK_H_
|
||||
#define _TILE1_CLK_H_
|
||||
|
||||
/* =====================================================================
|
||||
* tile1_clk.h -- tile[1] dynamic frequency scaling (动态降频)
|
||||
*
|
||||
* Divides tile[1]'s core PLL clock down when the tile is idle (FPS off or
|
||||
* audio not streaming) and restores full speed before audio flows back to
|
||||
* tile[1]. Ported from ds1 power_down.xc.
|
||||
*
|
||||
* Master enable: C1_DFS_EN. Defaults to the FPS build only (XMOS_FPS_EN),
|
||||
* so factory / other targets compile nothing and are unaffected.
|
||||
* Override on the command line (-DC1_DFS_EN=0/1) if needed.
|
||||
* ===================================================================== */
|
||||
|
||||
#ifndef C1_DFS_EN
|
||||
# ifdef XMOS_FPS_EN
|
||||
# define C1_DFS_EN XMOS_FPS_EN
|
||||
# else
|
||||
# define C1_DFS_EN 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#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. */
|
||||
#ifndef C1_TILE1_LP_XCORE_DIV_DEFAULT
|
||||
#define C1_TILE1_LP_XCORE_DIV_DEFAULT 40
|
||||
#endif
|
||||
|
||||
/* ~100 us settle after restoring full speed (100 MHz timer ticks). */
|
||||
#define C1_TILE1_CLK_SETTLE_TICKS 10000
|
||||
|
||||
/* Grace period before clocking down once tile[1] is unneeded (~1000 ms). */
|
||||
#define C1_TILE1_SHUTDOWN_GRACE_TICKS 100000000
|
||||
|
||||
/* Power state machine states. */
|
||||
#define C1_TILE1_ACTIVE 0
|
||||
#define C1_TILE1_PENDING_SHUTDOWN 1
|
||||
#define C1_TILE1_CLOCKED_DOWN 2
|
||||
|
||||
/* One-time enable of the tile[1] core divider output path. MUST run on tile[1]. */
|
||||
void c1_tile1_clk_enable(void);
|
||||
|
||||
/* Restore tile[1] to full speed (divider = 1). Cross-tile safe (run from tile[0]). */
|
||||
void c1_tile1_clock_up(void);
|
||||
|
||||
/* Throttle tile[1] core clock to 600 MHz / div. Cross-tile safe. */
|
||||
void c1_tile1_clock_down(unsigned div);
|
||||
|
||||
/* Periodic power-policy tick (call from AudioHwRemote2 periodic loop, tile[0]).
|
||||
* Owns the ACTIVE/PENDING_SHUTDOWN/CLOCKED_DOWN machine and the
|
||||
* g_tile1_audio_ready gate that UserBufferManagement checks before sending
|
||||
* audio to tile[1]. */
|
||||
void c1_tile1_power_tick(void);
|
||||
|
||||
#endif /* C1_DFS_EN */
|
||||
#endif /* _TILE1_CLK_H_ */
|
||||
113
sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/tile1_clk.xc
Normal file
113
sw_usb_audio/app_usb_aud_fosi_c1/src/extensions/tile1_clk.xc
Normal file
@@ -0,0 +1,113 @@
|
||||
/* =====================================================================
|
||||
* tile1_clk.xc -- tile[1] dynamic frequency scaling (动态降频)
|
||||
* Ported from ds1 power_down.xc; guarded by C1_DFS_EN (FPS build only).
|
||||
* In non-FPS builds this translation unit compiles to nothing.
|
||||
* ===================================================================== */
|
||||
|
||||
#include <platform.h>
|
||||
#include <xs1.h>
|
||||
#include "xua.h"
|
||||
#include "xc_ptr.h"
|
||||
#include "tile1_clk.h"
|
||||
|
||||
#if C1_DFS_EN
|
||||
|
||||
/* ---- policy globals (tile[0]); accessed elsewhere via GET/SET_SHARED_GLOBAL ---- */
|
||||
unsigned g_audio_streaming = 0; /* 1 while USB audio is streaming */
|
||||
unsigned g_tile1_audio_ready = 0; /* state-machine output: 1 => tile[0] may send to tile[1] */
|
||||
unsigned g_tile1_lp_div = C1_TILE1_LP_XCORE_DIV_DEFAULT;
|
||||
|
||||
extern unsigned g_3d_fps; /* defined in extra_i2s.xc: 0=bypass, 1=FPS */
|
||||
|
||||
/* ---- state (tile[0]) ---- */
|
||||
static unsigned c1_tile1_state = C1_TILE1_ACTIVE;
|
||||
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) ---- */
|
||||
|
||||
/* Local to tile[1]: uses per-core setps/getps. */
|
||||
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);
|
||||
unsigned val = getps(XS1_PS_XCORE_CTRL0);
|
||||
setps(XS1_PS_XCORE_CTRL0, val | (1u << 4));
|
||||
}
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* ---- policy tick ----
|
||||
* Invariants:
|
||||
* - restore-before-send: clock_up + settle BEFORE g_tile1_audio_ready = 1.
|
||||
* - bypass-before-slow: g_tile1_audio_ready = 0 BEFORE clock_down. */
|
||||
void c1_tile1_power_tick(void)
|
||||
{
|
||||
unsigned fps, aud_stream;
|
||||
GET_SHARED_GLOBAL(fps, g_3d_fps);
|
||||
GET_SHARED_GLOBAL(aud_stream, g_audio_streaming);
|
||||
int tile1_needed = (fps != 0) && (aud_stream != 0);
|
||||
|
||||
switch (c1_tile1_state)
|
||||
{
|
||||
case C1_TILE1_ACTIVE:
|
||||
if (!tile1_needed)
|
||||
{
|
||||
SET_SHARED_GLOBAL(g_tile1_audio_ready, 0); /* bypass-before-slow */
|
||||
unsigned now; c1_tile1_tmr :> now;
|
||||
c1_tile1_grace_target = now + C1_TILE1_SHUTDOWN_GRACE_TICKS;
|
||||
c1_tile1_grace_armed = 1;
|
||||
c1_tile1_state = C1_TILE1_PENDING_SHUTDOWN;
|
||||
}
|
||||
break;
|
||||
|
||||
case C1_TILE1_PENDING_SHUTDOWN:
|
||||
if (tile1_needed)
|
||||
{
|
||||
/* Clock still up; just re-arm audio. */
|
||||
c1_tile1_grace_armed = 0;
|
||||
SET_SHARED_GLOBAL(g_tile1_audio_ready, 1);
|
||||
c1_tile1_state = C1_TILE1_ACTIVE;
|
||||
}
|
||||
else if (c1_tile1_grace_armed)
|
||||
{
|
||||
unsigned now; c1_tile1_tmr :> now;
|
||||
if ((int)(now - c1_tile1_grace_target) >= 0)
|
||||
{
|
||||
c1_tile1_grace_armed = 0;
|
||||
c1_tile1_clock_down(g_tile1_lp_div);
|
||||
c1_tile1_state = C1_TILE1_CLOCKED_DOWN;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case C1_TILE1_CLOCKED_DOWN:
|
||||
if (tile1_needed)
|
||||
{
|
||||
c1_tile1_clock_up(); /* restore-before-send */
|
||||
unsigned t; c1_tile1_tmr :> t;
|
||||
c1_tile1_tmr when timerafter(t + C1_TILE1_CLK_SETTLE_TICKS) :> void;
|
||||
SET_SHARED_GLOBAL(g_tile1_audio_ready, 1);
|
||||
c1_tile1_state = C1_TILE1_ACTIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Apply a live divider change (SET_TILE1_DIV) while staying clocked down. */
|
||||
c1_tile1_clock_down(g_tile1_lp_div);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* C1_DFS_EN */
|
||||
Reference in New Issue
Block a user