Last edited 2 weeks ago

MDF device tree configuration

Applicable for STM32MP21x lines, STM32MP23x lines, STM32MP25x lines


1. Article purpose[edit | edit source]

The purpose of this article is to explain how to configure the MDF internal peripheral using the device tree mechanism, relying on the bindings documentation, that is the description of the required and optional device-tree properties.

If the peripheral is assigned to another execution context, refer to How to assign an internal peripheral to an execution context article for guidelines on peripheral assignment and configuration.

2. DT bindings documentation[edit | edit source]

The MDF can serve multiple functions: ADC and DMIC (for audio).

Each one is represented by a separate compatible string, documented in STM32 MDF device tree bindings[1].

Each channel is described by a dedicated DT sub node, filled in with properties documented in Generic IIO bindings for ADC channels[2].

The external analog backend (e.g. sigma-delta modulator) is documented in Device-Tree bindings for sigma delta modulator[3]

3. DT configuration[edit | edit source]

This hardware description is a combination of the STM32 microprocessor device tree files (.dtsi extension) and board device tree files (.dts extension). See the Device tree for an explanation of the device-tree file organization.

The STM32CubeMX can be used to generate the board device tree. Refer to How to configure the DT using STM32CubeMX for more details.

3.1. DT configuration (STM32/SoC level)[edit | edit source]

The MDF node is located in the device tree file for the software components, supporting the peripheral and listed in the above DT bindings documentation paragraph.

  • DT root node ('mdf') describes the MDF hardware block common parameters such as registers area, reset, clocks, power domain and pins.
  • DT child nodes ('sitf0', 'sitf1', ...) describe each serial interface independently: compatible string, registers area, pins, ...
  • DT child nodes ('filter0', 'filter1', ...) describe each filter path independently: compatible string, registers area, interrupts, DMAs, ...
3.1.1. On STM32MP21x lines More info.png and STM32MP25x lines More info.png[edit | edit source]

On STM32MP21x lines More info.png, the MDF nodes are declared in stm32mp211.dtsi[4].

On STM32MP25x lines More info.png, the MDF nodes are declared in stm32mp251.dtsi[5].

 mdf: mdf@404d0000 {
 	compatible = "st,stm32mp25-mdf";
 	...  /* common resources in 'mdf' root node. */
 	sitf0: sitf@80 {
 		compatible = "st,stm32mp25-sitf-mdf";
 		reg = <0x80 0x4>;
 		... /* private resources in serial interface 0 child node. */
 	};
 	filter0: filter@84 {
 		compatible = "st,stm32mp25-mdf-adc";  /* can either be st,stm32-mdf-(adc or dmic) */
 		reg = <0x84 0x70>;
 		...  /* private resources in filter 0 child node. */
 	}
 };
3.1.2. On STM32MP23x lines More info.png[edit | edit source]

On STM32MP23x lines More info.png, the MDF nodes are declared in stm32mp231.dtsi[6].

 mdf: mdf@404d0000 {
 	compatible = "st,stm32mp23-mdf";
 	...  /* common resources in 'mdf' root node. */
 	sitf0: sitf@80 {
 		compatible = "st,stm32mp25-sitf-mdf";
 		reg = <0x80 0x4>;
 		... /* private resources in serial interface 0 child node. */
 	};
 	filter0: filter@84 {
 		compatible = "st,stm32mp25-mdf-adc";  /* can either be st,stm32-mdf-(adc or dmic) */
 		reg = <0x84 0x70>;
 		...  /* private resources in filter 0 child node. */
 	}
 };
Warning white.png Warning
This device tree part is related to STM32 microprocessors. It must be kept as is, without being modified by the end-user.

3.2. DT configuration (board level)[edit | edit source]

The objective of this chapter is to explain how to enable and configure the MDF DT nodes for a board. The peripheral configuration must be done in specific board device tree files (board dts file and pinctrl dtsi file).

3.2.1. Common resources for all MDF filters[edit | edit source]

Configure the 'mdf1' DT root node:

  • Enable the DT root node for the MDF, by setting status = "okay".
  • Optionally configure the MDF as a clock provider (for example, to feed external MEMS microphones), as shown in MDF audio example.
 &mdf1 {
 	status = "okay";
 };

3.2.2. Private resources for each MDF serial interface[edit | edit source]

Configure the sitf(s) DT child node(s):

  • Enable the SITF child node for the MDF, by setting status = "okay".
  • Configure the pin for input bitstream, via pinctrl, by setting pinctrl-0, pinctrl-1 and pinctrl-names. Also used to configure a pin for optional input clock.
  • Configure serial interface protocol, by setting st,sitf-mode property.
  • Optionally configure the serial interface as a clock consumer, as shown in MDF audio example.
 &mdf1 {
  	...
 	sitf6: sitf@380 {
 		pinctrl-names = "default", "sleep";
 		pinctrl-0 = <&mdf_sdi6_pins_a>;
 		pinctrl-1 = <&mdf_sdi6_sleep_pins_a>;
 		st,sitf-mode = "spi";
 		status = "okay";
 	};
 };

3.2.3. Private resources for each MDF filter[edit | edit source]

3.2.3.1. Filter(s) DT child node(s) for analog[edit | edit source]
 filter0: filter@84 {
 	st,cic-mode = <5>;                /* Configure filter order */
  	st,sitf = <&sitf6 0>;             /* Configure the input bitstream serial interface source. Parameter sets the clock active edge for SPI modes. (0/1 for rising/falling edge) */
 	st,filter0-sync;                  /* Optional: if set, synchronize filter with filter 0. (Property not relevant for filter0) */
 	status = "okay";                  /* Enable filter node */
 
 	channel@0 {
 		reg = <0>;                    /* Specify channel index */
 		settling-time-us;             /* Optional: wait time for stable data */
 		io-backends = <&sd_adc0>;     /* Optional: connect channel to an IIO backend for analog use cases only (e.g. a Sigma Delta modulator) */
 	};
 
 	channel@1 {
 		...                           /* Optional channel 1 for analog scan mode use cases */
   	};
 
 	channel@2 {
 		...                           /* Optional channel 2 for analog scan mode use cases */
   	};
 	...
 };

The MDF ADC device is usually connected to a Sigma Delta modulator, which is described as an IIO backend node in the Device Tree. (see the generic sd-modulator[3] example here after).

3.2.3.2. Filter(s) DT child node(s) for audio[edit | edit source]
 filter0: filter@84 {
 	compatible = "st,stm32mp25-mdf-dmic"; /* Override the compatible string for audio use cases only (e.g. dmic record) */
 	st,cic-mode = <5>;                    /* Configure filter order */
  	st,sitf = <&sitf6 0>;                 /* Configure the input bitstream serial interface source. Parameter sets the clock active edge for SPI modes. (0/1 for rising/falling edge) */
 	st,filter0-sync;                      /* Optional: if set, synchronize filter with filter 0. (Property not relevant for filter0) */
 	status = "okay";                      /* Enable filter node */
 
 	asoc_pdm0: mdf-dai {
 		compatible = "st,stm32mp25-mdf-dai";  /* MDF Digital Audio Interface (DAI) compatible */
 		io-channels = <&filter0 0>;           /* Connect the MDF DAI to filter0 channel0 */
 		status = "okay";                      /* Enable the MDF DAI node */
 
 		mdf1_port0: port {
 			...;                              /* Connect MDF DAI to an audio device node. (e.g. a digital microphone) */
 		};
 	};
 };

Examples of MDF DT configuration for audio can be found in soundcard configuration article.

3.3. DT configuration examples[edit | edit source]

3.3.1. MDF audio example[edit | edit source]

The following example demonstrates how to capture data from two digital microphones and asynchronously retrieve the data on two ALSA audio devices. The MDF provides a clock on the CCK0 output to the two digital microphones. The CCK0 frequency is set to 1536 kHz, which is an effective compromise to support 8, 16, 32, and 48 kHz audio sampling rates, as it is both a power of 2 and a multiple of 3 (1536 equal 3 x 2^9). The signals from the two microphones are multiplexed onto a single data line connected to the serial interface 6 (alternatively, two independent data lines connected to two serial interfaces may be used). This example can serve as a foundation for subsequent audio examples.

 &mdf1 {
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&mdf_cck0_pins_a>;          /* Configure output pin for CCK0 clock */
 	pinctrl-1 = <&mdf_cck0_sleep_pins_a>;
 	#clock-cells = <1>;                      /* Set MDF as clock provider */
 	clock-output-names = "cck0";             /* Enable CCK0 output clock to feed the digital microphones */
 	clock-frequency = <1536000>;             /* Set CCK0 output clock to 1536 kHz.  */
  	status = "okay";
 
 	sitf6: sitf@380 {
 		pinctrl-names = "default", "sleep";
 		pinctrl-0 = <&mdf_sdi6_pins_a>;
 		pinctrl-1 = <&mdf_sdi6_sleep_pins_a>;
 		st,sitf-mode = "spi";                /* Set SPI protocol on serial interface6 */
 		clocks = <&mdf1 0>;                  /* Set CCK0 as input clock for serial interface6 */
 		status = "okay";
 	};
  
 	filter0: filter@84  {
 		compatible = "st,stm32mp25-mdf-dmic";
 		st,cic-mode = <4>;                   /* Set CIC filter sync4 mode */
 		st,sitf = <&sitf6 0>;                /* Feed filter0 with input data from serial interface6 on clock rising edge */
 		st,hpf-filter-cutoff-bp = <625>;
 		status = "okay";
 
 		asoc_pdm0: mdf-dai {
 			compatible = "st,stm32mp25-mdf-dai";
 			#sound-dai-cells = <0>;
 			io-channels = <&filter0 0>;
 			power-domains = <&RET_PD>;
 			status = "okay";
 
 			mdf1_port0: port {
 				mdf_endpoint0: endpoint {
 					remote-endpoint = <&dmic0_endpoint>;
 				};
 			};
 		};
 
 	filter1: filter@104  {
 		compatible = "st,stm32mp25-mdf-dmic";
 		st,cic-mode = <4>;
 		st,sitf = <&sitf6 1>;                /* Feed filter1 with input data from serial interface6 on clock falling edge */
 		st,hpf-filter-cutoff-bp = <625>;
 		status = "okay";
 
 		asoc_pdm1: mdf-dai {
 			compatible = "st,stm32mp25-mdf-dai";
 			#sound-dai-cells = <0>;
 			io-channels = <&filter1 0>;
 			power-domains = <&RET_PD>;
 			status = "okay";
 
 			mdf1_port1: port {
 				mdf_endpoint1: endpoint {
 					remote-endpoint = <&dmic1_endpoint>;
 				};
 			};
 		};
 	};

3.3.2. MDF audio interleaved channels configuration example[edit | edit source]

This example shows how to configure the MDF to capture data from two digital microphones, and retrieve the data synchronously on a single ALSA audio device. The channel data are interleaved.

Info white.png Information
Only the update of the MDF audio example is described and highlighted in this chapter.
Info white.png Information
This example can be expanded to capture samples from N microphones, but with the condition that the first filter must be filter0 and the subsequent filters must have consecutive indexes up to N-1.
 &mdf1 {
 	 st,interleave = <&filter0 &filter1>;  /* Configure filter0 and filter1 as interleaved */
 	...
 
 	filter0: filter@84  {
 		...
 
 		asoc_pdm0: mdf-dai {
 			io-channels = <&filter0 0>;    /* Filter0 provides interleaved stereo data to the ALSA audio device */
 
 			mdf1_port0: port {};
 		};
 	};
 
 	filter1: filter@104  {
 		st,sitf = <&sitf6 1>;              /* Specify data source and inherit other configurations from filter0 */
 	};
 };
 
 dmic0: dmic-0 {
 	num-channels = <2>;                    /* Stereo dmic codec */
 	...
 };

3.3.3. MDF audio synchronous channels configuration example[edit | edit source]

This example shows how to configure the MDF to capture data from two digital microphones, and retrieve the data synchronously on two ALSA audio devices. The typical use is to launch filter3 first, waiting from acquisition on filter2 to start.

Info white.png Information
Only the update of the MDF audio example is described and highlighted in this chapter.
Info white.png Information
This example can be expanded to capture samples from N microphones. Any filter can be set as the synchronization provider and any other filters may be synchronized to it.
 &mdf1 {
 	...
 
 	filter0: filter@84  {
 		...
 
 		asoc_pdm0: mdf-dai {
 			io-channels = <&filter0 0>;
 
 			mdf1_port0: port {};
 		};
 	};
 
 	filter1: filter@104  {
 		st,sync = <&filter0>;           /* Synchronize filter1 with filter0 */
 
 		asoc_pdm1: mdf-dai {
 			io-channels = <&filter1 0>;
 
 			mdf1_port1: port {};
 		};
 	};

3.3.4. MDF IIO example[edit | edit source]

This example demonstrates how to configure the MDF to capture data from a Sigma-Delta modulator ADC and retrieve the data on two IIO devices. In this example, it is assumed that the MDF provides a clock to the Sigma-Delta modulator and the serial interface via the CCK0 output. However, this clock can also be provided by another system clock.

 sd_adc0: adc-0 {
 	compatible = "sd-modulator";
 	#io-backend-cells = <0>;
 	vref-supply = <&v3v3>;
 };
 
 sd_adc1: adc-1 {
 	compatible = "sd-modulator";
 	#io-backend-cells = <0>;
 	vref-supply = <&v3v3>;
 };
 
 &mdf1: mdf@504d0000 {
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&mdf_cck0_pins_a>;       /* Configure output pin for CCK0 clock */
 	pinctrl-1 = <&mdf_cck0_sleep_pins_a>;
 	#clock-cells = <1>;                   /* Set MDF as a clock provider */
 	clock-output-names = "cck0";
 	clock-frequency = <1024000>;          /* Set CCK0 output clock to 1024 kHz */
  	status = "okay";
 
 	sitf6: sitf@380 {
 		compatible = "st,stm32mp25-sitf-mdf";
 		reg = <0x380 0x4>;
 		st,sitf-mode = "spi";             /* Configure the serial interface in SPI mode. */
 		clocks = <&mdf1 0>;               /* Set CCK0 as input clock for serial interface 6 */
 		status = "okay";
 	};
 
 	filter0: filter@84  {
 		compatible = "st,stm32mp25-mdf-adc";
 		st,cic-mode = <2>;
 		st,sitf = <&sitf6 0>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 		status = "okay";
 
 		channel@0 {
 			reg = <0>;
 			io-backends = <&sd_adc0>;
 		};
 	};
 
 	filter1: filter@104  {
 		compatible = "st,stm32mp25-mdf-adc";
 		st,cic-mode = <2>;
 		st,sitf = <&sitf6 1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 		status = "okay";
 
 		channel@1 {
 			reg = <1>;
 			io-backends = <&sd_adc1>;
 		};
 	};
 };

3.3.5. MDF IIO scan mode example[edit | edit source]

This example demonstrates how to configure the MDF to capture data from a Sigma Delta modulator ADC, and retrieve the data from one or several channels on a single IIO device.

Info white.png Information
Only the update of the MDF IIO example is described and highlighted in this chapter.
 &mdf1: mdf@504d0000 {
 	st,interleave = <&filter0 &filter1>;   /* Configure filter0 and filter1 as interleaved */
 	...
 
 	sitf6: sitf@380 {
 		...
 	};
 
 	filter0: filter@84  {
 		compatible = "st,stm32mp25-mdf-adc";
 		st,cic-mode = <2>;
 		st,sitf = <&sitf6 0>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
 		channel@0 {
 			reg = <0>;                     /* Channel0 connected to serial interface associated to filter0 */
 		};
 		channel@1 {
 			reg = <1>;                     /* Channel1 connected to serial interface associated to filter1 */
 		};
 	};
 
 	filter1: filter@104  {
 		compatible = "st,stm32mp25-mdf-adc";
 		st,cic-mode = <2>;
 		st,sitf = <&sitf6 1>;
 	};
 };

4. How to configure the DT using STM32CubeMX[edit | edit source]

The STM32CubeMX tool can be used to configure the STM32MPU device and get the corresponding platform configuration device tree files.
STM32CubeMX may not support all the properties described in DT binding files listed in the above DT bindings documentation paragraph. If so, the tool inserts user sections in the generated device tree. These sections can then be edited to add some properties, and they are preserved from one generation to another. Refer to STM32CubeMX user manual for further information.

5. References[edit | edit source]

Refer to the following links for additional information: