- 固件
- 嵌入式
- 操作系统
- 驱动开发
【免费下载链接】coreboot
Read-only mirror of https://review.coreboot.org/coreboot.git. Synced every hour. We don't handle Pull Requests.
导读
本文围绕 coreboot 仓库中 Documentation/soc/qualcomm/sc7180/index.md 这一份 SOC 级文档展开,系统梳理 Qualcomm SC7180(Snapdragon 7c 系列)在 coreboot 中的落地方式。你将了解 SOC 代码如何组织 MMU、时钟、GPIO、QUPv3 固件桥、UART、SPI-NOR、AOP 固件与 USB 等八大模块,并结合src/soc/qualcomm/sc7180/与src/soc/qualcomm/common/下的源码,弄清 bootblock 到 ramstage 各阶段的初始化调用链,以及构建时所需的 Kconfig 选项与二进制固件(blob)清单。读完本文,你可以看懂 SC7180 参考主板(Google Trogdor 系列)的启动配置,也能为基于该 SoC 的 coreboot 移植提供直接依据。
SOC 代码的功能清单与目录结构
原文档明确指出,SOC folder(即 coreboot 源码树中的 SoC 支持代码)包含以下功能的实现:
- MMU(内存管理单元)
- CLOCK(时钟)
- GPIO(通用输入输出)
- QUPv3 FW(为串行接口提供桥接)
- UART
- SPI-NOR
- AOP FW(Always-On Processor 固件)
- USB
在仓库中,这些功能分散在两个目录:SoC 特有代码位于 src/soc/qualcomm/sc7180/,而多个 Qualcomm SoC 共享的通用代码位于 src/soc/qualcomm/common/。SC7180 目录下的文件与模块对应关系如下:
| 功能模块 | SC7180 特有源码 | 共享通用源码 |
|---|---|---|
| MMU | mmu.c、decompressor.c | common/mmu.c |
| CLOCK | clock.c、include/soc/clock.h | common/clock.c |
| GPIO | include/soc/gpio.h、include/soc/addressmap.h | common/gpio.c |
| QUPv3 FW | qcom_qup_se.c | common/qupv3_config.c、common/qup_se_handler.c |
| UART | include/soc/uart.h | common/qupv3_uart.c |
| SPI-NOR | include/soc/addressmap.h(QSPI 引脚与基址) | common/qspi.c、common/spi.c |
| AOP FW | clock.c(clock_reset_aop) | common/aop_load_reset.c |
| USB | — | common/usb/usb.c |
MMU:为各启动阶段建立页表与内存属性
SC7180 的 MMU 初始化函数sc7180_mmu_init()定义在 src/soc/qualcomm/sc7180/mmu.c,它在 decompressor 阶段由decompressor_soc_init()(decompressor.c)调用,遵循mmu_init() → mmu_config_range() → mmu_enable()的标准流程:
void sc7180_mmu_init(void) { mmu_init(); mmu_config_range((void *)(4 * KiB), ((4UL * GiB) - (4 * KiB)), DEV_MEM); mmu_config_range((void *)_ssram, REGION_SIZE(ssram), CACHED_RAM); mmu_config_range((void *)_bsram, REGION_SIZE(bsram), CACHED_RAM); mmu_config_range((void *)_dma_coherent, REGION_SIZE(dma_coherent), UNCACHED_RAM); mmu_enable(); }可见 SC7180 的内存映射策略:
- 从 4 KiB 起到 4 GiB 的绝大部分地址空间映射为
DEV_MEM(设备内存,不可缓存),这覆盖了所有外设寄存器区域; - SoC 内置的SSRAM(系统 SRAM,基址 0x14680000)与BSRAM(启动 SRAM,基址 0x14800000)映射为
CACHED_RAM; - DMA 一致性缓冲区(
dma_coherent,位于 BSRAM 内 0x1484E000)映射为UNCACHED_RAM,供 QSPI DMA 等场景使用。
这些内存区域的布局细节由 src/soc/qualcomm/sc7180/memlayout.ld 定义:BSRAM 中依次排布了 PBL 时间戳、看门狗墓碑、bootblock(52K)、TPM 日志、预 RAM CBFS 缓存、CBMEM 控制台、时间戳、页表(TTB)、栈、vboot 工作区与 DMA 一致性区域,还预留了ddr_training、qclib_serial_log、ddr_information、dcb、pmic、qclib等与内存初始化相关的区域;DRAM 段(0x80000000 起)则划分出dram_aop、dram_soc、BL31、modem 专用区(dram_modem_wifi_only/dram_modem_extra)、POSTRAM CBFS 缓存与 ramstage 区段。cbmem_top_chipset()返回4 * GiB(cbmem.c),将 CBMEM 放在 4 GiB 边界之下。
CLOCK:GPLL0 初始化、外设时钟配置与 CPU 频率提升
SC7180 的时钟子系统分为两块:SoC 特有部分(clock.c)与共享的通用时钟框架(common/clock.c)。
系统时钟初始化(clock_init)
clock_init()(clock.c)在 bootblock 阶段被调用,完成三件事:
- 配置并启用 GPLL0:
clock_configure_gpll0()通过写 GCC 的 GPLL0 用户控制寄存器(user_ctl/user_ctl_u)设置偶数分频与多路输出(PLLOUT_EVEN / MAIN / ODD),使 GPLL0 输出 300 MHz(GPLL0_EVEN_HZ); - 为 QUPV3 的两组 Wrap 使能时钟投票:分别对
qup_wrap0与qup_wrap1的 core_2x、core、M_AHB、S_AHB 时钟在apcs_clk_br_en1投票寄存器上使能(偏移定义见 include/soc/clock.h); - 提升启动 CPU 频率:
speed_up_boot_cpu()(clock.c)通过pll_init_and_set()配置银核(Silver)PLL 到 1516.8 MHz、L3 PLL 到 1209.6 MHz,对应L_VAL_1516P8MHz = 0x4F与L_VAL_1209P6MHz = 0x3F,并打印调试日志。
外设时钟频率表
clock.c中还维护了两组静态频率配置表:
- QSPI 核心时钟表
qspi_core_cfg:提供 19.2 kHz(XO)、100 MHz、150 MHz、300 MHz 四档频率,分别由 XO 19.2 MHz 源或 GPLL0_EVEN 300 MHz 源经分频得到; - QUPv3 Wrap 时钟表
qupv3_wrap_cfg:提供 19.2 kHz、32 MHz、48 MHz、64 MHz、96 MHz、100 MHz 等档位,其中 32/48/64/96 MHz 使用 M/N/D_2 分数分频(如 32 MHz 对应 m=8、n=75、d_2=75),由clock_configure_dfsr()写入 DFSR(动态频率切换)表供串行引擎选择。
此外,mdss_clock_configure()/mdss_clock_enable()(clock.c)负责显示子系统 MDSS 的 ESC0、PCLK0、BYTE0、BYTE0_INTF 时钟,注意寄存器中的分频值以 "2n-1" 形式存储,调用方需传入 2n 值。
GPIO:TLMM 分片与引脚复用定义
SC7180 的 GPIO 支持基于 TLMM(Top Level Mode Multiplexer),地址映射中定义了四个分片的基址(addressmap.h):
TLMM_NORTH_TILE_BASE= 0x03900000TLMM_SOUTH_TILE_BASE= 0x03D00000TLMM_WEST_TILE_BASE= 0x03500000
include/soc/gpio.h 用PIN(index, tlmm, func1, ..., func7)宏为每个引脚同时生成:
- 寄存器地址
GPIO<idx>_ADDR = TLMM_<tile>_TILE_BASE + (idx * TLMM_GPIO_OFF_DELTA) - 引脚功能选择枚举
GPIO<idx>_FUNC_<func> = 1..7
例如PIN(0, SOUTH, QUP0_L0, ...)生成GPIO0_ADDR(位于南片 TLMM)与GPIO0_FUNC_QUP0_L0 = 1。SC7180 的 QSPI 引脚也在此定义(addressmap.h):QSPI_CLK = GPIO(63)、QSPI_DATA_0 = GPIO(64)、QSPI_DATA_1 = GPIO(65)、QSPI_CS = GPIO(68),对应的功能选择为GPIO63_FUNC_QSPI_CLK等。
在 qcom_qup_se.c 中,12 个 QUP 串行引擎(QUPV3_0_SE0 至 QUPV3_1_SE5)各自关联了寄存器基地址(QUP_SERIAL0_BASE0x00880000 起,见 addressmap.h)与最多 6 个引脚的功能映射,例如qup[8](QUPV3_1_SE2,即默认控制台 UART)使用 GPIO(42)~GPIO(45) 的QUP1_L0..L3功能。
QUPv3 FW:串行接口的固件桥与 GSI 初始化
原文档特别指出 QUPv3 FW 的作用是"为串行接口提供桥接"(provides a bridge to serial interfaces)。这是因为 SC7180 的 QUP 串行引擎(UART/SPI/I2C)硬件本身是一块可编程微序列器,需要加载专用固件后才能工作。
固件文件与 CBFS 打包
构建时(Makefile.mk)会从3rdparty/qc_blobs/sc7180/qup_fw/下取出三个固件并打入 CBFS:
| CBFS 名称 | 源文件 | 类型 |
|---|---|---|
fallback/uart_fw | qup_fw/uart_fw.bin | raw |
fallback/spi_fw | qup_fw/spi_fw.bin | raw |
fallback/i2c_fw | qup_fw/i2c_fw.bin | raw |
固件加载与引擎初始化
qupv3_se_fw_load_and_init(bus, protocol, mode)(common/qupv3_config.c)按高通 HPG(Hardware Programming Guide)的步骤完成一次完整的串行引擎初始化:
- 从 CBFS 映射对应协议固件(
cbfs_map("fallback/spi_fw", ...)等),并校验头部魔数SEFW(SEFW_MAGIC_HEADER); - 解锁引擎、关闭 GENI 固件与相关时钟门控;
- 对非 UART 协议启用 DFS 模式并配置 DFSR 时钟表;
- 根据
mode(GSI/FIFO/CPU_DMA/MIXED)设置geni_dma_mode_en、中断使能与事件使能寄存器; - 把固件头部携带的配置索引/值对写入
geni_cfg_reg0起始的配置寄存器,并把固件本体(fw_val_arr)拷贝进se_geni_cfg_ramn程序 RAM; - 最后写版本寄存器、重新锁定引擎。
bootblock 阶段的qupv3_fw_init()(common/qupv3_config.c)则为全部 12 个 QUP 使能时钟,并对 QUP_WRAP0/1 的公共配置寄存器(AHB 主机时钟门控、快速切换禁用)进行初始化。
参考主板 Trogdor 在 ramstage 的load_qup_fw()(src/mainboard/google/trogdor/mainboard.c)展示了实际分配:SE1 用于 eSIM SPI、SE3 用于蓝牙 UART、SE4/SE5 用于笔触与 SAR 的 I2C、QUPV3_1_SE1 用于触控板 I2C、QUPV3_1_SE3/SE5 用于音频功放与 Codec I2C、QUPV3_1_SE4 用于指纹 SPI,并在禁用串口控制台时仍为 OS 加载控制台 UART 的固件。
UART:基于 QUPv3 的控制台串口实现
SC7180 的 UART 控制台走 QUPv3 通用引擎,实现在 common/qupv3_uart.c。uart_init(idx)(L47-L115)的关键逻辑包括:
- 若 RX 次序列器已激活(
GENI_STATUS_S_GENI_CMD_ACTIVE_MASK),说明前一阶段已初始化过,直接跳过避免重复配置; - 调用
qupv3_se_fw_load_and_init(idx, SE_PROTOCOL_UART, FIFO)加载 UART 固件并校验协议版本; - 波特率按"16 个时钟脉冲采样 1 位"计算:
uart_freq = baud_rate * 16,分频div = DIV_ROUND_CLOSEST(SRC_XO_HZ, uart_freq)(XO 为 19.2 MHz),写入geni_ser_m_clk_cfg/geni_ser_s_clk_cfg; - 对发送(TX)与接收(RX)引脚执行
gpio_configure()复用配置并设置上拉; - 配置 TX/RX 水印、8 位字长、禁用奇偶校验、设置 FIFO 打包向量(每字 8 bit),最后写入
geni_s_cmd0启动 RX。
默认控制台实例由UART_FOR_CONSOLE决定,默认值为 8(即QUPV3_1_SE2,见 Kconfig)。SC7180 特有的UART_TX_PIN = GPIO(44)定义在 include/soc/uart.h,与 qup[8] 的 TX 引脚(GPIO(44))一致。构建时CONFIG_DRIVERS_UART决定将common/qupv3_uart.c编入 verstage/romstage/ramstage(Makefile.mk),而 bootblock 阶段使用比特bang 方式(common/uart_bitbang.c)输出早期日志。
SPI-NOR:QSPI 控制器与 DMA 描述符链
SPI-NOR 由 SC7180 的 QSPI(Qualcomm SPI-NOR)控制器驱动,实现在 common/qspi.c。它支持 SDR/DDR 与 1/2/4-bit 多种模式(enum qspi_mode:SDR_1BIT到DDR_4BIT),核心机制是基于 DMA 的描述符链:
- 三个预分配的
cmd_desc描述符(存放在_dma_coherent一致性内存中)通过next_descriptor串联,描述符内的位域包含方向、多 I/O 模式、fragment、长度与反弹(bounce)缓冲区地址; dma_transfer_chain()把链首地址写入next_dma_desc_addr后轮询mstr_int_sts等待DMA_CHAIN_DONE;flush_chain()在传输完成后处理反弹缓冲与缓存一致性:对读方向要么dcache_invalidate_by_mva()使缓存失效,要么把 bounce 数据memcpy回目标缓冲区。
QSPI 控制器基址为QSPI_BASE = 0x088DC000,其核心时钟由clock_configure_qspi(hz)(clock.c)配置并使能qspi_cnoc_ahb_cbcr/qspi_core_cbcr时钟。bootblock 的bootblock_soc_init()(bootblock.c)即以 37.5 MHz 调用quadspi_init(37500 * KHz)初始化 QSPI,用于读取 CBFS 中的启动固件。配置项SC7180_QSPI(默认在启用COMMON_CBFS_SPI_WRAPPER时打开)控制是否用 SPI-NOR 作为启动介质,BOOT_DEVICE_SPI_FLASH_BUS默认值为 16(见 Kconfig)。
AOP FW:Always-On Processor 固件的加载与复位
AOP(Always-On Processor)是 SC7180 上负责低功耗管理的小核,其固件由 ramstage 的soc_init()(soc.c)通过aop_fw_load_reset()(common/aop_load_reset.c)加载:
- 先把 AOP 代码 RAM 区域(0x0B000000,256 KiB,见 memlayout.ld)临时映射为
CACHED_RAM,保证 4 字节对齐的写入路径; - 用
selfload()从 CBFS 加载名为aop的 payload(源文件3rdparty/qc_blobs/sc7180/aop/aop.mbn,见 Makefile.mk); - 对缓存区域执行
dcache_clean_by_mva()刷回,再重新映射为DEV_MEM; - 最后调用
clock_reset_aop()(include/soc/clock.h)——通过 AOSS_CC 的aoss_cc_apcs_misc寄存器对 AOP 子系统执行复位,使其从新固件启动。
USB:DWC3 控制器与 PHY 初始化
USB 支持基于 Qualcomm 通用 USB 代码(common/usb/usb.c),驱动 DWC3 控制器并配合两套 PHY:
- QUSB2 PHY:高速 USB2 PHY,基址
QUSB_PRIM_PHY_BASE = 0x088e3000(含 DIG 部分 0x088e3200); - QMP PHY:USB3 组合 PHY,包含 QSERDES COM/TX/RX 与 PCS 寄存器块(0x088e9000 起)。
usb_port0结构把 DWC3 控制器(USB_HOST_DWC3_BASE = 0x0a60c100)与 GCC 中的usb30_prim_bcr、qusb2phy_prim_bcr、usb3_dp_phy_prim_bcr、usb3_phy_prim_bcr复位寄存器关联起来。romstage 中主板会先执行reset_usb0()(见 src/mainboard/google/trogdor/romstage.c),"趁早踢出复位以便至少 1 ms 稳定"。ramstage 的setup_usb_host0(&usb0_board_data)则通过usb_board_data结构(如pll_bias_control_2、imp_ctrl1、port_tune1)下发 PHY 调谐参数。此外,include/soc/efuse.h 定义了 QFPROM 中 USB 发射端微调(qusb_hstx_trim_lsb@ 0x4258)的读取入口。
硬件笔记:定时器来自 ARMv8 架构代码
原文档的"Notes about the hardware"明确指出:定时器使用 ARMv8 架构特有的代码(The timer is used from the ARMv8 architecture specific code)。这对应 common/timer.c 的实现:
void init_timer(void) { raw_write_cntfrq_el0(19200*KHz); }即把 ARM 通用计时器频率寄存器CNTFRQ_EL0设置为 19.2 MHz(与 XO 时钟同频)。相应地,Kconfig 中SOC_QUALCOMM_SC7180显式选择了ARM64_USE_ARCH_TIMER(使用 ARM 架构计时器)、HAVE_MONOTONIC_TIMER与GENERIC_UDELAY,整个 SoC 采用 ARMv8 64 位架构(ARCH_BOOTBLOCK/VERSTAGE/ROMSTAGE/RAMSTAGE_ARMV8_64),并依赖ARM64_USE_ARM_TRUSTED_FIRMWARE集成 BL31(构建参数BL31_MAKEARGS += PLAT=sc7180,见 Makefile.mk)。
启动流程与各阶段的 SOC 代码分工
把上述模块串起来,SC7180 的启动流程与各阶段分工如下:
| 阶段 | 主要 SOC 代码 | 职责 |
|---|---|---|
| decompressor | decompressor.c | 解压 bootblock 前先执行sc7180_mmu_init()建立页表 |
| bootblock | bootblock.c | clock_init()初始化时钟、quadspi_init(37500*KHz)使 QSPI 可访问 CBFS、qupv3_fw_init()使能 QUP 时钟 |
| verstage | common/qupv3_uart.c | vboot 验证阶段的串口控制台输出 |
| romstage | qclib.c、carve_out.c、common/qclib.c | 加载并运行 QCLib 完成 DDR 初始化/训练;按调制解调器 ID 预留内存 |
| ramstage | soc.c、common/aop_load_reset.c | 注册内存资源、加载 AOP 固件、USB 与显示初始化 |
其中值得注意的细节:
- QCLib(DDR 初始化):
qclib_soc_override()(qclib.c)在运行前从 CBFS 加载dcb(DDR 配置块)并加入 QCLib 接口表;qclib_override_soc_file()会根据 efuse 位(LONG_SYS_DCB_REG0x7801C0 的 bit 15)判断是否改用dcb_longsys1p8(Longsys 1.8V 内存)配置。Trogdor 主板还通过qclib_mainboard_override()(romstage.c)为 Lazor 板设置 DDR 频率上限(QCLIB_GA_DDR_FMAX_LIMIT_HYNIX8GB)以规避内存稳定性问题; - 内存预留:
soc_read_resources()(soc.c)上报 DDR 主区域与dram_aop、dram_soc预留区,soc_modem_carve_out()(carve_out.c)按_modem_id中的调制解调器 ID(LTE/WiFi)动态切出 modem 专用内存; - bootblock 打包:构建时用
util/qualcomm/createxbl.py将 bootblock 与qc_sec.mbn安全镜像合并,再用util/qualcomm/qgpt.py生成最终bootblock.bin(Makefile.mk)。
构建配置与固件依赖清单
启用 SC7180 SoC 的 Kconfig 入口为SOC_QUALCOMM_SC7180(默认关闭),关键配置项汇总如下(均见 Kconfig):
| 配置项 | 类型/默认值 | 说明 |
|---|---|---|
SOC_QUALCOMM_SC7180 | bool,默认 n | 总开关,自动选择 ARMv8-64 各阶段架构、ATF、GPIO 库、架构计时器等 |
QC_SDI_ENABLE | bool,default y if QC_RAMDUMP | 启用 QcSdi 调试镜像(构建libqtisec_dbg.a)并打包fallback/qcsdi |
MEMLAYOUT_LD_FILE | string,src/soc/qualcomm/sc7180/memlayout.ld | 内存布局链接脚本 |
SC7180_QSPI | bool,default y if COMMON_CBFS_SPI_WRAPPER | 使用 SPI-NOR 作为启动介质 |
BOOT_DEVICE_SPI_FLASH_BUS | int,默认 16 | 启动设备 SPI 总线号 |
UART_FOR_CONSOLE | int,默认 8 | 用于控制台输出的 QUP 实例(QUPV3_1_SE2) |
VBOOT | — | 选择VBOOT_SEPARATE_VERSTAGE、VBOOT_RETURN_FROM_VERSTAGE、VBOOT_MUST_REQUEST_DISPLAY、VBOOT_STARTS_IN_BOOTBLOCK |
在CONFIG_USE_QC_BLOBS=y时,构建还需从3rdparty/qc_blobs/sc7180/提供的二进制固件(完整清单见 Makefile.mk):boot/QcLib.elf(QCLib,DDR 初始化)、boot/Pmic.bin(PMIC 配置)、boot/dcb.bin与boot/dcb_slow.bin(DDR 配置块)、aop/aop.mbn(AOP 固件)、qup_fw/uart_fw.bin/spi_fw.bin/i2c_fw.bin(QUP 串行引擎固件)、qc_sec/qc_sec.mbn(安全启动镜像)、qtiseclib/libqtisec.a(ATF 安全库)。
在主板侧,参考实现是 Google Trogdor 系列(src/mainboard/google/trogdor/),覆盖 Bubs、Coachz、Gelarshie、Homestar、Kingoftown、Lazor、Marzipan、Mrbland、Pazquel、Pompom、Quackingstick、Trogdor、Wormdingler 等衍生板卡,通过select SOC_QUALCOMM_SC7180接入该 SoC,并在 bootblock 初始化 TPM 与 EC 的 QUP SPI 总线(bootblock.c)。coreboot 对 Qualcomm SC7180 的支持自 4.11 版本起加入(见 Documentation/releases/coreboot-4.11-relnotes.md)。更多 Qualcomm SoC 文档可参见 Documentation/soc/qualcomm/index.md。
- 固件
- 嵌入式
- 操作系统
- 驱动开发
【免费下载链接】coreboot
Read-only mirror of https://review.coreboot.org/coreboot.git. Synced every hour. We don't handle Pull Requests.
相关推荐
coreboot 对 Qualcomm SoC 的支持:SC7180 与 SC7280 平台代码解析
coreboot 对 Qualcomm SoC 的支持:SC7180 与 SC7280 平台代码解析 本篇技术指南以仓库中 Qualcomm SoC 专属文档
固件嵌入式操作系统驱动开发coreboot 中的 Qualcomm SC7280 SoC 支持解析:MMU、时钟、GPIO 与外围设备驱动实现
coreboot 中的 Qualcomm SC7280 SoC 支持解析:MMU、时钟、GPIO 与外围设备驱动实现 导读 本文以 coreboot 官方文档
固件嵌入式操作系统驱动开发coreboot 支持 System76 Gazelle 17(gaze17)笔记本:硬件规格、固件源码解析与刷写指南
coreboot 支持 System76 Gazelle 17(gaze17)笔记本:硬件规格、固件源码解析与刷写指南 本文以 coreboot 仓库中的 ga
固件嵌入式操作系统驱动开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考