zoukankan      html  css  js  c++  java
  • zc706 flash compatible引发的思考

    zynq-zc706.dts

    &qspi {
        u-boot,dm-pre-reloc;
        status = "okay";
        is-dual = <1>;
        num-cs = <1>;
        flash@0 {
            compatible = "n25q128a11";
    compatible = "n25q128a11";
    找不到对应的驱动


    qspi控制器驱动的疑惑:
    zynq-7000.dtsi
            qspi: spi@e000d000 {
                clock-names = "ref_clk", "pclk";
                clocks = <&clkc 10>, <&clkc 43>;
                compatible = "xlnx,zynq-qspi-1.0";
                status = "disabled";
                interrupt-parent = <&intc>;
                interrupts = <0 19 4>;
                reg = <0xe000d000 0x1000>;
                #address-cells = <1>;
                #size-cells = <0>;
            };
    
    

    drivers/spi/spi-zynq-qspi.c qspi控制器驱动

    830 static const struct of_device_id zynq_qspi_of_match[] = {
    831     { .compatible = "xlnx,zynq-qspi-1.0", },
    832     { /* end of table */ }
    833 };

    这个路径比较奇怪,因为其他控制器不是放在spi目录下

    比如cadence qspi控制器

    compatible = "cdns,qspi-nor"

    源码在drivers/mtd/spi-nor/cadence-quadspi.c

    /linux-xxxx/drivers/mtd/spi-nor/spi-nor.c 是spi nor的封装层 可参考 https://blog.csdn.net/u011011827/article/details/95786541

    颗粒的驱动在linux-xxxx/drivers/mtd/devices目录下

    用的是m25p80.c

    static const struct spi_device_id m25p_ids[] = {
        {"spi-nor"},
    
        /*
         * Entries not used in DTs that should be safe to drop after replacing
         * them with "spi-nor" in platform data.
         */
        {"s25sl064a"},    {"w25x16"},    {"m25p10"},    {"m25px64"},
    
        /*
         * Entries that were used in DTs without "jedec,spi-nor" fallback and
         * should be kept for backward compatibility.
         */
        {"at25df321a"},    {"at25df641"},    {"at26df081a"},
        { },
    };
    
    
    MODULE_DEVICE_TABLE(spi, m25p_ids);
    
    static const struct of_device_id m25p_of_table[] = {
        /*
         * Generic compatibility for SPI NOR that can be identified by the
         * JEDEC READ ID opcode (0x9F). Use this, if possible.
         */
        { .compatible = "jedec,spi-nor" },
        {}
    };
    MODULE_DEVICE_TABLE(of, m25p_of_table);
    
    
    static struct spi_mem_driver m25p80_driver = {
        .spidrv = {
            .driver = {
                .name    = "m25p80",
                .of_match_table = m25p_of_table,
            },
            .id_table    = m25p_ids,
        },
        .probe    = m25p_probe,
        .remove    = m25p_remove,
        .shutdown    = m25p_shutdown,
    
        /* REVISIT: many of these chips have deep power-down modes, which
         * should clearly be entered on suspend() to minimize power use.
         * And also when they're otherwise idle...
         */
    };

    驱动和设备的匹配有四种方法,我们依次来看一下: 第 11~12行,第一种匹配方式, OF类型的匹配,也就是设备树采用的匹配方式, of_driver_match_device函数定义在文件 include/linux/of_device.h中。 device_driver结构体 (表示 设备驱动 )中有个名为 of_match_table的成员变量,此成员变量保存着驱动的 compatible匹配表, 设备树中的每个设备节点的 compatible属性会和 of_match_table表中的所有成员比较,查看是 否有相同的条目,如果有的话就表示设备和此驱动匹配,设备和驱动匹配成功以后 probe函数 就会执行。 第 15~16行,第二种匹配方式, ACPI匹配方式。 第 19~20行,第三种匹配方式, id_table匹配,每个 platform_driver结构体有一个 id_table成员变量,顾名思义,保存了很多 id信 息。这些 id信息存放着这个 platformd驱动所 支持 的驱 动类型。 第 23行,第四种匹配方式,如果第三种匹配方式的 id_table不存在的话就直接比较驱动和 设备的 name字段,看看是不是相等,如果相等的话就匹配成功。 对于支持设备树的 Linux版本号,一般设备驱动为了兼容性都支持设备树和无设备树两种 匹配方式。也就是第一种匹配方式一般都会存在,第三种和第四种只要存在一种就可以,一般 用的最多的还是第四种,也就是直接比较驱动和设备的 name字段,毕竟这种方式最简单了。


    以上是linux中的驱动,对于u-boot中
    drivers/spi/zynq_qspi.c中
    864 static const struct udevice_id zynq_qspi_ids[] = {
    865     { .compatible = "xlnx,zynq-qspi-1.0" },
    866     { }
    867 };
    
    
    869 U_BOOT_DRIVER(zynq_qspi) = {
    870     .name   = "zynq_qspi",
    871     .id     = UCLASS_SPI,
    872     .of_match = zynq_qspi_ids,
    873     .ops    = &zynq_qspi_ops,
    874     .ofdata_to_platdata = zynq_qspi_ofdata_to_platdata,
    875     .platdata_auto_alloc_size = sizeof(struct zynq_qspi_platdata),
    876     .priv_auto_alloc_size = sizeof(struct zynq_qspi_priv),
    877     .probe  = zynq_qspi_probe,
    878     .child_pre_probe = zynq_qspi_child_pre_probe,
    879 };

    flash器件

    compatible = "n25q128a11";

    
    

    sf probe

    
    

      do_spi_flash (cmd/sf.c)

    
    

        do_spi_flash_probe (cmd/sf.c)

          /* Remove the old device, otherwise probe will just be a nop */

          spi_find_bus_and_cs (spi-uclass.c)

    
    

            uclass_find_device_by_seq   (drivers/core/uclasee.c)//寻找spi总线设备(SPI控制器) 没有probe

            //ret = uclass_find_device_by_seq(UCLASS_SPI, busnum, false, &bus);

            spi_find_chip_select  (drivers/spi/spi-uclass.c)//在SPI总线设备下找到FLASH设备

    
    

          spi_flash_probe_bus_cs(driver/mtd/spi/sf-uclass.c)

    
    

            spi_get_bus_and_cs  (drivers/spi/spi-uclass.c)

            /*ret = spi_get_bus_and_cs(busnum, cs, max_hz, spi_mode,
                      "spi_flash_std", str, &bus, &slave); 这里直接指定了driver name*/
    
    

              uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus); //UCLASS_SPI cadence_spi_probe

    
    

              spi_find_chip_select(bus, cs, &dev);

              if (ret == -ENODEV && drv_name) 

                ret = device_bind_driver(bus, drv_name, dev_name, &dev);

    
    

              device_probe (qspi flash颗粒 激活)

    
    

     那么flash器件的dts参数如何获得呢?

    cadence_spi_ofdata_to_platdata

    static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
    {
        struct cadence_spi_platdata *plat = bus->platdata;
        const void *blob = gd->fdt_blob;
        int node = dev_of_offset(bus);
        int subnode;
    
        plat->regbase = (void *)devfdt_get_addr_index(bus, 0);
        plat->ahbbase = (void *)devfdt_get_addr_index(bus, 1);
        plat->is_decoded_cs = fdtdec_get_bool(blob, node, "cdns,is-decoded-cs");
        plat->fifo_depth = fdtdec_get_uint(blob, node, "cdns,fifo-depth", 128);
        plat->fifo_width = fdtdec_get_uint(blob, node, "cdns,fifo-width", 4);
        plat->trigger_address = fdtdec_get_uint(blob, node,
                            "cdns,trigger-address", 0);
    
        /* All other paramters are embedded in the child node */
      //以下是flash颗粒dts的解析
    subnode = fdt_first_subnode(blob, node); if (subnode < 0) { printf("Error: subnode with SPI flash config missing! "); return -ENODEV; } /* Use 500 KHz as a suitable default */ plat->max_hz = fdtdec_get_uint(blob, subnode, "spi-max-frequency", 500000); /* Read other parameters from DT */ plat->page_size = fdtdec_get_uint(blob, subnode, "page-size", 256); plat->block_size = fdtdec_get_uint(blob, subnode, "block-size", 16); plat->tshsl_ns = fdtdec_get_uint(blob, subnode, "cdns,tshsl-ns", 200); plat->tsd2d_ns = fdtdec_get_uint(blob, subnode, "cdns,tsd2d-ns", 255); plat->tchsh_ns = fdtdec_get_uint(blob, subnode, "cdns,tchsh-ns", 20); plat->tslch_ns = fdtdec_get_uint(blob, subnode, "cdns,tslch-ns", 20); debug("%s: regbase=%p ahbbase=%p max-frequency=%d page-size=%d ", __func__, plat->regbase, plat->ahbbase, plat->max_hz, plat->page_size); return 0; }

  • 相关阅读:
    c++中的extern
    DOS性能监视器
    谈谈.NET中的内存管理(转帖)
    static_cast和dynamic_cast
    关于对EventHandler 和e的理解(转帖)
    使用Windows Mobile 6模拟器上网的步骤(转帖)
    接口抽象类类
    当前不会命中断点 尚未加载指定的模块 windows mobile
    C# 编码的双重检验锁定
    Loadrunner 监控Unix系统性能指标的解释
  • 原文地址:https://www.cnblogs.com/idyllcheung/p/14017283.html
Copyright © 2011-2022 走看看