Rockchip RK3399 - Platform驱动(DMA&i2s0)

本文详细介绍了Rockchip RK3399 SoC中I2S0设备的平台驱动,包括设备树配置、时钟频率设置、Platform驱动的模块入口及匹配过程。内容涵盖了I2S0的设备节点配置、引脚配置、时钟频率配置,以及Platform驱动的入口函数和探针函数,深入解析了音频数据传输的DMA配置和时钟链路。
摘要由CSDN通过智能技术生成

Platfrom driver提供了配置/使能SoC音频接口的能力;Plaftrom驱动分为三个部分:dma driver、cpu dai driver、dsp driver。

(1) cpu dai driver:在嵌入式系统里面通常指SoC的 I2S、PCM 总线控制器,负责把音频数据从I2S tx FIFO 搬运Codec(这是回放的情形,录制则方向相反)。每个cpu dai driver必须提供以下功能:

  • DAI描述信息;
  • DAI配置信息;
  • PCM描述信息;
  • 系统时钟配置;
  • 挂起和恢复(可选);

更多信息参考: Documentation/sound/soc/dai.rst。

(2) DMA driver :负责把dma buffer中的音频数据搬运到 I2S tx FIFO。值得留意的是:某些情形下是不需要dma操作的,比如Modem和Codec直连,因为Modem本身已经把数据送到 FIFO 了,这时只需启动codec_dai 接收数据即可;DMA driver可以参考soc/pxa/pxa2xx-pcm.c;

(3) DSP driver

每个DSP driver通常提供以下功能:

  • DAPM拓扑;
  • Mixer controls;
  • DMA IO to/from DSP buffers (if applicable);
  • Definition of DSP front end (FE) PCM devices;

更多信息参考: Documentation/sound/soc/platform.rst,https://www.kernel.org/doc/html/v6.3/sound/soc/platform.html。驱动代码位于sound/soc/rockchip/rockchip_i2s.c文件。

一、设备树配置

1.1 设备节点i2s0

设备节点i2s0定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi文件:

i2s0: i2s@ff880000 {
        compatible = "rockchip,rk3399-i2s", "rockchip,rk3066-i2s";
        reg = <0x0 0xff880000 0x0 0x1000>;
        rockchip,grf = <&grf>;
        interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH 0>;
        dmas = <&dmac_bus 0>, <&dmac_bus 1>;
        dma-names = "tx", "rx";
        clock-names = "i2s_clk", "i2s_hclk";
        clocks = <&cru SCLK_I2S0_8CH>, <&cru HCLK_I2S0_8CH>;
        pinctrl-names = "bclk_on", "bclk_off";
        pinctrl-0 = <&i2s0_8ch_bus>;
        pinctrl-1 = <&i2s0_8ch_bus_bclk_off>;
        power-domains = <&power RK3399_PD_SDIOAUDIO>;
        #sound-dai-cells = <0>;
        status = "disabled";
};

这是Rockchip RK3399中I2S0设备节点描述。它包括以下属性:

  • compatible:指定设备驱动程序的兼容性,即告诉内核该设备可以被哪些驱动程序所使用;
  • reg:指定I2S0控制器的基地址和地址空间大小,从0xff880000到0xff881000共有0x1000个字节的寄存器空间,其中0xff880000为I2S0寄存器基地址;
  • rockchip,grf:设置为grf设备节点,GRF表示的是通用寄存器文件,由许多用于系统控制的寄存器组成,GRF可以分为两部分;
    • GRF:used for generalnon-secure system;
    • PMUGRF:used for always on sysyem;
  • interrupts:指定I2S控制器的中断号为GIC_SPI 39,并且取值方式为IRQ_TYPE_LEVEL_HIGH,意味着中断信号为高电平触发;
  • dmas:指定数据传输时使用的DMA控制器,第一个表示tx数据使用的DMA控制器,第二个表示rx数据使用的DMA控制器;
  • dma-names:分别对应"tx"和"rx"的DMA名称;
  • clock-names:指定时钟名称,"i2s_clk"表示I2S0控制器时钟,"i2s_hclk" 表示I2S总线时钟;
  • clocks:i2s_clk时钟来自SCLK_I2S0_8CH,i2s_hclk时钟来自 HCLK_I2S0_8CH;
  • pinctrl-names:指定设备pinctrl配置集合;
  • pinctrl-0:设置bclk_on状态对应的引脚配置为i2s0_8ch_bus,这里主要配置I2S0相关引脚复用为I2S功能;
  • pinctrl-1:设置bclk_off状态对应的引脚配置为i2s0_8ch_bus_bclk_off,这里主要配置I2S0相关引脚复用为I2S功能,但是SCLK被设置为了GPIO,因此此时I2S0功能是禁用的;
  • power-domains:指定设备隶属于的电源域,这里是 RK3399_PD_SDIOAUDIO;
  • #sound-dai-cells:表示定义这个节点的sound DAI数据单元格的数量,这里为0表示没有单元格;
  • status:表示设备状态,这里 "disabled" 表示该设备当前是禁用状态;

其中设备节点grf定义如下:

grf: syscon@ff770000 {
        compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
        reg = <0x0 0xff770000 0x0 0x10000>;  // GRF基地址0xff770000 大小64kb
        #address-cells = <1>;
        #size-cells = <1>;

        io_domains: io-domains {
                compatible = "rockchip,rk3399-io-voltage-domain";
                status = "disabled";
        };
        ......
}

我们需要在arch/arm64/boot/dts/rockchip/rk3399-evb.dts文件添加如下属性,启用I2S0控制器:

&i2s0 {
        rockchip,playback-channels = <8>;
        rockchip,capture-channels = <8>;
        status = "okay";
};

其中:

  • rockchip,playback-channels:为最大播放通道数;
  • rockchip,capture-channels:为最大录音通道数;

这里配置为8,以播放音频为例我谈一谈我个人的理解,应该是RK3399 I2S0有4条数据线可以用来传输收音频数据,I2S0_SDI0、I2S0_SDI1、I2S0_SDI02、I2S0_SDI03;由于在每条数据线上传输左通道、右通道的信号,因此4*2=8,一共就是8个通道;

关于设备节点属性可以参考文档Documentation/devicetree/bindings/sound/rockchip-i2s.yaml。

而RK3399 I2S控制器驱动代码位于sound/soc/rockchip/rockchip_i2s.c文件。

1.2 引脚配置节点i2s0_8ch_bus

引脚配置节点i2s0_8ch_bus和i2s0_8ch_bus_bclk_off定义在pinctrl设备节点下:

i2s0 {
        i2s0_2ch_bus: i2s0-2ch-bus {
                rockchip,pins =
                        <3 RK_PD0 1 &pcfg_pull_none>,
                        <3 RK_PD1 1 &pcfg_pull_none>,
                        <3 RK_PD2 1 &pcfg_pull_none>,
                        <3 RK_PD3 1 &pcfg_pull_none>,
                        <3 RK_PD7 1 &pcfg_pull_none>,
                        <4 RK_PA0 1 &pcfg_pull_none>;
        };

        i2s0_8ch_bus: i2s0-8ch-bus {
                rockchip,pins =
                        <3 RK_PD0 1 &pcfg_pull_none>,
                        <3 RK_PD1 1 &pcfg_pull_none>,
                        <3 RK_PD2 1 &pcfg_pull_none>,
                        <3 RK_PD3 1 &pcfg_pull_none>,
                        <3 RK_PD4 1 &pcfg_pull_none>,
                        <3 RK_PD5 1 &pcfg_pull_none>,
                        <3 RK_PD6 1 &pcfg_pull_none>,
                        <3 RK_PD7 1 &pcfg_pull_none>,
                        <4 RK_PA0 1 &pcfg_pull_none>;
        };

        i2s0_8ch_bus_bclk_off: i2s0-8ch-bus-bclk-off {
                rockchip,pins =
                        <3 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>,
                        <3 RK_PD1 1 &pcfg_pull_none>,
                        <3 RK_PD2 1 &pcfg_pull_none>,
                        <3 RK_PD3 1 &pcfg_pull_none>,
                        <3 RK_PD4 1 &pcfg_pull_none>,
                        <3 RK_PD5 1 &pcfg_pull_none>,
                        <3 RK_PD6 1 &pcfg_pull_none>,
                        <3 RK_PD7 1 &pcfg_pull_none>,
                        <4 RK_PA0 1 &pcfg_pull_none>;
        };
}; 

这里我们只关注i2s0_8ch_bus引脚配置节点,这里定义了9个引脚,管脚与具体的功能和电气特性如下:

  • GPIO3_PD0:功能复用为I2S0_SCLK,电气特性配置为pcfg_pull_none;
  • GPIO3_PD1:功能复用为I2S0_LRCK_RX,电气特性配置为pcfg_pull_none;
  • GPIO3_PD2:功能复用为I2S0_LRCK_TX,电气特性配置为pcfg_pull_none;
  • GPIO3_PD3:功能复用为I2S0_SDI0,电气特性配置为pcfg_pull_none;
  • GPIO3_PD4:功能复用为I2S0_SDI1/I2S0_SDO3,电气特性配置为pcfg_pull_none;
  • GPIO3_PD5:功能复用为I2S0_SDI2/I2S0_SDO2,电气特性配置为pcfg_pull_none;
  • GPIO3_PD6:功能复用为I2S0_SDI3/I2S0_SDO1,电气特性配置为pcfg_pull_none;
  • GPIO3_PD7:功能复用为I2S0_SDO0,电气特性配置为pcfg_pull_none;
  • GPIO4_PA0:功能复用为I2S0_MCLK,电气特性配置为pcfg_pull_none;
1.3 时钟频率

这里我们看看一下时钟频率配置:

clock-names = "i2s_clk", "i2s_hclk";
clocks = <&cru SCLK_I2S0_8CH>, <&cru HCLK_I2S0_8CH>;

SCLK_I2S0_8CH、HCLK_I2S0_8CH为平台为时钟分配的特定的id,定义在drivers/clk/rockchip/clk-rk3399.c:

GATE(SCLK_I2S0_8CH, "clk_i2s0", "clk_i2s0_mux", CLK_SET_RATE_PARENT,
                RK3399_CLKGATE_CON(8), 5, GFLAGS),
GATE(HCLK_I2S0_8CH, "hclk_i2s0", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 0, GFLAGS),

他们都是gate类型的时钟,其中GATE宏定义在drivers/clk/rockchip/clk.h:

#define GATE(_id, cname, pname, f, o, b, gf)                    \
        {                                                       \
                .id             = _id,                          \
                .branch_type    = branch_gate,                  \
                .name           = cname,                        \
                .parent_names   = (const char *[]){ pname },    \
                .num_parents    = 1,                            \
                .flags          = f,                            \
                .gate_offset    = o,                            \
                .gate_shift     = b,                            \
                .gate_flags     = gf,                           \
        }
1.3.1 hclk_i2s0

我们以GATE(HCLK_I2S0_8CH, "hclk_i2s0", "hclk_perilp1", 0, RK3399_CLKGATE_CON(34), 0, GFLAGS)为例:

  • id表示平台为时钟特定分配的id,这里被设置为了HCLK_I2S0_8CH;定义在include/dt-bindings/clock/rk3399-cru.h,值为468;
  • name表示时钟的名称,这里设置为hclk_i2s0;
  • parent_name为父时钟的名称,这里设置为hclk_perilp1;
  • gate_offset表示控制时钟开关的寄存器偏移地址,这里设置为RK3399_CLKGATE_CON(34);
  • gate_shift表示控制时钟开关bit位,这里设置为0;
<
Rockchip RK3566是一款由Rockchip推出的高性能应用处理器,其集成了四核ARM Cortex-A55 CPU和ARM Mali-G52 GPU。在移植U-Boot 2023.04时,我们需要考虑以下几个方面的工作: 1. 了解RK3566芯片的硬件架构和技术规格,包括处理器核心、内存控制器、外设接口等。这将有助于理解U-Boot如何与硬件交互,并进行相应的配置。 2. 下载并准备U-Boot 2023.04的源代码。在Rockchip官方网站或开源社区中可以找到最新的U-Boot源代码。将其下载并解压到开发机上。 3. 设置交叉编译环境。因为U-Boot是一个跨平台的项目,所以需要配置适合RK3566的交叉编译器,确保能够正确编译U-Boot源代码。 4. 配置U-Boot。根据RK3566的硬件架构和技术规格,需要进行相应的配置,包括处理器、内存、外设等设置。这些设置在U-Boot的配置文件中进行,可以根据需求进行修改。 5. 编译U-Boot。在配置好U-Boot后,使用交叉编译器编译U-Boot源代码。编译完成后,将生成的U-Boot二进制文件烧录到RK3566的启动设备上,如eMMC或SD卡。 6. 测试U-Boot。将准备好的启动设备插入RK3566开发板中,根据开发板的启动方式,进入U-Boot命令行界面。在命令行界面中可以进行各种操作和调试,如加载内核、启动操作系统等。 7. 调试和优化。在移植和测试U-Boot过程中,可能会出现一些问题和不稳定的情况。需要通过调试和优化来解决这些问题,确保U-Boot的正常运行和稳定性。 总之,移植U-Boot 2023.04到Rockchip RK3566需要了解芯片的硬件架构和技术规格,配置和编译U-Boot源代码,进行测试和调试。这样可以确保U-Boot能够与RK3566正常交互,并为后续的操作系统加载和启动提供基础支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Graceful_scenery

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值