註冊總覽

應使用註冊驅動程式的註冊, 可讓多個駕駛人存取。

概念

驅動程式通常會透過註冊式介面與硬體通訊。 概念上,暫存器是 8/16/32/64 位元的群組,可讀取或 能夠透過位址空間編寫您可以透過 CPU 的 記憶體位址空間,而 I2C 暫存器則透過 I2C 匯流排存取。

大部分硬體僅支援不可分割的暫存器寫入。因此,需要 若要變更暫存器的某些部分,必須透過讀取/修改/寫入來變更 作業。例如,假設要變更 32 位元暫存器, 0 至 1 位元和 0 之間,您需要讀取該暫存器的全部 32 位元, 說 0xFFFFFFFF,然後寫回該註冊 0xFFFFFFFC

同步處理

讀取/修改/寫入作業可能造成資料競爭。 傳統交易範例「提款 $10 美元,銀行帳戶」為 這就等同於讀取/修改/寫入作業請參閱「資料競爭」: 請參閱「範例」一節中的具體說明。

註冊者為「專屬」時駕駛人 ,將其存取權同步到暫存器,以避免資料競爭。( 儘管風險仍然存在,但這不在 註冊驅動程式庫)。

當註冊者「共用」時可讓多位駕駛人存取 (也可以存取) 協調事件工作暫存器驅動程式庫可執行此操作 所有驅動程式庫只需存取不連貫的子集 。全球協調人員會 讀取/寫入暫存器之間的同步處理作業。

隔離

暫存器驅動程式庫不僅藉由提供同步處理機制來阻止賽跑 但也能區隔位元欄位暫存器的驅動程式庫分割 註冊多項資源,並確保每位驅動程式都只執行單一驅動程式 就能存取那些部分駕駛人可能不會意外讀取或寫入 但其實不然

營運理論

桌遊驅動程式中, 由多個驅動程式存取時,系統會宣告 所有要公開的 Pod註冊驅動程式庫會為每個裝置建立裝置 缺少部分符記想要存取這些位元欄位需求的驅動程式 繫結至對應的裝置。

在註冊驅動程式庫中,系統會使用各暫存器的鎖定來確保 且只能讀取/寫入一次暫存器。Google Cloud 的介面 註冊驅動程式庫由 registers-util.fidl 定義。

使用方法

目前只有重設註冊是唯一的暫存器 改用註冊驅動程式庫的容器。這個部分會使用 做為如何使用暫存器驅動程式庫的範例

  1. 董事會驅動程式庫變更

    中繼資料格式是在 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. 宣告 Bitfields

    RegistersMetadataToFidl 輔助工具 函式可用於宣告 Bitfields:

      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(),
            },
          },
      };
    

    其中 Bitfields 已在 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 版本則不需要。
      • mmio_offset:從 MMIO 開始的起始偏移 透過 mmio_id 來識別。
      • count:這個位元欄位遮罩的註冊位址數量 適用於後續 mmio_offset。預設為 1
      • overlap_check_on:如果為 true,註冊驅動程式庫會 並確定這些位元欄位並未與任何其他 已定義 Bitfields否則系統會略過檢查。預設值 至 true

    註冊驅動程式庫會建立提供 registers-util.fidl 的裝置 具有繫結屬性: {:.devsite-disable-click-to-copy} bind_fuchsia_register::NAME == bind_id

  2. 繫結至註冊驅動程式庫

    想要存取這些 Bit 欄位的驅動程式接著必須繫結至 。

  3. 使用註冊驅動程式庫介面

    成功連線至註冊裝置後,例如 fidl::WireSyncClient<fuchsia_hardware_registers::Device> register, 您可以根據 FIDL 呼叫對應的 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;
    }
    
  4. 歡迎體驗獨立的同步註冊裝置!

範例

資料競爭

假設我們的暫存器同時由驅動程式庫 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 資料表 6-186 中的 RESET1_REGISTER。例如,USB 重設是 由位元 2 和 SD_EMMC 由位元 12-14 控制。硬體設計團隊 我們會將「RESET1_REGISTER」分享給多名司機,包括 EMMC 以及 USB 驅動程式庫

如要瞭解重設的 Jamboard 檔案變更,請參閱 nelson-registers。 暫存器和 nelson-usb - 用於新增重設裝置數量的 aml_usb_phy 部裝置 註冊片段。aml-usb-phyAmlUsbPhy::InitPhy() 用途 要寫入重設暫存器的 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、顯示器等) 共用,處於唯讀狀態。 您可以同時存取這個暫存器中的資料,不需任何競爭風險。 因此不需要使用暫存器驅動程式庫進行同步處理。如果 我們仍可能會使用暫存器驅動程式庫來隔離資源。