总览:从复位到主循环
实际上 main() 之前还有一段汇编启动代码,完整链路是:芯片复位 → STARTUP.A51(汇编) → main()(CORE_MAIN.C) → while(1) 主循环。

1.Oem_StartUp() (main()之前)
主要作用是在 C 运行时之前,先初始化键盘扫描硬件,并检测 电源键 + Home 键 是否触发固件 Mirror 恢复。

void Oem_StartUp(void)
{
    /* Sample Code: Power,Vol Up/Dn 3 buttons down trigger mirror code. */
#if 0   /* 1:Support "3 Buttons" entry recovery mirror function */
    if (IS_EC_PWRSW_DN())
    {
        if (IS_VOLUME_UP_DN() && IS_VOLUME_DOWN_DN())
        {
            FLHCTRL3R = 0x28;
            //FLHCTRL3R = 0x48;   /* Force Mirror active (Max. sizes) */
            ETWCFG = EWDKEYEN;  /* Force Watchdog active */
            EWDCNTLLR = 0x01;   // for 1ms counter
            EWDKEYR = 0x5A;     // External WDTreset not match
            /* if FLHCTRL3R=0x28 --> Force Mirror active after WDT */
        }
    }
#endif
    /* Sample Code: Power, Matrix-[Home] Key down trigger mirror code. */
#if 1
    KSOCTRL = KSOOD + KSOPU;
    KSICTRL = KSIPU;
    KSOL = 0xFF;
    KSOH1 = 0xBF;
    WNCKR = 0x00;
    while (IS_EC_PWRSW_DN())
    {
        if (KSI == 0xFD)    //Home Key = KSO14,KSI1
        {
            ITempB01++;
            if (ITempB01 == 0)
            {
                FLHCTRL3R = 0x28;
                //FLHCTRL3R = 0x48;   /* Force Mirror active (Max. sizes) */
                ETWCFG = EWDKEYEN;  /* Force Watchdog active */
                EWDCNTLLR = 0x01;   // for 1ms counter
                EWDKEYR = 0x5A;     // External WDTreset not match
                /* if FLHCTRL3R=0x28 --> Force Mirror active after WDT */
            }
        }
        else
        {
            break;
        }
    }
#endif
}

2.main() 前半段 — 硬件底层配置
主要有关中断、设置栈指针SP、设置ESPI电压和频率、确认与BIOS共享Flash空间等

void main(void)
{
    DisableAllInterrupt();
    SP = 0xC0;
    ResetBANKDATA();
    /* eSPI 初始化(本项目 SUPPORT_INTERFACE_eSPI = TRUE) */
    SCRA0H = 0x07;              // 清 Scratch SRAM
    GCR22 |= VCCPDS;            // eSPI 总线 1.8V
    REG_3105 = _eSPI_MAX_FREQ_66MHZ;  // eSPI 66MHz
    ChangePLLFrequency(_PLL_FREQ_32_3_MHZ);  // PLL 32.3MHz
    REG_3115 = _SUPPORT_MAFS;  // Flash Access Channel
    // EC 间接寻址初始化
    ECINDAR3~0 = 0;
    ITempB01 = ECINDDR;
    Hook_Before_SpiTriState();
    // Mirror 一次性标记处理
    // ...
    // SPI Flash 引脚设为 Tri-State(与 BIOS 共享 Flash)
    SET_MASK(FLHCTRL3R, BIT(0));

3.分支判断 — 正常启动或Follow Mode 恢复

if (Hook_ECRetunrMainFuncKeepCondition() == 0x33)
{
    // 【分支 A】从 Follow Mode / Scratch ROM 退出(异常恢复路径)
    CLEAR_MASK(FBCFG,SSMC);
    Hook_ECExitFollowMode();
    Init_Timers();
    EnableModuleInterrupt();
}
else
{
    // 【分支 B】正常冷启动(绝大多数情况走这里)
    Core_Initialization();
    Oem_Initialization();
    InitEnableInterrupt();
}

正常开机走分支B。
4.Core_Initialization() — 内核初始化

void Core_Initialization(void)
{
    Init_Kbd();           // 键盘控制器硬件初始化
    cold_reset();         // 冷启动变量初始化
    common_reset();       // 通用复位(清 Service 标志等)
    Init_Mouse();         // 鼠标接口(本项目未用)
    Init_Timers();        // 定时器硬件初始化(1ms 中断源)
    Core_Init_Regs();     // 内核寄存器表初始化
    Core_Init_SMBus();    // SMBus 硬件初始化

    ESGCTRL1 = 0x80;      // eSPI 中断使能
    ESGCTRL2 = 0x10;      // eSPI → WUC 唤醒使能

    Init_EC_Indirect_Selection(SPI_selection_internal);
}

cold_reset() 清什么?

void cold_reset(void)
{
    Ext_Cb2.byte = EXT_CB2_INIT;
    Save_Typematic = SAVE_TYPEMATIC_INIT;
    Flag.SCAN_INH = 1;      // 暂时禁止键盘扫描
    Flag.VALID_SCAN = 0;
    // ... 键盘/KBC 相关状态清零
}

Core_Init_Regs() 配什么?

void Core_Init_Regs(void)
{
	BYTE index = 0x00;
    while(index < (sizeof(Core_reg_init_table)/sizeof(sREG_INIT)))
    {
        Tmp_XPntr = Core_reg_init_table[index].address;
		*Tmp_XPntr = Core_reg_init_table[index].initdata;
        index ++;
    }

    CLEAR_MASK(FLHCTRL2R,BIT3);
}

通过 Core_reg_init_table[] 批量写寄存器,主要包括:Host 接口;PS/2;键盘扫描;
5.Oem_Initialization() — 项目初始化

void Oem_Initialization(void)
{
    Init_SMBus();     // SMBus 通道时钟/引脚(电池/充电器通信)
    Init_GPIO();      // 全部 GPIO 方向/默认值(电源轨控制引脚)
    Init_PWM();       // PWM 初始化(风扇)
    Init_ADC();       // ADC 初始化(适配器检测等)
    Init_Kbd();       // OEM 键盘配置
    Init_WDT();       // 看门狗
    Reload_EC_Ver();  // 加载 EC 版本号

    // 清 BRAM 备份区
    for (...) BRAM[...] = 0;
    for (...) BRAM2[...] = 0;

    xEC_PowerOnFirst = 1;

    // 等 500ms,等 3.3V 电源稳定
    DelayXms(250);
    DelayXms(250);
    while(IS_V3P3A_PGOOD_LO())
    {
        if(IS_EC_PWRSW_DN())
            _nop_();
        else
            EC_PWR_LATCH_LO();  // 没按电源键就关掉电源锁存
    }
}

要点:
1.按顺序初始化所有外设(SMBus → GPIO → PWM → ADC → 键盘)
2.等待 500ms + V3P3A_PGOOD 电源好信号
3.若电源键未按下,会拉低 EC_PWR_LATCH 防止误上电
4.初始化结束后,电源时序还没跑——那要等主循环里 Hook_Timer1msEvent 触发
6.InitEnableInterrupt() — 开中断
使能各模块中断,包括:1ms 定时器中断(最重要,驱动整个调度体系);eSPI 中断;键盘扫描中断;SMBus 完成中断。
从此刻起,1ms 定时器开始滴答,Hook 函数开始被周期性调用。
7.while(1) 主循环 — 永不返回

while(1)
{
    if(OEM_SkipMainServiceFunc()==Normal_MainService)
    {
        main_service();         // 处理所有 Service 请求
        EnableModuleInterrupt();

        // 无 Service 时进入 idle 省电
        if((Service==0x00)&&(Service1==0x00))
        {
            PCON = 1;           // 进入 idle,等中断唤醒
            _nop_(); _nop_(); ...  // 8 个 nop 总线翻转延时
        }
    }
}

┌─────────────────────────────────────┐
│ while(1) 主循环 │
│ │
│ 1. main_service() 检查 Service 标志 │
│ ├─ F_Service_MS_1 → service_1mS() → Hook_Timer1msEvent
│ ├─ F_Service_KEY → service_scan() → 键盘扫描
│ ├─ F_Service_PCI → service_pci1() → eSPI Host 命令
│ └─ … 其他 Service │
│ │
│ 2. 所有 Service 处理完? │
│ ├─ 是 → PCON=1 进入 idle 省电 │
│ └─ 否 → 继续处理 │
│ │
│ 3. 中断唤醒 → 回到步骤 1 │
└─────────────────────────────────────┘
main_service() 优先级(从高到低)

void main_service(void)
{
    while(Service != 0 || Service1 != 0)
    {
        // eSPI Boot Ready / Warm Boot 处理
        if(F_Service_PCI)      → service_pci1();    // Host 命令
        if(F_Service_UNLOCK)   → service_unlock();
        if(F_Service_SEND)     → service_send();     // KBC 发送
        if(F_Service_MS_1)     → service_1mS();      // ★ 1ms 定时器
        if(F_Service_PCI2)     → service_pci2();
        if(F_Service_KEY)      → service_scan();     // ★ 键盘扫描
        Hook_main_service_H();
        if(F_Service_Low_LV)   → service_Low_LVEvent();
        // ... service_pci3/4, service_OEM_1~4
        Hook_main_service_L();
    }
}

其中 service_1mS() 最重要,它驱动整个定时器分频树,最终调用 Hook_Timer1msEvent() → 电源管理、SMBus 轮询等。
完整启动时序图
[芯片复位]
│
▼
STARTUP.A51
├─ SP=0xC0, Bank0
├─ Oem_StartUp() ← Mirror检测、键盘早期初始化
├─ Core_Init_ClearRam() ← 清 0x000~0x0FF
├─ Init_ClearRam() ← 清 0x100~0xFFF
├─ CheckResetSource()
│
▼
main() ─────────────────────────────────────────────
├─ DisableAllInterrupt()
├─ eSPI 1.8V + 66MHz + PLL 32.3MHz
├─ Flash Tri-State
│
├─ Core_Initialization()
│ ├─ Init_Kbd()
│ ├─ cold_reset() / common_reset()
│ ├─ Init_Timers() ← 1ms 定时器就绪
│ ├─ Core_Init_Regs() ← KBC/PM/eSPI 寄存器
│ └─ Core_Init_SMBus()
│
├─ Oem_Initialization()
│ ├─ Init_SMBus/GPIO/PWM/ADC/Kbd/WDT
│ ├─ Reload_EC_Ver()
│ └─ 等 500ms + V3P3A_PGOOD
│
├─ InitEnableInterrupt() ← ★ 中断开启,系统"活"了
│
▼
while(1) 主循环
├─ main_service()
│ ├─ service_1mS() → Hook_Timer1msEvent()
│ │ ├─ 电源状态分支 (S0/S3/S5/G3)
│ │ ├─ Oem_SysPowSequence() (若 F_PST_BUSY)
│ │ └─ SMBusA/B 轮询
│ ├─ service_scan() → 键盘扫描
│ └─ service_pci1() → Host eSPI 命令
│
└─ PCON=1 idle → 等中断 → 循环

启动后第一件事是什么?
中断开启后,1ms 定时器开始触发 Hook_Timer1msEvent():

void Hook_Timer1msEvent(IBYTE EventId)
{
    // 根据 SysPowState 走不同分支
    if (SysPowState == S0/S1)  → Oem_SysPowState_S0_S1();
    if (SysPowState == S3)     → Oem_SysPowState_S3();
    if (SysPowState == S4/S5)  → Oem_SysPowState_S4_S5();
    if (F_PST_BUSY)            → Oem_SysPowSequence();  // 电源时序
    else                       → SMBus 轮询 + ADP_Control();

刚启动时 SysPowState 通常是 S5,所以一开始走 Oem_SysPowState_S4_S5()。用户按电源键后,F_PST_BUSY 置位,开始执行 TGL_sSEQ_S5_to_S0[] 上电时序表,最终进入 S0。

更多推荐