zoukankan      html  css  js  c++  java
  • 翻译:A Tutorial on the Device Tree (Zynq) -- Part IV

    获取资源信息

    内核模块驱动加载之后,就开始把硬件资源管理起来,如读写寄存器、接收中断。

    来看看设备树里的一条:

        xillybus_0: xillybus@50000000 {
          compatible = "xlnx,xillybus-1.00.a";
          reg = < 0x50000000 0x1000 >;
          interrupts = < 0 59 1 >;
          interrupt-parent = <&gic>;
    
          xlnx,max-burst-len = <0x10>;
          xlnx,native-data-width = <0x20>;
          xlnx,slv-awidth = <0x20>;
          xlnx,slv-dwidth = <0x20>;
          xlnx,use-wstrb = <0x1>;
        } ;
    

    驱动一般在探测函数里就取得了硬件内存段的所有权(探测函数就是probe指针指向的函数)。

    来看看一个典型探测函数的框架:

    static int __devinit xilly_drv_probe(struct platform_device *op)
    {
      const struct of_device_id *match;
    
      match = of_match_device(xillybus_of_match, &op->dev);
    
      if (!match)
        return -EINVAL;
    

    第一个操作就是检查probe是否作用在相关硬件上。

    访问寄存器

    下一步,分配一段内存并映射到虚拟内存中。

      int rc = 0;
      struct resource res;
      void *registers;
    
      rc = of_address_to_resource(&op->dev.of_node, 0, &res);
      if (rc) {
        /* Fail */
      }
    
      if  (!request_mem_region(res.start, resource_size(&res), "xillybus")) {
        /* Fail */
      }
    
      registers = of_iomap(op->dev.of_node, 0);
    
      if (!registers) {
        /* Fail */
      }
    
    

    of_address_to_resource() 在设备树中找到第一个"reg",并将解析到的信息填充在"res"结构体里。这个例子里"reg = < 0x50000000 0x1000 >”, 指的是分配一块起始物理地址是0x50000000,长度为0x1000字节的空间。of_address_to_resource()会设置res.start = 0x50000000, res.end = 0x50000fff。

    调用request_mem_region()是为了注册特殊的内存段。目的是避免两个驱动访问同一段寄存器空间而造成的冲突。resource_size()是个内联函数,返回segment的大小(此处是0x1000)。

    of_iomap()函数是of_address_to_resource()和ioremap()的组合,本质上等效于ioremap(re.start, resource_size(&res)).确保物理段已经映射到虚拟内存中,函数返回内存段的虚拟地址空间起始地址。

    显然,当模块卸载或某个错误发生时,这些操作都需要有恢复动作。

    访问硬件寄存器请使用iowrite32(),ioread32()以及其他的函数和宏,而不要直接使用上面的"register"指针。

    中断处理

    这部分的驱动很简单,类似如下:

      irq = irq_of_parse_and_map(op->dev.of_node, 0);
    
      rc = request_irq(irq, xillybus_isr, 0, "xillybus", op->dev);
    

    irq_of_parse_and_map()在设备树里查找中断的描述项,然后返回中断号,request_irq()将使用这个中断号来注册。第二个参数是0,表示使用设备树中的第一个中断。

    设备树里面描述是:

          interrupts = < 0 59 1 >;
          interrupt-parent = <&gic>;
    

    那么使用了这三个数据中的哪一个呢?

    第一个0是一个标志,用于指示中断是否是SPI(共享中断,shared peripheral interrupt)。非0值表示它是SPI。事实上在Zynq硬件上,这些中断都是共享的,这里是为了方便才写0, 软件上认为它不共享。

    第二个数据表示中断号。

    第三个数字是中断类型,可以有如下值:

    • 0 - 内核不改变它,开机或uboot设置它是什么样就什么样。
    • 1 - 上升沿触发
    • 4 - 电平触发,高电平表示来中断。

    不允许有其他值,下降沿触发和低电平中断目前不支持,因为硬件不支持那些模式。如果需要这样的触发方式,就得在硬件上加一个非门。

    值得注意的是第三个数字在设备树里通常都是0, 所以Linux内核不去改变中断模式。这通常意味着高电平触发。这也让驱动依赖于bootloader里的设置。

    interrupt-parent 这一句,必须指向中断控制器&gic。如果反编译一个DTB文件,这里的&gic会被一个数字代替,通常是0x1。

  • 相关阅读:
    sql mysql
    sql练习
    re正则表达式
    《大道至简 第二章》读后感
    读《大道至简:编程的精义》有感
    爬取汽车之家新闻图片的python爬虫代码
    Linux系统封装成iso文件
    使用Zabbix进行IPMI监控
    zabbix支持的主要监控方式
    python虚拟环境搭建
  • 原文地址:https://www.cnblogs.com/sammei/p/3984463.html
Copyright © 2011-2022 走看看