NVMe-eMMC Bridge 芯片固件开发(七):低功耗与定时器设计

概述

在 MCU 资源紧凑的嵌入式环境中,如何合理使用硬件资源、实现性能与功耗的最优平衡是固件开发的核心挑战。本文基于 NVMe-eMMC Bridge 项目,详解:

  • PLL 时钟与高精度 Timer 复用:多功能共享有限定时器资源
  • 低功耗时钟域控制:PLL/CPU 动态频率管理
  • PCIe 电源状态管理:L0/L1.x 状态机与 FW_STATUS 设计
  • 空闲检测与任务计数器:精确判断固件忙/闲状态
  • 硬件资源优化亮点:GPIO 复用、LED 控制、看门狗集成

1. 系统时钟架构

1.1 时钟域层次结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
┌─────────────────────────────────────────────────────────────────────────┐
│ 时钟域层次架构 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ │
│ │ 10MHz │ 外部晶振 │
│ │ Crystal │ │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ PLL (锁相环) │ │
│ │ ┌───────────────────────────────────────────────────────────┐ │ │
│ │ │ 可配置输出频率 (dmdn_tbl) │ │ │
│ │ │ • 125 MHz (低功耗模式) │ │ │
│ │ │ • 150 MHz │ │ │
│ │ │ • 187.5 MHz │ │ │
│ │ │ • 200 MHz │ │ │
│ │ │ • 225 MHz │ │ │
│ │ │ • 250 MHz (高性能模式) │ │ │
│ │ └───────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────┬────────────────────────────────────────┘ │
│ │ │
│ ┌────────────────┼────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ CPU Clock │ │ AHB Bus │ │ eMMC Clock │ │
│ │ (÷1 or ÷2) │ │ Clock │ │ (÷N) │ │
│ │ │ │ │ │ │ │
│ │ cpu_rate │ │ ahb_rate │ │ 25/50/200M │ │
│ └───────┬───────┘ └───────────────┘ └───────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ Timer 时基 (依赖 cpu_rate) │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Timer0 │ │ Timer1 │ │ Timer2 │ │ Timer3 │ CPU内部 │ │
│ │ │ (任务) │ │(SMART) │ │ (eMMC) │ │ (备用) │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │HW_Timer1│ │HW_Timer2│ │HW_Timer3│ 外部硬件定时器 │ │
│ │ │(SMART) │ │ (备用) │ │(APST) │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘

1.2 PLL 频率表设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// emmc_host.c - PLL 分频配置表 (10MHz 晶振输入)
// dmdn_tbl[eMMC速度模式][PLL频率等级]
// 每个值编码: [31:16]=M分频, [15:8]=D分频, [7:0]=N分频
u32 dmdn_tbl[6][6] = {
// PLL: 125M 150M 187.5M 200M 225M 250M
{0x01F42150, 0x01F42150, ...}, // eMMC 200KHz (初始化)
{0x00042150, 0x00042150, ...}, // eMMC 25MHz
{0x00022150, 0x00022150, ...}, // eMMC 50MHz (HS)
{0x00012150, 0x00012150, ...}, // eMMC 100MHz (HS200)
{0x00012150, 0x00012150, ...}, // eMMC 200MHz (HS400)
{0x00012150, 0x00012150, ...}, // eMMC 400MHz (预留)
};

// 初始化时设置 PLL 和 CPU 频率
static void InitPLLCPU()
{
init_dmdn_tbl(); // 初始化分频表
set_pll_freq(PLL_FREQ_DEGRADE_LEVEL); // 根据配置设置 PLL
cpu_rate = set_cpu_freq(); // 设置 CPU 频率并返回实际值
}

1.3 动态时钟控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// power_manage.h - PLL 动态开关
static inline void keep_pll_on(boolean on)
{
if (on == TRUE)
*(volatile u32 *)(BAYBRIDGE_SETTING_BASE + 0x04) &= ~(1 << 2);
else
*(volatile u32 *)(BAYBRIDGE_SETTING_BASE + 0x04) |= (1 << 2);
}

// 设置 PLL 保持活跃(防止进入低功耗时 PLL 关闭)
void set_keep_PLL_active(u8 val)
{
if (val == 0) {
BAYBRIDGE_CTRLER_PM = ((1 << 17) | (0 << 1)); // 允许 PLL 关闭
} else {
BAYBRIDGE_CTRLER_PM = ((1 << 17) | (1 << 1)); // 强制 PLL 活跃
}
}

2. PCIe 电源状态管理

2.1 电源状态机架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
┌────────────────────────────────────────────────────────────────────────────┐
│ PCIe 电源状态管理架构 │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ PCIe Link 状态 │ │
│ │ │ │
│ │ ┌─────────┐ ASPM ┌─────────┐ ASPM ┌────────┐│ │
│ │ │ L0 │◀────────────▶│ L1 │◀────────────▶│ L1.x ││ │
│ │ │ (Active)│ │ (Idle) │ │(Deep ││ │
│ │ │ │ │ │ │ Sleep) ││ │
│ │ └────┬────┘ └────┬────┘ └────┬───┘│ │
│ │ │ │ │ │ │
│ │ │ PLL: ON │ PLL: ON │ PLL:│ │
│ │ │ CPU: Running │ CPU: Running │ OFF │ │
│ │ │ │ │ │ │
│ └────────┼────────────────────────┼────────────────────────┼─────┘ │
│ │ │ │ │
│ ┌────────┼────────────────────────┼────────────────────────┼─────┐ │
│ │ ▼ ▼ ▼ │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ Firmware 状态控制寄存器 │ │ │
│ │ │ │ │ │
│ │ │ ┌────────────┐ ┌────────────┐ ┌────────────────┐ │ │ │
│ │ │ │ Keep_L0 │ │Keep_PLL_ │ │ FW_STATUS │ │ │ │
│ │ │ │ [bit 0] │ │Active[1] │ │ [bit 8] │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ 1=强制L0 │ │ 1=PLL常开 │ │ 1=FW忙碌 │ │ │ │
│ │ │ │ 0=允许ASPM │ │ 0=允许关闭 │ │ 0=FW空闲 │ │ │ │
│ │ │ └────────────┘ └────────────┘ └────────────────┘ │ │ │
│ │ │ │ │ │
│ │ │ 写入方式: BAYBRIDGE_CTRLER_PM = (mask << 16) | value │ │ │
│ │ │ 确保原子操作,避免读-改-写竞争 │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ 电源管理状态描述符 │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────┘

2.2 电源状态描述符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// power_manage.h - 电源管理状态描述符
typedef struct bb_state_dscp {
u8 keep_L0; // 强制保持 L0 状态
u8 keep_PLL_active; // 强制 PLL 保持活跃
u8 fw_status; // 固件忙/闲状态
u8 power_state; // NVMe Power State (PS0/PS1)
u32 pre_idle_threshold;
u32 apst_threshold;
u32 task_counter[2]; // [0]=NVMe任务, [1]=后台任务
} pm_dscp_t;

// 电源管理操作函数集
typedef struct {
void (*set_powermode)(u8); // 设置电源模式
void (*set_internalstate)(pm_dscp_p, u8, u8); // 设置内部状态
u8 (*get_internalstate)(pm_dscp_p, u8); // 获取内部状态
void (*update_task_counter)(pm_dscp_p, u8, u8); // 更新任务计数
int (*check_idle)(pm_dscp_p); // 检查空闲状态
} pm_ops_t;

2.3 FW_STATUS 控制流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
┌────────────────────────────────────────────────────────────────────────┐
│ FW_STATUS 控制状态机 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ FW_STATUS = 1 (忙碌) │ │
│ │ 条件: 收到 NVMe 命令 / 后台任务进行中 / Keep_L0 强制 │ │
│ │ 效果: 硬件阻止 PCIe 进入 L1/L1.x │ │
│ └────────────────────────────┬────────────────────────────────────┘ │
│ │ │
│ │ 空闲检测通过 │
│ │ (loopcnt_idle >= threshold) │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ FW_STATUS = 0 (空闲) │ │
│ │ 条件: task_counter[0,1] == 0 && SQ/CQ 队列空 │ │
│ │ 效果: 允许硬件进入 L1/L1.x 低功耗 │ │
│ └────────────────────────────┬────────────────────────────────────┘ │
│ │ │
│ │ 收到新 NVMe 命令 │
│ │ (SQ Doorbell 中断) │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 自动唤醒: FW_STATUS = 1 │ │
│ │ 触发源: 硬件自动检测 SQ Doorbell 更新 │ │
│ │ 固件动作: ISR 中清除 loopcnt_idle │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────┘

2.4 核心实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// power_manage.c - 设置 FW_STATUS
void set_fwstatus(u8 val)
{
if (val == 0) {
// 清除 FW_STATUS,允许进入低功耗
BAYBRIDGE_CTRLER_PM = ((1 << 24) | (0 << 8));

#if (MONITOR_4GPIO_DSU == MODE_GPIO)
// GPIO 调试信号:输出低电平表示空闲
pinshare_data.gpio.pin = GPIO1;
pinshare_data.gpio.mode = OUTPUT_LOW_LEVEL;
set_gpio_function(pinshare_data.gpio.pin, pinshare_data.gpio.mode);
#endif
} else {
// 设置 FW_STATUS = 1,保持活跃
BAYBRIDGE_CTRLER_PM = ((1 << 24) | (1 << 8));

#if (MONITOR_4GPIO_DSU == MODE_GPIO)
pinshare_data.gpio.pin = GPIO1;
pinshare_data.gpio.mode = OUTPUT_HIGH_LEVEL;
set_gpio_function(pinshare_data.gpio.pin, pinshare_data.gpio.mode);
#endif
}
}

// 设置内部状态(统一接口)
void drv_set_internalstate(pm_dscp_p pm_dscp, u8 opt, u8 val)
{
switch (opt) {
case ID_KEEP_L0:
set_keepL0(val);
pm_dscp->keep_L0 = val;
break;
case ID_KEEP_PLL_ACTIVE:
set_keep_PLL_active(val);
pm_dscp->keep_PLL_active = val;
break;
case ID_FW_STATUS:
// 特殊处理: Keep_L0 = 1 时强制 FW_STATUS = 1
if (drv_get_internalstate(pm_dscp, ID_KEEP_L0) == 1) {
val = 1; // 强制忙碌状态
}
set_fwstatus(val);
break;
case ID_PWR_STATE:
set_pwrstate(val);
pm_dscp->power_state = val;
break;
}
}

3. 空闲检测机制

3.1 多条件空闲判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// power_manage.c - 检查固件是否空闲
int drv_check_idle(pm_dscp_p pm_dscp)
{
// 综合判断以下条件:
// 1. NVMe 任务计数器为 0
// 2. 后台任务计数器为 0
// 3. 所有 SQ/CQ 队列状态为空
// 4. 无命令缓冲区就绪中断

if (!(pm_dscp->task_counter[NVME_TASK]) && // 无 NVMe 任务
!(pm_dscp->task_counter[BACKGROUND_TASK]) && // 无后台任务
!(BAYBRIDGE_INTERNAL_STATUS & (ALL_SQ_STATUS_MASK | ALL_CQ_STATUS_MASK)) &&
!(BAYBRIDGE_INTERNAL_INTERRUPT_STATUS &
(CMD_BUFFER0_READ_READY_INTERRUPT_STATUS_BIT |
CMD_BUFFER1_READ_READY_INTERRUPT_STATUS_BIT))) {
return 1; // 空闲
}
return 0; // 忙碌
}

3.2 任务计数器管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 任务类型定义
enum {
NVME_TASK = 0, // NVMe I/O 任务
BACKGROUND_TASK, // 后台任务 (SMART 写回、FFU 等)
ADD, // 任务计数 +1
SUB, // 任务计数 -1
};

// 更新任务计数器
void drv_update_task_counter(pm_dscp_p pm_dscp, u8 task_type, u8 update_opt)
{
if (update_opt == ADD) {
pm_dscp->task_counter[task_type]++;
} else if (update_opt == SUB) {
if (pm_dscp->task_counter[task_type] != 0)
pm_dscp->task_counter[task_type]--;
else
LOG(ERROR, "try to sub task_counter[%d] that is already 0\n", task_type);
}
}

// 使用示例: SMART 后台写入
void smart_info_emmc_rw(smart_rw_emmc_p smart_rw, smart_health_info_data_p smart_data)
{
// 唤醒 PLL
u8 temp = pm.get_internalstate(&pm_dscp, ID_FW_STATUS);
if (temp == 0) {
pm.set_internalstate(&pm_dscp, ID_FW_STATUS, 1);
}

// 注册后台任务
pm.update_task_counter(&pm_dscp, BACKGROUND_TASK, ADD);

// 执行 eMMC 读写...
emmc_usersblock_readwrite(smart_rw->addr_ram, smart_rw->addr_offset,
smart_rw->rw_size, smart_rw->rw_opt);

// 完成后恢复状态
if (temp == 0) {
pm.set_internalstate(&pm_dscp, ID_FW_STATUS, 0);
}
pm.update_task_counter(&pm_dscp, BACKGROUND_TASK, SUB);
}

3.3 主循环空闲控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// main.c - 主循环中的空闲检测
int loopcnt_idle = 0;
int already_idle_but_keepl0 = 0;

while (1) {
// ... 命令处理 ...

if (pm.check_idle(&pm_dscp)) {
// 空闲状态: 累计空闲循环计数
if (pm.get_internalstate(&pm_dscp, ID_FW_STATUS)) {
loopcnt_idle++;

// 达到空闲阈值,尝试清除 FW_STATUS
if (loopcnt_idle == fwstatus_idle_entry_latency_loop) {
loopcnt_idle = 0;
pm.set_internalstate(&pm_dscp, ID_FW_STATUS, 0);

// 如果因 Keep_L0 导致清除失败,设置延迟标志
if (pm.get_internalstate(&pm_dscp, ID_FW_STATUS) == 1) {
already_idle_but_keepl0 = 1;
}
}
}

// Keep_L0 释放后立即清除 FW_STATUS
if (already_idle_but_keepl0 &&
pm.get_internalstate(&pm_dscp, ID_KEEP_L0) == 0) {
pm.set_internalstate(&pm_dscp, ID_FW_STATUS, 0);
already_idle_but_keepl0 = 0;
}
} else {
// 非空闲状态: 立即重置计数器并设置 FW_STATUS
loopcnt_idle = 0;
already_idle_but_keepl0 = 0;
pm.set_internalstate(&pm_dscp, ID_FW_STATUS, 1);
}
}

4. 定时器多路复用设计

4.1 定时器资源分配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
┌────────────────────────────────────────────────────────────────────────┐
│ 定时器资源分配架构 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ CPU 内部定时器 (依赖 cpu_rate) │ │
│ │ │ │
│ │ ┌────────────────────────────────────────────────────────┐ │ │
│ │ │ Timer0: 任务调度器 (1秒周期) │ │ │
│ │ │ ├── OS_READY 计数器 (30秒后清除 Keep_L0) │ │ │
│ │ │ ├── SHUTDOWN_TIME 计数器 │ │ │
│ │ │ └── PRE_NOPS 计数器 (APST 触发) │ │ │
│ │ │ 实现: 单定时器 + 多任务计数器数组 │ │ │
│ │ └────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌────────────────────────────────────────────────────────┐ │ │
│ │ │ Timer1: SMART 信息定时器 (1分钟周期) │ │ │
│ │ │ ├── 60分钟: 持久化写回 eMMC │ │ │
│ │ │ ├── 60分钟: power_on_hours++ │ │ │
│ │ │ └── 1分钟: controller_busy_time++ (忙碌时) │ │ │
│ │ └────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌────────────────────────────────────────────────────────┐ │ │
│ │ │ Timer2/3: eMMC 超时检测 (按需启动) │ │ │
│ │ │ • 单次触发模式 │ │ │
│ │ │ • 命令执行前启动,完成后关闭 │ │ │
│ │ └────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 外部硬件定时器 (独立于 CPU 时钟) │ │
│ │ │ │
│ │ ┌────────────────────────────────────────────────────────┐ │ │
│ │ │ HW_Timer1: SMART 定时器 (备选方案) │ │ │
│ │ │ • 可在 CPU 休眠时继续运行 │ │ │
│ │ └────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌────────────────────────────────────────────────────────┐ │ │
│ │ │ HW_Timer3: APST (Autonomous Power State Transition) │ │ │
│ │ │ • 40秒空闲后触发 NOPS 状态切换 │ │ │
│ │ │ • 独立计数,不影响 CPU 负载 │ │ │
│ │ └────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────┘

4.2 多任务计数器复用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// timer.h - 多任务计数器定义
enum {
OS_READY = 0, // OS 就绪等待
SHUTDOWN_TIME, // 关机超时
PRE_NOPS, // APST 预触发
EMMC_NCQ_WAIT_EVENT, // eMMC 命令超时
CNT_NUM, // 计数器总数
};

typedef struct {
u8 id;
u8 start_flag; // 是否启动
u8 end_flag; // 是否超时
u32 cnt_num; // 剩余计数值
} counter_t;

// 全局任务调度器
typedef struct {
u8 start_flag; // 定时器是否运行
u8 end_flag;
u8 task_num; // 活跃任务数
} timer_task_t;

// Timer0 中断处理: 更新所有任务计数器
void timer0_update_flags()
{
for (int i = 0; i < CNT_NUM; i++) {
if (T0_Counter[i].start_flag && T0_Counter[i].cnt_num) {
T0_Counter[i].cnt_num--; // 计数值减 1
if (T0_Counter[i].cnt_num == 0) {
T0_Counter[i].end_flag = 1; // 触发超时标志
}
}
}
}

4.3 定时器动态启停

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// main.c - 定时器按需启停(节省功耗)
void timer_scheduler()
{
// 有新任务且定时器未启动 -> 启动定时器
if (T0_Task.task_num > 0 && T0_Task.start_flag == 0 && !loopcnt) {
timer.set_timer(BB_TIMER0, &timer_dscp[0], 1000); // 1秒周期
T0_Task.start_flag = 1;
}
// 所有任务完成且定时器运行中 -> 关闭定时器
else if (T0_Task.task_num == 0 && T0_Task.start_flag == 1) {
timer.close_timer(BB_TIMER0);
T0_Task.start_flag = 0;
}
}

// 使用示例: OS 就绪等待
void start_os_ready_timer()
{
T0_Counter[OS_READY].start_flag = 1;
T0_Counter[OS_READY].cnt_num = 30; // 30秒超时
T0_Task.task_num++; // 注册任务
T0_Task.start_flag = 1;
timer.set_timer(BB_TIMER0, &timer_dscp[0], 1000);
}

// 超时处理: 清除 Keep_L0
if (T0_Counter[OS_READY].end_flag && async_event_received) {
pm.set_internalstate(&pm_dscp, ID_KEEP_L0, 0);
T0_Counter[OS_READY].end_flag = 0;
T0_Counter[OS_READY].start_flag = 0;
T0_Task.task_num--; // 注销任务
}

4.4 SMART 定时器多事件复用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// timer.c - SMART 定时器事件处理
static void timer_update_flags(timer_flags_p timer_flags, timer_clock_p timer_clock)
{
// 避免首分钟误触发
if (timer_clock->minute == 0 && timer_clock->hour == 0)
return;

// 事件1: 每60分钟持久化 SMART 数据到 eMMC
if ((timer_clock->minute % SMART_UPDATE_EMMC_MINUTE) == 0 &&
timer_get_flags(timer_flags, ID_SMARTINFO_UPDATE_EMMC) == 0) {
timer_set_flags(timer_flags, ID_SMARTINFO_UPDATE_EMMC, 1);
}

// 事件2: 每分钟累计忙时间(仅在忙碌状态)
if ((timer_clock->minute % SMART_BUSY_MINUTE) == 0 &&
timer_get_flags(timer_flags, ID_NVME_IO_BUSY) == 1) {
timer_set_flags(timer_flags, ID_SMARTINFO_BUSY_TIME, 1);
}

// 事件3: 每60分钟累计运行小时数
if ((timer_clock->minute % SMART_PWRON_MINUTE) == 0 &&
timer_get_flags(timer_flags, ID_SMARTINFO_POWER_ON_HOUR) == 0) {
timer_set_flags(timer_flags, ID_SMARTINFO_POWER_ON_HOUR, 1);
}
}

5. 硬件资源优化亮点

5.1 GPIO 复用设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 引脚复用枚举
enum {
MODE_RESET = 0,
MODE_UART, // UART 调试输出
MODE_SPI, // SPI Flash 通信
MODE_GPIO, // 通用 GPIO
MODE_MONITOR, // 内部信号监测
MODE_LED, // LED 指示灯
};

// 同一组引脚支持多种功能,运行时动态切换
void set_pinshare_mode(u8 mode)
{
switch (mode) {
case MODE_UART:
// 设置为 UART 模式: TX/RX 功能
break;
case MODE_GPIO:
// 设置为 GPIO: 用于调试信号输出
break;
case MODE_MONITOR:
// 设置为监测模式: 观察内部 PLL/DLL 状态
break;
}
}

5.2 LED 指示设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// emmc_support_functions.c - LED 忙闲指示
void led_blink_control(int loopcnt_idle, u32 fwstatus_idle_entry_latency_loop)
{
boolean fw_idle;
int led_blink_stop_delay_loop = (fwstatus_idle_entry_latency_loop > LED_BLINK_KEEP_MIN_LOOP) ?
LED_BLINK_KEEP_MIN_LOOP : fwstatus_idle_entry_latency_loop;

if (fw_param.led_uart_gpio0_select == 2) { // LED 模式
fw_idle = pm.check_idle(&pm_dscp);

if (!fw_idle && !g_led_blinking) {
// FW 忙碌 & LED 未亮 -> 点亮
led_on();
} else if (fw_idle && g_led_blinking) {
// FW 空闲 & LED 亮着 -> 延迟熄灭
// 延迟约 1 秒确保肉眼可见闪烁
if (loopcnt_idle == led_blink_stop_delay_loop)
led_off();
}
}
}

5.3 中断资源统一管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// controller_register.h - 中断状态位定义
#define BAYBRIDGE_INTERNAL_INTERRUPT_STATUS (*(volatile u32 *)(BAYBRIDGE_CONTROL_BASE + 0x0))

// 各功能模块中断位分配
#define NVMECC_UPDATED_INTERRUPT_STATUS_BIT (1 << 31) // CC 寄存器更新
#define DEVICE_DISABLE_INTERRUPT_STATUS_BIT (1 << 30) // 设备禁用
#define HW_TIMER1_INTERRUPT_STATUS_BIT (1 << 28) // 硬件定时器1
#define HW_TIMER3_INTERRUPT_STATUS_BIT (1 << 26) // 硬件定时器3
#define NVMESQ_0TDBL_UPDATED_INTERRUPT_STATUS_BIT (1 << 16) // SQ0 Doorbell
#define CMD_BUFFER0_READ_READY_INTERRUPT_STATUS_BIT (1 << 0) // 命令缓冲区0

// 统一的中断处理入口
void interrupt_process()
{
u32 status = BAYBRIDGE_INTERNAL_INTERRUPT_STATUS;

// 按优先级处理
if (status & CMD_BUFFER0_READ_READY_INTERRUPT_STATUS_BIT) {
// 处理 NVMe 命令
}
if (status & HW_TIMER1_INTERRUPT_STATUS_BIT) {
ext_hwtimer1_intr_handler();
}
if (status & HW_TIMER3_INTERRUPT_STATUS_BIT) {
ext_hwtimer3_intr_handler();
}
// ...
}

6. 性能-功耗平衡策略

6.1 电源模式配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 三级电源模式
void drv_set_pm(u8 pm)
{
BAYBRIDGE_SETTING_PM &= ~(3 << 8); // 清除当前设置

switch (pm) {
case 0: // 低功耗模式
BAYBRIDGE_SETTING_PM |= (1 << 8);
// PLL 可降频,积极进入 L1.x
break;
case 1: // 平衡模式 (默认)
BAYBRIDGE_SETTING_PM |= (0 << 8);
// 根据负载自适应
break;
case 2: // 高性能模式
BAYBRIDGE_SETTING_PM |= (2 << 8);
// PLL 最高频率,减少 L1 进入
break;
case 4: // 强制 L0 (调试)
set_keepL0(1);
break;
}
}

6.2 L1.2 低功耗配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// main.c - L1.2 能力配置
if (fw_param.l1_2_cap_enable == 0) {
// 禁用 L1.2
set_reg(BAYBRIDGE_PCI_CFG_BASE, 0x154, 0x5, 0x0);
} else {
// 启用 L1.2
set_reg(BAYBRIDGE_PCI_CFG_BASE, 0x154, 0x5, 0x5);
}

// LTR (Latency Tolerance Reporting) 配置
if (fw_param.l1_1_exit_bug_fix == 0) {
set_reg(BAYBRIDGE_CONTROL_BASE, 0x60, 0xFFFFFFFF, FAST_LTR_VALUE);
set_reg(BAYBRIDGE_CONTROL_BASE, 0x64, 0xFFFFFFFF, SLOW_LTR_VALUE);
} else {
// L1.1 退出问题修复: 使用更保守的 LTR 值
set_reg(BAYBRIDGE_CONTROL_BASE, 0x60, 0xFFFFFFFF, SLOW_LTR_VALUE);
set_reg(BAYBRIDGE_CONTROL_BASE, 0x64, 0xFFFFFFFF, SLOW_LTR_VALUE);
}

7. 要点总结

7.1 定时器复用技巧

技巧 说明
计数器数组 单个定时器 + 多计数器,节省硬件资源
按需启停 无任务时关闭定时器,降低功耗
分层设计 CPU 内部定时器(高精度) + 硬件定时器(独立运行)
事件复用 一个 1 分钟定时器触发多个周期性事件

7.2 低功耗设计要点

机制 作用
FW_STATUS 软件精确控制 PCIe 链路状态
任务计数器 原子级忙/闲判断,避免误进入低功耗
延迟进入 loopcnt_idle 阈值防止频繁状态切换
Keep_L0 互锁 关键操作期间强制保持 L0

7.3 资源优化亮点

资源 优化方式
GPIO 多功能复用:UART/SPI/LED/调试信号
定时器 4 个定时器支持 10+ 独立功能
中断 32-bit 状态寄存器统一管理所有中断源
PLL 动态频率表,根据负载选择最优功耗点

8. 参考规范

  • PCIe Base Spec 4.0:ASPM L1/L1.1/L1.2 状态管理
  • NVMe 1.4:Power State Descriptor, APST
  • SPARC LEON2:CPU Timer 架构
  • JEDEC eMMC 5.1:Power Management 特性