平臺
Linux4.9
tiny4412
概述
結合tiny4412開發板分析一下Exynos4412的外部中斷是如何組織的。
在Exynos4412的用戶手冊第9章Interrupt Controller列出了支持的外部中斷:
第1列是按Shared Peripheral Interrupt 排序的
第2列是按Software Generated Interrupt + Peripheral Interrupt(PPI+SPI)排序的, 目前GIC提供了16個SGI中斷和16個PPI中斷
從上面可以看到,硬件上提供了32個外部中斷,但是我們在第6章的GPIO Control一節說:
圖2
上面說,有172個外部中斷以及32個外部可喚醒中斷,那么這些GPIO控制器提供的中斷是如何跟GIC提供的那32個外部中斷對應的呢?
其實上面圖1中列出的從SPI-16到SPI-32僅僅對應的是圖2中說的那32個外部可喚醒中斷,而剩下的那172個會使用其他的SPI中斷,并不是圖1列出的那幾個。
下面是結合設備樹和GIC以及Combiner驅動得到的:
圖3
上面圖3列出的那些組GPIO會最終會共享SPI-47這個SPI中斷,圖3的EXT_INTxx跟圖1的EINT沒有任何關系,僅僅表示一種GPIO功能復用,而且這些中斷是不具備wake up功能的。上面是硬件連接,那么在驅動層面是處理的呢?
這里我們需要關注下面兩個驅動文件:
drivers/pinctrl/samsung/pinctrl-exynos.c
drivers/pinctrl/samsung/pinctrl-samsung.c
在populate的時候,SPI-47這個硬件中斷會被映射為對應的虛擬中斷(如virq_47),函數samsung_pinctrl_probe會獲得virq_47:
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res)
drvdata->irq = res->start;
在執行ctrl->eint_gpio_init(drvdata)的時候將drvdata傳入,在函數exynos_eint_gpio_init中,會注冊virq_47的中斷處理函數:
ret = devm_request_irq(dev, d->irq, exynos_eint_gpio_irq,
0, dev_name(dev), d);
也就是當GIC上的SPI-47這個中斷被觸發后,中斷處理函數exynos_eint_gpio_irq會被調用。
然后就是對圖3中的每一組GPIO都注冊對應的irq_domain:
1 bank = d->pin_banks;
2 for (i = 0; i < d->nr_banks; ++i, ++bank) {
3 if (bank->eint_type != EINT_TYPE_GPIO)
4 continue;
5
6 bank->irq_domain = irq_domain_add_linear(bank->of_node,
7 bank->nr_pins, &exynos_eint_irqd_ops, bank);
8
9 bank->irq_chip = &exynos_gpio_irq_chip;
10 }
也就是圖3中的每一組GPIO都可以是一個中斷控制器,bank->nr_pins是該組GPIO有幾個引腳,每一個引腳對應一個中斷,所以也就表示該irq_domain可以最大支持的中斷個數。第9行設置了irq_chip,用戶控制每一個引腳中斷的打開、關閉、清除等。
下面以GPA0_0這個引腳觸發中斷為例簡單看看是如何處理的?
GPA1_5產生中斷后,會在SPI-47上也引發中斷,函數exynos_eint_gpio_irq會被調用,其中會查詢到產生的中斷的引腳,然后在對應的引腳所屬的irq_domain中查詢引腳對應的虛擬中斷,最后執行到用戶注冊的中斷處理函數。
1 static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
2 {
3 struct samsung_pinctrl_drv_data *d = data;
4 struct samsung_pin_bank *bank = d->pin_banks;
5 unsigned int svc, group, pin, virq;
6
7 svc = readl(d->virt_base + EXYNOS_SVC_OFFSET);
8 group = EXYNOS_SVC_GROUP(svc);
9 pin = svc & EXYNOS_SVC_NUM_MASK;
10
11 if (!group)
12 return IRQ_HANDLED;
13 bank += (group - 1);
14
15 virq = irq_linear_revmap(bank->irq_domain, pin);
16 if (!virq)
17 return IRQ_NONE;
18 generic_handle_irq(virq);
19 return IRQ_HANDLED;
20 }
第7行的宏EXYNOS_SVC_OFFSET是0xB08,這個需要結合Exynos4412的用戶手冊看:
當GPA1_5觸發中斷話,[7:3]的值就是2,而[2:0]就是5
第13行根據得到的group編號得到bank,也就得到了irq_domain
第9行得到的就是引發中斷的引腳編號,也就是hwirq
第15行利用上面找到的irq_domain和hwirq,就可以得到對應virq,然后就可以繼續處理該virq,一般此時就會調用到用戶注冊的具體的中斷處理程序。
跟上面同樣的道理,可以得到下面的圖4和圖5:
圖4
圖5
分析方法跟圖3一樣。
下面的幾組GPIO跟前面的略有不同:GPX和GPZ。其中GPX一共有32個引腳,對應的是圖2說的32個具有wake up功能的外部中斷,而GPZ不同之處是,它沒有直接連到GIC上,而是連到了Combiner上。
GPX:
圖6
對于GPX0和GPX1來說,每一個引腳都對應到一個SPI中斷。而GPX2和GPX3的所有引腳共享一個SPI中斷。下面我們看看在驅動層面主要是在函數exynos_eint_wkup_init中處理的:
對于GPX0和GPX1來說:
1 for (i = 0; i < d->nr_banks; ++i, ++bank) {
2 if (bank->eint_type != EINT_TYPE_WKUP)
3 continue;
4
5 bank->irq_domain = irq_domain_add_linear(bank->of_node,
6 bank->nr_pins, &exynos_eint_irqd_ops, bank);
7
8 bank->irq_chip = irq_chip;
9
10 if (!of_find_property(bank->of_node, "interrupts", NULL)) {
11 bank->eint_type = EINT_TYPE_WKUP_MUX;
12 ++muxed_banks;
13 continue;
14 }
15
16 weint_data = devm_kzalloc(dev, bank->nr_pins
17 * sizeof(*weint_data), GFP_KERNEL);
18
19 for (idx = 0; idx < bank->nr_pins; ++idx) {
20 irq = irq_of_parse_and_map(bank->of_node, idx);
21
22 weint_data[idx].irq = idx;
23 weint_data[idx].bank = bank;
24 irq_set_chained_handler_and_data(irq,
25 exynos_irq_eint0_15,
26 &weint_data[idx]);
27 }
28 }
在設備樹中GPX0和GPX1設置interupts屬性,而GPX2和GPX3沒有。所以執行完上面的邏輯,muxed_banks為2,就是GPX2和GPX3,而其bank->eint_type被設置為了EINT_TYPE_WKUP_MUX。
第20行會解析GPX0和GPX1節點interrupts屬性,并將每一個hwirq都映射為對應的virq
第24行調用irq_set_chained_handler_and_data設置SPI中斷對應的handler,可以理解為級聯。意味著GPX0、GPX1的引腳會在所屬的bank的irq_domain里映射一次,而對應的SPI中斷也會在GIC的irq_domain里映射一次。因為每個irq都傳遞了對應的weint_data[idx],所以exynost_irq_eint0_15雖然被共享了,但是其邏輯卻很簡單:
1 static void exynos_irq_eint0_15(struct irq_desc *desc)
2 {
3 struct exynos_weint_data *eintd = irq_desc_get_handler_data(desc);
4 struct samsung_pin_bank *bank = eintd->bank;
5 struct irq_chip *chip = irq_desc_get_chip(desc);
6 int eint_irq;
7
8 chained_irq_enter(chip, desc);
9
10 eint_irq = irq_linear_revmap(bank->irq_domain, eintd->irq);
11 generic_handle_irq(eint_irq);
12
13 chained_irq_exit(chip, desc);
14 }
下面是GPX2和GPX3:
這兩組GPIO共享一個SPI中斷,所以會涉及到mux操作。驅動也是在exynos_eint_wkup_init處理的:
1 irq = irq_of_parse_and_map(wkup_np, 0);
2
3 muxed_data = devm_kzalloc(dev, sizeof(*muxed_data)
4 + muxed_banks*sizeof(struct samsung_pin_bank *), GFP_KERNEL);
5
6 irq_set_chained_handler_and_data(irq, exynos_irq_demux_eint16_31,
7 muxed_data);
8
9 bank = d->pin_banks;
10 idx = 0;
11 for (i = 0; i < d->nr_banks; ++i, ++bank) {
12 if (bank->eint_type != EINT_TYPE_WKUP_MUX)
13 continue;
14
15 muxed_data->banks[idx++] = bank;
16 }
17 muxed_data->nr_banks = muxed_banks;
第1行解析設備樹里"wakeup-interrupt-controller"節點的interrupts屬性,映射獲得對應的virq
第6行設置級聯
第15行的for循環中,banks[0]對應的是GPX2,banks[1]對應的是GPX3,
由于GPX2和GPX3共享了一個SPI中斷,所以第6行的exynos_irq_demux_eint16_31就需要完成mux的操作:
1 static void exynos_irq_demux_eint16_31(struct irq_desc *desc)
2 {
3 struct irq_chip *chip = irq_desc_get_chip(desc);
4 struct exynos_muxed_weint_data *eintd = irq_desc_get_handler_data(desc);
5 struct samsung_pinctrl_drv_data *d = eintd->banks[0]->drvdata;
6 unsigned long pend;
7 unsigned long mask;
8 int i;
9
10 chained_irq_enter(chip, desc);
11
12 for (i = 0; i < eintd->nr_banks; ++i) {
13 struct samsung_pin_bank *b = eintd->banks[i];
14 pend = readl(d->virt_base + b->irq_chip->eint_pend
15 + b->eint_offset);
16 mask = readl(d->virt_base + b->irq_chip->eint_mask
17 + b->eint_offset);
18 exynos_irq_demux_eint(pend & ~mask, b->irq_domain);
19 }
20
21 chained_irq_exit(chip, desc);
22 }
第12行的for循環依次處理GPX2和GPX3,主要就是看是不是有那個引腳的中斷處于pengding中,如果有的話,函數exynos_irq_demux_eint會進行處理。
1 static inline void exynos_irq_demux_eint(unsigned long pend,
2 struct irq_domain *domain)
3 {
4 unsigned int irq;
5
6 while (pend) {
7 irq = fls(pend) - 1;
8 generic_handle_irq(irq_find_mapping(domain, irq));
9 pend &= ~(1 << irq);
10 }
11 }
最后說一下GPZ這組GPIO:
圖7
結合設備樹,可以看到GPZ使用了Combiner的Group10的第0號中斷源。
Exynos4412的第10章有隊Interrupts Combiner的介紹,Interrupt Combiner也是一個中斷控制器,跟GIC之間采用級聯的方式。Interrupt Combiner后面可以支持116路中斷源,然后將這些中斷源進行分組上報給GIC,每一組對應一個GIC上中斷,在interrupt combiner的設備節點可以看到它使用了GIC上的20個SPI中斷,也就是將116個中斷分成20個組,每組下面最多支持8個中斷源,每組對應一個GIC上的SPI中斷,每組下面對應那些中斷源都是定死的。
inerrupt combiner對應的驅動文件是:drivers/irqchip/exynos-combiner.c
1 static void __init combiner_init(void __iomem *combiner_base,
上一篇:淺析基于ARM的Linux下的系統調用的實現
下一篇:交叉編譯Python-2.7.13到ARM(aarch32)—— 支持sqlite3
推薦閱讀
史海拾趣
DCX-CHOL Enterprises成立于一個科技蓬勃發展的時代。公司的創始人是一群熱衷于電子技術的年輕人,他們看到市場上對于高性能、低功耗芯片的巨大需求,于是決定自主研發。經過數年的艱苦努力,他們成功開發出了一款具有革命性意義的低功耗芯片,該芯片不僅性能卓越,而且成本遠低于同類產品。這一創新成果迅速贏得了市場的認可,DCX-CHOL Enterprises因此獲得了第一桶金,為公司后續的發展奠定了堅實的基礎。
APX Technologies在追求經濟效益的同時,也積極履行社會責任。公司注重環保和可持續發展,致力于研發和生產低能耗、低污染的電子產品。此外,APX Technologies還積極參與社會公益活動,為社會的和諧發展貢獻自己的力量。這些舉措不僅提升了公司的品牌形象,也贏得了社會各界的廣泛贊譽。
以上五個故事均基于虛構的APX Technologies公司的發展情況,旨在展示一個電子行業公司可能經歷的不同發展階段和面臨的挑戰。這些故事并不代表任何真實情況,僅供參考和啟發。
近年來,DYMO公司越來越注重環保和可持續發展。公司采用環保材料制造產品,并推廣循環使用和回收計劃。此外,DYMO公司還積極參與各種環保活動,致力于減少生產過程中的碳排放和廢棄物排放。這些舉措不僅提高了DYMO公司的社會形象,也為其未來的發展奠定了更加堅實的基礎。
近年來,DYMO公司越來越注重環保和可持續發展。公司采用環保材料制造產品,并推廣循環使用和回收計劃。此外,DYMO公司還積極參與各種環保活動,致力于減少生產過程中的碳排放和廢棄物排放。這些舉措不僅提高了DYMO公司的社會形象,也為其未來的發展奠定了更加堅實的基礎。
進入20世紀,Emerson迎來了一系列技術突破。1903年,公司成功研發出馬力超過1/2的電機,這些電機被廣泛應用于洗衣機、縫紉機等家用電器,進一步拓寬了公司的業務范圍。此外,Emerson還積極開拓海外市場,通過并購和戰略合作,逐步將業務拓展至全球范圍。
進入20世紀,Emerson迎來了一系列技術突破。1903年,公司成功研發出馬力超過1/2的電機,這些電機被廣泛應用于洗衣機、縫紉機等家用電器,進一步拓寬了公司的業務范圍。此外,Emerson還積極開拓海外市場,通過并購和戰略合作,逐步將業務拓展至全球范圍。
本篇文章純屬個人對數字信號的粗淺理解,如有不對的地方,還望高手指點。 FIR:有限脈沖響應濾波器。有限說明其脈沖響應是有限的。與IIR相比,它具有線性相位、容易設計的優點。這也就說明,IIR濾波器具有相位不線性,不容易設計的缺點。而另一方 ...… 查看全部問答∨ |
|
uClinux在ARM開發板44b0芯片上運行程序,提示中斷異常錯誤? 請教高人,在44B0的ARM開發板上uClinux操作系統下,調試ADC與LCD應用程序。 兩個程序分別運行的時候,都正常。但是把ADC與LCD應用程序都加入到一個文件work中,編譯后運行,就提示如下問題: Unhandled fault: alignment exception ...… 查看全部問答∨ |
|
大家好,剛剛接觸WINCE,什么都不懂,現請教幾個問題: 我使用一個軟件(西門子WinCC flexible)來開發監控程序,然后下載到觸摸屏(MP370)上。下載程序的功能是WinCC flexible自身提供的。 在觸摸屏上運行的是windows se 3.1英文系統。觸摸屏提供了RS2 ...… 查看全部問答∨ |
|
幾個月前新買電腦總是無故死機,請教高手? 相關癥狀如下: 1.畫面定格,除非重啟或關機,其它一切操作均無效,沒有一點反應。 2.玩反恐等游戲時死機頻率大約一個半小時一次;放電影大約四小時一次。第一次開機到死 ...… 查看全部問答∨ |