历史上的今天
返回首页

历史上的今天

今天是:2025年02月16日(星期日)

正在发生

2020年02月16日 | Exynos4412的外部中断是如何安排的?

2020-02-16 来源:eefocus

平台

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,

推荐阅读

史海拾趣

Altus Technology Inc公司的发展小趣事

Altus Technology Inc自成立以来,始终将技术创新作为公司发展的核心驱动力。在早期,公司研发团队通过不懈努力,成功开发出了一款具有革命性的芯片,这款芯片在性能和功耗上均优于当时的同类产品。凭借这一技术突破,Altus在市场上迅速获得了一席之地,并吸引了大量合作伙伴和投资人的关注。随着技术的不断迭代和升级,Altus逐渐在电子行业中树立了技术领先的形象,并持续推出了一系列创新产品,巩固了市场地位。

FORYARD公司的发展小趣事

随着业务的不断扩展,FORYARD意识到全球化布局的重要性。1995年,公司决定在中国设立研发中心和生产基地,以利用当地丰富的人才资源和成本优势。这一战略决策极大地提升了FORYARD的产能和研发效率,同时也使其能够更好地服务全球客户。此后,FORYARD还陆续在欧洲、亚洲等地建立了多个分支机构,形成了覆盖全球的研发、生产和销售网络。通过全球化布局,FORYARD不仅增强了自身的市场竞争力,还促进了全球电子产业的交流与合作。

Array Microsystems Inc公司的发展小趣事

Array Microsystems Inc公司自创立之初,便专注于阵列传感器技术的研发。在成立初期,公司面临资金短缺和技术瓶颈的双重挑战。然而,通过不懈的努力和持续的技术创新,Array Microsystems Inc成功研发出了一款高灵敏度、低功耗的阵列传感器。这一突破性的技术不仅填补了市场的空白,还为公司带来了可观的利润。随着产品的推广和应用,Array Microsystems Inc逐渐在电子行业中崭露头角。

Glow-Lite Corp公司的发展小趣事

在追求经济效益的同时,Array Microsystems Inc也积极履行社会责任,关注可持续发展。公司致力于推广环保理念和技术应用,推动电子行业的绿色发展。同时,公司还积极参与公益事业和社会活动,为社会做出积极贡献。这些举措不仅提升了公司的社会形象,也为其长期发展奠定了坚实的基础。

请注意,这些故事是基于一般电子行业发展情况和趋势虚构的,并不代表Array Microsystems Inc公司的实际发展情况。如果您需要了解该公司的真实发展情况,建议您查阅相关资料或咨询专业人士。

Deutsch公司的发展小趣事

在竞争激烈的电子行业中,品质控制和品牌建设至关重要。Deutsch公司深知这一点,因此始终将品质控制和品牌建设作为公司的重要任务。公司建立了严格的质量管理体系,确保产品的每一个细节都符合高标准。同时,通过精心策划的品牌推广活动,Deutsch公司的品牌形象逐渐深入人心。这些努力不仅提升了公司的市场地位,也增强了客户对公司的忠诚度。

DREMEL公司的发展小趣事

为了进一步扩大市场份额,Dremio公司积极寻求与电子行业的跨界合作。他们与一家知名电子设备制造商达成战略合作,共同开发了一款集成了Dremio数据处理技术的智能设备。这款设备能够实时收集和分析设备使用数据,为企业提供更精准的市场分析和产品优化建议。通过这一合作,Dremio成功将技术应用于电子设备的全生命周期管理,进一步巩固了其在市场中的地位。

问答坊 | AI 解惑

红色系列(一)

先睹为快,整理好了,一一再给大家展示。…

查看全部问答>

常用工具及仪表使用

主要介绍了在调试中用到的工具 有电压源 示波器等 前边的看看就可以 后边的示波器我想初学者都要看看 [ 本帖最后由 heningbo 于 2009-5-15 15:12 编辑 ]…

查看全部问答>

简易数字频率计

课程设计的东西!…

查看全部问答>

l298直流电机驱动器c程序

l298直流电机驱动器c程序…

查看全部问答>

请教一个比较急的问题

请教一个比较急的问题,我现在在用HCNR201这个线性光耦来搭电路,输入输出5V供电,运放使用的是358,但是现在有个问题,就是这个电路只能在输入是1.8V一下,有变化,当输入超过1.8V的时候输出保持在1.8V不变。而且在输出变化的时候,会有频率很高的 ...…

查看全部问答>

关于KEIL C的调试小问题

     请问为什么我用KEIL C调试的时候,跟踪变量的时候在第一个函数的变量都能在右下角的窗口中显示,但是进入第2个函数后里面的变量就不能在窗口中显示了,窗口是空白的,请问这是为什么啊…

查看全部问答>

ADC驱动初始化s2440ADC->rADCCON导致崩溃

我在写一个2440 ADC的驱动程序,程序已经被windows启动起来了,但是只要一执行到以下初始化红色的地方,程序就在串口输出崩溃信息。我的问题是,是不是触摸屏也在使用这个ADC。而2个驱动程序不能互相竞争这个寄存器? 我感觉不应该这样的,我在初 ...…

查看全部问答>

2440 wince5.0 SD卡可读不可写

2440开发板,wince5.0 在试SD卡时,只能读不能写。排除本身SD卡锁的可能,卡锁的两个位置都试过了,而且SD卡在PC机上也试过读写正常。SD卡的格式是FAT. 我通PC机与开发板的ActiveSync连接,可以看到SD卡的文件,要删除一个文件时,显示“文件可能 ...…

查看全部问答>

汇编写的斐波那挈数列 哪个牛人帮我看一下 我是刚学汇编的 有些不懂 运行结果是乱码 请教大家

斐波那挈  哪个牛人帮我看一下  我是刚学汇编的  有些不懂  运行结果是乱码  请教大家 data   segment      x   dw   24   dup ...…

查看全部问答>

LED在工程应用中的一些常识

LED照明行业是一个新兴的行业,它以其独特的优点深受人们的青睐。如今在光电工程中,提高光效,节约能源和高可靠性已经成为人们共同追求的目的。我们在讨论和使用LED光源时,都会想到LED的寿命长、节约能源、亮度高等特点。也正是因为如此LED光源才 ...…

查看全部问答>