寄存器驱动程序应该用于 可以由多个驱动程序访问。
概念
驱动程序通常通过基于寄存器的接口与硬件通信。 从概念上讲,寄存器是指可读取或 通过地址空间写入。MMIO 寄存器通过 CPU 的 内存地址空间,而 I2C 寄存器是通过 I2C 总线访问的。
大多数硬件仅支持原子寄存器写入。想要
要更改寄存器中的一些位,必须通过读取/修改/写入来实现
操作。例如,对于 32 位寄存器,如果要更改
将 0-1 位都写入 0
,则需要读取该寄存器的所有 32 位。
说 0xFFFFFFFF
,然后回写到该寄存器 0xFFFFFFFC
。
同步
读取/修改/写入操作可能会导致出现数据争用。通过 经典交易示例“从银行账户提取 10 美元”为 实际上是读取/修改/写入操作请参阅 示例部分提供了具体图示。
注册为“独家所有”的注册机构司机应承担的责任 将其访问同步至寄存器,从而避免出现数据争用。( 可能性仍然存在,但这不在 注册驱动程序)。
当寄存器“共享”时(可以被多个驱动程序访问),我们需要 全球协调员,避免出现比赛。寄存器驱动程序可以这样操作 全局协调器,当每个驾驶员只需要访问不相交的子集时, 寄存器的位数。全球协调员将提供所需的 寄存器读写之间的同步。
隔离
寄存器驱动程序不仅通过提供同步来阻止竞态, 还能隔离位字段寄存器驱动程序拆分 注册到多个资源中,并确保每个驱动程序 可以访问这些位驱动程序可能不会意外读取或写入 与自身无关的位。
运行理论
在板驱动程序中,一个寄存器 由多个驱动程序访问,声明了不同的位字段 它想要公开的对象。寄存器驱动程序为每个 位字段。想要访问这些位字段的驱动程序需要 才能绑定到相应的设备
在寄存器驱动程序中,每个寄存器都有对应的锁,以确保 同时只有一个读/写可以访问寄存器。 寄存器驱动程序由 registers-util.fidl 定义。
使用方法
目前,重置寄存器是仅有的寄存器 改为使用寄存器驱动程序。本部分将使用它们 如何使用寄存器驱动程序。
板驱动程序变更
元数据格式在 metadata.fidl 中声明。
在板驱动程序(即 nelson-registers)中, 更改。
a. MMIO
确保寄存器驱动程序有权访问 MMIO。否则, 添加 MMIO 和相应的 MMIO 索引:
enum MmioMetadataIdx { kResetMmio, kMmioCount, }; static const std::vector<fpbus::Mmio> registers_mmios{ { { .base = A311D_RESET_BASE, .length = A311D_RESET_LENGTH, }, }, };
请注意,
MmioMetadataIndex
必须与 MMIO 的registers_mmios
中的索引。b. 声明位字段
RegistersMetadataToFidl
帮助程序 函数可用于声明位字段:auto metadata_bytes = fidl_metadata::registers::RegistersMetadataToFidl<uint32_t>(kRegisters); if (metadata_bytes.is_error()) { zxlogf(ERROR, "%s: Failed to FIDL encode registers metadata %s\n", __func__, metadata_bytes.status_string()); return metadata_bytes.error_value(); } const std::vector<fpbus::Metadata> registers_metadata{ { { .type = DEVICE_METADATA_REGISTERS, .data = metadata_bytes.value(), }, }, };
其中,位字段在
kRegisters
字段中定义:static const fidl_metadata::registers::Register<uint32_t> kRegisters[]{ { .bind_id = aml_registers::REGISTER_USB_PHY_V2_RESET, .mmio_id = kResetMmio, .masks = { { .value = aml_registers::USB_RESET1_REGISTER_UNKNOWN_1_MASK | aml_registers::USB_RESET1_REGISTER_UNKNOWN_2_MASK, .mmio_offset = A311D_RESET1_REGISTER, }, { .value = aml_registers::USB_RESET1_LEVEL_MASK, .mmio_offset = A311D_RESET1_LEVEL, }, }, }, ... };
bind_id
:每个位字段定义的唯一 ID, 用于在绑定期间识别它mmio_id
:与该位字段的 MMIO 对应的 ID 指的是什么。masks
:描述特定位字段的掩码列表, 应可通过此寄存器设备访问。value
:可供访问的位掩码,使用1
表示可访问,0
表示无法访问。例如,对于 32 位寄存器,位掩码可以是0xFFFF0000
,这意味着 可通过该容器访问寄存器的高 16 位 而后 16 位数则不行。mmio_offset
:从 MMIO 开头算起的起始偏移量 由这些位字段定义的mmio_id
标识。count
:此位字段掩码的寄存器地址数 适用于以下mmio_offset
。默认为1
。overlap_check_on
:如果为true
,寄存器驱动程序将 验证这些位字段是否 已定义的位字段否则,系统会跳过该检查。默认值 发送至true
。
寄存器驱动程序将创建一个提供 registers-util.fidl 的设备。 具有绑定属性:
{:.devsite-disable-click-to-copy} bind_fuchsia_register::NAME == bind_id
绑定到寄存器驱动程序
然后,希望访问这些位字段的驱动程序必须绑定到 上述创建的设备。
使用寄存器驱动程序接口
成功连接到寄存器设备后,例如通过
fidl::WireSyncClient<fuchsia_hardware_registers::Device> register
, 您可以根据 FIDL 调用相应的 registers-util.fidl 中定义的接口。 例如,对于 32 位寄存器,auto result = reset_register_->WriteRegister32(RESET1_LEVEL_OFFSET, aml_registers::USB_RESET1_LEVEL_MASK, aml_registers::USB_RESET1_LEVEL_MASK); if ((result.status() != ZX_OK) || result->is_error()) { zxlogf(ERROR, "Write failed\n"); return ZX_ERR_INTERNAL; }
享受隔离的同步寄存器!
示例
数据争用
假设我们有一个寄存器可供驱动程序 A 和驱动程序 B 访问。
现在,驱动程序 A 想要将 b01
写入寄存器和驱动程序的位 0-1 中
B 想要将 b001
写入寄存器的第 8-10 位。视时间而定
驱动程序 A 可能会读取寄存器的原始值,例如 0xFFFFFFFF
,
驱动程序 B 也可以读取相同的值。然后,驱动程序 A 向位 0-1 写入数据
并放入内存 0xFFFFFFFD
。然后,驱动程序 B 向内存写入数据
0xFFFFF9FF
。在这一事件序列中,寄存器现在存储
0xFFFFF9FF
(驱动程序 B 在最后写入的内容)。不过,下次
驱动程序 A 读取该寄存器的位 0-1,因此不会获得
与之前写入的值相同。
AMLogic SoC
本部分通过一些示例来说明寄存器驱动程序应在何处 。注册数据库驱动程序时, 在多个驱动程序之间进行同步, 不一定是 仅用于隔离资源请注意,下方并未列出所有情况 AMLogic SoC 中的共享寄存器列表。
重置寄存器
AMLogic SoC 具有针对各种硬件单元的重置功能
集中在几个 32 位寄存器中。这以
S905D3 中的 RESET1_REGISTER
表 6-186。例如,USB 重置操作
由位 2 控制,SD_EMMC 由位 12-14 控制。硬件设计影响
我们可以在多个驱动程序(包括 EMMC)之间共享 RESET1_REGISTER
驱动程序和 USB 驱动程序。
如需了解针对重置所做的板级文件更改,请参阅 nelson-registers
寄存器和 nelson-usb - 用于添加重置功能的 aml_usb_phy
设备
注册 fragment。AmlUsbPhy::InitPhy()
的 aml-usb-phy 使用次数
FIDL 客户端写入重置寄存器。
功率寄存器
与上述重置寄存器类似,AO_RTI_GEN_PWR_SLEEP0
(S905D3 表 6-17)和 AO_RTI_GEN_PWR_ISO0
(S905D3 表)
6-18)由多个驱动程序(包括显示屏、USB 和机器学习)共享,
由寄存器驱动程序管理,因为它们是可写入的,并且需要
协调。此迁移目前正在进行中。
另一方面,虽然 AO_RTI_GEN_PWR_ACK0
(S905D3 表 6-19)
将由多个驱动程序(PCIE、USB、显示器等)共享,且处于只读状态。
可以同时访问此寄存器中的数据,而不会产生任何竞选风险,
因此无需使用寄存器驱动程序进行同步。如果
我们仍然可以使用寄存器驱动程序来隔离资源。