色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

電源管理入門-3. provider-reset驅動

yzcdx ? 來源:OS與AUTOSAR研究 ? 2023-10-16 17:11 ? 次閱讀

之前的文章電源管理入門-1關機重啟詳解介紹了整機SoC的重啟也可以說是reset,那么子系統的reset,例如某個驅動(網卡、USB等)或者某個子系統(NPU、ISP等運行在獨立的M核或者R核上的AI系統),這些零碎模塊的reset就需要用另外一種機制,Linux提供了reset framework框架,我們可以使用這個框架對子系統reset,然后操作硬件CRU寄存器進行硬件的reset操作。

考慮到安全的因素對CRU寄存器的操作可以放在:

  • ATF里面的BL31(通過SMC指令)
  • 或者放到SCP里面(通過Linux-SCMI-》SCP)里面進行。

本小節先介紹下Linux里面的通用reset框架,下篇介紹arm-scmi到SCP進行CRU硬件操作的實現。

1. 簡介

復雜SoC內部有很多具有獨立功能的硬件模塊,例如CPU cores、GPU cores、USB控制器、MMC控制器、等等,出于功耗、穩定性等方面的考慮,有些SoC在內部為這些硬件模塊設計了復位信號(reset signals),軟件可通過寄存器(一般1個bit控制1個硬件)控制這些硬件模塊的復位狀態。

fabb64f4-6bf8-11ee-939d-92fbcf53809c.png

例如有3個軟件I2C/EMMC/IPC都有復位某個硬件模塊的需求,那么要寫三個復位操作代碼。

  • 這些代碼可以進行抽象出來一個獨立的軟件框架-reset framework,
  • 這樣軟件使用者(consumer:I2C/EMMC/IPC)直接使用硬件模塊的名字,就可以對硬件進行復位。
  • 一個模塊硬件的復位實現為單獨的reset driver(provider),只用實現一次就可以了。

再次說明了,解決復雜問題的普遍方法就是抽象,而Linux內核可以說是玩得一手好抽象,也是操作系統的必備技能。

2. consumer-驅動軟件

對于硬件驅動來的需求來說,就是復位某個硬件,在驅動代碼里面可以通過硬件的名字進行復位,這個名字對應設置放在了dts文件中,例如:

i2c0: i2c@0xA1006000 {
        compatible = "arch64,a10-i2c";
        reg = <0 0xA1006000 0 0x100>;
        interrupt-parent = <&gic>;
        interrupts = <0 32 4>;
        clock-frequency = <24000000>;
        resets = <&rst 0x50 11>;
        reset-names = "i2c0";
        status = "disabled";
};

&rst:使用rst驅動,0x50:寄存器偏移,11:使用那個bit 進行復位的時候,在驅動軟件里面加上

    i2c_dev->i2c_rst =
            devm_reset_control_get(i2c_dev->dev, "i2c0");

static int i2c_reset_assert(struct reset_control *rstc)
{
        int rc = 0;
        rc = reset_control_assert(rstc);
        if (rc < 0) {
                pr_err("%s: failed
", __func__);
                return rc;
        }

        return rc;
}
static int i2c_reset_assert(struct reset_control *rstc)
{
        int rc = 0;
        rc = reset_control_assert(rstc);
        if (rc < 0) {
                pr_err("%s: failed
", __func__);
                return rc;
        }

        return rc;
}

static int i2c_hw_reset(struct i2c_dev *i2c_dev)
{
                i2c_reset_assert(i2c_dev->i2c_rst );
                udelay(1);
                i2c_reset_release(i2c_dev->i2c_rst );

}

i2c_dev->i2c_rst是一個reset_control的結構體

struct reset_control {
    struct reset_controller_dev *rcdev;
    struct list_head list;
    unsigned int id;
    struct kref refcnt;
    bool acquired;
    bool shared;
    bool array;
    atomic_t deassert_count;
    atomic_t triggered_count;
};

上面i2c驅動作為consumer調用了reset framework提供的API函數(include/linux/reset.h),如下:

/* 通過reset_control_get或者devm_reset_control_get獲得reset句柄 */ 
struct reset_control *reset_control_get(struct device *dev, const char *id);    
void reset_control_put(struct reset_control *rstc);                             
struct reset_control *devm_reset_control_get(struct device *dev, const char *id);

/* 通過reset_control_reset進行復位,或者通過reset_control_assert使設備處于復位生效狀態,通過reset_control_deassert使復位失效 */ 
reset_control_deassert(struct reset_control *rstc)//解復位
reset_control_assert(struct reset_control *rstc)//復位
reset_control_reset(struct reset_control *rstc)//先復位,延遲一會,然后解復位

3. provider-reset驅動

3.1 整體介紹

reset驅動是一個獨立驅動,為其他驅動提供硬件復位的服務。首先在dts里面設置.compatible這樣驅動就可以加載了,如下定義了rst驅動:

        rst: reset-controller {
                compatible = "arch64,a10-reset";
                #reset-cells = <2>;
                reg = <0x0 0x91000000 0x0 0x1000>;
        };

上述是一個reset控制器的節點,0x91000000是寄存器基址,0x1000是映射大小。#reset-cells代表引用該reset時需要的cells個數。

然后就是reset驅動的實現,reset驅動編寫的基本步驟:

  1. 實現struct reset_control_ops結構體中的.reset、.assert、.deassert、.status函數
  2. 分配struct reset_controller_dev結構體,填充ops、owner、nr_resets等成員內容
  3. 調用reset_controller_register函數注冊reset設備

首先定義platform_driver:

static const struct of_device_id a10_reset_dt_ids[] = {
        { .compatible = "hobot,a10-reset", },
        { },
};
static struct platform_driver a10_reset_driver = {
        .probe  = a10_reset_probe,
        .driver = {
                .name       = KBUILD_MODNAME,
                .of_match_table = a10_reset_dt_ids,
        },
};

static int __init a10_reset_init(void)
{
    return platform_driver_register(&a10_reset_driver);
}

系統初始化,dts中配置了此reset驅動,就會調用a10_reset_probe

static int a10_reset_probe(struct platform_device *pdev)
{
        struct a10_reset_data *data;
        struct resource *res;
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
        u32 modrst_offset;

        /*
         * The binding was mainlined without the required property.
         * Do not continue, when we encounter an old DT.
         */
        if (!of_find_property(pdev->dev.of_node, "#reset-cells", NULL)) {
                dev_err(&pdev->dev, "%s missing #reset-cells property
",
                        pdev->dev.of_node->full_name);
                return -EINVAL;
        }

        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;

        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        data->membase = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(data->membase))
                return PTR_ERR(data->membase);

        spin_lock_init(&data->lock);

        data->rcdev.owner = THIS_MODULE;
        data->rcdev.nr_resets = a10_MAX_NR_RESETS;
        data->rcdev.ops = &a10_reset_ops;
        data->rcdev.of_node = pdev->dev.of_node;
        data->rcdev.of_xlate = a10_reset_of_xlate;
        data->rcdev.of_reset_n_cells = 2;

        return devm_reset_controller_register(dev, &data->rcdev);
}

data->rcdev的定義如下:

struct reset_controller_dev{
    const struct reset_control_ops *ops;//復位控制操作函數
    struct list_head list;//全局鏈表,復位控制器注冊后掛載到全局鏈表
    struct list_head reset_control_head;//各個模塊復位的鏈表頭
    struct device *dev;int of_reset_n_cells;//dts中引用時,需要幾個參數
        
    //通過dts引用的參數,解析復位控制器中相應的參數
    int (*of_xlate)(struct reset_controller_dev *rcdev, const struct of_phandle_args *reset_spec);unsigned int nr_resets;//復位設備個數
}
  • ops提供reset操作的實現,基本上是reset provider的所有工作量。
  • of_xlate和of_reset_n_cells用于解析consumer device dts node中的“resets = ; ”節點,如果reset controller比較簡單(僅僅是線性的索引),可以不實現,使用reset framework提供的簡單版本----of_reset_simple_xlate即可。
  • nr_resets,該reset controller所控制的reset信號的個數。

a10_reset_ops定義了reset framework的回調函數,對具體寄存器位進行操作

//reset可控制設備完成一次完整的復位過程。
//assert和deassert分別控制設備reset狀態的生效和失效。
static const struct reset_control_ops a10_reset_ops = {
        .assert     = a10_reset_assert,
        .deassert   = a10_reset_deassert,
        .status     = a10_reset_status,
};

static int a10_reset_assert(struct reset_controller_dev *rcdev,
        unsigned long id)
{
        void __iomem    *regaddr;
        uint32_t reg_val, offset;
        unsigned long flags;
        u8 bit;
        struct a10_reset_data *data = to_a10_reset_data(rcdev);

        if (rcdev == NULL || id < 0)
                return -EINVAL;

        spin_lock_irqsave(&data->lock, flags);
        offset = (id & RESET_REG_OFFSET_MASK) >> RESET_REG_OFFSET_SHIFT;
        regaddr = data->membase + offset;

        reg_val = readl(regaddr);
        bit = (id & RESET_REG_BIT_MASK);
        reg_val |= BIT(bit);
        writel(reg_val, regaddr);

        spin_unlock_irqrestore(&data->lock, flags);

        return 0;
}

static int a10_reset_deassert(struct reset_controller_dev *rcdev,
        unsigned long id)
{
        void __iomem    *regaddr;
        uint32_t reg_val, offset;
        unsigned long flags;
        u8 bit;
        struct a10_reset_data *data = to_a10_reset_data(rcdev);

        if (rcdev == NULL || id < 0)
                return -EINVAL;

        spin_lock_irqsave(&data->lock, flags);
        offset = (id & RESET_REG_OFFSET_MASK) >> RESET_REG_OFFSET_SHIFT;
        regaddr = data->membase + offset;

        reg_val = readl(regaddr);
        bit = (id & RESET_REG_BIT_MASK);
        reg_val &= ~(BIT(bit));
        writel(reg_val, regaddr);

        spin_unlock_irqrestore(&data->lock, flags);
        return 0;
}
static int a10_reset_status(struct reset_controller_dev *rcdev,
        unsigned long id)
{
        return 0;
}

3.2 reset復位API說明

devm_reset_control_get

struct reset_control *devm_reset_control_get(struct device *dev, const char *id)
?作用:獲取相應的reset句柄
?參數:
? dev:指向申請reset資源的設備句柄
? id:指向要申請的reset資源名(字符串),可以為NULL
?返回:
? 成功:返回reset句柄
? 失敗:返回NULL

reset_control_deassert

int reset_control_deassert(struct reset_control *rstc)
?作用:對傳入的reset資源進行解復位操作
?參數:
? rstc:指向申請reset資源的設備句柄
?返回:
? 成功:返回0
? 失敗:返回錯誤碼

reset_control_assert

int reset_control_assert(struct reset_control *rstc)
?作用:對傳入的reset資源進行復位操作。
參數和返回值與reset_control_deassert相同

reset_control_reset

int reset_control_reset(struct reset_control *rstc)
?作用:對傳入的reset資源先進行復位操作,然后等待5us,再進行解復位操作。
?相當于執行了一遍reset_control_assert后,然后delay一會,再調用reset_control_deassert

后記:

使用markdown寫中文發現段落行首空格實在不好搞,然后調研了很多牛人寫的中文博客發現行首不用空格的很多,咱們這里為了方便書寫,也不要行首空格了。畢竟工具是服務人的,規則都是在變化的。

后續文章先在稀土掘金首發(寫的快),然后復制過來,歡迎關注:https://juejin.cn/user/2052111227697336

電源管理,可能很多人不喜歡看,我分幾次多篇一塊發完。也歡迎大家把喜歡看的技術留言。

電源管理這個專欄其實比較小眾,大伙并不是那么愛看,我就先多寫幾篇存著,到時一塊推送,避免公共資源的浪費,節省點大家的時間。有時候我也劃開微信看看直播和視頻號,發現很多無腦的直播,比如河邊鋼筋磨石頭、在家轉大棍子,什么科目三,感覺這些都有人看,這么無腦,我就算寫點垃圾文字也比這強的吧,也有可能人看視頻就是為了無腦休息下。


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 控制器
    +關注

    關注

    112

    文章

    16332

    瀏覽量

    177806
  • 寄存器
    +關注

    關注

    31

    文章

    5336

    瀏覽量

    120230
  • reset
    +關注

    關注

    0

    文章

    34

    瀏覽量

    12877

原文標題:3. provider-reset驅動

文章出處:【微信號:OS與AUTOSAR研究,微信公眾號:OS與AUTOSAR研究】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Linux reset子系統及驅動實例

    上篇講了Linux clock驅動,今天說說Linux的reset驅動
    發表于 05-31 16:16 ?1127次閱讀
    Linux <b class='flag-5'>reset</b>子系統及<b class='flag-5'>驅動</b>實例

    電源管理入門-關機重啟基礎知識詳解

    當我們接觸電源管理的時候,最簡單的流程就是關機重啟,但是仔細分析其涉及的所有源代碼就會發現,關機重啟雖然簡單
    發表于 09-19 11:41 ?2606次閱讀
    <b class='flag-5'>電源</b><b class='flag-5'>管理入門</b>-關機重啟基礎知識詳解

    電源管理入門-Regulator驅動是什么?Regulator的作用是什么?

    Regulator是Linux系統中電源管理的基礎設施之一,用于穩壓電源管理,是各種驅動子系統中設置 電壓的標準接口。
    的頭像 發表于 11-16 16:51 ?9968次閱讀
    <b class='flag-5'>電源</b><b class='flag-5'>管理入門</b>-Regulator<b class='flag-5'>驅動</b>是什么?Regulator的作用是什么?

    電源管理入門:Thermal熱管理

    管理指的是在電子設備或系統中通過各種方式控制其溫度來保證其正常工作或延長壽命的過程。其中包括散熱設計、溫度監測、溫度控制等方面。熱管理的重要性越來越凸顯,尤其在高性能計算、人工智能等領域的應用中更為重要。
    的頭像 發表于 11-29 10:09 ?4840次閱讀
    <b class='flag-5'>電源</b><b class='flag-5'>管理入門</b>:Thermal熱<b class='flag-5'>管理</b>

    電源管理入門驅動Runtime PM管理

    Runtime PM管理也就是設備驅動里面的電源管理,即設備驅動結構體里面的struct dev_pm_ops,只控制設備自己的
    的頭像 發表于 11-29 10:13 ?3024次閱讀
    <b class='flag-5'>電源</b><b class='flag-5'>管理入門</b>:<b class='flag-5'>驅動</b>Runtime PM<b class='flag-5'>管理</b>

    電源管理入門:Power supply子系統

    對于便攜設備來說,電源管理更加的重要,因為電池電量有限,容易電量焦慮。除了省電管理外,還需要對電池進行監控管理和充放電管理,這樣保護好電池和
    的頭像 發表于 11-29 10:15 ?4166次閱讀
    <b class='flag-5'>電源</b><b class='flag-5'>管理入門</b>:Power supply子系統

    電源管理入門:Power Domain管理

    SoC中通常有很多IP,按邏輯可以把幾個相關功能的IP劃為一個電源域。一個電源域內的IP,通常按相同的方式由同一個硬件模塊PMIC供電,電壓一樣并且電源管理例如休眠喚醒一致。
    的頭像 發表于 11-29 10:16 ?3388次閱讀
    <b class='flag-5'>電源</b><b class='flag-5'>管理入門</b>:Power Domain<b class='flag-5'>管理</b>

    電源管理入門-芯片設計中的電源管理介紹

    SCP直接控制SoC的電源和時鐘,而AP通過硬件和軟件接口協同管理
    的頭像 發表于 12-06 09:16 ?3260次閱讀
    <b class='flag-5'>電源</b><b class='flag-5'>管理入門</b>-芯片設計中的<b class='flag-5'>電源</b><b class='flag-5'>管理</b>介紹

    電源管理入門:Hypervisor中的電源管理

    很多時候聽說Hypervisor,但是對底層軟件技術不了解的人感覺挺神秘。本篇文章簡單介紹下Hypervisor的基本概念,另外介紹下電源管理在Hypervisor之上多OS間怎么應用。
    的頭像 發表于 12-06 09:27 ?1447次閱讀
    <b class='flag-5'>電源</b><b class='flag-5'>管理入門</b>:Hypervisor中的<b class='flag-5'>電源</b><b class='flag-5'>管理</b>

    防火墻原理入門

    防火墻原理入門 防火墻能增強機構內部網絡的安全性。防火墻系統決定了哪些內部服務可以被外界訪問;外界的哪些人可以訪問內部的服務以及哪
    發表于 08-01 10:21 ?1022次閱讀
    防火墻原<b class='flag-5'>理入門</b>

    數字信號處理入門指南

    數字信號處理入門指南什么是DSP? 數字信號處理器(DSP)采集已被數字化的現實世界的聲音、音頻、視頻、溫度、壓力或位置等信號,并從數學的角度對其進
    發表于 09-15 08:55 ?1345次閱讀
    數字信號處<b class='flag-5'>理入門</b>指南

    Linux reset子系統有什么功能

    Linux reset子系統 reset子系統非常簡單,與clock子系統非常類似,但在驅動實現上,reset驅動更簡單。 因為clock
    的頭像 發表于 09-27 14:06 ?764次閱讀
    Linux <b class='flag-5'>reset</b>子系統有什么功能

    reset API使用示例步驟

    時鐘和復位是兩個不同的驅動,但通常都是由負責clock驅動的人,把reset驅動完成。同樣,reset
    的頭像 發表于 09-27 14:17 ?1101次閱讀

    Linux內核reset驅動實例

    reset驅動實例 類似于clock驅動reset驅動也是編進內核的,在Linux啟動時,完成rese
    的頭像 發表于 09-27 14:21 ?766次閱讀

    電源管理入門-5 arm-scmi和mailbox核間通信

    在scmi協議初始化的時候,scmi_reset_register會注冊0x16的回調函數,詳細分析見2.2.1 SCMI reset協議初始化內容。在drivers/firmware/arm_scmi/reset.c中
    的頭像 發表于 10-16 17:09 ?5328次閱讀
    <b class='flag-5'>電源</b><b class='flag-5'>管理入門</b>-5 arm-scmi和mailbox核間通信
    主站蜘蛛池模板: 18动漫在线观看| 穿着丝袜被男生强行啪啪| 国产成年人在线观看| 麻豆高潮AV久久久久久久| 亚洲成人黄色在线| s8sp视频高清在线播放| 久久偷拍国2017的| 香港论理午夜电影网| 纯肉合集(高H)| 免费观看男生桶美女私人部位| 亚洲免费观看| 国产精品午夜福利在线观看| 欧美xxxav| 2019午夜福合集不打码| 黄桃AV无码免费一区二区三区| 天天躁夜夜踩很很踩2022| fryee性欧美18 19| 美女大BXXXXN内射| 友田真希息与子中文字幕| 国产午夜亚洲精品一区| 体育生爆操| 高H黄暴NP辣H一女多男| 青柠高清在线观看完整版| 3d在线看小舞被躁视频| 久久精品国产96精品亚洲| 亚洲欧美一级久久精品| 国产日韩欧美另类| 外女思春台湾三级| 国产69精品久久久久麻豆| 欧美高清18| 99影视久久电影网久久看影院| 久久只精品99品免费久| 一本道综合久久免费| 黄色免费在线网址| 亚洲精品永久免费| 国产在线高清亚洲精品一区| 亚洲 综合 欧美在线视频| 国产精品青青草原app大全| 色婷婷五月综合中文字幕| 丰满的女朋友韩国版在线观看| 日本少妇内射视频播放舔|