9. [mmc subsystem] host(第三章)——sdhci-pltfm說明

来源:https://www.cnblogs.com/linhaostudy/archive/2019/05/06/10818083.html
-Advertisement-
Play Games

一、sdhci pltfm說明 sdhci pltfm並不是實際某個host的driver。 sdhci pltfm是指在sdhci core的基礎上,提供了統一對sdhci_host的必要屬性進行解析和設置的方法。 但是,對於sdhci類的host driver來說,使用sdhci pltfm並不 ...


一、sdhci-pltfm說明

sdhci-pltfm並不是實際某個host的driver。

sdhci-pltfm是指在sdhci core的基礎上,提供了統一對sdhci_host的必要屬性進行解析和設置的方法。

但是,對於sdhci類的host driver來說,使用sdhci-pltfm並不是必須的,host driver也可以自己來實現對應的操作。

通過《host(第二章)——sdhci》,我們知道了host driver調用sdhci_add_host註冊sdhci_host的之前需要設置的信息如下:

  • sdhci的寄存器的映射過後的基地址(sdhci_host->ioaddr)
  • sdhci的癖好quirks、quirks2(sdhci_host->quirks,sdhci_host->quirks2)
  • sdhci的中斷號(sdhci_host->irq)
  • host提供給sdhci core用來操作硬體的操作集(sdhci_host->ops)

因此,sdhci-pltfm實現了兩個方法來統一設置這些信息,方便host driver對於sdhci driver的使用。

後續繼續說明。

二、數據結構說明

1、sdhci_pltfm_data

首先看一下sdhci-pltfm要設置的sdhci_host的成員的來源信息:

  • sdhci的寄存器的映射過後的基地址(sdhci_host->ioaddr)

由DTS節點中的地址屬性解析出來寄存器的物理地址之後,進行映射得到

  • sdhci的癖好quirks、quirks2(sdhci_host->quirks,sdhci_host->quirks2)

由平臺host驅動(host driver)提供最基本的值,後續會進行調整

  • sdhci的中斷號(sdhci_host->irq)

由DTS節點中的中斷屬性解析出來

  • host提供給sdhci core用來操作硬體的操作集(sdhci_host->ops)

由平臺host驅動(host driver)提供

綜上,ops、quirks和quirks2這幾個的值是必須由平臺host驅動(host driver)提供,而ioaddr和irq可以通過解析屬性得到。

因此,sdhci-pltfm把ops、quirks和quirks2的值封裝到sdhci_pltfm_data中,由底層host驅動提供。

其內容如下:

struct sdhci_pltfm_data {
    const struct sdhci_ops *ops;   // host提供給sdhci core用來操作硬體的操作集
    unsigned int quirks;   // sdhci的癖好quirks
    unsigned int quirks2;  // sdhci的癖好quirks2
};

2、sdhci_pltfm_host

sdhci_pltfm也為host抽象出一個host結構體sdhci_pltfm_host來作為sdhci_host和平臺定製的host的中間層。

struct sdhci_pltfm_host {
    struct clk *clk;

    /* migrate from sdhci_of_host */
    unsigned int clock;
    u16 xfer_mode_shadow;

    unsigned long private[0] ____cacheline_aligned;
};

以高通定製的host結構體sdhci_msm_host為例,三者之間的關係如下:

sdhci_host->private = sdhci_pltfm_host
sdhci_pltfm_host->priv = sdhci_msm_host
platform_get_drvdata(sdhci_msm_host->struct platform_device) = sdhci_host
sdhci_pltfm_host = sdhci_priv(sdhci_host);
sdhci_msm_host= sdhci_pltfm_priv(sdhci_pltfm_host);

三、API總覽

1、sdhci_pltfm分配和釋放相關

  • sdhci_pltfm_init & sdhci_pltfm_free
    由底層host driver調用。

sdhci_pltfm_init 用於分配sdhci_pltfm_host和sdhci_host的部分成員進行設置。

sdhci_pltfm_free用於釋放sdhci_pltfm_host和sdhci_host。

    原型:struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, const struct sdhci_pltfm_data *pdata)
    參數說明:struct platform_device *pdev——》host對應的平臺設備的device
                    struct sdhci_pltfm_data *pdata——》需要host driver提供給sdhci_host的一些信息,前面說過了
    使用案例:sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata);

    原型:void sdhci_pltfm_free(struct platform_device *pdev)

2、屬性解析相關

  • sdhci_get_of_property

由底層host driver調用。

用來解析host的dtsi節點的部分屬性,前提是要求這部分屬性必須按照一定的規範來。

    原型:void sdhci_get_of_property(struct platform_device *pdev)

3、sdhci_host註冊相關

  • sdhci_pltfm_register & sdhci_pltfm_unregister

由底層host driver調用。

sdhci_pltfm_register 直接根據sdhci_pltfm_data來註冊一個sdhci_host,會調用上述的sdhci_pltfm_init 和sdhci_get_of_property操作。

註意,但是一般用得比較少,因為host driver得到sdhci_host可能需要根據自己的需求來設置sdhci_host,而不是馬上註冊sdhci_host。

    原型:int sdhci_pltfm_register(struct platform_device *pdev, const struct sdhci_pltfm_data *pdata)
    參數說明:struct platform_device *pdev——》host對應的平臺設備的device
                    struct sdhci_pltfm_data *pdata——》需要host driver提供給sdhci_host的一些信息,前面說過了

四、介面代碼說明

1、sdhci_pltfm_init

  • 主要工作

    • 調用sdhci_alloc_host分配一個sdhci_host
    • 根據sdhci_pltfm_data設置sdhci_host->ops
    • 根據sdhci_pltfm_data設置sdhci_host->quirks
    • 根據sdhci_pltfm_data設置sdhci_host->quirks2
    • 獲取dtsi節點中的第一個中斷屬性並申請,設置sdhci_host->irq
    • 獲取dtsi節點中的第一個寄存器屬性並映射,設置sdhci_host->ioaddr
    • 調用平臺的初始化操作
  • 具體代碼如下

struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
                    const struct sdhci_pltfm_data *pdata)
{
// struct platform_device:sdhci host的平臺設備
// const struct sdhci_pltfm_data:sdhci host的平臺數據結構體,包含了對應host的sdhci_ops操作集
    struct sdhci_host *host;
    struct sdhci_pltfm_host *pltfm_host;
    struct device_node *np = pdev->dev.of_node;
    struct resource *iomem;
    int ret;

/* 獲取sdhci記憶體資源區域 */
    iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); // 所以在dtsi節點中,sdhci的記憶體資源必須作為記憶體列表的第一個屬性!!!!

/* 調用sdhci_alloc_host獲取一個標準的struct sdhci_host結構體 */
        host = sdhci_alloc_host(&pdev->dev, sizeof(*pltfm_host));

/* 將struct sdhci_host的私有數據和struct sdhci_pltfm_host關聯 */
    pltfm_host = sdhci_priv(host);

/* 根據傳進來的sdhci host的平臺數據來初始化sdhci_host的ops、quirks */
    host->hw_name = dev_name(&pdev->dev);
    host->ops = pdata->ops;
    host->quirks = pdata->quirks;

/* 獲取中斷 */
    host->irq = platform_get_irq(pdev, 0);  // 所以在dtsi節點中,sdhci的中斷屬性必須作為中斷列表的第一個屬性!!!!!

/* 申請sdhci的記憶體資源並且進行映射 */
    if (!request_mem_region(iomem->start, resource_size(iomem),
        mmc_hostname(host->mmc))) {
        dev_err(&pdev->dev, "cannot request region\n");
        ret = -EBUSY;
        goto err_request;
    }

    host->ioaddr = ioremap(iomem->start, resource_size(iomem));
    if (!host->ioaddr) {
        dev_err(&pdev->dev, "failed to remap registers\n");
        ret = -ENOMEM;
        goto err_remap;
    }

/* 調用host->ops->platform_init進行初始化 */
    if (host->ops && host->ops->platform_init)
        host->ops->platform_init(host);

/* 將struct sdhci_host作為對應host的私有數據 */
    platform_set_drvdata(pdev, host);

    return host;
}

註意,通過上述代碼,sdhci-pltfm要求必須把sdhci的寄存器屬性放在host的dtsi的寄存器屬性的第一個,同時,也要把sdhci的中斷屬性放在host的dtsi的中斷屬性的第一個。簡單dtsi的例子如下圖所示:

        sdhc_1: sdhci@07824000 {
        reg = <0x07824900 0x11c>, <0x07824000 0x800>;
        reg-names = "hc_mem", "core_mem";   // 其中,hc_mem表示sdhci的寄存器屬性,放在了第一個

        interrupts = <0 123 0>, <0 138 0>;
        interrupt-names = "hc_irq", "pwr_irq";   // 其中,hc_irq表示sdhci的中斷,放在了第一個

2、sdhci_get_of_property

代碼如下:

void sdhci_get_of_property(struct platform_device *pdev)
{
    struct device_node *np = pdev->dev.of_node;
    struct sdhci_host *host = platform_get_drvdata(pdev);    // 從平臺設備結構體中獲取私有數據,對應就是sdhci_host
    struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);    // sdhci_host的私有護具就是struct sdhci_pltfm_host
    const __be32 *clk;
    u32 bus_width;
    int size;

    if (of_device_is_available(np)) {
        if (of_get_property(np, "sdhci,auto-cmd12", NULL))
            host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
                // 解析"sdhci,auto-cmd12"屬性,設置quirks的SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12標識
                // sdhci,auto-cmd12————》SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12
                //  Controller uses Auto CMD12 command to stop the transfer,控制器使用CMD12自動結束傳輸

        if (of_get_property(np, "sdhci,1-bit-only", NULL) ||
            (of_property_read_u32(np, "bus-width", &bus_width) == 0 &&
            bus_width == 1))
            host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
                // 解析"sdhci,1-bit-only"屬性,設置quirks的SDHCI_QUIRK_FORCE_1_BIT_DATA標識
                // sdhci,1-bit-only————》SDHCI_QUIRK_FORCE_1_BIT_DATA
                // Controller can only handle 1-bit data transfers,該sdhci controller只支持1bit位寬傳輸

        if (sdhci_of_wp_inverted(np))
            host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
                // sdhci,wp-inverted | wp-inverted————》SDHCI_QUIRK_INVERTED_WRITE_PROTECT

        if (of_get_property(np, "broken-cd", NULL))
            host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
                // broken-cd————》SDHCI_QUIRK_BROKEN_CARD_DETECTION
                // Controller has unreliable card detection,sdhci controller沒有實現card檢測

        if (of_get_property(np, "no-1-8-v", NULL))
            host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
                // no-1-8-v————》SDHCI_QUIRK2_NO_1_8_V
                //  The system physically doesn't support 1.8v, even if the host does,不支持1.8V

        clk = of_get_property(np, "clock-frequency", &size);
        if (clk && size == sizeof(*clk) && *clk)
            pltfm_host->clock = be32_to_cpup(clk);
                // clock-frequency————》pltfm_host->clock
                // 獲取時鐘頻率

        if (of_find_property(np, "keep-power-in-suspend", NULL))
            host->mmc->pm_caps |= MMC_PM_KEEP_POWER;

        if (of_find_property(np, "enable-sdio-wakeup", NULL))
            host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
    }
}

3、sdhci_pltfm_register

使用得比較少,簡單瞭解下即可。

int sdhci_pltfm_register(struct platform_device *pdev,
             const struct sdhci_pltfm_data *pdata)
{
    struct sdhci_host *host;
    int ret = 0;

/* 調用sdhci_pltfm_init分配並初始化一個sdhci_host */
    host = sdhci_pltfm_init(pdev, pdata);        
    if (IS_ERR(host))
        return PTR_ERR(host);

/* 調用sdhci_get_of_property解析dtsi屬性並設置sdhci_host的部分成員 */
    sdhci_get_of_property(pdev);

/* 調用sdhci_add_host將該sdhci_host註冊到sdhci core中 */
    ret = sdhci_add_host(host);
    if (ret)
        sdhci_pltfm_free(pdev);

    return ret;
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • DHCP伺服器的架設 一、DHCP伺服器的安裝要求: 搭建DHCP伺服器需要一些必備條件支持,主要有以下方面: 二、安裝DHCP伺服器 以管理員身份登陸伺服器 右擊【電腦】 選擇【管理】 打開【伺服器管理器】 單擊【角色】 單擊【添加角色】 單擊【添加角色嚮導】 勾選【DHCP伺服器】 單擊【確定 ...
  • [TOC] 找到.ini路徑 Centos中重啟PHP 修改etc/php.ini後,必須重啟PHP才能生效 方式一 如果在安裝PHP時,設置了許可權並啟動php fpm: 方式二 也可以服務的方式啟動、停止和重啟: 一些經驗 ...
  • 本文將把Linux 系統管理遇到的問題進行彙總 一、用戶修改密碼 問題現象 用戶登錄後,修改自己的密碼,出現 passwd:Authentication token manipulation error(身份驗證令牌操作錯誤),一般是密碼文件的許可權的問題,不過也有可能是根目錄空間滿。 問題定位 ls ...
  • 我的內容來自於《馬哥Linux2016最新高薪運維視頻課程-Nginx應用基礎及配置詳解》 httpd:MPM prefork,worker,event prefork:主進程,生成多個子進程,每個子進程處理一個請求; worker:主進程,生成多個子進程,每個子進程再生成多個線程,每個線程響應一個 ...
  • python django uwsgi nginx安裝 已安裝完成python/django的情況下安裝 pip install uwsgi cd /usr/share/nginx/html/ vim uwsgi.ini輸入以下內容 #uwsgi.ini file [uwsgi] # Django- ...
  • 1.去官網下載適用於linux的jdk包,如jdk-8u162-linux-x64.tar.gz 2.創建目錄,將jdk包拷貝到該目錄下,如home/haha/user/java 3.在控制臺中進入該目錄,執行tar zxvf jdk-8u162-linux-x64.tar.gz 進行解壓 4.配置 ...
  • 一、前言 1、簡介 回顧上一篇UART發送當中,已經講解瞭如何實現UART的發送操作了,接下來這一篇將會繼續講解如何實現UART的接收操作。 2、UART簡介 嵌入式開發中,UART串口通信協議是我們常用的通信協議之一,全稱叫做通用非同步收發傳輸器(Universal Asynchronous Rec ...
  • 一、說明 sdhci msm是指高通的mmc host,其使用了標準SDHC標準。故可以使用前面說的《host(第二章)——sdhci》和《host(第三章)——sdhci pltfm說明》的介面。 後續代碼以msm8916平臺的host實現以及linux 4.6.0版本中的sdhci msm的實現 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...