[openharmony]L2系统SPI的实现原理

2022-04-13  本文已影响0人  itsenlin

摘要

本文基于Hi3516DV300开发板进行分析,此开发板使用的是海思的一款基于双核Cortex-A7的soc,提供了3路SPI总线(但是开发板上没有对外提供SPI接口,需要使用的话就需要飞线)。由于工作需要使用SPI连接了一个外设芯片进行调试,在调试过程中学习了Openharmony在L2上SPI实现的原理

DT和HDF

在分析SPI总线实现原理之前,先了解一下linux系统以及openharmony下对硬件描述最为关键的几个概念

linux系统

openharmony

对比说明

从前面两节的几个概念描述看,Openharmony中实现了一套与linux系统下类似的硬件描述结构

linux openharmony 说明
DT HDF 硬件描述的结构
DTS HCS 硬件结构描述的源码
DTB HCB 硬件结构描述的源码编译后的二进制文件
DTC HC-GEN 将硬件结构描述源码转换为二进制文件的编译工具

对比来看两者的功能基本上类似,Openharmony重新实现一套机制的好处是将Openharmony下的L0/L1/L2系统(分别对应的是liteos-m/liteos-a/linux)统一起来。但是个人理解其实还有一种实现方式,就是将linux下的dt移植到openharmony的L0/L1系统,而L2完全使用linux默认的DT,这样可能对于开发人员的学习成本会低很多(只是个人理解)。

然而还有一个问题,在分析SPI实现原理的过程中发现,openharmony的L2系统中其实DT和HDF是共存的,并不是替换的关系(只是在L0/L1上是独有的)。并且两边都有对SPI的配置及解析,两者是怎么配合的呢,下面一步步来分析一下。

linux下SPI总线的配置及实现

从前面描述看SPI总线的配置也是在DTS中,对于Hi3568DV300开发板来说对应的dts文件路径为:

linux-5.10/arch/arm/boot/dts/hi3516dv300.dtsi
linux-5.10/arch/arm/boot/dts/hi3516dv300-demb.dts

但是在源码中发现并没有这两个文件,而是在编译好版本之后在输出目录out/KERNEL_OBJ/kernel/src_tmp/可以找到,原因就是这两个文件不是linux自带的,而是在编译的时候给内核打补丁出现的,参见patch文件kernel/linux/patches/linux-5.10/hi3516dv300_patch/hi3516dv300.patch

dtsi中SPI配置如下(三路SPI配置类似):

        spi_bus1: spi@120c1000 {
            compatible = "arm,pl022", "arm,primecell";
            arm,primecell-periphid = <0x00800022>;
            reg = <0x120c1000 0x1000>, <0x12030000 0x4>;
            interrupts = <0 69 4>;
            clocks = <&clock HI3516DV300_SPI1_CLK>;
            clock-names = "apb_pclk";
            #address-cells = <1>;
            #size-cells = <0>;
            num-cs = <2>;
            hisi,spi_cs_sb = <2>;
            hisi,spi_cs_mask_bit = <0x4>;//0100
#ifdef CONFIG_HIEDMACV310
            dmas = <&hiedmacv310_0 29 29>, <&hiedmacv310_0 28 28>;
            dma-names = "tx","rx";
#endif
            status = "disabled";
        };

而在dts文件中将status改为OK,如下

&spi_bus1{
    status = "okay";
    num-cs = <2>;

    spidev@0 {
        compatible = "rohm,dh2228fv";
        reg = <0>;
        pl022,interface = <0>;
        pl022,com-mode = <1>;
        spi-max-frequency = <25000000>;
    };
    spidev@1 {
        compatible = "rohm,dh2228fv";
        reg = <1>;
        pl022,interface = <0>;
        pl022,com-mode = <0>;
        spi-max-frequency = <25000000>;
    };
};

在启动时就会将spi_dev挂到设备树中。

从配置的compatible字段看,SPI总线驱动使用的是arm内核一种公共的SPI驱动pl022,驱动文件路径为kernel/linux/linux-5.10/drivers/spi/spi-pl022.c ,主要接口配置如下:

  static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
  {
      ......
      master->cleanup = pl022_cleanup;
      master->setup = pl022_setup;
      master->auto_runtime_pm = true;
      master->transfer_one_message = pl022_transfer_one_message;
      master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
      ......
  }

而linux系统对SPI总线提供了一个统一的接口,放在kernel/linux/linux-5.10/drivers/spi/spi.c中。

Openharmony下SPI总线的配置及实现

配置

HDF驱动开发方法可以先看下官网文档

HCS配置文件路径:

vendor/<company>/<product>/hdf_config/khdf/device_info/device_info.hcs
vendor/<company>/<product>/hdf_config/khdf/platform/hi35xx_spi_config.hcs

在HDF下SPI在platform-host下,如下

        platform :: host {
            hostName = "platform_host";
            priority = 50;
            ......
            device_spi :: device {
                ......
                device1 :: deviceNode {
                    policy = 1;
                    priority = 60;
                    permission = 0644;
                    moduleName = "HDF_PLATFORM_SPI";
                    serviceName = "HDF_PLATFORM_SPI_1";
                    deviceMatchAttr = "hisilicon_hi35xx_spi_1";
                }
                ......
            }
        ......
        }

SPI私有配置

root {
    platform {
        spi_config {
            template spi_controller {
                serviceName = "";
                match_attr = "";
                busNum = 0;
                numCs = 0;
            }

            controller_0x120c0000 :: spi_controller {
                busNum = 0;
                numCs = 1;
                match_attr = "hisilicon_hi35xx_spi_0";
            }

            controller_0x120c1000 :: spi_controller {
                match_attr = "hisilicon_hi35xx_spi_1";
                busNum = 1;
                numCs = 2;
            }

            controller_0x120c2000 :: spi_controller {
                match_attr = "hisilicon_hi35xx_spi_2";
                busNum = 2;
                numCs = 1;
            }
        }
    }
}

HDF下SPI总线驱动代码

代码路径为drivers/adapter/khdf/linux/platform/spi/hi35xx_spi_adapter.c
提供了下面几个接口,并将spi_driver加入到HDF框架下面

struct SpiCntlrMethod g_method = {
    .Transfer = SpiAdatperTransfer,
    .SetCfg = SpiAdatperSetCfg,
    .GetCfg = SpiAdatperGetCfg,
    .Open = SpiAdatperOpen,
    .Close = SpiAdatperClose,
};

Openharmony下SPI总线的使用

从前面分析来看,Openharmony下SPI总线驱动最终调用的还是linux下对应的具体的驱动实现。这样HDF与DT之间就建立起了关联。而在Openharmony下SPI总线又给其他驱动提供了统一的驱动接口,路径为:

drivers/framework/support/platform/src/spi/spi_if.c
drivers/framework/support/platform/src/spi/spi_core.c

从这两个源文件分析,实际就是从HDF下查找HDF_PLATFORM_SPI,从上一节分析看,这个就是drivers/adapter/khdf/linux/platform/spi/hi35xx_spi_adapter.c的实现。
这样调用顺序就是

图片1.png

总结

在Openharmony的L2下使用SPI总线,其实最底层还是调用的linux下具体的SPI总线驱动代码。而对于SPI-slave设备使用SPI总线通信时:

这样后续移植代码到Openharmony的L1/L0时就比较简单了。

上一篇下一篇

猜你喜欢

热点阅读