乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Linux DRM (三) RK 平臺 DRM 代碼分析 · Rockchip

       老匹夫 2019-09-26

      本篇是 DRM 的第三篇文章。 在 《Linux DRM (一) Display Server》 中我們了解了 DRM 誕生的歷史。 在 《Linux DRM (二) 基本概念和特性》 中我們了解了一些基本的概念。 現(xiàn)在,我們終于要向 DRM 源碼進軍了。

      +

      一、概覽

      不知大家是否還記得,之前我有引用 Wiki 中對 DRM 的介紹,這里我們再回顧一下: DRM 由兩個部分組成: 一是 Kernel 的子系統(tǒng),這個子系統(tǒng)對硬件 GPU 操作進行了一層框架封裝。 二是 提供了一個 libdrm 庫,里面封裝了一系列 API,用來進行圖像顯示。 整體來看和 Android 上所采用的 Direct Frame Buffer 差不多。 Android Kernel 走的是 FB 的框架,并在 HAL 抽象出一個 FBDEV,來進行 FB IOCTL 統(tǒng)一管理。 DRM 就相當于直接對圖形設備集中處理,并且多出了一個 libdrm 庫。

      +

      其整體脈絡如下:

      +

      源碼文件

      component framework

      在講述啟動過程之前,先簡單了解一下 component framework。

      +

      因為 drm下掛了許多的設備, 啟動順序經(jīng)常會引發(fā)各種問題:

      +
      1. 一個驅動完全有可能因為等另一個資源的準備, 而probe deferral, 導致順序不定

      2. 子設備沒有加載好, 主設備就加載了, 導致設備無法工作

      3. 子設備相互之間可能有時序關系,不定的加載順序,可能帶來有些時候設備能工作,有些時候又不能工作

      4. 現(xiàn)在編kernel是多線程編譯的,編譯的前后順序也會影響驅動的加載順序.

      這時就需要有一個統(tǒng)一管理的機制, 將所有設備統(tǒng)合起來, 按照一個統(tǒng)一的順序加載, Display-subsystem正是用來解決這個問題的, 依賴于component的驅動, 通過這個驅動, 可以把所有的設備以組件的形式加在一起, 等所有的組件加載完畢后, 統(tǒng)一進行bind/unbind.

      +

      代碼路徑 drivers/base/component.c

      +

      以下為rockchip drm master probe階段component 主要邏輯, 為了減小篇幅, 去掉了無關的代碼:

      +
      static int rockchip_drm_platform_probe(struct platform_device *pdev)
      {
          for (i = 0;; i++) {
              /* ports指向了vop的設備節(jié)點 */
              port = of_parse_phandle(np, "ports", i);
              component_match_add(dev, &match, compare_of, port->parent);
          }
          for (i = 0;; i++) {
              port = of_parse_phandle(np, "ports", i);
              /* 搜查port下的各個endpoint, 將它們也加入到match列表 */
              rockchip_add_endpoints(dev, &match, port);
          }
          return component_master_add_with_match(dev, &rockchip_drm_ops, match);
      }
      
      static void rockchip_add_endpoints(...)
      {
          for_each_child_of_node(port, ep) {
              remote = of_graph_get_remote_port_parent(ep);
                  /* 這邊的remote即為和vop關聯(lián)的輸出設備, 即為edp, mipi或hdmi */
              component_match_add(dev, match, compare_of, remote);
          }
      }

      啟動過程

      圖自 markyzq gitbook:

      +

      基于 component 框架,在 probe 階段

      +
      1. 解析 dts 中各個設備的信息

      2. 加到 component match 列表中

      3. 設備加載完畢后,master 設備進行 bind

      RK DRM Device Driver

      device tree

      display_subsystem: display-subsystem {
          compatible = "rockchip,display-subsystem";
          ports = <&vopl_out>, <&vopb_out>;
          status = "disabled";
      };
      
      - compatible: Should be "rockchip,display-subsystem"
      - ports: Should contain a list of phandles pointing to display interface port
        of vop devices. vop definitions as defined in
        kernel/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt

      drm driver

      代碼路徑

      drivers/gpu/drm/rockchip/rockchip_drm_drv.c
      drivers/gpu/drm/rockchip/rockchip_drm_drv.h
      static struct drm_driver rockchip_drm_driver = {
          .driver_features    = DRIVER_MODESET | DRIVER_GEM |
                        DRIVER_PRIME | DRIVER_ATOMIC |
                        DRIVER_RENDER,
          .preclose        = rockchip_drm_preclose,
          .lastclose        = rockchip_drm_lastclose,
          .get_vblank_counter    = drm_vblank_no_hw_counter,
          .open            = rockchip_drm_open,
          .postclose        = rockchip_drm_postclose,
          .enable_vblank        = rockchip_drm_crtc_enable_vblank,
          .disable_vblank        = rockchip_drm_crtc_disable_vblank,
          .gem_vm_ops        = &rockchip_drm_vm_ops,
          .gem_free_object    = rockchip_gem_free_object,
          .dumb_create        = rockchip_gem_dumb_create,
          .dumb_map_offset    = rockchip_gem_dumb_map_offset,
          .dumb_destroy        = drm_gem_dumb_destroy,
          .prime_handle_to_fd    = drm_gem_prime_handle_to_fd,
          .prime_fd_to_handle    = drm_gem_prime_fd_to_handle,
          .gem_prime_import    = drm_gem_prime_import,
          .gem_prime_export    = drm_gem_prime_export,
          .gem_prime_get_sg_table    = rockchip_gem_prime_get_sg_table,
          .gem_prime_import_sg_table    = rockchip_gem_prime_import_sg_table,
          .gem_prime_vmap        = rockchip_gem_prime_vmap,
          .gem_prime_vunmap    = rockchip_gem_prime_vunmap,
          .gem_prime_mmap        = rockchip_gem_mmap_buf,
      #ifdef CONFIG_DEBUG_FS
          .debugfs_init        = rockchip_drm_debugfs_init,
          .debugfs_cleanup    = rockchip_drm_debugfs_cleanup,
      #endif
          .ioctls            = rockchip_ioctls,
          .num_ioctls        = ARRAY_SIZE(rockchip_ioctls),
          .fops            = &rockchip_drm_driver_fops,
          .name    = DRIVER_NAME,
          .desc    = DRIVER_DESC,
          .date    = DRIVER_DATE,
          .major    = DRIVER_MAJOR,
          .minor    = DRIVER_MINOR,
      };

      vop driver

      代碼路徑:

      +
      drivers/gpu/drm/rockchip/rockchip_drm_vop.c
      drivers/gpu/drm/rockchip/rockchip_vop_reg.c

      結構體:

      struct vop;
      // vop 驅動根結構, 一個vop對應一個struct vop結構
      
      struct vop_win;
      // 描述圖層信息, 一個硬件圖層對應一個struct vop_win結構

      寄存器讀寫: 為了兼容各種不同版本的vop, vop驅動里面使用了寄存器級的抽象, 由一個結構體來保存抽象關系, 這樣主體邏輯只需要操作抽象后的功能定義, 由抽象的讀寫接口根據(jù)抽象關系寫到真實的vop硬件中.

      +

      示例:

      static const struct vop_win_phy rk3288_win23_data = {
             .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4),
        }
        static const struct vop_win_phy rk3368_win23_data = {
             .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4),
        }

      rk3368和rk3288圖層的地址分布不同, 但在結構定義的時候, 可以將不同的硬件圖層bit 映射到同一個enable功能上, 這樣vop驅動主體調用VOP_WIN_SET(vop, win, enable, 1);時就能操作到真實的vop寄存器了.

      +

      2.1 設備文件 cardX

      DRM 處于內核空間,這意味著用戶空間需要通過系統(tǒng)調用來申請它的服務。 不過 DRM 并沒有定義它自己的系統(tǒng)調用。相反,它遵循“Everything is file”的原則,通過文件系統(tǒng),在 /dev/dri/目錄下暴露了 GPU 的訪問方式。 DRM 會檢測每個 GPU,并生成對應的 DRM 設備,創(chuàng)建設備文件 /dev/dri/cardX與 GPU 相接。X 為 0-15 的數(shù)值,默認是 Card0。

      +

      用戶空間的程序如果希望訪問 GPU 則必須打開該文件,并使用 ioctl 與 DRM 通信。不同的 ioctl 對應 DRM API 的不同功能。

      +

      2.2 用戶空間的內存操作

      我們定義一個外部的內存結構來更好的描述如何進行 userspace 的 drm 操作。 首先使用到 DRM 相關操作的時候需要引用 drm.h。

      +
      #include <drm.h>
      struct bo {
         int fd;
         void *ptr;
         size_t size;
         size_t offset;
         size_t pitch;
         unsigned handle;
      };

      2.2.1 獲取設備節(jié)點

      bo->fd = open("/dev/dri/card0"),O_RDWR,0);

      2.2.2 分配內存空間

      struct drm_mode_create_dumb arg;
      int handle, size, pitch;
      int ret;
      memset(&arg, 0, sizeof(arg));
      arg.bpp = bpp;
      arg.width = width;
      arg.height = height;
      ret = drmIoctl(bo->fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
      if (ret) {
          fprintf(stderr, "failed to create dumb buffer: %s\n", strerror(errno));
          return ret;
      }
      bo->handle = arg.handle;
      bo->size = arg.size;
      bo->pitch = arg.pitch;

      2.2.3 映射物理內存

      struct drm_mode_map_dumb arg;
      void *map;
      int ret;
      
      memset(&arg, 0, sizeof(arg));
      arg.handle = bo->handle;
      ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
      if (ret)
          return ret;
      map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, arg.offset);
      if (map == MAP_FAILED)
         return -EINVAL;
      bo->ptr = map

      2.2.4 解除物理內存映射

      drm_munmap(bo->ptr, bo->size);
      bo->ptr = NULL;

      2.2.5 釋放內存

      struct drm_mode_destroy_dumb arg;
      int ret;
      
      memset(&arg, 0, sizeof(arg));
      arg.handle = bo->handle;
      ret = drmIoctl(bo->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
      if (ret)
          fprintf(stderr, "failed to destroy dumb buffer: %s\n", strerror(errno));

      2.2.6 釋放 gem handle

      struct drm_gem_close args;
      memset(&args, 0, sizeof(args));
      args.handle = bo->handle;
      drmIoctl(bo->fd, DRM_IOCTL_GEM_CLOSE, &args);

      2.2.7 export dmafd

      int export_dmafd;
      ret = drmPrimeHandleToFD(bo->fd, bo->handle, 0, &export_dmafd);
      // drmPrimeHandleToFD是會給dma_buf加引用計數(shù)的
      // 使用完export_dmafd后, 需要使用  close(export_dmafd)來減掉引用計數(shù)

      2.2.8 import dmafd

      ret = drmPrimeFDToHandle(bo->fd, import_dmafd, &bo->handle);
      // drmPrimeHandleToFD是會給dma_buf加引用計數(shù)的
      // 使用完bo->handle后, 需要對handle減引用, 參看free gem handle部分.

      2.2 DRM libdrm

      libdrm 被創(chuàng)建以用于方便用戶空間和 DRM 子系統(tǒng)的聯(lián)系。它僅僅只提供了一些函數(shù)的包裝(C),這些函數(shù)是為 DRM API 的每一個 ioctl、常量、結構體 而寫。 使用 libdrm 這個庫不僅僅避免了將內核接口直接暴露給用戶空間,也有代碼復用等常見優(yōu)點。

      +

      2.3 DRM 代碼結構

      分為兩個部分:通用的 DRM Core 和適配于不同類型硬件的 DRM Driver。 DRM Core 提供了不同 DRM 驅動程序可以注冊的基本框架, 并且為用戶空間提供了具有通用,獨立于硬件功能的最小 ioctl 集合。 DRM Driver 實現(xiàn)了 API 的硬件依賴部分。 它提供了沒有被 DRM core 覆蓋的其余 ioctl 的實現(xiàn),它也可以拓展 API,提供額外的 ioctl。比如某個特定的 DRM Driver 提供了一個增強的 API ,用戶空間的 libdrm 也需要以額外的 libdrm-driver 拓展,用來使用這些額外的 ioctl。

      +

      2.4 DRM API

      DRM Core 向用戶空間應用程序導出了多個接口,讓相應的 libdrm 包裝成函數(shù)后來使用。 DRM Driver 導出的特定設備的接口,可以通過 ioctls 和 sysfs 來供用戶空間使用。

      +

      2.5 DRM-Master 和 DRM-Auth

      DRM API 中有幾個 ioctl 由于并發(fā)問題僅限于用戶空間的單個進程使用。 為了實現(xiàn)這種限制,將 DRM 設備分為 Master 和 Auth。 上述的那些 ioctl 只能被 DRM-Master 的進程調用。 打開了 /dev/dri/cardX的進程的文件句柄會被標志為 master,特別是第一個掉喲該 SET_MASTERioctl 的進程。如果不是 DRM-Master 的進程在使用這些限制 ioctl 的時候會返回錯誤。進程也可以通過 DROP_MASTERioctl 放棄 Master 角色,來讓其他進程變成 Master。

      +

      X Server 或者其他的 Display Server 通常會是他們所管理的 DRM 設備的 DRM-Master 進程。當 DRM 設備啟動的時候哦,這些 Display Server 打開設備節(jié)點,獲取 DRM-Master 權限,直到關閉設備。

      +

      對于其他的用戶空間進程,還有一種辦法可以獲得 DRM 設備的這些 受限權限,這就是 DRM-Auth。它是一種針對 DRM 設備的驗證方式,用來證明該進程已經(jīng)獲得了 DRM-Master 對于他們去訪問受限 ioctls 的許可。

      +

      步驟:

      1. DRM Client 使用 GET_MAGIC ioctl 從 DRM 設備獲取一個 32bit整型的 token。并通過任何方式(通常是 IPC)傳遞給 DRM-Master。

      2. DRM-Master 進程使用 AUTH_MAGIC ioctl 返回 token 給 DRM 設備。

      3. 設備將 DRM-Master 所給的 token 和 Auth 的進行對比。通過的話就賦予進程文件句柄特殊的權限。

      #

      DRM 在源碼中的架構 (圖自 Mark.Yao):

      +

      使用 DRM 訪問 Video Card (圖自 wikipedia):

      +

      沒有 DRM 時,用戶空間進程訪問 GPU 的方式有 DRM 后,用戶空間訪問 GPU 的方式

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約