A short introduction about me:
Hey! I'm Anushka. I'm a UG college student, majoring in Information Technology, from India. I absolutely love learning about how systems work under the hood, and becoming a kernel developer is a dream of mine.
This year, I am applying to GSoC, specifically the Project under Device Tree Bindings, which involves converting Device Tree Bindings to DT Schema.
One of the prerequisites is to create a small patch that fixes a trivial issue in drivers/staging. So, in this post, I am documenting my process of doing exactly that.
Note: This is not a tutorial, just my own devjournal documenting my learning process.
In the last post, I submitted my first device tree binding patch, and my third kernel patch.
With my first patch submitted, I decided to continue looking for more txt DT bindings to convert.
While searching for new patches, and going through my last patch, I realized a core mistake I had made.
Mistake in previous patch
I realized that I had overlooked a major check in my first patch.. I hadn't checked for active users! And... turns out.. OLPC is quite an old device with minimal userbase..
How could I make such a crucial mistake? It seems I was so excited to start the last time, that I had forgotten to check whether the file has active users. Working on a file with active users doing so will actually benefit the community and be considered more meaningful. Old devices without active users can also be wrong, it's harder for the maintainers to manage such devices.
So this time around, I made sure to check whether this file has active users. To do that, we have to check whether this file has any active users that was built by arm64 defconfig.
The DT Binding that I chose to convert this time around was ROCKCHIP with MAX98357A/RT5514/DA7219 codecs on GRU boards.
This is the file:
ROCKCHIP with MAX98357A/RT5514/DA7219 codecs on GRU boards.
Required properties:
- compatible: "rockchip,rk3399-gru-sound"
- rockchip,cpu: The phandle of the Rockchip I2S controller that's
connected to the codecs
- rockchip,codec: The phandle of the audio codecs
Optional properties:
- dmic-wakeup-delay-ms : specify delay time (ms) for DMIC ready.
If this option is specified, which means it's required dmic need
delay for DMIC to ready so that rt5514 can avoid recording before
DMIC send valid data
Example:
sound {
compatible = "rockchip,rk3399-gru-sound";
rockchip,cpu = <&i2s0>;
rockchip,codec = <&max98357a &rt5514 &da7219>;
dmic-wakeup-delay-ms = <20>;
};
To check if there are any active users, I search the compatible property in the above file to check if there's a .dtsi or .dts file available that uses my controller.
And..
anu@laptop:~/kernel-dev/source/linux$ git grep "rockchip,rk3399-gru-sound" -- arch/arm64
arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi: compatible = "rockchip,rk3399-gru-sound";
It is in use!
I checked lore, and didn't find anyone working on this file so, it's mine now~
I'll start working!
Understanding the hardware
Rockchip SoC (system on chip) processors are ARM-based processors commonly used in Chromebooks, Tablets, embedded systems, etc.
This device is the sound subsystem machine that orchestrates multiple codecs. It gives audio capabilities to Rockchip RK3399 SoC.
Rockchip RK3399 SoC by itself doesnt have audio capabilites. It has to be paired with external codecs, like Realtek codec, etc, in order to gain these capabilites.
Working on the code
A thing that I found useful while writing the code, was -- I first filled my empty yaml file with everything I was 100% sure of (like the header and compatible property) , and then slowly worked on towards the things I was unsure of, i.e the vendor properties.
Understanding the vendor properties
rockchip,cpu: phandle of the Rockchip I2S controller
I2S is standard audio protocol to send/recieve digital audio data between chips.
So, this means that this property contains a pointer (phandle) to another device in the device tree - specifically I2S controller chip.-
rockchip,codec: phandle of the audio codecs
it is a pointer (phandle) to the audio codec devices. The sound driver needs to know which codec is available and how to control them.Understanding the codecs
- MAX98357A — Class D speaker amplifier (typically for built-in speakers)
- RT5514 — Microphone codec (input path, often includes DSP for voice detection)
- DA7219 — Full-featured audio codec (can do both input/output, often handles headphone/headset)
I started looking if the vendor properties that were defined here were already defined elsewhere, in which case, I should refer to those.
I used the search tool rg because I found it much faster than grep or git grep.
anu@laptop:~/kernel-dev/source/linux$ rg "rockchip,codec" Documentation/devicetree/bindings/ -t yaml
anu@laptop:~/kernel-dev/source/linux$ rg "rockchip,cpu" Documentation/devicetree/bindings/ -t yaml
As the result shows, no. they weren't used before.
So, I decided to refer to a rockchip schema, Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.yaml here, there was a vendor property rockchip,grf defined.
I also opened the example schema to understand how to define such properties.
rockchip,cpu:
$ref: /schemas/types.yaml#/definitions/phandle
description:
The phandle of the Rockchip I2S controller that's connected to the codecs
rockchip,codec:
$ref: /schemas/types.yaml#/definitions/phandle-array
description: The phandle of the audio codecsi
to confirm the type, I had referred to the example given in my original DT binding txt file
rockchip,cpu = <&i2s0>; # <--- phandle
rockchip,codec = <&max98357a &rt5514 &da7219>; # <---phandle-array
Understanding the optional property
dmic-wakeup-delay-ms: specify delay time for DMIC ready
DMIC: Digital Microphone -- for the microphone codec (RT5514)
The DMIC requires a small amount of time after waking up to stabilize and start recording to produce valid audio data, else it can record garbage data.
So, this property tells that it's required for DMIC to wait for X ms before starting to record.
Thus, I checked out the dmic codec in Documentation/devicetree/bindings/sound/dmic-codec.yaml and checked out it's wakeup property.
I found this defined in that file:
wakeup-delay-ms:
description: Delay (in ms) after enabling the DMIC
Searching for parent files for my schema
It seems that in the above code, this property does the same thing as the property I defined..
Does this file need to be inherited.. ?
so I searched for the files that had used the wakeup-delay-ms property, and I found:
Documentation/devicetree/bindings/sound/adi,adau7002.yaml
wakeup-delay-ms:
description:
Delay after power up needed for device to settle.
however.. for this file.. the dmic file wasnt included.. why?
So, I looked up this device:
ADAU7002 is Analog Devices' audio converter chip. It converts PDM (pulse density modulation) to I2S. It's a codec, but it's not a DMIC.
This means that their property having the same names.... means nothing.
Then I noticed something:
This property... it seemed to not be a core DT property since I had not seen it in the example-schema.yaml .. is this a clue?
Answer: no. it isn't. It's just a property. I had this concept in my internal mind that the referring to the parent properties (using allOf: $ref:) are somewhat like "inheritence" in OOPS. That is why I had thought that if a property has a same name, then it must be "imported" from another file. This is not the case at all.
A file being a parent simply means that along with the rules defined in the current schema, the DTS should also satisfy all the rules defined by the parent schema.
No inheritence, the OOP concepts have no relation to this concept.
Then, I noticed another thing, while going through similar files.
All the yaml schema files that I had checked from this folder seemed to inherit the dai-common.yaml
even the DT Binding converstion patch about Maxim integrated Audio Codec that I had analysed while learning about DT schemas had this file as a parent...
I had learnt at that time:
DAI = Digital Audio Interface
codec needs to handle separate i/o (mic, speaker, etc) -- so each device would have a separate DAI port
Does that mean my file will need it though?
My device just needs to orchestrate multiple codecs which will manage the DAI. I needn't do that.
i checked in the dtsi file with rockchip,rk3399-gru-sound keyword to find where my file is referenced, and no it does not reference any 'sound-dai-cells' property. This proves that I should not include it in my file.
it does however contains maxim,max98357a -- that refeneces the dai property, but that's a difference audio codec file. not related to me
sound: sound {
compatible = "rockchip,rk3399-gru-sound";
rockchip,cpu = <&i2s0 &spdif>;
};
thus my driver does not require the soudn dai property
now, i have to prevent the schema from allowing any extra properties, so i referred to example-schema.yaml
# Ideally, the schema should have this line otherwise any other properties
# present are allowed. There's a few common properties such as 'status' and
# 'pinctrl-*' which are added automatically by the tooling.
#
# This can't be used in cases where another schema is referenced
# (i.e. allOf: [{$ref: ...}]).
# If and only if another schema is referenced and arbitrary children nodes can
# appear, "unevaluatedProperties: false" could be used. A typical example is
# an I2C controller where no name pattern matching for children can be added.
additionalProperties: false
Thus, I set additionalProperties: false
and done!
final file:
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/rockchip,rk3399-gru-sound.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ROCKCHIP with MAX98357A/RT5514/DA7219 codecs on GRU boards
maintainers:
- Heiko Stuebner <heiko@sntech.de>
properties:
compatible:
const: rockchip,rk3399-gru-sound
rockchip,cpu:
$ref: /schemas/types.yaml#/definitions/phandle
description:
The phandle of the Rockchip I2S controller that's connected to the codecs
rockchip,codec:
$ref: /schemas/types.yaml#/definitions/phandle-array
description: The phandle of the audio codecs
dmic-wakeup-delay-ms:
description:
specify delay time (ms) for DMIC ready.
If this option is specified, which means it's required dmic need
delay for DMIC to ready so that rt5514 can avoid recording before
DMIC sends valid data
required:
- compatible
- rockchip,cpu
- rockchip,codec
additionalProperties: false
examples:
- |
sound {
compatible = "rockchip,rk3399-gru-sound";
rockchip,cpu = <&i2s0>;
rockchip,codec = <&max98357a &rt5514 &da7219>;
dmic-wakeup-delay-ms = <20>;
};
Now it's time to test it!
So, following the same steps as the last time,
I first test it against the core DT schema, to check if the binding is correct --
anu@laptop:~/kernel-dev/source/linux$ make -j8 dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.yaml
make[1]: Entering directory '/home/anu/kernel-dev/source/linux/out'
SCHEMA Documentation/devicetree/bindings/processed-schema.json
CHKDT ../Documentation/devicetree/bindings
LINT ../Documentation/devicetree/bindings
DTEX Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.example.dts
DTC [C] Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.example.dtb
make[1]: Leaving directory '/home/anu/kernel-dev/source/linux/out'
and it is!
now it's time to validate it against the specified dtb schema
(note: i had not been able to try this in the past file because that file had no DTB file for it..)
I tried this:
anu@laptop:~/kernel-dev/source/linux$ ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make CHECK_DTBS=y DT_SCHEMA_FILES=Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.yaml rockchip/rk3399-gru-kevin.dtb
***
*** Configuration file ".config" not found!
***
*** Please run some configurator (e.g. "make oldconfig" or
*** "make menuconfig" or "make xconfig").
***
/home/anu/kernel-dev/source/linux/Makefile:844: include/config/auto.conf.cmd: No such file or directory
make[1]: *** [/home/anu/kernel-dev/source/linux/Makefile:853: .config] Error 1
make: *** [Makefile:248: __sub-make] Error 2
the reason was that I had not built a .config file using defconfig first.
for searching for the answer, I had referred this post by Krzysztof Kozlowski: https://www.linaro.org/blog/tips-and-tricks-for-validating-devicetree-sources-with-the-devicetree-schema/
first, I cleaned the directory. I hadn't done this at the start, and got an error while building in the next steps, where I was pointed to run make mrproper
anu@laptop:~/kernel-dev/source/linux$ make mrproper
make[1]: Entering directory '/home/anu/kernel-dev/source/linux/out'
CLEAN Documentation/devicetree/bindings
CLEAN scripts/basic
CLEAN scripts/dtc
make[1]: Leaving directory '/home/anu/kernel-dev/source/linux/out'
I set up my environment
anu@laptop:~/kernel-dev/source/linux$ export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
export KBUILD_OUTPUT=out/
this builds the .config file:
anu@laptop:~/kernel-dev/source/linux$ make defconfig
make[1]: Entering directory '/home/anu/kernel-dev/source/linux/out'
GEN Makefile
*** Default configuration is based on 'defconfig'
#
# configuration written to .config
#
make[1]: Leaving directory '/home/anu/kernel-dev/source/linux/out'
now for this step, I had run a full make dtbs_check.. however it took a lot of time, almost 20 mins to finish.
when I first ran this command, I got this error:
ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make CHECK_DTBS=y DT_SCHEMA_FILES=Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.yaml rockchip/rk3399-gru-kevin.dtb DTC [C] arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dtb /home/anu/kernel-dev/source/linux/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dtb: sound (rockchip,rk3399-gru-sound): rockchip,cpu:0: [211, 212] is too long from schema $id: http://devicetree.org/schemas/sound/rockchip,rk3399-gru-sound.yaml
look at this part:
rockchip,cpu:0: [211, 212] is too long from schema $id:
this means that the property rockchip,cpu should be a phandle-array and not a phandle, that I had set it to.
So, I went to the DT Schema, changed it and ran make dtbs_check again.
This time, it passed.
make[1]: Leaving directory '/home/anu/kernel-dev/source/linux/out'
make dtbs_check had taken way too much time the last time around. Now, I decided to test it against a dtb file.
When I had searched for the dts file before to find active users, there was a .dtsi file, but no .dts file.
it was this one: arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
so, i decided to see whether there are any dts files that import this dtsi file.
anu@laptop:~/kernel-dev/source/linux$ rg "rk3399-gru.dtsi"
arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi
8:#include "rk3399-gru.dtsi"
arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi
8:#include "rk3399-gru.dtsi"
248: * set this here, because rk3399-gru.dtsi ensures we can generate this
and I found.. 2 more .dtsi files.. I didn't give up and kept digging
anu@laptop:~/kernel-dev/source/linux$ rg "rk3399-gru-scarlet.dtsi"
arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet-kd.dts
10:#include "rk3399-gru-scarlet.dtsi"
arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet-inx.dts
10:#include "rk3399-gru-scarlet.dtsi"
arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet-dumo.dts
10:#include "rk3399-gru-scarlet.dtsi"
anu@laptop:~/kernel-dev/source/linux$ rg "rk3399-gru-chromebook.dtsi"
arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
9:#include "rk3399-gru-chromebook.dtsi"
arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts
9:#include "rk3399-gru-chromebook.dtsi"
and I found .dts files!
now, I can test them!
anu@laptop:~/kernel-dev/source/linux$ make CHECK_DTBS=y DT_SCHEMA_FILES=Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.yaml rockchip/rk3399-gru-kevin.dtb
make[1]: Entering directory '/home/anu/kernel-dev/source/linux/out'
HOSTCC scripts/dtc/dtc.o
HOSTCC scripts/dtc/flattree.o
HOSTCC scripts/dtc/fstree.o
HOSTCC scripts/dtc/data.o
HOSTCC scripts/dtc/livetree.o
HOSTCC scripts/dtc/treesource.o
HOSTCC scripts/dtc/srcpos.o
HOSTCC scripts/dtc/checks.o
HOSTCC scripts/dtc/util.o
LEX scripts/dtc/dtc-lexer.lex.c
YACC scripts/dtc/dtc-parser.tab.[ch]
HOSTCC scripts/dtc/dtc-lexer.lex.o
HOSTCC scripts/dtc/dtc-parser.tab.o
HOSTLD scripts/dtc/dtc
HOSTCC scripts/dtc/libfdt/fdt.o
HOSTCC scripts/dtc/libfdt/fdt_ro.o
HOSTCC scripts/dtc/libfdt/fdt_wip.o
HOSTCC scripts/dtc/libfdt/fdt_sw.o
HOSTCC scripts/dtc/libfdt/fdt_rw.o
HOSTCC scripts/dtc/libfdt/fdt_strerror.o
HOSTCC scripts/dtc/libfdt/fdt_empty_tree.o
HOSTCC scripts/dtc/libfdt/fdt_addresses.o
HOSTCC scripts/dtc/libfdt/fdt_overlay.o
HOSTCC scripts/dtc/fdtoverlay.o
HOSTLD scripts/dtc/fdtoverlay
SCHEMA Documentation/devicetree/bindings/processed-schema.json
UPD include/config/kernel.release
DTC [C] arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dtb
make[1]: Leaving directory '/home/anu/kernel-dev/source/linux/out'
and done!
I also checked it against a few other .dts files that I found, and they also succeeded!
anu@laptop:~/kernel-dev/source/linux$ make CHECK_DTBS=y DT_SCHEMA_FILES=Documentation/devicetree/bindings/sound/rockchip,rk3399-gru-sound.yaml rockchip/rk3399-gru-scarlet-dumo.dtb
make[1]: Entering directory '/home/anu/kernel-dev/source/linux/out'
DTC [C] arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet-dumo.dtb
make[1]: Leaving directory '/home/anu/kernel-dev/source/linux/out'
I also tested
arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts
arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet-kd.dts
and they both succeeded!
My patch is ready to submit!
Note: I have sent this patch to review with my mentors currently, and I will edit it as I get updates.
Top comments (0)