diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 1437ec59..11b29b37 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -32,10 +32,10 @@ jobs: supported-reqs: name: 'Supported scripts/requirements.txt' - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # FIXME: remove this time consuming step once github stops # providing a broken package index, see @@ -74,20 +74,20 @@ jobs: # https://docs.github.com/en/actions/guides/storing-workflow-data-as-artifacts - name: upload HTML for deploy if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/publish' }} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: html path: _build/html deploy: needs: supported-reqs - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/publish' }} steps: # download the build result from the same workflow # https://docs.github.com/en/actions/guides/storing-workflow-data-as-artifacts - name: download HTML - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4.1.7 with: name: html path: html @@ -102,11 +102,11 @@ jobs: lax: name: "PIP_IGNORE_INSTALLED=0 requirements-lax.txt" - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 # Makefile downgrades the Sphinx warnings, they are not errors any more env: {LAX: 1} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # FIXME: remove this time consuming step once github stops # providing a broken package index, see diff --git a/.github/workflows/woke.yml b/.github/workflows/woke.yml old mode 100644 new mode 100755 index 8943d2a7..8338578c --- a/.github/workflows/woke.yml +++ b/.github/workflows/woke.yml @@ -19,7 +19,7 @@ jobs: name: woke check for all file runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: woke uses: get-woke/woke-action@v0 with: diff --git a/.github/workflows/woke_pr.yml b/.github/workflows/woke_pr.yml old mode 100644 new mode 100755 index 0c307257..7aa97088 --- a/.github/workflows/woke_pr.yml +++ b/.github/workflows/woke_pr.yml @@ -21,7 +21,7 @@ jobs: name: woke check for patch runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: get-woke/woke-action-reviewdog@v0 with: github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/CODEOWNERS b/CODEOWNERS old mode 100755 new mode 100644 index 86c19cad..6339b6f0 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,5 +1,8 @@ -#This file identifies people who are automatically notified when Pull Requests are made for /sof-docs. -#At this time, the following people are notified and are expected to review the PRs: -#Liam Girdwood (technical review), Anton Bobkov (technical/grammatical/style review), and Deb Taylor (grammatical/style review). +# This file identifies people who are automatically notified when Pull Requests are made for /sof-docs. +# At this time, the following people are notified and are expected to review the PRs: +# Liam Girdwood (technical review), # Deb Taylor (grammatical/style review), +# Marcin Maka (technical review) and Michal Wasko (technical review). -* @lgirdwood @anton-intel @deb-intel @intelkevinputnam @greg-intel +# So if a pull request only touches javascript files, only these owners + +* @lgirdwood @deb-intel @intelkevinputnam @greg-intel @mmaka1 @mwasko diff --git a/Makefile b/Makefile index f2b63f5a..64785f0d 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ else Q = @ endif -SOF_DOC_BUILD = ../sof/doc +SOF_DOC_BUILD = ../sof/build_doxygen/ SPHINXBUILD = sphinx-build SPHINXPROJ = "SOF Project" SOURCEDIR = . @@ -44,8 +44,11 @@ apidocs: ifeq (${APIS_CMAKE},$(wildcard ${APIS_CMAKE})) ninja -C ${SOF_DOC_BUILD} $${VERBOSE:+-v} doc else - # To build doxygen APIs too run this first: + # To include doxygen APIs run this first: # cmake -GNinja -S ../sof/doc -B ${SOF_DOC_BUILD} + # Note this will make the build CONSIDERABLY LONGER! + # Conversely, you can have _instant builds from scratch_ + # by disabling UML diagrams in the conf.py file. endif html: apidocs diff --git a/algos/demux/demux.rst b/algos/demux/demux.rst old mode 100755 new mode 100644 diff --git a/algos/eq/Picture_FIR_equalized_response.png b/algos/eq/Picture_FIR_equalized_response.png new file mode 100644 index 00000000..9407914b Binary files /dev/null and b/algos/eq/Picture_FIR_equalized_response.png differ diff --git a/algos/eq/Picture_FIR_impulse_response.png b/algos/eq/Picture_FIR_impulse_response.png new file mode 100644 index 00000000..8abbb95d Binary files /dev/null and b/algos/eq/Picture_FIR_impulse_response.png differ diff --git a/algos/eq/Picture_FIR_response.png b/algos/eq/Picture_FIR_response.png new file mode 100644 index 00000000..9cbc688f Binary files /dev/null and b/algos/eq/Picture_FIR_response.png differ diff --git a/algos/eq/Picture_FIR_response_absolute.png b/algos/eq/Picture_FIR_response_absolute.png new file mode 100644 index 00000000..35b615f0 Binary files /dev/null and b/algos/eq/Picture_FIR_response_absolute.png differ diff --git a/algos/eq/Picture_FIR_right_channel_equalized.png b/algos/eq/Picture_FIR_right_channel_equalized.png new file mode 100644 index 00000000..bf58810c Binary files /dev/null and b/algos/eq/Picture_FIR_right_channel_equalized.png differ diff --git a/algos/eq/Picture_IIR_FIR_target_vs_achieved_response.png b/algos/eq/Picture_IIR_FIR_target_vs_achieved_response.png new file mode 100644 index 00000000..cbac1eec Binary files /dev/null and b/algos/eq/Picture_IIR_FIR_target_vs_achieved_response.png differ diff --git a/algos/eq/Picture_iir_absolute_response.png b/algos/eq/Picture_iir_absolute_response.png new file mode 100644 index 00000000..5995dfc5 Binary files /dev/null and b/algos/eq/Picture_iir_absolute_response.png differ diff --git a/algos/eq/Picture_iir_filter_response_vs_ideal_target.png b/algos/eq/Picture_iir_filter_response_vs_ideal_target.png new file mode 100644 index 00000000..26a4e27b Binary files /dev/null and b/algos/eq/Picture_iir_filter_response_vs_ideal_target.png differ diff --git a/algos/eq/Picture_iir_impulse_response.png b/algos/eq/Picture_iir_impulse_response.png new file mode 100644 index 00000000..308368af Binary files /dev/null and b/algos/eq/Picture_iir_impulse_response.png differ diff --git a/algos/eq/Picture_iir_poles_and_zeros.png b/algos/eq/Picture_iir_poles_and_zeros.png new file mode 100644 index 00000000..968a48f8 Binary files /dev/null and b/algos/eq/Picture_iir_poles_and_zeros.png differ diff --git a/algos/eq/Picture_iir_simulated_left_and_channel_responses.png b/algos/eq/Picture_iir_simulated_left_and_channel_responses.png new file mode 100644 index 00000000..37c13898 Binary files /dev/null and b/algos/eq/Picture_iir_simulated_left_and_channel_responses.png differ diff --git a/algos/eq/Picture_imported_frequency_response_for_iir.png b/algos/eq/Picture_imported_frequency_response_for_iir.png new file mode 100644 index 00000000..ed42b918 Binary files /dev/null and b/algos/eq/Picture_imported_frequency_response_for_iir.png differ diff --git a/algos/eq/Picture_raw_frequency_response.png b/algos/eq/Picture_raw_frequency_response.png new file mode 100644 index 00000000..d4bc8ff2 Binary files /dev/null and b/algos/eq/Picture_raw_frequency_response.png differ diff --git a/algos/eq/Picture_response_with_smoothing.png b/algos/eq/Picture_response_with_smoothing.png new file mode 100644 index 00000000..b9d1c7b5 Binary files /dev/null and b/algos/eq/Picture_response_with_smoothing.png differ diff --git a/algos/eq/Picture_right_channel_FIR_absolute_response.png b/algos/eq/Picture_right_channel_FIR_absolute_response.png new file mode 100644 index 00000000..50450729 Binary files /dev/null and b/algos/eq/Picture_right_channel_FIR_absolute_response.png differ diff --git a/algos/eq/Picture_right_channel_response.png b/algos/eq/Picture_right_channel_response.png new file mode 100644 index 00000000..e995b01a Binary files /dev/null and b/algos/eq/Picture_right_channel_response.png differ diff --git a/algos/eq/Picture_simulated_IIR_FIR_frequency_response.png b/algos/eq/Picture_simulated_IIR_FIR_frequency_response.png new file mode 100644 index 00000000..edd732a2 Binary files /dev/null and b/algos/eq/Picture_simulated_IIR_FIR_frequency_response.png differ diff --git a/algos/eq/Picture_simulated_left_and_right_channel_responses.png b/algos/eq/Picture_simulated_left_and_right_channel_responses.png new file mode 100644 index 00000000..79f22238 Binary files /dev/null and b/algos/eq/Picture_simulated_left_and_right_channel_responses.png differ diff --git a/algos/eq/Picture_speaker_meas.jpg b/algos/eq/Picture_speaker_meas.jpg new file mode 100644 index 00000000..414a3139 Binary files /dev/null and b/algos/eq/Picture_speaker_meas.jpg differ diff --git a/algos/eq/Picture_tested_speaker_frequency_response.png b/algos/eq/Picture_tested_speaker_frequency_response.png new file mode 100644 index 00000000..ec1cb738 Binary files /dev/null and b/algos/eq/Picture_tested_speaker_frequency_response.png differ diff --git a/algos/eq/equalizers_tuning.rst b/algos/eq/equalizers_tuning.rst new file mode 100644 index 00000000..45335c60 --- /dev/null +++ b/algos/eq/equalizers_tuning.rst @@ -0,0 +1,924 @@ +.. _equalizers_tuning: + +Equalizers, IIR and FIR +####################### + +.. contents:: + :depth: 3 + +Introduction +************ + +Frequency response is the system output level specific to a +frequency. It can be measured in acoustical, electrical analog, or +digital domain. Standards such as AES17 [1]_ define how it is measured +and reported. + +The frequency response between e.g. 20 Hz and 20 kHz, that +is typical human max. range, is measured by sweeping signal generator +frequency and observing and recording the system output level into a +curve. + +The speaker frequency responses can rarely be optimized by mechanical +and acoustical design in the mass market devices. The industrial +design and miniaturization typically limit the performance. The +non-flat frequency response is a form of linear distortion. It causes +the sound reproduction to be unnatural in a way that could be called +thin, dark, etc. Such systematic issues in speaker frequency response +can be improved with equalization. + +Equalization is a simple technique that creates by signal processing +in an open loop pre-defined opposite linear distortion into signal to +cancel the linear distortion caused by speaker. However the cancel +cannot be perfect since the fixed equalization response need to be in +practice common for all production devices. Optimizing for one device +could cause another device to fail if the characteristic at that +frequency would differ. Hence the equalization can address only +systematic issues in the frequency response. Also when applying +equalization the system performance is impacted. Equalization nearly +always reduces achievable peak sound pressure level (SPL) and reduces +system dynamic range (DR). When tuning the equalization the trade-offs +need to be considered. + +The document describes speaker equalization. Microphones equalization +is similar but measurements are done in opposite domain: Acoustical -> +digital. In both cases use of calibrated reference microphone is +needed. + +Preparations +************ + +The device should allow remote ssh without password for the automatic +scripts to work. Since the developers have usually their public and +private keys setup only this is needed. Find out the IP address from +ifconfig command output on your device. + +.. code-block:: bash + + ssh-copy-id -i ~/.ssh/id_rsa.pub user@aa.bb.cc.dd + +For ssh to work with low delay the development PC and tuned device +should be on the same local IP network. You can check that remote +playback works to DUT with example command: + +.. code-block:: bash + + ssh user@aa.bb.cc.dd "aplay -l" + +Since the tests are done with low-level ALSA aplay and arecord +utilities it is recommended to temporarily rename in DUT the audio +servers to disable them. Kill manually the processes or reboot to +avoid them continue running. The audio servers can be disabled from OS +system control in more elegant way but it is harder to remember how to +do it and restore to normal vs. the brute force way. + +.. code-block:: bash + + cd /usr/bin + sudo mv pulseaudio pulseaudio.disabled + sudo mv pipewire pipewire.disabled + + +Frequency response measurement +****************************** + +Note: More professional audio analyzer systems are recommended to be +used for final tuning. The procedures described in this document are +for coarse initial settings. Final tuning, especially if dependence +to regulations and standards need to be done with care in professional +environment with calibrated measurement equipment. + +To measure speakers an omnidirectional USB measurement microphone is +recommended, e.g. UMM6 [2]_ or UMIK-1 [3]_. Such microphones are +inexpensive and do not necessarily have a flat frequency response but +the manufacturers provide a serial number based downloadable +calibration file for them. The calibration can be applied to these +measurements in SOF as well by referencing the downloaded calibration +data to measurement script. + +Next step up are analog condenser measurement microphones with a +high-end USB sound card that can provide the 48V phantom voltage. But +analog microphones add more calibration consideration for analog +level. The measurement microphones can be also calibrated for absolute +level with dedicated microphone calibrators those can output into the +sealed compartment a reference 94 dBSPL tone. + +The tools for measurement and EQ design are in located in directory +$SOF_WORKSPACE/sof/tools/tune/eq. The test setup is such that the DUT +device plays back the measurement wav file via ssh commands and the +development PC connected USB microphone captures the output. To +achieve this the configuration files for playback and capture need to +be edited. + +The capture device UMM6 is hw:3.0 (card 3, device 0), this can be seen +from output of arecord command on a the development PC example. We +also know that this device supports one capture channel. + +.. code-block:: bash + + arecord -l + **** List of CAPTURE Hardware Devices **** + card 0: PCH [HDA Intel PCH], device 0: ALC257 Analog [ALC257 Analog] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 1: Ultra [Fast Track Ultra], device 0: USB Audio [USB Audio] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 2: Audio [ThinkPad Dock USB Audio], device 0: USB Audio [USB Audio] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 3: UMM6 [UMM-6], device 0: USB Audio [USB Audio] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + +The settings file + +.. code-block:: bash + + $ cat mls_rec_config.txt + %% Recording device configuration + + rec.ssh = 0; % Set to 1 for remote capture + rec.user = ''; % Set to user@domain for ssh + rec.dir = '/tmp'; % Directory for temporary files + rec.dev = 'hw:3,0'; % Audio capture device + rec.nch = 1; % Number audio capture channels to use + + % Use '' if calibration is not needed. Otherwise set to + % e.g. '1234567.txt'. Such calibration data format is supported for + % some reasonably priced measurement microphones. The ASCII text + % calibration data file is the measured frequency response of the used + % microphone. Lines in the beginning those start with character " are + % treated as comment. The successive lines should be + % number pairs. Their unit must be Hz and dB. + rec.cal = ''; + +Similarly check with remote aplay command the playback devices and +then edit the playback settings. + +.. code-block:: bash + + ssh user@aa.bb.cc.dd "aplay -l" + **** List of PLAYBACK Hardware Devices **** + card 0: sofglkda7219max [sof-glkda7219max], device 0: Speakers (*) [] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 0: sofglkda7219max [sof-glkda7219max], device 1: Headset (*) [] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 0: sofglkda7219max [sof-glkda7219max], device 5: HDMI1 (*) [] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 0: sofglkda7219max [sof-glkda7219max], device 6: HDMI2 (*) [] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + card 0: sofglkda7219max [sof-glkda7219max], device 7: HDMI3 (*) [] + Subdevices: 1/1 + Subdevice #0: subdevice #0 + +On the DUT the speakers are provided by device hw:0,0. It's known that +there's two playback channels in the device. + +.. code-block:: bash + + $ cat mls_play_config.txt + play.ssh = 1; % Set to use remote ssh commands + play.user = 'user@aa.bb.cc.dd'; % Set user@domain for ssh + play.dir = '/tmp'; % directory for temporary files + play.dev = 'hw:0,0'; % Audio device for playback + play.nch = 2; % Number of playback channels to test + +Next the measurement orientation and measurement microphone place is +considered. A notebook could be placed on top of a table symmetrically +where the measurement microphone location should be symmetrical to +display center axis. The microphone location could be near the center +of user’s ears. If the measurement microphone capture is too silent or +disturbed by ambient noise the microphone should be placed closer into +near field. + +.. figure:: Picture_speaker_meas.jpg + :width: 600 + + On-axis measurement position for bottom located speakers. + +Since this example device is a convertible type with a near 360 degree +display hinge there are several usage orientations. It was chosen to +measure the speakers from about their firing axis. Since the response +is impacted by orientation this was felt as safest choice. It also +gave the flattest looking frequency response. + +The MLS measurement tolerates some noise but the more silent the +environment is the better it is. An anechoic chamber would be ideal +naturally. The used MLS signal sets stress for the speakers so start +with a low volume setting with “alsamixer -Dhw:0”. Find the speaker +playback volume control PGA or volume controlin speaker amplifier and +start with e.g. 50%. + +Start Octave and launch the measurement + +.. code-block:: octave + + [f, m] = mls_freq_resp('DUT'); + +If the script warns about too silent audio increase the volume and/or +bring the microphone closer to the device. If the device has small +speakers and test signal playback sounds like at being near to their +capability limit, it is best to ignore the warning. The speakers may +permanently damage if the playback is too loud. + +If problems the script contains a self test for quick integrity +check. The self test measures a recursive filter that simulates a +non-flat response. The measurement and theoretical response that’s +computed directly from filter coefficients should match. + +.. code-block:: octave + + [f, m] = mls_freq_resp('selftest'); + +The test signal contains two chirps and a few times repeated +pseudo-random numbers sequence. The chirps are used to locate and +extract the MLS part. The MLS sequence has such a characteristic the +the correlation with itself is minimal. The sufficient length of the +sequence is used to suppress room reverberation from the +measurement. It provides nearly similar measured frequency responses +as achieved in anechoic conditions. As in anechoic chamber the setup +should be as much as possible like free-field. The desk/stand where +the device is measured should be away from reflecting surfaces. + +This MLS measurement would naturally also benefit from doing in +anechoic chamber since the MLS technique cannot eliminate all reverb +impact form measurement. Though usually in chambers there’s +professional equipment available like Audio Precision ® and other. If +such are available this measurement step with SOF can be avoided and +continued from next section for data import for tuning. + +.. figure:: Picture_raw_frequency_response.png + :width: 600 + + Frequency response measurement. The first channel is aligned to 0 + dB at 1 kHz. The second channel is shown with true offset + vs. first. + +After a successful measurement a plot with frequency (Hz) and +magnitude (dB) as x and y axis will be shown. The variable f will +contain the frequency response and variable m the magnitude. If the +number of measured channels was larger than 1 the m is a matrix. The +result can be saved for equalizer design into a .mat file. + +.. code-block:: octave + + save example_dut.mat f m + +Equalizer design +**************** + +It can be seen from the picture that the output of speakers is weak at +below 200 Hz. There’s two resonances, first at about 700 Hz and second +at about 5 kHz (better visible on table orientation). The response is +within -10 .. +10 dB in about 300 - 13000 Hz range. The equalization +should not be applied outside these frequencies to avoid a large loss +of SPL. It can be also seen that the left and right speaker have +slightly different frequency response. + +Next the measurement data is imported to SOF. It can be done by load +of previously saved file or importing e.g. in MS Excel format from +other equipment. The matrix columns for frequency and channel specific +levels need to be known. + +The tool in SOF is a set of functions to be used in user created +script. Therefore programming knowledge is needed. The benefit of +using script is the procedure is easy to repeat and documented by +itself. + +FIR equalizer +************* + +The finite impulse response (FIR) filter type has the advantages that +design for any finite time impulse response / frequency response is +simple and robust. The filters do not oscillate by design so the +rounding errors do not appear as noise. The rounding of coefficients +into a fixed word length only impairs slightly the response but the +effect can be usually ignored. Therefore the FIR equalizers especially +when used with 24 and 32 bit audio format are compatible with studio +like 24 bit audio quality. + +Due finite response (often limited by DSP resources) the FIR filters +are not practical for lowest frequencies unless very long filters are +used. The longer the filter is the more DSP RAM and MCPS the +processing consumes. However FIR filters are great for mid and high +frequencies equalization. The next example equalizes those frequencies +for the previously done measurement. + +The initial script for tuning is shown below. Alternatively for other +equipment the data import could be done in Excel format and use +function xlsread(); to read a matrix and then extract the frequency +and magnitude columns. + +.. code-block:: octave + + %% Load measurement data, variable f and m + load example_dut.mat; + + %% EQ settings + eq1 = eq_defaults(); % Get defaults + eq1.fs = 48e3; % Set sample rate + eq1.norm_type = 'loudness'; % Normalize criteria can be loudness/peak/1k + eq1.norm_offs_db = -3; % Offset in dB to normalize, -3dB loudness + eq1.logsmooth_plot = 1.0; % Smooth over 1.0 octaves + eq1.logsmooth_eq = 1.0; % Smooth over 1.0 octaves + eq1.enable_fir = 1; % By default both FIR and IIR disabled + eq1.fir_beta = 3.0; % Lower beta is more accurate but be careful + eq1.fir_length = 90; % Minimize this vs. fmin/fmax choice + eq1.fir_autoband = 0; % Select manually frequency limits + eq1.fmin_fir = 700; % Equalization starts from 800 Hz + eq1.fmax_fir = 13e3; % Equalization ends at 13 kHz + eq1.fir_minph = 1; % Check result carefully if 1 is used, 0 is safe + eq2 = eq1; % Copy settings to second EQ + + %% Design left channel EQ + eq1.raw_f = f; % Measurement Hz + eq1.raw_m_db = m(:,1); % Measurement dB, left ch + eq1 = eq_compute(eq1); + eq_plot(eq1, 10); + +The run of this script creates these plots. Note the choice of 1.0 +octaves smoothing for both plotting and EQ target derivation. It’s +best to start carefully with such a high amount of smoothing to avoid +to equalize highly uncertain details of frequency response. + +The smoothed version of the response becomes very flat in the +equalized version. However the simulated raw response still contains a +lot of ripple especially at high bands. It’s an industry standard to +use ⅓ octaves smoothing since it quite well matches human ear +psycho-acoustics. Therefore ⅓ octaves should be the smallest feasible +width of octaves smoothing to use. + +.. figure:: Picture_response_with_smoothing.png + :width: 600 + + Imported frequency response with and without octaves + smoothing. Note that the strong 1.0 octaves wide smoothing + “flattens” most of the narrow (high Q) resonances and leaves the + two mentioned resonances at 700 Hz and 4 kHz. + +.. figure:: Picture_FIR_right_channel_equalized.png + :width: 600 + + Simulated frequency response after equalization + +.. figure:: Picture_FIR_response.png + :width: 600 + + Frequency response of equalizer. The blue curve is the ideal + inverse response including the smoothing. The red curve is the band + limited and filter design parameters constrained actual EQ + response. The y-axis is offset in such way that 1 kHz frequency is + shifted to 0 dB. Try the impact of filter length to see how it + impacts the accuracy and find a fair compromise. + +.. figure:: Picture_FIR_response_absolute.png + :width: 600 + + Frequency response of equalizer. This curve shows the absolute gain + of the equalization. It can be seen that the normalization of + loudness (-3 dB) does some fairly high gain above 10 kHz. The + attenuation of frequencies below 200 Hz may or may not be + sufficient to give signal headroom for this boost. Need to watch + out for distortion in playback, if observed the loudness need to be + decreased. + +.. figure:: Picture_FIR_impulse_response.png + :width: 600 + + Impulse response of equalizer. The chosen minimum phase + non-symmetrical impulse response can be seen in the shape. A linear + phase response would have symmetrical pre- and post oscillation in + the impulse response. + +Add of right channel measurement import and EQ design is done by +adding these lines to above script. + + +.. code-block:: octave + + %% Design right channel EQ + eq2.raw_f = f; % Measurement Hz + eq2.raw_m_db = m(:,2); % Measurement dB, right ch + eq2 = eq_compute(eq2); + eq_plot(eq2, 20); + +The resulting EQ can be seen from these plots. If the left and right +channel results are different need to know if it is due to +non-symmetrical mechanics. If there’s designed non-symmetry it’s safe +to go ahead and design different EQ for left and right channels. If +the hardware is symmetrical then it is likely to better to equalize +e.g. average response of left and right instead. + +Note: The left and right responses are quite similar. The mechanics & +acoustics is likely symmetrical so a common EQ could be the best +choice. The average of left and right response could be suitable to +use. However in this in this case the design is done as stereo for +tutorial purpose. + +.. figure:: Picture_right_channel_response.png + :width: 600 + + Import right channel frequency response. + + +.. figure:: Picture_FIR_right_channel_equalized.png + :width: 600 + + Simulated response of equalizer. + +.. figure:: Picture_right_channel_FIR_absolute_response.png + :width: 600 + + Frequency response of the right channel filter. Notice the difference to left channel filter. + +The next step is to check the stereo EQ design. The left and right +channels should as equalized have similar loudness. Since the SOF tool +currently does not add much help to multi-channel design this step +needs some additional own code. + +.. code-block:: octave + + %% Stereo EQ + figure(30); + l_ch = eq1.m_db+eq1.fir_eq_db; + r_ch = eq2.m_db+eq2.fir_eq_db; + semilogx(eq1.f, l_ch, eq2.f, r_ch); + grid on; + axis([100 20e3 -20 10]); + xlabel('Frequency (Hz)'); + ylabel('Magnitude (dB)'); + + %% Calculate level offset at 1 - 4 kHz from RMS + idx0 = find(eq1.f < 4e3); + idx = find(eq1.f(idx0) > 1e3); + l_lev = 20*log10(sqrt(mean(10.^(l_ch(idx)/10)))); + r_lev = 20*log10(sqrt(mean(10.^(r_ch(idx)/10)))); + fprintf('L ch level %3.1f dB\n', l_lev); + fprintf('R ch level %3.1f dB\n', r_lev); + delta_lev = l_lev-r_lev; + fprintf('delta %3.1f dB\n', delta_lev); + +The plot shows the raw data plus EQ impact. Since the offset is hard +to judge from the non-smoothed plot (the smoothed data is +unfortunately for this purpose 1 kHz, 0 dB aligned) the offset is +computed from RMS level difference in 1 - 4 kHz band. In this example +the difference was 0.2 dB. The offset is next added to right channel +align. + +.. code-block:: octave + + %% Design right channel EQ + eq2.norm_offs_db = -3 + 0.2; % Offset in dB to normalize, -3dB plus L-R + eq2.raw_f = f; % Measurement Hz + eq2.raw_m_db = m(:,2); % Measurement dB, right ch + eq2 = eq_compute(eq2); + eq_plot(eq2, 20); + + +.. figure:: Picture_simulated_left_and_right_channel_responses.png + :width: 600 + + Simulated frequency responses of left and right speaker channels. + +The complete tuning script is shown below for completeness. It can be a +starting point for your own stereo speaker equalizer design case! + + +.. code-block:: octave + + %% Load measurement data, variable f and m + load example_dut.mat; + + %% EQ settings + eq1 = eq_defaults(); % Get defaults + eq1.fs = 48e3; % Set sample rate + eq1.norm_type = 'loudness'; % Normalize criteria can be loudness/peak/1k + eq1.norm_offs_db = -3; % Offset in dB to normalize, -3dB loudness + eq1.logsmooth_plot = 1.0; % Smooth over 1.0 octaves + eq1.logsmooth_eq = 1.0; % Smooth over 1.0 octaves + eq1.enable_fir = 1; % By default both FIR and IIR disabled + eq1.fir_beta = 3.0; % Lower beta is more accurate but be careful + eq1.fir_length = 90; % Minimize this vs. fmin/fmax choice + eq1.fir_autoband = 0; % Select manually frequency limits + eq1.fmin_fir = 700; % Equalization starts from 800 Hz + eq1.fmax_fir = 13e3; % Equalization ends at 20 kHz + eq1.fir_minph = 1; % Check result carefully if 1 is used, 0 is safe + eq2 = eq1; % Copy settings to second EQ + + %% Design left channel EQ + eq1.raw_f = f; % Measurement Hz + eq1.raw_m_db = m(:,1); % Measurement dB, left ch + eq1 = eq_compute(eq1); + eq_plot(eq1, 10); + + %% Design right channel EQ + eq2.norm_offs_db = -3 + 0.2; % Offset in dB to normalize, -3dB plus L-R + eq2.raw_f = f; % Measurement Hz + eq2.raw_m_db = m(:,2); % Measurement dB, right ch + eq2 = eq_compute(eq2); + eq_plot(eq2, 20); + + %% Stereo EQ + figure(30); + l_ch = eq1.m_db+eq1.fir_eq_db; + r_ch = eq2.m_db+eq2.fir_eq_db; + semilogx(eq1.f, l_ch, eq2.f, r_ch); + grid on; + axis([100 20e3 -20 10]); + xlabel('Frequency (Hz)'); + ylabel('Magnitude (dB)'); + + %% Calculate level offset at 1 - 4 kHz from RMS + idx0 = find(eq1.f < 4e3); + idx = find(eq1.f(idx0) > 1e3); + l_lev = 20*log10(sqrt(mean(10.^(l_ch(idx)/10)))); + r_lev = 20*log10(sqrt(mean(10.^(r_ch(idx)/10)))); + fprintf('L ch level %3.1f dB\n', l_lev); + fprintf('R ch level %3.1f dB\n', r_lev); + delta_lev = l_lev-r_lev; + fprintf('delta %3.1f dB\n', delta_lev); + +IIR equalizer +************* + +Infinite impulse response (IIR) filter is the other main filter type +for equalization. Here it’s described after FIR because despite the +simpler look (much lower filter orders needed) using them needs more +expertise. An IIR design can fail fatally if not used with care and +plenty of testing. Therefore it is recommended to use simple low order +filters and do the more complex response manipulation with FIR. The +risks of IIR are in stability (unwanted loud oscillation), noise, and +loss of SNR due to scaling need. However IIR filters are great for +enhancing frequency response at lowest frequencies and generally doing +stronger adjustment. + +The tool in SOF does not support automatic design. Instead the design +is manual with parametric first and second order blocks. The second +order blocks are called often bi-quads. The parametric blocks are +specified by their type (high-pass, low-pass, low-shelf, high-shelf, +peak/notch). The shelving and peaking filters are second order. The +high-pass and low-pass filters can be first or second order. Therefore +the parametric blocks are called with abbreviations HP1, HP2, LP1, +LP2, LS2, HS2, and PN2. All parametric blocks have a resonant +frequency parameter in Hz. The shelving filters and peaking filters +have also gain in Decibels as parameter. Finally the peaking filter +has a Q-value parameter. The higher the Q-value is the narrower is the +resonance. The syntax for describing parametric EQ is shown below: + +.. code-block:: octave + + eq1.peq = [ eq1.PEQ_HP2 200 0 0 ; ... + eq1.PEQ_PN2 750 -5.0 1.3 ; ... + eq1.PEQ_PN2 5000 -4.0 0.6 ; ... + ]; + + +The example can be equalized with IIR only. First, since there is very +little output from the speaker below 200 Hz we can with second order +high-pass suppress the not audible frequencies from output. It +increases the headroom for equalization a lot since typical music and +speech content has large energy there. Then, a peaking EQ is set to +attenuate the 750 Hz region by 5 dB and Q-value 1.3 for flatter +response. Finally, a peaking filter is set to attenuate the wide bump +at 5 kHz by 4 dB and Q-value 0.6. The resulting EQ is 6th order. It +also could be possible to boost the low frequencies at 400 Hz a bit +with a low-shelf but it is not done here to keep filter order +low. Boost at low frequencies creates risk for signal clipping while +the achievable bandwidth extension is not large. + +.. figure:: Picture_imported_frequency_response_for_iir.png + :width: 600 + + Simulated frequency response. The difference in parametric + low-order IIR can be seen as more remaining small ripple in the + smoothed equalized response vs. FIR. + +.. figure:: Picture_iir_filter_response_vs_ideal_target.png + :width: 600 + + IIR filter response vs. ideal target. + +.. figure:: Picture_iir_absolute_response.png + :width: 600 + + Absolute response. The loudness normalize suggests a fairly high + gain for the filter since a lot of loudness is lost due to suppress + of lowest frequencies. Need to be careful with this. + +.. figure:: Picture_iir_poles_and_zeros.png + :width: 600 + + Poles and zeros plot. In recursive filters the poles (x) need to be + inside unit circle for stable design. This plot is for 64 bit float + coefficients, fixed scaled coefficients could have issues even if + this looks OK. + +.. figure:: Picture_iir_impulse_response.png + :width: 600 + + Impulse response. The main purpose of this to do another stability + check. A stable filter decays to zero while an unstable design + might remain oscillation at steady or increasing amplitude. + +The right channel is tuned similarly. The resulting non-smoothed +left/right balance corrected responses and the complete code for +tuning are shown below. + + +.. figure:: Picture_iir_simulated_left_and_channel_responses.png + :width: 600 + + Simulated frequency responses of left and right speakers with + IIR equalizer. + + +.. code-block:: octave + + %% Load measurement data, variable f and m + load example_dut.mat; + + %% EQ settings + eq1 = eq_defaults(); % Get defaults + eq1.fs = 48e3; % Set sample rate + eq1.norm_type = 'loudness'; % Normalize criteria can be loudness/peak/1k + eq1.norm_offs_db = -3; % Offset in dB to normalize, -3 dB loudness + eq1.logsmooth_plot = 1.0; % Smooth over 1.0 octaves + eq1.logsmooth_eq = 1.0; % Smooth over 1.0 octaves + eq1.enable_iir = 1; % By default both FIR and IIR disabled + eq2 = eq1; % Copy settings to second EQ + + %% Design left channel EQ + eq1.raw_f = f; % Measurement Hz + eq1.raw_m_db = m(:,1); % Measurement dB, left ch + eq1.peq = [ eq1.PEQ_HP2 200 0 0 ; ... + eq1.PEQ_PN2 750 -5.0 1.3 ; ... + eq1.PEQ_PN2 5000 -4.0 0.6 ; ... + ]; + eq1 = eq_compute(eq1); + eq_plot(eq1, 10); + + %% Design right channel EQ + eq2.norm_offs_db = -3 + 0.1; % Offset in dB to normalize, -3dB plus L-R + eq2.raw_f = f; % Measurement Hz + eq2.raw_m_db = m(:,2); % Measurement dB, right ch + eq2.peq = [ eq2.PEQ_HP2 200 0 0 ; ... + eq2.PEQ_PN2 750 -5.0 1.4 ; ... + eq2.PEQ_PN2 4500 -4.0 0.6 ; ... + ]; + eq2 = eq_compute(eq2); + eq_plot(eq2, 20); + + %% Stereo EQ + figure(30); + l_ch = eq1.m_db+eq1.iir_eq_db; + r_ch = eq2.m_db+eq2.iir_eq_db; + semilogx(eq1.f, l_ch, eq2.f, r_ch); + grid on; + axis([100 20e3 -20 20]); + xlabel('Frequency (Hz)'); + ylabel('Magnitude (dB)'); + + %% Calculate level offset at 1 - 4 kHz from RMS + idx0 = find(eq1.f < 4e3); + idx = find(eq1.f(idx0) > 1e3); + l_lev = 20*log10(sqrt(mean(10.^(l_ch(idx)/10)))); + r_lev = 20*log10(sqrt(mean(10.^(r_ch(idx)/10)))); + fprintf('L ch level %3.1f dB\n', l_lev); + fprintf('R ch level %3.1f dB\n', r_lev); + delta_lev = l_lev-r_lev; + fprintf('delta %3.1f dB\n', delta_lev); + +Combined IIR and FIR +******************** + +The EQ tool can support use of both types simultaneously. The IIR type +is applied first and the impact is subtracted from the target. This +allows the FIR to fine tune the response where IIR could not match +fully the target. + +For this example the IIR high shelf is left out because FIR can do it +efficiently. Instead of boosting at 2 kHz this script tests +attenuation at 700 Hz to flatten and extend a bit the flat frequency +response region down. + +Note: In current version the norm_offs_db parameter impacts both FIR +and IIR part by the given amount. Therefore the level adjust need to +be entered as 0.5*adjust. + +.. figure:: Picture_IIR_FIR_target_vs_achieved_response.png + :width: 600 + + Right channel equalization filters. The red solid plot is the combined IIR and FIR response + that matches well the smoothed target response in solid blue. The dashed yellow and purple + lines show the IIR and FIR responses. + +.. figure:: Picture_simulated_IIR_FIR_frequency_response.png + :width: 600 + + Simulated raw frequency response + +Exporting coefficients to SOF +***************************** + +The coefficients can be exported into a format for m4 topology for +automatic boot time setup. The topology file can include the m4 +scripts instead of the default “flat” response coefficients. It is +also possible to set up an equalizer with .txt or .bin format blob in +device run-time with sof-ctl utility to test the response and iterate +the design. + +The complete script for equalizers tuning and coefficients export for +the previous example is shown below. + +.. code-block:: octave + + %% Load measurement data, variable f and m + load example_dut.mat; + + %% EQ settings + eq1 = eq_defaults(); % Get defaults + eq1.fs = 48e3; % Set sample rate + eq1.norm_type = 'loudness'; % Normalize criteria can be loudness/peak/1k + eq1.norm_offs_db = -3; % Offset in dB to normalize, -3dB loudness + eq1.logsmooth_plot = 1.0; % Smooth over 1.0 octaves + eq1.logsmooth_eq = 1.0; % Smooth over 1.0 octaves + eq1.enable_fir = 1; % By default both FIR and IIR disabled + eq1.enable_iir = 1; % Enable too + eq1.fir_beta = 3.0; % Lower beta is more accurate but be careful + eq1.fir_length = 40; % Minimize this vs. fmin/fmax choice + eq1.fir_autoband = 0; % Select manually frequency limits + eq1.fmin_fir = 700; % Equalization starts from 800 Hz + eq1.fmax_fir = 13e3; % Equalization ends at 13 kHz + eq1.fir_minph = 1; % Check result carefully if 1 is used, 0 is safe + eq2 = eq1; % Copy settings to second EQ + + %% Design left channel EQ + eq1.raw_f = f; % Measurement Hz + eq1.raw_m_db = m(:,1); % Measurement dB, left ch + eq1.peq = [ eq1.PEQ_HP2 200 0 0 ; ... + eq1.PEQ_PN2 750 -5.0 1.3 ; ... + ]; + eq1 = eq_compute(eq1); + eq_plot(eq1, 10); + + %% Design right channel EQ + eq2.norm_offs_db = -3 + 0.1; % Offset in dB to normalize, -4dB plus L-R + eq2.raw_f = f; % Measurement Hz + eq2.raw_m_db = m(:,2); % Measurement dB, right ch + eq2.peq = [ eq2.PEQ_HP2 200 0 0 ; ... + eq2.PEQ_PN2 750 -5.0 1.4 ; ... + ]; + eq2 = eq_compute(eq2); + eq_plot(eq2, 20); + + %% Stereo EQ + figure(30); + l_ch = eq1.m_db+eq1.tot_eq_db; + r_ch = eq2.m_db+eq2.tot_eq_db; + semilogx(eq1.f, l_ch, eq2.f, r_ch); + grid on; + axis([100 20e3 -20 10]); + xlabel('Frequency (Hz)'); + ylabel('Magnitude (dB)'); + + %% Calculate level offset at 1 - 4 kHz from RMS + idx0 = find(eq1.f < 4e3); + idx = find(eq1.f(idx0) > 1e3); + l_lev = 20*log10(sqrt(mean(10.^(l_ch(idx)/10)))); + r_lev = 20*log10(sqrt(mean(10.^(r_ch(idx)/10)))); + fprintf('L ch level %3.1f dB\n', l_lev); + fprintf('R ch level %3.1f dB\n', r_lev); + delta_lev = l_lev-r_lev; + fprintf('delta %3.1f dB\n', delta_lev); + + %% Export FIR + fir_ascii_fn = 'dut_spk_fir.txt'; + fir_tplg_fn = 'dut_spk_fir.m4'; + fir_eq1_quant = eq_fir_blob_quant(eq1.b_fir); + fir_eq2_quant = eq_fir_blob_quant(eq2.b_fir); + channels_in_config = 2; % Setup max 2 channels EQ + assign_response = [0 1]; % Switch to response #0 and #1 + num_responses = 2; % Two responses + fir_bm = eq_fir_blob_merge(channels_in_config, ... + num_responses, ... + assign_response, ... + [fir_eq1_quant fir_eq2_quant]); + fir_bp = eq_fir_blob_pack(fir_bm); + eq_alsactl_write(fir_ascii_fn, fir_bp); + eq_tplg_write(fir_tplg_fn, fir_bp, 'FIR'); + + %% Export IIR + iir_ascii_fn = 'dut_spk_iir.txt'; + iir_tplg_fn = 'dut_spk_iir.m4'; + iir_eq1_quant = eq_iir_blob_quant(eq1.p_z, eq1.p_p, eq1.p_k); + iir_eq2_quant = eq_iir_blob_quant(eq2.p_z, eq2.p_p, eq2.p_k); + iir_bm = eq_iir_blob_merge(channels_in_config, ... + num_responses, ... + assign_response, ... + [iir_eq1_quant iir_eq2_quant]); + iir_bp = eq_iir_blob_pack(iir_bm); + eq_alsactl_write(iir_ascii_fn, iir_bp); + eq_tplg_write(iir_tplg_fn, iir_bp, 'IIR'); + +Testing the response with sof-ctl +********************************* + +The sof-ctl tool is practical for testing new EQ settings and iterate +the design without need to reboot the device. The pre-requisite is that +the DUT runs for speaker path a topology that contains the IIR and FIR +equalizers. + +First the numids of the equalizers are found out with amixer +command. The lines with prompt $ are user entered commands and other +text shown is command output. + +.. code-block:: bash + + $ amixer -Dhw:0 controls | grep EQIIR + numid=66,iface=MIXER,name='EQIIR1.0 EQIIR' + + $ amixer -Dhw:0 controls | grep EQFIR + numid=67,iface=MIXER,name='EQFIR1.0 EQFIR' + +The numids are in this device 66 and 67 for IIR and FIR. Next the +exported ALSA binary controls are passed to equalizers with sof-ctl: + +.. code-block:: bash + + $ ./sof-eqctl -n 66 -s dut_spk_iir.txt + Applying configuration "dut_spk_iir.txt" into device hw:0 control numid=66. + + 4607827,0,196,50331648,0,0,0,0,196,2,2,0,0,0,0,0,1,2,2,0,0,0,0,3260252783,2107733822, + 528275171,3238416955,528275171,0,16384,3324016838,2034846530,497901563,3275128193, + 526872106,4294967293,20454,2,2,0,0,0,0,3260252783,2107733822,528275171,3238416955, + 528275171,0,16384,3317002057,2041827532,500647939,3271629404,527641448,4294967293,20551 + + Success. + + $ ./sof-eqctl -n 67 -s dut_spk_fir.txt + Applying configuration "dut_spk_fir.txt" into device hw:0 control numid=67. + + 4607827,0,244,50331648,0,0,0,0,244,131074,0,0,0,0,65536,44,0,0,0,0,3801503801,233243489, + 4293068324,74908123,1901269,7733144,6422742,4290772934,17039467,1114313,4293328827, + 4291756033,4289658785,4291297224,4293459912,589833,4294115318,4294246391,4294442989, + 1310731,13,0,44,0,0,0,0,3785054386,221118972,13436579,74515002,8520459,10551247,10944817, + 4292018112,23789790,4291559609,4293984167,4288479207,4290576265,4293394406,131047,1179673, + 4293853177,4293853167,4294901744,851980,6,0 + + Success. + + + +.. figure:: Picture_tested_speaker_frequency_response.png + :width: 600 + + The response is simple to test acoustically by re-running + mls_freq_resp(); The overall response is now much more flat and is + very similar to previously shown simulated response. + + +Using the EQ settings in topology +********************************* + +The generated .m4 suffix files for FIR and IIR can be included or +embedded into topology m4 scripts. There are a few examples of such +topologies in $SOF_WORKSPACE/sof/tools/topology/topology1/development. +The CMakeLists.txt file builds e.g. topologies +sof-cml-rt1011-rt5682-eq.tplg and sof-hda-generic-2ch-loud.tplg those +can be used as example. + +The playback pipeline is set with -DSPKPROC=eq-iir-eq-fir-volume +or -DHSPROC=eq-iir-eq-fir-volume to contain the equalizers and volume +control components. The macros -DHSPROC_FILTER1=eq_iir_coef_pass.m4 +and -DHSPROC_FILTER2=eq_fir_coef_pass.m4 are flat default responses. + +Setting -DHSPROC_FILTER1=dut_spk_iir.m4 and +-DHSPROC_FILTER2=dut_spk_fir.m4 would set the just exported equalizer +tuning to be applied at device boot. + +Note: Unfortunately the SOF topology1 equalizers definitions at top +CMakeLists.txt are not very systematic and there may be bugs with some +platforms triggered by small topology changes. The new topology needs +extensive testing for all audio endpoints (that other existing filters +are not modified) and preferably manual inspection of topology .conf +file that the m4 parsed output matches expectation. + +The development now focuses to to topology2 and hopefully this part +can be cleaned up and made easier for product audio tuning. + +References +********** + +.. [1] AES17-2020: AES standard method for digital audio engineering - Measurement of digital audio equipment, + https://www.aes.org/publications/standards/search.cfm?docID=21 + +.. [2] Dayton audio UMM-6 USB measurement microphone, + https://www.daytonaudio.com/product/1116/umm-6-usb-measurement-microphone + +.. [3] MiniDSP UMIK-1 USB measurement microphone, + https://www.minidsp.com/products/acoustic-measurement/umik-1 diff --git a/algos/index.rst b/algos/index.rst index 34776ba9..6cd9fb9c 100644 --- a/algos/index.rst +++ b/algos/index.rst @@ -37,6 +37,7 @@ Further information on specific algorithms is forthcoming. .. toctree:: :maxdepth: 1 - src/sample_rate_conversion demux/demux.rst + eq/equalizers_tuning + src/sample_rate_conversion tdfb/time_domain_fixed_beamformer diff --git a/architectures/dsp/index.rst b/architectures/dsp/index.rst deleted file mode 100644 index 1d19a785..00000000 --- a/architectures/dsp/index.rst +++ /dev/null @@ -1,95 +0,0 @@ -.. _architecture-dsp: - -DSP Architecture -################ - -Currently SOF has support for the Cadence Xtensa DSP architecture in UP and SMP -modes in the upstream code base today. - -The diagram below shows the high-level firmware architecture with the -Baytrail platform integration as an example. The firmware is divided into four -main sections: - -#. **Generic microkernel.** The microkernel manages and abstracts the - DSP hardware for the rest of the system. It also exports C APIs for - memory allocation, scheduling work, event notifications, and power - management. - -#. **Audio components.** The audio components can be used to form an - audio processing pipeline from the host DMA buffer to the DSP digital - audio interface. Audio components will have a source and sink buffer - where they will usually transform or route audio data as part of their - processing. - -#. **Audio task.** The audio task manages the audio pipelines at run - time; it manages the transportation of data from source to sink - component within the pipeline. The pipelines are currently statically - defined in the firmware, but infrastructure is now in place to allow the - dynamic creation of pipelines from Linux userspace. - -#. **Platform drivers.** The platform drivers are used to control any - external IP to the DSP IP. This will usually be things like DMA engines - or DAI (Digital Audio Interface) controllers. These drivers are used by - the audio components and pipelines to send/receive data to/from the host - and external codecs. - - .. figure:: ../images/fw-arch-diag.png - :align: center - :alt: SOF Architecture - :width: 800px - - `Sound Open Firmware Architecture using Intel Baytrail Platform` - - -Each section above is well insulated from the other sections by partitioning -code into separate directories and by using DSP and platform agnostic generic -APIs for orchestration between the sections. - -Adding a new DSP architecture to SOF -==================================== - -This is not yet a guide for architecure porting, but in general are two ways to -add support for new DSP architectures to SOF. - -#. Write a new Hardware Abstraction Layer (HAL) for your DSP. - -#. Use an existing RTOS that supports your DSP architecture as a HAL for SOF. - -Both methods require a working compiler for the new DSP architecture and -preferrably an emulation environment or hardware debugger to help with the -bringup and debug. - -Method 1 - New HAL ------------------- - -The main work in adding the new architecture HAL is duplicating and porting the -src/arch directory to your new architecture. The code in the architecture -directory mainly deals with architecture abstraction and initialization of any -architecture IP like MMU, IRQs and caches alongside providing optimized -versions of some common C functions (memcpy, memset, etc) for that architecture. -Adding a new architecture also usually means adding a new host platform too. - -Method 2 - Use existing RTOS ----------------------------- - -This method involves creating a HAL by wrapping the RTOS functions used by SOF -as thinly as possible (i.e. to compile out). It also means removing unused code -from the SOF build in order to use the RTOS version if desireable i.e. -allocator, schedulers, messaging etc. The final stage is to link the SOF audio -code to the RTOS. - - -Vendor Specific Architecture Information -======================================== - -Architecture details of any vendor specific code and flows. This is architecture -specific to a single vendor that falls outside the scope of the high level -generic SOF architecture. - -Intel ------ - -.. toctree:: - :maxdepth: 1 - - intel/index diff --git a/architectures/firmware/index.rst b/architectures/firmware/index.rst new file mode 100644 index 00000000..86c79454 --- /dev/null +++ b/architectures/firmware/index.rst @@ -0,0 +1,12 @@ +.. _architecture-firmware: + +Firmware Architecture +##################### + +.. toctree:: + :maxdepth: 1 + + sof-common/index + sof-xtos/index + sof-zephyr/index + intel/index \ No newline at end of file diff --git a/architectures/firmware/intel/ace/iadk_modules.rst b/architectures/firmware/intel/ace/iadk_modules.rst new file mode 100644 index 00000000..2410faa7 --- /dev/null +++ b/architectures/firmware/intel/ace/iadk_modules.rst @@ -0,0 +1,48 @@ +.. _iadk-modules: + +IADK Modules Adapter +#################### + +IADK Modules +============ + +An IADK module is a software component that can be represented by a processing +block with some input pins and output pins capable to transport a digital +signal into the block or out of the block. Processing is applied on an input +signal or a combination of input signals, some input signals may only be used +as reference signals that influence the processing on other input signals. +The result of the processing is written into the output signals. The behavior +of the block can be controlled using a configuration parameter interface. + +An IADK module communicates with base firmware and other modules through +ProcessingModuleInterface API and access base firmware services via +System Service API. + + +IADK Module Adapter +=================== + +The IADK Module Adapter is an extension to SOF component infrastructure that +allows to integrate modules developed under IADK (Intel Audio Development Kit) +Framework. +IADK modules uses uniform set of interfaces and are linked into separate +library. These modules are loaded in runtime through Library Manager and then +after registration into SOF component infrastructure are interfaced through +module adapter API. +Since IADK modules uses ProcessingModuleInterface API to control/data transfer +and SystemService API to use base FW services from internal module code, there +is a communication shim layer defined. + +The SOF IADK Module Adapter is designed to interact with IADK modules without +their code modification. Therefore C++ function, structures and variables +definition are here kept with original form from IADK Framework. +This provides binary compatibility with already developed 3rd party modules. + +There are three entities in IADK Module Adapter Package: + * System Agent - A mediator to allow the custom module to interact with the + base SOF FW. It calls IADK module entry point and provides all necessary + information to connect both sides of ProcessingModuleInterface and + System Service. + * System Service - exposes of SOF base FW services to the module. + * Processing Module Adapter - SOF base FW side of ProcessingModuleInterface + API diff --git a/architectures/firmware/intel/ace/index.rst b/architectures/firmware/intel/ace/index.rst new file mode 100644 index 00000000..8f2507bd --- /dev/null +++ b/architectures/firmware/intel/ace/index.rst @@ -0,0 +1,13 @@ +.. _ace-architecture-intel: + +Intel ACE Architecture +###################### + +The details below are specific to Intel products with an audio DSP ACE +architecture using SOF. Intel ACE is a next generation of Intel Audio DSP +solution that replaces Intel cAVS architecture. + +.. toctree:: + :maxdepth: 1 + + iadk_modules diff --git a/architectures/dsp/intel/cavs-boot/apollolake/apl-boot-ldr.rst b/architectures/firmware/intel/cavs/cavs-boot/apollolake/apl-boot-ldr.rst similarity index 94% rename from architectures/dsp/intel/cavs-boot/apollolake/apl-boot-ldr.rst rename to architectures/firmware/intel/cavs/cavs-boot/apollolake/apl-boot-ldr.rst index 2b6c68c5..04fd5d0e 100644 --- a/architectures/dsp/intel/cavs-boot/apollolake/apl-boot-ldr.rst +++ b/architectures/firmware/intel/cavs/cavs-boot/apollolake/apl-boot-ldr.rst @@ -1,7 +1,7 @@ .. _apl-boot-ldr: -Apollolake Boot Loader -###################### +Apollo Lake Boot Loader +####################### * Additional HPSRAM memory initialization. * L2 cache disabled in ``boot_entry`` (enabled by default by APL ROM). diff --git a/architectures/dsp/intel/cavs-boot/apollolake/apl-boot-rom.rst b/architectures/firmware/intel/cavs/cavs-boot/apollolake/apl-boot-rom.rst similarity index 99% rename from architectures/dsp/intel/cavs-boot/apollolake/apl-boot-rom.rst rename to architectures/firmware/intel/cavs/cavs-boot/apollolake/apl-boot-rom.rst index 037b5718..5070e745 100644 --- a/architectures/dsp/intel/cavs-boot/apollolake/apl-boot-rom.rst +++ b/architectures/firmware/intel/cavs/cavs-boot/apollolake/apl-boot-rom.rst @@ -1,7 +1,7 @@ .. _apl-boot-rom: -Apollolake Boot ROM -################### +Apollo Lake Boot ROM +#################### Progress of the boot process is reflected by the status information updated by the ROM in an SRAM area called *FW Registers*. It is available to the host diff --git a/architectures/dsp/intel/cavs-boot/apollolake/images/apl-rom-flow.pu b/architectures/firmware/intel/cavs/cavs-boot/apollolake/images/apl-rom-flow.pu similarity index 100% rename from architectures/dsp/intel/cavs-boot/apollolake/images/apl-rom-flow.pu rename to architectures/firmware/intel/cavs/cavs-boot/apollolake/images/apl-rom-flow.pu diff --git a/architectures/dsp/intel/cavs-boot/apollolake/index.rst b/architectures/firmware/intel/cavs/cavs-boot/apollolake/index.rst similarity index 62% rename from architectures/dsp/intel/cavs-boot/apollolake/index.rst rename to architectures/firmware/intel/cavs/cavs-boot/apollolake/index.rst index 043d6503..21ee69cb 100644 --- a/architectures/dsp/intel/cavs-boot/apollolake/index.rst +++ b/architectures/firmware/intel/cavs/cavs-boot/apollolake/index.rst @@ -1,7 +1,7 @@ .. _cavs-boot-apl: -Apollolake Boot Process -####################### +Apollo Lake Boot Process +######################## .. toctree:: :maxdepth: 1 diff --git a/architectures/dsp/intel/cavs-boot/cavs-dsp-boot-overview.rst b/architectures/firmware/intel/cavs/cavs-boot/cavs-dsp-boot-overview.rst old mode 100755 new mode 100644 similarity index 100% rename from architectures/dsp/intel/cavs-boot/cavs-dsp-boot-overview.rst rename to architectures/firmware/intel/cavs/cavs-boot/cavs-dsp-boot-overview.rst diff --git a/architectures/dsp/intel/cavs-boot/images/boot-dsp.pu b/architectures/firmware/intel/cavs/cavs-boot/images/boot-dsp.pu similarity index 100% rename from architectures/dsp/intel/cavs-boot/images/boot-dsp.pu rename to architectures/firmware/intel/cavs/cavs-boot/images/boot-dsp.pu diff --git a/architectures/dsp/intel/cavs-boot/images/boot-ldr-flow.pu b/architectures/firmware/intel/cavs/cavs-boot/images/boot-ldr-flow.pu similarity index 100% rename from architectures/dsp/intel/cavs-boot/images/boot-ldr-flow.pu rename to architectures/firmware/intel/cavs/cavs-boot/images/boot-ldr-flow.pu diff --git a/architectures/dsp/intel/cavs-boot/images/loading-bins.pu b/architectures/firmware/intel/cavs/cavs-boot/images/loading-bins.pu similarity index 100% rename from architectures/dsp/intel/cavs-boot/images/loading-bins.pu rename to architectures/firmware/intel/cavs/cavs-boot/images/loading-bins.pu diff --git a/architectures/dsp/intel/cavs-boot/images/write-bin.pu b/architectures/firmware/intel/cavs/cavs-boot/images/write-bin.pu similarity index 100% rename from architectures/dsp/intel/cavs-boot/images/write-bin.pu rename to architectures/firmware/intel/cavs/cavs-boot/images/write-bin.pu diff --git a/architectures/dsp/intel/cavs-boot/index.rst b/architectures/firmware/intel/cavs/cavs-boot/index.rst similarity index 66% rename from architectures/dsp/intel/cavs-boot/index.rst rename to architectures/firmware/intel/cavs/cavs-boot/index.rst index 098f12f2..54ba2ef6 100644 --- a/architectures/dsp/intel/cavs-boot/index.rst +++ b/architectures/firmware/intel/cavs/cavs-boot/index.rst @@ -4,9 +4,9 @@ Booting up CAVS ADSP #################### Intel has several generations of audio DSP. "CAVS" versions relate to the audio -DSP in Skylake Core and Apollolake Atom platforms onwards. +DSP in Skylake Core and Apollo Lake Atom platforms onwards. -Baytrail, Cherrytrail, Braswell, Haswell and Broadwell audio DSPs have a simpler +Bay Trail, Cherry Trail, Braswell, Haswell, and Broadwell audio DSPs have a simpler boot flow using memory copy and not authentication. diff --git a/architectures/dsp/intel/images/idc-send-message.pu b/architectures/firmware/intel/cavs/images/idc-send-message.pu similarity index 100% rename from architectures/dsp/intel/images/idc-send-message.pu rename to architectures/firmware/intel/cavs/images/idc-send-message.pu diff --git a/architectures/dsp/intel/index.rst b/architectures/firmware/intel/cavs/index.rst similarity index 54% rename from architectures/dsp/intel/index.rst rename to architectures/firmware/intel/cavs/index.rst index cd96cc5a..4f3ac9a7 100644 --- a/architectures/dsp/intel/index.rst +++ b/architectures/firmware/intel/cavs/index.rst @@ -1,9 +1,10 @@ -.. _architecture-intel: +.. _cavs-architecture-intel: -Intel DSP Architecture -###################### +Intel cAVS Architecture +####################### -The details below are specific to Intel products with an audio DSP using SOF. +The details below are specific to Intel products with an audio DSP cAVS +architecture using SOF. .. toctree:: :maxdepth: 1 diff --git a/architectures/dsp/intel/smp/index.rst b/architectures/firmware/intel/cavs/smp/index.rst similarity index 98% rename from architectures/dsp/intel/smp/index.rst rename to architectures/firmware/intel/cavs/smp/index.rst index b3893da3..5aff7fc0 100644 --- a/architectures/dsp/intel/smp/index.rst +++ b/architectures/firmware/intel/cavs/smp/index.rst @@ -1,7 +1,7 @@ .. _architecture-intel-smp: -Intel Architecture -################## +Intel SMP Architecture +###################### Description *********** diff --git a/architectures/firmware/intel/index.rst b/architectures/firmware/intel/index.rst new file mode 100644 index 00000000..c7a5c4ea --- /dev/null +++ b/architectures/firmware/intel/index.rst @@ -0,0 +1,14 @@ +.. _vendor-specific: + +Vendor-Specific Architecture Information +######################################## + +Architecture details of any vendor specific code and flows. This is architecture +specific to a single vendor that falls outside the scope of the high level +generic SOF architecture. + +.. toctree:: + :maxdepth: 1 + + cavs/index + ace/index \ No newline at end of file diff --git a/developer_guides/firmware/components/component-mgmt-api.rst b/architectures/firmware/sof-common/components/component-mgmt-api.rst similarity index 100% rename from developer_guides/firmware/components/component-mgmt-api.rst rename to architectures/firmware/sof-common/components/component-mgmt-api.rst diff --git a/architectures/firmware/sof-common/components/component-module-api.rst b/architectures/firmware/sof-common/components/component-module-api.rst new file mode 100644 index 00000000..15560b87 --- /dev/null +++ b/architectures/firmware/sof-common/components/component-module-api.rst @@ -0,0 +1,42 @@ +.. _apps-comp-world: + +Component & Module Interfaces +############################# + +Introduction of the Module Adapter, an intermediate layer which provides common +code for different module API adapters, created multi-level sequences of calls +to functions and this mechanism is very expensive during run-time processing +with regards to additional cycles consumed for parameter translation and copying +as well as the additional memory for extra buffers, contexts, and the call +stack. The `module_adapter` translates the `comp_ops` interface required by the +existing infrastructure (pipelines etc.) into the `module_interface`. Then +appropriate adapter translates the `module_interface` into the final module +interface like `Cadence Codec API` or `IADK ProcessingModuleInterface`. These +dependencies are illustrated in the next figure. + +.. uml:: images/comp-module-api.pu + :caption: Component & Module API + +Maintenance of two base component (alias module) interfaces is expensive and +also confusing for the developers who wants to create a module that provides SOF +native module API. It is unclear whether this should be the `comp_ops` or the +`module_interface`. The latter is much more convenient since it is tailored for +the audio processing modules while the `comp_ops` is a multipurpose interface +cluttered with many optional operations required for *dai-comp* modules only. + +Therefore the `module_interface` should become the only SOF native module +interface that the rest of underlying infrastructure would interact with +directly. The `comp_ops` would become obsolete and eventually would be removed +from the SOF. + +The cost of extra memory required at the moment for intermediate audio data +buffers allocated inside the `module_adapter` layer (see the *Preparation Flow* +figure below) as well as cost of extra cycles required to copy the data to/from +the intermediate buffers (see the *Processing Flow* figure below) could be +avoided by removing the `comp_ops` as well. + +.. uml:: images/comp-prepare-flow.pu + :caption: Preparation Flow + +.. uml:: images/comp-copy-flow.pu + :caption: Processing Flow diff --git a/developer_guides/firmware/components/component-overview.rst b/architectures/firmware/sof-common/components/component-overview.rst similarity index 100% rename from developer_guides/firmware/components/component-overview.rst rename to architectures/firmware/sof-common/components/component-overview.rst diff --git a/architectures/firmware/sof-common/components/images/comp-copy-flow.pu b/architectures/firmware/sof-common/components/images/comp-copy-flow.pu new file mode 100644 index 00000000..0f015622 --- /dev/null +++ b/architectures/firmware/sof-common/components/images/comp-copy-flow.pu @@ -0,0 +1,42 @@ +actor pipeline +box "Module Adapter\no-- comp_ops" + participant "module_adapter" as module_adapter +end box +box "IADK Module Adapter\no-- module_interface" + participant "iadk_adapter" as iadk_adapter +end box +box "IADK Module\no-- ProcessingModuleInterface" + participant iadk_module +end box + +pipeline -> module_adapter : (1) ops->module_adapter_copy() + activate module_adapter + + module_adapter -> module_adapter : find min bytes\nto process + + note left of module_adapter + This logic is WRONG for some modules!! + end note + + module_adapter -> module_adapter : copy input from sources\nto internal buffers + + module_adapter -> module_adapter : module_process() + activate module_adapter +note left of module_adapter +Why all those extra internal calls +used only once?? +end note + + module_adapter -> iadk_adapter : (2) ops->process() + activate iadk_adapter + iadk_adapter -> iadk_module : (3) processing + module_adapter <-- iadk_adapter + deactivate iadk_adapter + + deactivate module_adapter + + module_adapter -> module_adapter : module_adapter_process_output() + activate module_adapter + module_adapter -> module_adapter : copy output from internal buffers\ntosinks + deactivate module_adapter +pipeline <-- module_adapter diff --git a/developer_guides/firmware/components/images/comp-dev-states.pu b/architectures/firmware/sof-common/components/images/comp-dev-states.pu similarity index 100% rename from developer_guides/firmware/components/images/comp-dev-states.pu rename to architectures/firmware/sof-common/components/images/comp-dev-states.pu diff --git a/developer_guides/firmware/components/images/comp-driver.pu b/architectures/firmware/sof-common/components/images/comp-driver.pu similarity index 100% rename from developer_guides/firmware/components/images/comp-driver.pu rename to architectures/firmware/sof-common/components/images/comp-driver.pu diff --git a/architectures/firmware/sof-common/components/images/comp-module-api.pu b/architectures/firmware/sof-common/components/images/comp-module-api.pu new file mode 100644 index 00000000..5f7ef971 --- /dev/null +++ b/architectures/firmware/sof-common/components/images/comp-module-api.pu @@ -0,0 +1,160 @@ +scale 1024 width + +component "pipelines" { + class pipeline + hide pipeline methods + hide pipeline attributes +} +component "component" { + + class comp_driver <> { + } + hide comp_driver methods + hide comp_driver attributes + + class comp_dev <> { + state + position + frames + pipeline + min_sink_bytes + min_source_bytes + task + size + period + ... + } + hide comp_dev methods + + interface buffer + hide buffer methods + hide buffer attributes + + interface comp_ops { + create() : comp_dev* + free(comp_dev*) + params(params) + dai_get_hw_params(params, dir) + dai_config(dai_config, dai_spec_config) + cmd(int cmd, void *data) + trigger(int cmd) + prepare() + reset() + copy() + position() + get_attribute() + set_attribute() + dai_ts_config() + dai_ts_start() + dai_ts_stop() + unbind() + get_large_config() + set_large_config() + } + hide comp_ops attributes + + + comp_driver -> comp_dev : creates + comp_dev *-right- comp_ops +} +pipeline -> comp_ops : calls + +component "module_adapter" { + + class module_adapter <> { + ops : comp_ops = + .create = adapter_shim_new + .prepare = module_adapter_prepare + .params = module_adapter_params + .copy = module_adapter_copy + + adapter_shim_new() + module_adapter_prepare() + module_adapter_params() + module_adapter_copy() + } + + interface module_interface { + init(processing_module*) + prepare(processing_module*) + process(processing_module*) + set_configuration() + get_configuration() + set_processing_mode() + get_processing_mode() + reset() + free() + } + hide module_interface attributes + + class processing_module <> { + stream_params + sink_buffer_list + period_bytes + deep_buff_bytes + output_buffer_size + input_buffers[] + output_buffers[] + } + hide processing_module methods + + module_adapter -left-> processing_module : creates + module_adapter -> module_interface : calls + +} +module_adapter -up-|> comp_ops + +component "cadence adapter" { + class cadence_codec { + cadence_codec_init() + cadence_codec_prepare() + cadence_codec_process() + cadence_codec_set_configuration() + cadence_codec_reset() + cadence_codec_free() + } + hide cadence_codec attributes + + interface "Cadence Codec API" as cadence_codec_api + hide cadence_codec_api methods + hide cadence_codec_api attributes + + cadence_codec -> cadence_codec_api : calls +} +cadence_codec -up-|> module_interface + +component "custom extensions" { + class "mp3 codec" as mp3_codec + hide mp3_codec methods + hide mp3_codec attributes + + class "aac codec" as aac_codec + hide aac_codec methods + hide aac_codec attributes +} +mp3_codec -up-|> cadence_codec_api +aac_codec -up-|> cadence_codec_api + +component "IADK adapter" { + class adp_interface { + intel_modules_init() + intel_modules_prepare() + intel_modules_process() + } + hide adp_interface attributes + + interface ProcessingModuleInterface <> { + Init() + Delete() + Process() + Reset() + SetProcessingMode() + GetProcessingMode() + SetConfiguration(config_id, fragment_pos, data_in, data_out) + GetConfiguration(config_id, fragment_pos, data_out) + } + hide ProcessingModuleInterface attributes + + adp_interface -> ProcessingModuleInterface : calls +} +adp_interface -up-|> module_interface diff --git a/developer_guides/firmware/components/images/comp-new-flow.pu b/architectures/firmware/sof-common/components/images/comp-new-flow.pu similarity index 100% rename from developer_guides/firmware/components/images/comp-new-flow.pu rename to architectures/firmware/sof-common/components/images/comp-new-flow.pu diff --git a/architectures/firmware/sof-common/components/images/comp-prepare-flow.pu b/architectures/firmware/sof-common/components/images/comp-prepare-flow.pu new file mode 100644 index 00000000..960b8623 --- /dev/null +++ b/architectures/firmware/sof-common/components/images/comp-prepare-flow.pu @@ -0,0 +1,22 @@ +actor pipeline +box "Module Adapter\no-- comp_ops" + participant "module_adapter" as module_adapter +end box +box "IADK Module Adapter\no-- module_interface" + participant "iadk_adapter" as iadk_adapter +end box +box "IADK Module\no-- ProcessingModuleInterface" + participant iadk_module +end box + +pipeline -> module_adapter : (1) ops->module_adapter_prepare() + activate module_adapter + module_adapter -> module_adapter : module_prepare() + activate module_adapter + module_adapter -> iadk_adapter : (2) ops->prepare() + activate iadk_adapter + iadk_adapter -> iadk_module : (3) preparation + module_adapter <-- iadk_adapter + deactivate iadk_adapter + module_adapter -> module_adapter : alloc buf descriptors + module_adapter -> module_adapter : alloc buffers diff --git a/developer_guides/firmware/components/images/component-mgmt-api.pu b/architectures/firmware/sof-common/components/images/component-mgmt-api.pu similarity index 100% rename from developer_guides/firmware/components/images/component-mgmt-api.pu rename to architectures/firmware/sof-common/components/images/component-mgmt-api.pu diff --git a/developer_guides/firmware/components/index.rst b/architectures/firmware/sof-common/components/index.rst similarity index 83% rename from developer_guides/firmware/components/index.rst rename to architectures/firmware/sof-common/components/index.rst index a78e796e..76db7fdd 100644 --- a/developer_guides/firmware/components/index.rst +++ b/architectures/firmware/sof-common/components/index.rst @@ -8,3 +8,4 @@ Components component-overview component-mgmt-api + component-module-api diff --git a/architectures/firmware/sof-common/index.rst b/architectures/firmware/sof-common/index.rst new file mode 100644 index 00000000..6e093246 --- /dev/null +++ b/architectures/firmware/sof-common/index.rst @@ -0,0 +1,12 @@ +.. _sof-common: + +SOF Common Architecture +####################### + +Architecture chapters and details that are common both for SOF Legacy and SOF +with Zephyr. + +.. toctree:: + :maxdepth: 1 + + components/index diff --git a/developer_guides/firmware/drivers/dai/images/dai-ops.pu b/architectures/firmware/sof-xtos/drivers/dai/images/dai-ops.pu similarity index 100% rename from developer_guides/firmware/drivers/dai/images/dai-ops.pu rename to architectures/firmware/sof-xtos/drivers/dai/images/dai-ops.pu diff --git a/developer_guides/firmware/drivers/dai/images/dai-set-config.pu b/architectures/firmware/sof-xtos/drivers/dai/images/dai-set-config.pu similarity index 100% rename from developer_guides/firmware/drivers/dai/images/dai-set-config.pu rename to architectures/firmware/sof-xtos/drivers/dai/images/dai-set-config.pu diff --git a/developer_guides/firmware/drivers/dai/index.rst b/architectures/firmware/sof-xtos/drivers/dai/index.rst similarity index 100% rename from developer_guides/firmware/drivers/dai/index.rst rename to architectures/firmware/sof-xtos/drivers/dai/index.rst diff --git a/developer_guides/firmware/drivers/dma/images/dma-ops.pu b/architectures/firmware/sof-xtos/drivers/dma/images/dma-ops.pu similarity index 100% rename from developer_guides/firmware/drivers/dma/images/dma-ops.pu rename to architectures/firmware/sof-xtos/drivers/dma/images/dma-ops.pu diff --git a/developer_guides/firmware/drivers/dma/images/dma-transfer.pu b/architectures/firmware/sof-xtos/drivers/dma/images/dma-transfer.pu similarity index 100% rename from developer_guides/firmware/drivers/dma/images/dma-transfer.pu rename to architectures/firmware/sof-xtos/drivers/dma/images/dma-transfer.pu diff --git a/developer_guides/firmware/drivers/dma/index.rst b/architectures/firmware/sof-xtos/drivers/dma/index.rst similarity index 100% rename from developer_guides/firmware/drivers/dma/index.rst rename to architectures/firmware/sof-xtos/drivers/dma/index.rst diff --git a/developer_guides/firmware/drivers/dma/intel/hda-dma.rst b/architectures/firmware/sof-xtos/drivers/dma/intel/hda-dma.rst similarity index 100% rename from developer_guides/firmware/drivers/dma/intel/hda-dma.rst rename to architectures/firmware/sof-xtos/drivers/dma/intel/hda-dma.rst diff --git a/developer_guides/firmware/drivers/dma/intel/images/hda-host-output.pu b/architectures/firmware/sof-xtos/drivers/dma/intel/images/hda-host-output.pu similarity index 100% rename from developer_guides/firmware/drivers/dma/intel/images/hda-host-output.pu rename to architectures/firmware/sof-xtos/drivers/dma/intel/images/hda-host-output.pu diff --git a/developer_guides/firmware/drivers/dma/intel/images/hda-link.pu b/architectures/firmware/sof-xtos/drivers/dma/intel/images/hda-link.pu similarity index 100% rename from developer_guides/firmware/drivers/dma/intel/images/hda-link.pu rename to architectures/firmware/sof-xtos/drivers/dma/intel/images/hda-link.pu diff --git a/developer_guides/firmware/drivers/dma/intel/images/hda-start-flow.pu b/architectures/firmware/sof-xtos/drivers/dma/intel/images/hda-start-flow.pu similarity index 100% rename from developer_guides/firmware/drivers/dma/intel/images/hda-start-flow.pu rename to architectures/firmware/sof-xtos/drivers/dma/intel/images/hda-start-flow.pu diff --git a/developer_guides/firmware/drivers/dma/intel/images/hda-stop-flow.pu b/architectures/firmware/sof-xtos/drivers/dma/intel/images/hda-stop-flow.pu similarity index 100% rename from developer_guides/firmware/drivers/dma/intel/images/hda-stop-flow.pu rename to architectures/firmware/sof-xtos/drivers/dma/intel/images/hda-stop-flow.pu diff --git a/developer_guides/firmware/drivers/dma/intel/index.rst b/architectures/firmware/sof-xtos/drivers/dma/intel/index.rst similarity index 100% rename from developer_guides/firmware/drivers/dma/intel/index.rst rename to architectures/firmware/sof-xtos/drivers/dma/intel/index.rst diff --git a/developer_guides/firmware/drivers/images/device-disco.pu b/architectures/firmware/sof-xtos/drivers/images/device-disco.pu similarity index 100% rename from developer_guides/firmware/drivers/images/device-disco.pu rename to architectures/firmware/sof-xtos/drivers/images/device-disco.pu diff --git a/developer_guides/firmware/drivers/images/device-probe.pu b/architectures/firmware/sof-xtos/drivers/images/device-probe.pu similarity index 100% rename from developer_guides/firmware/drivers/images/device-probe.pu rename to architectures/firmware/sof-xtos/drivers/images/device-probe.pu diff --git a/developer_guides/firmware/drivers/images/device-remove.pu b/architectures/firmware/sof-xtos/drivers/images/device-remove.pu similarity index 100% rename from developer_guides/firmware/drivers/images/device-remove.pu rename to architectures/firmware/sof-xtos/drivers/images/device-remove.pu diff --git a/developer_guides/firmware/drivers/index.rst b/architectures/firmware/sof-xtos/drivers/index.rst similarity index 100% rename from developer_guides/firmware/drivers/index.rst rename to architectures/firmware/sof-xtos/drivers/index.rst diff --git a/developer_guides/firmware/images/edf-scheduler-deps.pu b/architectures/firmware/sof-xtos/images/edf-scheduler-deps.pu similarity index 100% rename from developer_guides/firmware/images/edf-scheduler-deps.pu rename to architectures/firmware/sof-xtos/images/edf-scheduler-deps.pu diff --git a/developer_guides/firmware/images/edf-scheduler-flow.pu b/architectures/firmware/sof-xtos/images/edf-scheduler-flow.pu similarity index 100% rename from developer_guides/firmware/images/edf-scheduler-flow.pu rename to architectures/firmware/sof-xtos/images/edf-scheduler-flow.pu diff --git a/architectures/images/fw-arch-diag.png b/architectures/firmware/sof-xtos/images/fw-arch-diag.png similarity index 100% rename from architectures/images/fw-arch-diag.png rename to architectures/firmware/sof-xtos/images/fw-arch-diag.png diff --git a/developer_guides/firmware/images/ll-scheduler-deps.pu b/architectures/firmware/sof-xtos/images/ll-scheduler-deps.pu similarity index 100% rename from developer_guides/firmware/images/ll-scheduler-deps.pu rename to architectures/firmware/sof-xtos/images/ll-scheduler-deps.pu diff --git a/developer_guides/firmware/images/ll-scheduler-flow.pu b/architectures/firmware/sof-xtos/images/ll-scheduler-flow.pu similarity index 100% rename from developer_guides/firmware/images/ll-scheduler-flow.pu rename to architectures/firmware/sof-xtos/images/ll-scheduler-flow.pu diff --git a/developer_guides/firmware/images/memory-zones.dot b/architectures/firmware/sof-xtos/images/memory-zones.dot similarity index 100% rename from developer_guides/firmware/images/memory-zones.dot rename to architectures/firmware/sof-xtos/images/memory-zones.dot diff --git a/developer_guides/firmware/images/runtime-zone.dot b/architectures/firmware/sof-xtos/images/runtime-zone.dot similarity index 100% rename from developer_guides/firmware/images/runtime-zone.dot rename to architectures/firmware/sof-xtos/images/runtime-zone.dot diff --git a/developer_guides/firmware/images/scheduler-ops.pu b/architectures/firmware/sof-xtos/images/scheduler-ops.pu similarity index 100% rename from developer_guides/firmware/images/scheduler-ops.pu rename to architectures/firmware/sof-xtos/images/scheduler-ops.pu diff --git a/developer_guides/firmware/images/system-zone.dot b/architectures/firmware/sof-xtos/images/system-zone.dot similarity index 100% rename from developer_guides/firmware/images/system-zone.dot rename to architectures/firmware/sof-xtos/images/system-zone.dot diff --git a/architectures/firmware/sof-xtos/index.rst b/architectures/firmware/sof-xtos/index.rst new file mode 100644 index 00000000..1063889e --- /dev/null +++ b/architectures/firmware/sof-xtos/index.rst @@ -0,0 +1,15 @@ +.. _sof-xtos: + +SOF with XTOS Architecture +########################## + +.. toctree:: + :maxdepth: 1 + + overview + mem-mgmt + pm-runtime/index + schedulers + drivers/index + pipelines/index + kd_integration/index diff --git a/developer_guides/firmware/kd_integration/images/kd-component-diagram.pu b/architectures/firmware/sof-xtos/kd_integration/images/kd-component-diagram.pu similarity index 100% rename from developer_guides/firmware/kd_integration/images/kd-component-diagram.pu rename to architectures/firmware/sof-xtos/kd_integration/images/kd-component-diagram.pu diff --git a/developer_guides/firmware/kd_integration/images/kd-e2e-sequence-diagram.pu b/architectures/firmware/sof-xtos/kd_integration/images/kd-e2e-sequence-diagram.pu similarity index 100% rename from developer_guides/firmware/kd_integration/images/kd-e2e-sequence-diagram.pu rename to architectures/firmware/sof-xtos/kd_integration/images/kd-e2e-sequence-diagram.pu diff --git a/developer_guides/firmware/kd_integration/images/kd-state-diagram.pu b/architectures/firmware/sof-xtos/kd_integration/images/kd-state-diagram.pu similarity index 100% rename from developer_guides/firmware/kd_integration/images/kd-state-diagram.pu rename to architectures/firmware/sof-xtos/kd_integration/images/kd-state-diagram.pu diff --git a/developer_guides/firmware/kd_integration/images/kd-timing-diagram.pu b/architectures/firmware/sof-xtos/kd_integration/images/kd-timing-diagram.pu similarity index 100% rename from developer_guides/firmware/kd_integration/images/kd-timing-diagram.pu rename to architectures/firmware/sof-xtos/kd_integration/images/kd-timing-diagram.pu diff --git a/developer_guides/firmware/kd_integration/index.rst b/architectures/firmware/sof-xtos/kd_integration/index.rst similarity index 100% rename from developer_guides/firmware/kd_integration/index.rst rename to architectures/firmware/sof-xtos/kd_integration/index.rst diff --git a/developer_guides/firmware/kd_integration/kd-integration.rst b/architectures/firmware/sof-xtos/kd_integration/kd-integration.rst similarity index 100% rename from developer_guides/firmware/kd_integration/kd-integration.rst rename to architectures/firmware/sof-xtos/kd_integration/kd-integration.rst diff --git a/developer_guides/firmware/mem-mgmt.rst b/architectures/firmware/sof-xtos/mem-mgmt.rst similarity index 100% rename from developer_guides/firmware/mem-mgmt.rst rename to architectures/firmware/sof-xtos/mem-mgmt.rst diff --git a/architectures/firmware/sof-xtos/overview.rst b/architectures/firmware/sof-xtos/overview.rst new file mode 100644 index 00000000..94b44a8a --- /dev/null +++ b/architectures/firmware/sof-xtos/overview.rst @@ -0,0 +1,46 @@ +.. _sof-legacy-overview: + +Overview +########## + +Currently SOF has support for the Cadence Xtensa DSP architecture in UP and SMP +modes in the upstream code base. + +The diagram below shows the high-level firmware architecture with the +Bay Trail platform integration as an example. The firmware is divided into four +main sections: + +#. **Generic microkernel.** The microkernel manages and abstracts the + DSP hardware for the rest of the system. It also exports C APIs for + memory allocation, scheduling work, event notifications, and power + management. + +#. **Audio components.** The audio components can be used to form an + audio processing pipeline from the host DMA buffer to the DSP digital + audio interface. Audio components will have a source and sink buffer + where they will usually transform or route audio data as part of their + processing. + +#. **Audio task.** The audio task manages the audio pipelines at run + time; it manages the transportation of data from source to sink + component within the pipeline. The pipelines are currently statically + defined in the firmware, but infrastructure is now in place to allow the + dynamic creation of pipelines from Linux userspace. + +#. **Platform drivers.** The platform drivers are used to control any + external IP to the DSP IP. This will usually be things like DMA engines + or DAI (Digital Audio Interface) controllers. These drivers are used by + the audio components and pipelines to send/receive data to/from the host + and external codecs. + + .. figure:: ./images/fw-arch-diag.png + :align: center + :alt: SOF Architecture + :width: 800px + + `Sound Open Firmware Architecture using Intel Bay Trail Platform` + + +Each section above is well insulated from the other sections by partitioning +code into separate directories and by using DSP and platform agnostic generic +APIs for orchestration between the sections. diff --git a/developer_guides/firmware/pipelines/images/ppl-new.pu b/architectures/firmware/sof-xtos/pipelines/images/ppl-new.pu similarity index 100% rename from developer_guides/firmware/pipelines/images/ppl-new.pu rename to architectures/firmware/sof-xtos/pipelines/images/ppl-new.pu diff --git a/developer_guides/firmware/pipelines/images/ppl-op-downstream.pu b/architectures/firmware/sof-xtos/pipelines/images/ppl-op-downstream.pu similarity index 100% rename from developer_guides/firmware/pipelines/images/ppl-op-downstream.pu rename to architectures/firmware/sof-xtos/pipelines/images/ppl-op-downstream.pu diff --git a/developer_guides/firmware/pipelines/images/ppl-operations.pu b/architectures/firmware/sof-xtos/pipelines/images/ppl-operations.pu similarity index 100% rename from developer_guides/firmware/pipelines/images/ppl-operations.pu rename to architectures/firmware/sof-xtos/pipelines/images/ppl-operations.pu diff --git a/developer_guides/firmware/pipelines/images/ppl-params.pu b/architectures/firmware/sof-xtos/pipelines/images/ppl-params.pu similarity index 100% rename from developer_guides/firmware/pipelines/images/ppl-params.pu rename to architectures/firmware/sof-xtos/pipelines/images/ppl-params.pu diff --git a/developer_guides/firmware/pipelines/images/ppl-reset.pu b/architectures/firmware/sof-xtos/pipelines/images/ppl-reset.pu similarity index 100% rename from developer_guides/firmware/pipelines/images/ppl-reset.pu rename to architectures/firmware/sof-xtos/pipelines/images/ppl-reset.pu diff --git a/developer_guides/firmware/pipelines/images/ppl-struct.pu b/architectures/firmware/sof-xtos/pipelines/images/ppl-struct.pu similarity index 100% rename from developer_guides/firmware/pipelines/images/ppl-struct.pu rename to architectures/firmware/sof-xtos/pipelines/images/ppl-struct.pu diff --git a/developer_guides/firmware/pipelines/images/ppl-task.pu b/architectures/firmware/sof-xtos/pipelines/images/ppl-task.pu similarity index 100% rename from developer_guides/firmware/pipelines/images/ppl-task.pu rename to architectures/firmware/sof-xtos/pipelines/images/ppl-task.pu diff --git a/developer_guides/firmware/pipelines/index.rst b/architectures/firmware/sof-xtos/pipelines/index.rst similarity index 100% rename from developer_guides/firmware/pipelines/index.rst rename to architectures/firmware/sof-xtos/pipelines/index.rst diff --git a/developer_guides/firmware/pm-runtime/images/pm-dsp-core-idle.pu b/architectures/firmware/sof-xtos/pm-runtime/images/pm-dsp-core-idle.pu similarity index 100% rename from developer_guides/firmware/pm-runtime/images/pm-dsp-core-idle.pu rename to architectures/firmware/sof-xtos/pm-runtime/images/pm-dsp-core-idle.pu diff --git a/developer_guides/firmware/pm-runtime/images/pm-dsp-core-init.pu b/architectures/firmware/sof-xtos/pm-runtime/images/pm-dsp-core-init.pu similarity index 100% rename from developer_guides/firmware/pm-runtime/images/pm-dsp-core-init.pu rename to architectures/firmware/sof-xtos/pm-runtime/images/pm-dsp-core-init.pu diff --git a/developer_guides/firmware/pm-runtime/index.rst b/architectures/firmware/sof-xtos/pm-runtime/index.rst similarity index 100% rename from developer_guides/firmware/pm-runtime/index.rst rename to architectures/firmware/sof-xtos/pm-runtime/index.rst diff --git a/developer_guides/firmware/pm-runtime/intel/images/dsp-core-lps-cavs-d0-d0i3-d0.pu b/architectures/firmware/sof-xtos/pm-runtime/intel/images/dsp-core-lps-cavs-d0-d0i3-d0.pu similarity index 100% rename from developer_guides/firmware/pm-runtime/intel/images/dsp-core-lps-cavs-d0-d0i3-d0.pu rename to architectures/firmware/sof-xtos/pm-runtime/intel/images/dsp-core-lps-cavs-d0-d0i3-d0.pu diff --git a/developer_guides/firmware/pm-runtime/intel/pm-dsp-core-cavs.rst b/architectures/firmware/sof-xtos/pm-runtime/intel/pm-dsp-core-cavs.rst similarity index 100% rename from developer_guides/firmware/pm-runtime/intel/pm-dsp-core-cavs.rst rename to architectures/firmware/sof-xtos/pm-runtime/intel/pm-dsp-core-cavs.rst diff --git a/developer_guides/firmware/pm-runtime/pm-dsp-core.rst b/architectures/firmware/sof-xtos/pm-runtime/pm-dsp-core.rst similarity index 100% rename from developer_guides/firmware/pm-runtime/pm-dsp-core.rst rename to architectures/firmware/sof-xtos/pm-runtime/pm-dsp-core.rst diff --git a/developer_guides/firmware/schedulers.rst b/architectures/firmware/sof-xtos/schedulers.rst similarity index 99% rename from developer_guides/firmware/schedulers.rst rename to architectures/firmware/sof-xtos/schedulers.rst index 3070599c..17d751d2 100644 --- a/developer_guides/firmware/schedulers.rst +++ b/architectures/firmware/sof-xtos/schedulers.rst @@ -1,4 +1,4 @@ -.. _schedulers: +.. _schedulers_xtos: Schedulers ########## diff --git a/architectures/firmware/sof-zephyr/app_layer/images/app_layer_diagram.pu b/architectures/firmware/sof-zephyr/app_layer/images/app_layer_diagram.pu new file mode 100644 index 00000000..dea00068 --- /dev/null +++ b/architectures/firmware/sof-zephyr/app_layer/images/app_layer_diagram.pu @@ -0,0 +1,68 @@ +@startuml +allowmixing + +scale max 1280 width + +package "SOF" { + + package "Application layer" as APP_CUSTOMIZATION { + + package "Example Loadable Module" as LOADABLE_MODULE { + component "3rd Party Post-Processing" as PROCESSING_3RD_PARTY + component "WoV" as WOV_MODULE + component "ACA" as ACA_MODULE + component "Other modules" as OTHER_MODULES + + PROCESSING_3RD_PARTY -[hidden]right- WOV_MODULE + WOV_MODULE -[hidden]right- ACA_MODULE + ACA_MODULE -[hidden]right- OTHER_MODULES + } + + package "Built-in Module" as BUILTIN_MODULE { + component "Copier" as COPIER + component "SRC" as SRC + component "Mixers" as MIXERS + component "History Buffer/KPB" as HISTORY_BUFFER + component "Probe" as PROBE + + COPIER -[hidden]right- SRC + SRC -[hidden]right- MIXERS + MIXERS -[hidden]right- HISTORY_BUFFER + HISTORY_BUFFER -[hidden]right- PROBE + } + + BUILTIN_MODULE -[hidden]down- LOADABLE_MODULE + } + + package "System Services" as SYS_SERVICES { + + interface "System Services" as SS + + package "Media Processing Pipelines Services extension" as KERNEL_EXTENSION { + component "Communication" as COMMUNICATION + component "Pipelines and Component Infrastructure" as PIPELINE_COMPONENT_INFRASTRUCTURE + component "AVS Scheduling" as AVS_SCHEDULERS + + COMMUNICATION -[hidden]right- PIPELINE_COMPONENT_INFRASTRUCTURE + PIPELINE_COMPONENT_INFRASTRUCTURE -[hidden]right- AVS_SCHEDULERS + } + + package "Zephyr" as ZEPHYR { + component "Services" as SERVICES + } + + SS -[hidden]down- KERNEL_EXTENSION + SS -[hidden]down- ZEPHYR + + KERNEL_EXTENSION -[hidden]right- ZEPHYR + } + + APP_CUSTOMIZATION -[hidden]down- SYS_SERVICES + BUILTIN_MODULE .down. SS + PROCESSING_3RD_PARTY .down. SS + WOV_MODULE .down. SS + ACA_MODULE .down. SS + OTHER_MODULES .down. SS +} + +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/app_layer/index.rst b/architectures/firmware/sof-zephyr/app_layer/index.rst new file mode 100644 index 00000000..fba32384 --- /dev/null +++ b/architectures/firmware/sof-zephyr/app_layer/index.rst @@ -0,0 +1,51 @@ +.. _app_layer: + +Application Layer +################# + +Application Layer represents the built-in FW modules (processing components), loadable FW +modules and example templates with application libraries required for +modules integration. Application layer content is assumed to be open source +and only proprietary 3rd party components should remain private. + +.. uml:: images/app_layer_diagram.pu + :caption: Application Layer + +Modules in Application Layer +**************************** + +The built-in modules are built together with base firmware and they have +direct access to all firmware drivers and service APIs. When built-in module +is enabled in configuration, it is guaranteed to exist in firmware binary. + +The loadable modules are built separately from base firmware and they are +loaded dynamically as a separate binary, depending on the host audio +configuration. To build, use LMDK(Loadable Module Development Kit) +which is standalone kit containing all required files. + +All the application layer module access base firmware services are via the System +Services ABI. + +**NOTE:** The built-in modules are utility components provided by the base +firmware/kernel. + +Examples of built-in modules: + +* Audio built-in components: Copiers, Mixers, Volume, SRC, etc. + +Example how to build a loadable module: + +* Example Up-Down-Mixer build using :ref:`lmdk_user_guide` + +Probe +===== + +The probe module is special module in FW infrastructure that allows to inject +or extract data from a specified probe point. The traditional client +platforms use HDA DMAs to transfer data in and out of such module. + +Loadable Modules +================ + +The loadable modules are build into separate binaries from the main SOF build. To communicate with them +is used native system agent and to control is used module api :ref:`apps-comp-world`. diff --git a/architectures/firmware/sof-zephyr/images/overview_diagram.pu b/architectures/firmware/sof-zephyr/images/overview_diagram.pu new file mode 100644 index 00000000..8ee7f089 --- /dev/null +++ b/architectures/firmware/sof-zephyr/images/overview_diagram.pu @@ -0,0 +1,42 @@ +@startuml +allowmixing + +scale max 1280 width + +package "SOF" { + + package "Application layer - user space" as APPLICATION_LAYER { + component "3rd party algorithms" - private" as 3RD_PARTY_ALGOS + component "Loadable libraries" as LOADABLE_COMPONENTS + component "Built-in Processing components" as BUILTIN_COMPONENTS + + BUILTIN_COMPONENTS -[hidden]right- LOADABLE_COMPONENTS + LOADABLE_COMPONENTS -[hidden]right- 3RD_PARTY_ALGOS + } + + package "Kernel space" { + + package "Media Processing Pipelines layer - kernel extension" as KERNEL_EXTENSION { + component "Communication" as COMMUNICATION + component "Pipelines and Component Infrastructure" as PIPELINE_COMPONENT_INFRASTRUCTURE + component "AVS Scheduling" as AVS_SCHEDULERS + + COMMUNICATION -[hidden]right- PIPELINE_COMPONENT_INFRASTRUCTURE + PIPELINE_COMPONENT_INFRASTRUCTURE -[hidden]right- AVS_SCHEDULERS + } + + package "Zephyr RTOS layer" as RTOS { + component "Services" as SERVICES + component "SoC HAL" as SOC + component "Drivers" as DRIVERS + + SERVICES --[hidden]right-- SOC + SOC --[hidden]right-- DRIVERS + } + + APPLICATION_LAYER -[hidden]down- KERNEL_EXTENSION + KERNEL_EXTENSION -[hidden]down- RTOS + } +} + +@enduml diff --git a/architectures/firmware/sof-zephyr/images/sof_lib.pu b/architectures/firmware/sof-zephyr/images/sof_lib.pu new file mode 100644 index 00000000..b819e2e4 --- /dev/null +++ b/architectures/firmware/sof-zephyr/images/sof_lib.pu @@ -0,0 +1,39 @@ +component "app/mpp" as app + +component lib <> { + interface cpu + interface dai + interface dma + interface pm_runtime + + component dai_mng + dai_mng -up- dai + component dma_mng + dma_mng -up- dma + component pm_runtime_impl + pm_runtime_impl -up- pm_runtime +} + +app .down.> dai : uses +app .down.> dma : uses +app .down.> pm_runtime : uses +app .down.> cpu : uses + +component "arch/xtensa/lib" as arch_xtensa { + component arch_cpu +} +arch_cpu -up- cpu + +component vendor { + component platform { + component dai_init + dai_init .up.> dai_mng : initialize + component dma_init + dma_init .up.> dma_mng : initialize + component platform_pm_runtime + } + component drivers + drivers .up.> dma : uses +} +arch_cpu .down.> platform +pm_runtime_impl .down.> platform_pm_runtime diff --git a/architectures/firmware/sof-zephyr/images/sof_lib_zephyr.pu b/architectures/firmware/sof-zephyr/images/sof_lib_zephyr.pu new file mode 100644 index 00000000..d39e6c48 --- /dev/null +++ b/architectures/firmware/sof-zephyr/images/sof_lib_zephyr.pu @@ -0,0 +1,53 @@ +component "app/mpp" as app + +component lib <> { + interface cpu + interface dai + interface dma + interface pm_runtime + + ' component dai_mng + ' dai_mng -up- dai + ' component dma_mng + ' dma_mng -up- dma + ' component pm_runtime_impl + ' pm_runtime_impl -up- pm_runtime +} + +app .down.> dai : uses +app .down.> dma : uses +app .down.> pm_runtime : uses +app .down.> cpu : uses + +component "lib-zephyr" as lib_zephyr { + component "cpu-flows" as cpu_flows + cpu_flows -up- cpu +} + +component "zephyr" as zephyr { + component "api" as zephyr_api +} + +cpu_flows .down.> zephyr_api : uses +zephyr_api -up- dai +zephyr_api -up- dma +zephyr_api -up- pm_runtime + +' component "arch/xtensa/lib" as arch_xtensa { +' component arch_cpu +' } +' arch_cpu -up- cpu + +' component vendor { +' component platform { +' component dai_init +' dai_init .up.> dai_mng : initialize +' component dma_init +' dma_init .up.> dma_mng : initialize +' component platform_pm_runtime +' } +' component drivers +' drivers .up.> dma : uses +' } +' arch_cpu .down.> platform +' pm_runtime_impl .down.> platform_pm_runtime diff --git a/architectures/firmware/sof-zephyr/index.rst b/architectures/firmware/sof-zephyr/index.rst new file mode 100644 index 00000000..e89e5913 --- /dev/null +++ b/architectures/firmware/sof-zephyr/index.rst @@ -0,0 +1,13 @@ +.. _sof-zephyr: + +SOF with Zephyr Architecture +############################ + +.. toctree:: + :maxdepth: 1 + + overview + app_layer/index + mpp_layer/index + rtos_layer/index + zephyr_api_integration diff --git a/architectures/firmware/sof-zephyr/mpp_layer/async_messaging.rst b/architectures/firmware/sof-zephyr/mpp_layer/async_messaging.rst new file mode 100644 index 00000000..77813193 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/async_messaging.rst @@ -0,0 +1,44 @@ +.. _async_msg: + +Asynchronous Messaging Service +############################## + +Asynchronous Messaging Service (AMS) is designed to exchange sporadic / +asynchronous events between firmware components, such as key phrase detection. +It can also be optionally selected in the firmware build configuration. The +service exposes an external interface to the host and is API accessible from +firmware components. + +**NOTE:** The AMS integration is currently a work in progress; it might not be +fully functional in SOF main branch. + +Asynchronous messages are one-way from producer to all consumers and allows to: + + - direct asynchronous communication between components (1:1) + - sending one asynchronous message to many components (1:N) + - producing asynchronous messages by many modules where 1 is receiving (M:1) + - producing asynchronous messages by many modules where many are receiving (M:N) + +Messages are exchanged over IDC protocol and shared memory with multi-core +support. Message producers and consumers can be run on different cores. + +Development guide: :ref:`async_messaging_best_practices` + +.. TODO: Add link to AMS interface generated from code + +Asynchronous Messaging Flows +**************************** + +Producer and consumer on the same core +====================================== + +.. uml:: images/async_messaging/flow_prod_cons_same_core.pu + :caption: Asynchronous Messaging example with WoV producer and custom module consumer running on single core + +Producer on primary core, consumer on secondary core +==================================================== + +.. uml:: images/async_messaging/flow_prod_primary_cons_secondary_core.pu + :caption: Asynchronous Messaging example with WoV producer on primary core and custom module consumer running on secondary core + +.. TODO: Port additional async messaging uml flows from internal FAS documentation diff --git a/architectures/firmware/sof-zephyr/mpp_layer/dp_scheduling.rst b/architectures/firmware/sof-zephyr/mpp_layer/dp_scheduling.rst new file mode 100644 index 00000000..c6adf7ff --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/dp_scheduling.rst @@ -0,0 +1,614 @@ +DP a.k.a. "Data processing" with EDF scheduling +************************************************ + +DP a.k.a. "Data processing" is an async scheduling method of data processing modules. Each module works in a separate, preemptible thread with lower priority than LL thread. It allows processing with periods longer than 1ms, on-demand processing, etc. + +Unlike in LL "low latency" method where a module started every 1ms cycle and all of LL modules together MUST finish processing 1ms, DP works async and gets CPU when a module is "ready for processing", what means: + + - on each module's input buffer there's at least IBS bytes of data and in each module's output buffer there's at least OBS bytes of free space + + OR + + - a module declared readiness by itself by an optional API call "is_ready_to_process" + +Critical part is that the module **must** finish processing before its **deadline**. A deadline is a time when the modules must provide a data chunk in order to keep next module(s) in the pipeline working. + +To ensure that all modules provide data on time - as long as CPU is not overloaded - regardless of modules' processing times and processing periods, a Earliest Deadline First (EDF) scheduling is used. https://en.wikipedia.org/wiki/Earliest_deadline_first_scheduling + +A list of all DP tasks, regardless on core the task is on, is to be iterated every time the situation of DP readiness or deadline timing may change, that include: + + - finish of processing of LL pipeline (on any core) + - finish of processing of any DP module (on any core) + +during the iteration, the following will be checked: + + - Readiness of each DP module. As mentioned before, module "is ready" when declared readiness by itself an API call or when it has at least IBS of data on each input and at least OBS free space on each out + - deadline calculation of each DP module. LFTs and Deadlines are not constant, they may change when a module consume/produce a portion of data. Therefore all LFTs and Deadlines must be re-calculated + +DEADLINE CALCULATIONS +====================== + +The most critical part is to calculate deadlines. Lets go from the beginning, there are some definitions: + +**def: buffers' Latest Feeding Time (LFT)** + +LFT is the latest time when **a buffer** must be fed with a portion of data allowing its data consumer to work and finish in its specific time + +LFT is a parameter specific to a buffer and can be calculated based on: + + - current amount of data in the buffer + - data reciever's consumption rate and period + - data source production rate and period + - data reciever's module's LST - latest start time + +so, in high level LFT is a sum of: + + - Latest start time (LST) of the data consumer (LST is defined later) + + - estimated time the consumer will drain the current data from the buffer: ``number_of_ms_in_buffer / consumer_period`` + + i.e. if there's 5ms of data in the buffer and period of the consumer is 2ms, the calculated time is ``4ms`` + + - correction for multiple source cycle + + in case the producer period < consumer period the LFT time needs to be corrected, as the producer must process more than once to provide enough data. The correction will be calculated as: ``producer_LPT * required_number_of_cycles`` where LPT is longest processing time, explained later + + ``correction = producer_LPT * ((consumer_period - number_of_ms_in_buffer) / producer_period)`` + + if correction is < 0, it should be set to zero. Note that in case producer_period >= consumer_period correction is always 0 + +finally: ``LFT = LST(consumer) + estimated_drain_time - correction`` + +**def: DP module's DEADLINE** + +a DEADLINE is the latest moment **a module** must finish processing to feed all target buffers before their LFTs. +Calculation is simple: + + - module's deadline is the nearest LFT of all target buffers + +in case te LFT of the buffer cannot be calculated - that may happen during pipeline startup or if there's no output buffer, i.e. a module like speech recognition - deadline should be set to "moment when module becomes ready + modules's period" + +**def: DP module's Longest Processing Time (LPT)** + +LPT is the longest time the module may process a portion of data, assuming it is scheduled 100% of CPU time. **LPT cannot be measured in runtime** as processing may change from cycle to cycle, etc. It can, however, be estimated based on: + +- declared (by a module vendor) number of CPU cycles required for processing. This declaration should be done separately for all combination of input/output data formats, platform, CPU type, using of HiFi etc. and either included in manifest od provided in an IPC call +- If declaration is not available, we can take "a period" as an approximation of longest possible processing time. "A period" is a value calculated using IBS and data consumption rate of a module. A module cannot possibly processing longer than its period, because it would never provide data in time (if LPT = period that means a module required 100% of CPU for processing, so it is really the worst possible case) + +*Example:* if a data rate is 48samples/msec and OBS = 480samples, the "worst case" period should be calculated 10ms + +*NOTE:* in case of sampling freq like 44.1 a round up should taken - if ration is 44.1 samples per mlisecond, 45 samples should be used for calculations + +The "worst case approximation", however a correct, is assuming that a module is a heavy one and it requires 100% of CPU time. Using it may lead to unnecessary buffering, see "delayed start" section below. + +**def: DP module's latest start time (LST)** + +LST is the latest time when **a module** must start processing a portion of data in order to meet its deadline. It can be calculated as: +``deadline - LPT`` When a module is in the middle of processing, its LST may be negative. In that case 0 should be taken to all futhure calculations. + +**Based on an above, it is clear that we do need to calculate first a deadline of the very latest module in a chain, than go back and calculate LFTs and deadline of each module separately** + +Fortunate is that the last module of a pipeline is almost always an LL module (usually DAI). For LL module deadline always is "NOW", so it is very easy to calculate LFTs for its input buffer(s). note: in case of data rates like 44.1, which cannot be divided to 1ms, a round up to 45 should be used: + + - LL module always start in 1ms periods + - LL module always consume constant number of bytes in a cycle (with an exception for frequencies like 44.1, a round up 45KHz should be taken for calculations) + + so ``LFT = NOW + number of data chunks in buffer * 1ms`` + +"NOW" in all of the calculations is "last start of LL scheduler". It makes all calculations simpler, as in the examples below (calculating CPU cycles would require taking extra care for 32bit overflows or use slow 64bit operations). Also all modules have the same timestamp as "NOW", regardless of moment in the cycle the deadlines are calculated. + +If a module is in the middle of processing, it should not release data from input buffer till the processing is finished, so the input buffer should be considered as it was at the moment the processing started, otherwise deadlines may be miscalculated. + +In case of pipeline like: + +.. uml:: images/dp_scheduling/pic1_chains.pu + +there are 2 separate deadline calculation chains: DP4 than DP3, and (independent) DP2 than DP1. **Also note that deadlines and other parameters may change, so re-calculation of all parameters should occur reasonable frequently and include all DP modules, regardless of a core it is run on** + +End of stream +============= + +When a SP module is in the middle of processing when a pipeline is stopping, it should finish processing its current chunk of data. Unformtunately there's no way to interrupt ongoing processing without risk of memory leaks etc. Therefore IPC stopping a pipeline should wait till all DP modules finish processing. + +EXAMPLE1 +========= +*data source period is longer or equal to data consumer period* +Note that in the example CPU load is very close to 100%, yet deadline calculation and EDF scheduling allow to keep the processing on time. + +for simplification lets assume: + + - the pipeline is in stable state (processing for a while, not in startup) + - no DP is currently processing + - whole CPU is dedicated to DP, like if LL is on core 0 and DPs on core 1 + +**0ms time:** + +.. uml:: images/dp_scheduling/example1.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 is ready for processing + + calculate deadlines: + + - ``buf3 LFT = 15 periods of LL2`` ==> ``DP2 deadline = 15ms`` + - ``DP2 LST = 15ms (DP2 deadline) - 9ms (DP2 LPT) = 6ms`` + - ``buf2 LFT = 6ms (DP2 LST) + 10ms (1 period in buf2) = 16ms`` ==> ``DP1 deadline = 16ms`` + + DP2 will be scheduled as it has earliest deadline, will process for 9ms + +**9ms time, DP2 finished processing but not yet released data from BUF2:** + +.. uml:: images/dp_scheduling/example1_1.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 just finished processing + + calculate deadlines: + + - ``buf3 LFT = 6 periods of LL2`` ==> ``DP2 deadline = 6ms`` + - ``DP2 LST = 6ms(DP2 deadline) - 9ms (DP2 LPT) = -3ms`` LST is negative, 0 should be used ``DP2 LST = 0`` + - ``buf2 LFT = 6ms (DP2 LST) + 10ms (1 period in buf2) = 16ms`` ==> ``DP1 deadline = 16ms`` + + DP1 will be scheduled + +**9ms time, DP2 released data from BUF2:** + +.. uml:: images/dp_scheduling/example1_2.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 is not ready for processing + + calculate deadlines: + + - ``buf3 LFT = 16 periods of LL2`` ==> ``DP2 deadline = 16ms`` + - ``DP2 LST = 16ms(DP2 deadline) - 9ms (DP2 LPT) = 7ms`` + - ``buf2 LFT = 7ms (DP2 LST) = 7ms`` ==> ``DP1 deadline = 7ms`` + + DP1 will be scheduled, will run for 5ms + +**14ms time, DP1 finished processing and released data from BUF1:** + +.. uml:: images/dp_scheduling/example1_3.pu + +Pipeline state: + + - DP1 is not ready for processing + - DP2 is ready for processing + + calculate deadlines: + + - ``buf3 LFT = 11 periods of LL2`` ==> ``DP2 deadline = 11ms`` + - ``DP2 LST = 11ms(DP2 deadline) - 9ms (DP2 LPT) = 2ms`` + - ``buf2 LFT = 2ms (DP2 LST) + 100ms (10 periods in buf2) = 102ms`` ==> ``DP1 deadline = 102ms`` + + DP2 will be scheduled + +**100ms time, 86ms passed, DP2 processed 9 times, is in the middle of 10th processing, having 5ms left:** + +.. uml:: images/dp_scheduling/example1_4.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 is ready for processing + + calculate deadlines: + + - ``buf3 LFT = 15 periods of LL2`` ==> ``DP2 deadline = 15ms`` + - ``DP2 LST = 15ms(DP2 deadline) - 9ms (DP2 LPT) = 6ms`` + - ``buf2 LFT = 6ms (DP2 LST) + 10ms (1 period in buf2) = 16ms`` ==> ``DP1 deadline = 16ms`` + + DP2 will be scheduled + +**105ms time, DP2 finished processing and released data from BUF2:** + +.. uml:: images/dp_scheduling/example1_5.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 is not ready for processing + + calculate deadlines: + + - ``buf3 LFT = 20 periods of LL2`` ==> ``DP2 deadline = 20ms`` + - ``DP2 LST = 20ms(DP2 deadline) - 9ms (DP2 LPT) = 11ms`` + - ``buf2 LFT = 11ms (DP2 LST) + 0ms = 11ms`` ==> ``DP1 deadline = 11ms`` + + DP1 will be scheduled + +EXAMPLE2 +========= +*data source period is shorter than data consumer period* + +**0ms time:** + +.. uml:: images/dp_scheduling/example2.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 is not ready for processing + + calculate deadlines: + + - ``buf3 LFT = 18 periods of LL2`` ==> ``DP2 deadline = 18ms`` + - ``DP2 LST = 18ms (DP2 deadline) - 10ms (DP2 LPT) = 8ms`` + - ``buf2 LFT = 8ms(DP2 LST) + 0 (0 complete periods of DP2 in buf2) = 8ms`` correction for multiple source cycle is = 0 + - ``DP1 deadline = 8ms`` + + DP1 will be scheduled + +**2ms time:** + +.. uml:: images/dp_scheduling/example2_1.pu + +Pipeline state: + + - DP1 is not ready for processing + - DP2 is ready for processing + + calculate deadlines: + + - ``buf3 LFT = 16 periods of LL2`` ==> ``DP2 deadline = 16ms`` + - ``DP2 LST = 16ms (DP2 deadline) - 10ms (DP2 LPT) = 6ms`` + - ``buf2 LFT = 6ms(DP2 LST) + 20 (1 complete periods of DP2 in buf2) = 26ms`` correction for multiple source cycle is < 0, so 0 is used + - ``DP1 deadline = 26ms`` + + DP2 will be scheduled + +**5ms time:** + +.. uml:: images/dp_scheduling/example2_1a.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 is in the middle of processing, still has to keep processing for 7ms. According to rules, the module should not release data from input buffer till the processing is finished, so buf2 still contains 20ms samples + + calculate deadlines: + + - ``buf3 LFT = 13 periods of LL2`` ==> ``DP2 deadline = 13ms`` + - ``DP2 LST = 13ms (DP2 deadline) - 10ms (DP2 LPT) = 3ms`` + - ``buf2 LFT = 3ms(DP2 LST) + 20 (1 complete periods of DP2 in buf2) = 23ms`` correction for multiple source cycle is < 0, so 0 is used + - ``DP1 deadline = 23ms`` + + DP2 will be scheduled and will keep processing for 7ms + +**12ms time, before releasing data from buf2 and acking data in buf3** + +.. uml:: images/dp_scheduling/example2_2a.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 finished processing, but not yet released data from buf2, so buf2 still contains 20ms samples + + calculate deadlines: + + - ``buf3 LFT = 6 periods of LL2`` ==> ``DP2 deadline = 6ms`` + - ``DP2 LST = 6ms (DP2 deadline) - 10ms (DP2 LPT) = -4ms`` LST is negative, so 0 should be used + - ``buf2 LFT = 0ms(DP2 LST) + 20ms (1 complete periods of DP2 in buf2) = 20ms`` correction for multiple source cycle is < 0, so 0 is used + - ``DP1 deadline = 20ms`` + + DP2 will be release data + +**12ms time, after releasing data from buf2 and acking data in buf3** + +.. uml:: images/dp_scheduling/example2_2.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 is not ready for processing + + calculate deadlines: + + - ``buf3 LFT = 26 periods of LL2`` ==> ``DP2 deadline = 26ms`` + - ``DP2 LST = 26ms (DP2 deadline) - 10ms (DP2 LPT) = 16ms`` + - ``buf2 LFT = 16ms(DP2 LST) + 0 (0 complete periods of DP2 in buf2) - 8ms correction (4 periods of DP2 * 2ms DP1 LPT) = 8ms`` + - ``DP1 deadline = 8ms`` + + DP1 will be scheduled + +**14ms time:** + +.. uml:: images/dp_scheduling/example2_3.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 is not ready for processing + + calculate deadlines: + + - ``buf3 LFT = 24 periods of LL2`` ==> ``DP2 deadline = 24ms`` + - ``DP2 LST = 24ms (DP2 deadline) - 10ms (DP2 LPT) = 14ms`` + - ``buf2 LFT = 14ms(DP2 LST) + 0 (0 complete periods of DP2 in buf2) - 6ms correction (3 periods of DP2 * 2ms DP1 LPT) = 8ms`` + - ``DP1 deadline = 8ms`` + + DP1 will be scheduled + +**16ms time:** + +.. uml:: images/dp_scheduling/example2_4.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 is not ready for processing + + calculate deadlines: + + - ``buf3 LFT = 22 periods of LL2`` ==> ``DP2 deadline = 22ms`` + - ``DP2 LST = 22ms (DP2 deadline) - 10ms (DP2 LPT) = 12ms`` + - ``buf2 LFT = 12ms(DP2 LST) + 0 (0 complete periods of DP2 in buf2) - 4ms correction (2 periods of DP2 * 2ms DP1 LPT) = 8ms`` + - ``DP1 deadline = 8ms`` + + DP1 will be scheduled + +**18ms time:** + +.. uml:: images/dp_scheduling/example2_5.pu + +Pipeline state: + + - DP1 is not ready for processing + - DP2 is not ready for processing + + calculate deadlines - however pointless at when no DP is ready: + + - ``buf3 LFT = 20 periods of LL2`` ==> ``DP2 deadline = 20ms`` + - ``DP2 LST = 20ms (DP2 deadline) - 10ms (DP2 LPT) = 10ms`` + - ``buf2 LFT = 10ms(DP2 LST) + 0 (0 complete periods of DP2 in buf2) - 2ms correction (2 periods of DP2 * 2ms DP1 LPT) = 8ms`` + - ``DP1 deadline = 8ms`` + + no DP will be scheduled + +**20ms time:** + +.. uml:: images/dp_scheduling/example2_6.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 is not ready for processing + + calculate deadlines - however pointless at when no DP is ready: + + - ``buf3 LFT = 18 periods of LL2`` ==> ``DP2 deadline = 18ms`` + - ``DP2 LST = 18ms (DP2 deadline) - 10ms (DP2 LPT) = 8ms`` + - ``buf2 LFT = 8ms(DP2 LST) + 0 (0 complete periods of DP2 in buf2) - 2ms correction (2 periods of DP2 * 2ms DP1 LPT) = 6ms`` + - ``DP1 deadline = 6ms`` + + DP1 will be scheduled + +**22ms time:** + +.. uml:: images/dp_scheduling/example2_7.pu + +Pipeline state: + + - DP1 is not ready for processing + - DP2 is ready for processing + + calculate deadlines + + - ``buf3 LFT = 16 periods of LL2`` ==> ``DP2 deadline = 16ms`` + - ``DP2 LST = 16ms (DP2 deadline) - 10ms (DP2 LPT) = 6ms`` + - ``buf2 LFT = 6ms(DP2 LST) +20 (1 complete period of DP2 in buf2) = 26ms`` correction for multiple source cycle is = 0 + - ``DP1 deadline = 26ms`` + + DP2 will be scheduled + + +STARTUP +========== + +Special case is "pipeline startup". When a pipeline is starting, deadlines cannot be calculated as all the modules are already late and deadlines are in the past. According to deadline calculation rules, the deadline is set to time when the module becomes ready + module's LPT. + +If a module finishes processing before its LPT. it is not guaranteed that it will do it again in any of next cycles. If it happens, the data should be held in the buffer till LPT passes. This prevents underruns in case any of future processing takes longer. This mechanism is called "delayed start". The module should stay in "delayed start" state till the next module becomes ready for the first time. + +Delayed start makes EDF scheduling possible and ensures that even when CPU load close to 100% every module have enough processing time to finish within its deadline. + +Example of a pipeline startup and 100% cpu usage +================================================ + +**0ms time:** + +.. uml:: images/dp_scheduling/example3.pu + +Pipeline state: + + - DP1 is not ready for processing, in startup delay state + - DP2 is not ready for processing, in startup delay state + + calculate deadlines + + - dedline of DP2 can't be calculated + - dedline of DP1 can't be calculated + + no DP will be scheduled + +**5ms time:** + +.. uml:: images/dp_scheduling/example3_1.pu + +Pipeline state: + + - DP1 is ready for processing, in startup delay state + - DP2 is not ready for processing, in startup delay state + + calculate deadlines + + - deadline for DP2 cant be calculated + - deadline of DP1 is fixed to 2ms (NOW + DP1 LPT) - because DP2 deadline cannot be calculated + + DP1 will be scheduled + +**7ms time:** + +.. uml:: images/dp_scheduling/example3_2.pu + +Pipeline state: + + - DP1 is not ready for processing, in startup delay state + - DP2 is not ready for processing, in startup delay state + + calculate deadlines + + - deadline for DP2 cant be calculated + - deadline for DP1 cant be calculated + + no DP will be scheduled + +**10ms time:** + +.. uml:: images/dp_scheduling/example3_3.pu + +Pipeline state: + + - DP1 is ready for processing, in startup delay state + - DP2 is not ready for processing, in startup delay state + + calculate deadlines + + - deadline for DP2 cant be calculated + - deadline of DP1 is fixed to 2ms (NOW + DP1 LPT) - because DP2 deadline cannot be calculated + + DP1 will be scheduled + +**12ms time:** + +.. uml:: images/dp_scheduling/example3_4.pu + +Pipeline state: + + - DP1 is not ready for processing, leaving startup delay state + - DP2 is ready for processing, in startup delay state + + calculate deadlines + + - deadline for DP2 is fixed to 6ms (NOW + DP2 LPT) + - ``DP2 LST = 6ms (DP2 deadline) - 6ms (DP2 LPT) = 0ms`` + - ``buf2 LFT = 0ms(DP2 LST) + 10ms (1 complete period of DP2 in buf2) = 10ms`` correction for multiple source cycle is = 0 + - ``DP1 deadline = 14ms`` + + DP2 will be scheduled + +**15ms time:** + +.. uml:: images/dp_scheduling/example3_5.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 is the middle for processing, 3ms left, in startup delay state + + calculate deadlines + + - deadline for DP2 was fixed to 6ms 3ms ago, so now it is 3ms + - ``DP2 LST = 3ms (DP2 deadline) - 6ms (DP2 LPT) = -3ms`` 0 will be used + - ``buf2 LFT = 0(DP2 LST) +10 (1 complete period of DP2 in buf2) = 10ms`` correction for multiple source cycle is = 0 + - ``DP1 deadline = 10ms`` + + DP2 will be scheduled + +**17ms time:** + +.. uml:: images/dp_scheduling/example3_6.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 is not ready for processing, leaving startup delay state + + calculate deadlines + + - ``buf3 LFT = 10 periods of LL2`` ==> ``DP2 deadline = 10ms`` + - ``DP2 LST = 10ms (DP2 deadline) - 6ms (DP2 LPT) = 4ms`` + - ``buf2 LFT = 4ms(DP2 LST) + 0 (0 complete periods of DP2 in buf2) - 2ms correction (2 periods of DP2 * 2ms DP1 LPT) = 2ms`` + - ``DP1 deadline = 2ms`` + + DP1 will be scheduled + +**19ms time:** + +.. uml:: images/dp_scheduling/example3_7.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 is not ready for processing + + calculate deadlines + + - ``buf3 LFT = 8 periods of LL2`` ==> ``DP2 deadline = 8ms`` + - ``DP2 LST = 10ms (DP2 deadline) - 6ms (DP2 LPT) = 2ms`` + - ``buf2 LFT = 2ms(DP2 LST) + 0 (0 complete periods of DP2 in buf2) - 0ms correction (0 periods of DP2 * 2ms DP1 LPT) = 2ms`` + - ``DP1 deadline = 2ms`` + + DP1 will be scheduled + + +Example of a 2 pipelines, one running and one in startup and 100% cpu usage +============================================================================ + +pipeline1 is running, DP use 80% of CPU, pipeline2 is starting. Calculating of DP1/DP2 LST and BUF1/BUF3 LFT makes no sense as they're connected to LLs + +**0ms time:** + +.. uml:: images/dp_scheduling/example4.pu + +Pipeline state: + + - DP1 is ready for processing + - DP2 is not ready for processing + + calculate deadlines + + - ``buf2 LFT = 10 periods of LL2`` ==> ``DP1 deadline = 10ms`` + - DP2 deadline cannot be calculated + + DP1 will be scheduled + +**5ms time:** + +.. uml:: images/dp_scheduling/example4_1.pu + +Pipeline state: + + - DP1 is in the middle of processing, 3ms left + - DP2 is ready for processing, in startup delay state + + calculate deadlines + + - ``buf2 LFT = 5 periods of LL2`` ==> ``DP1 deadline = 5ms`` + - DP2 deadline is fixed to ``DP2 period = 1ms`` + + DP1 will be preempted, DP2 will be scheduled + +**6ms time:** + +.. uml:: images/dp_scheduling/example4_2.pu + +Pipeline state: + + - DP1 is in the middle of processing, 3ms left + - DP2 is not ready for processing, leaving startup delay state + + calculate deadlines + + - ``buf2 LFT = 4 periods of LL2`` ==> ``DP1 deadline = 4ms`` + - ``buf4 LFT = 5 periods of LL2`` ==> ``DP2 deadline = 5ms`` + + + DP2 will be scheduled + + diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/async_messaging/flow_prod_cons_same_core.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/async_messaging/flow_prod_cons_same_core.pu new file mode 100644 index 00000000..876bea23 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/async_messaging/flow_prod_cons_same_core.pu @@ -0,0 +1,83 @@ +@startuml + +box "DSP #0 (primary)" #LightBlue + participant "DSP #0: AMS" as ams + participant "DSP #0: KR" as kr + participant "DSP #0: Custom module" as custom_module +end box + +box "Shared SRAM" + participant "AMS database" as ams_db +end box + +... + +group Register KEY_PHRASE_DETECTED producer + group Get Message ID + kr -> ams: am_service_get_message_type_id(KEY_PHRASE_DETECTED UUID) + activate ams + ams -> ams_db: Find ID for KEY_PHRASE_DETECTED message + activate ams_db + alt If no KEY_PHRASE_DETECTED is found + ams -> ams_db: Assign ID to KEY_PHRASE_DETECTED message + return + end + return + end + + kr -> ams: am_service_register_producer(message_id) + activate ams + return +end + +... + +group Register KEY_PHRASE_DETECTED consumer + group Get Message ID + custom_module-> custom_module + end + + custom_module -> ams: am_service_register_consumer(message_id, callback) + activate ams + ams -> ams_db: Add KEY_PHRASE_DETECTED message consumer + return +end + +... + +group Send Async Message + kr -> ams: am_service_send_message(lp_kpd_id, message) + activate ams + + ams -> ams_db: Get KEY_PHRASE_DETECTED consumers + loop Until all consumer are called + ams -> ams_db: Get AMS consumer Processor ID + + alt AMS Consumer Processor ID != Current Processor ID + ams -> ams: Forward AMS message to the consumer's core + else AMS Consumer Processor ID == Current Processor ID + ams -> ams_db: Get AMS consumer callback + ams -> ams: Call consumer AMS callback + end + end + return +end + +... + +group Unregister KEY_PHRASE_DETECTED consumer + custom_module -> ams: am_service_unregister_consumer(message_id, callback) + activate ams + ams -> ams_db: Remove KEY_PHRASE_DETECTED message consumer + return +end + +... + +group Unregister KEY_PHRASE_DETECTED producer + kr -> ams: am_service_unregister_producer(message_id) + activate ams + return +end + +@enduml diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/async_messaging/flow_prod_primary_cons_secondary_core.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/async_messaging/flow_prod_primary_cons_secondary_core.pu new file mode 100644 index 00000000..60b9a7db --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/async_messaging/flow_prod_primary_cons_secondary_core.pu @@ -0,0 +1,153 @@ +@startuml + +scale max 1280 width + +box "DSP #0 (primary)" #LightBlue + participant "DSP #0: IXC Service" as ixc_service_dsp_0 + participant "DSP #0: IDC" as idc_dsp_0 + participant "DSP #0: AMS" as ams_dsp_0 + participant "DSP #0: KR" as kr_dsp_0 +end box + +box "DSP #1 (secondary)" #LightGreen + participant "DSP #1: IDC" as idc_dsp_1 + participant "DSP #1: Scheduler" as scheduler_dsp_1 + participant "DSP #1: IDC Task" as idc_dsp_1 + participant "DSP #1: IXC Service" as ixc_service_dsp_1 + participant "DSP #1: AMS" as ams_dsp_1 + participant "DSP #1: Custom module" as custom_module_dsp_1 +end box + +box "Shared SRAM" + participant "AMS database" as ams_db +end box + +... + +group Register KEY_PHRASE_DETECTED producer + group Get Message ID + kr_dsp_0 -> ams_dsp_0: am_service_get_message_type_id(KEY_PHRASE_DETECTED UUID) + activate ams_dsp_0 + ams_dsp_0 -> ams_db: Find ID for KEY_PHRASE_DETECTED message + activate ams_db + alt If no KEY_PHRASE_DETECTED is found + ams_dsp_0 -> ams_db: Assign ID to KEY_PHRASE_DETECTED message + end + return + return + end + + kr_dsp_0 -> ams_dsp_0: am_service_register_producer(message_id) + activate ams_dsp_0 + return +end + +... + +group Register KEY_PHRASE_DETECTED consumer + group Get Message ID + custom_module_dsp_1 -> ams_dsp_1: am_service_get_message_type_id(KEY_PHRASE_DETECTED UUID) + activate ams_dsp_1 + + ams_dsp_0 -> ams_db: Find ID for KEY_PHRASE_DETECTED message + activate ams_db + alt If no KEY_PHRASE_DETECTED is found + ams_dsp_0 -> ams_db: Assign ID to KEY_PHRASE_DETECTED message + end + return + end + + custom_module_dsp_1 -> ams_dsp_1: am_service_register_consumer(message_id) + activate ams_dsp_1 + ams_dsp_1 -> ams_db: Add KEY_PHRASE_DETECTED message consumer + return +end + +... + +group Send Async Message + kr_dsp_0 -> ams_dsp_0: am_service_send_message(message_id, message) + activate ams_dsp_0 + ams_dsp_0 -> ams_db: Get KEY_PHRASE_DETECTED consumers + + note left of ams_db + "External" means the consumers located on the other DSP cores. + "Internal" means the consumers located on the same DSP core. + end note + + loop Until all consumer are called + ams_dsp_0 -> ams_db: Get AMS consumer Processor ID + + alt AMS Consumer Processor ID != Current Processor ID + alt If a first time AMS consumer on this DSP core + alt If it is a first external AMS consumer + loop Until AMS message slot is reserved or limit of tries is reached + ams_dsp_0 -> ams_db: Reserve AMS message slot + end + + ams_dsp_0 -> ams_db: Increment a 'core use count' for AMS slot + ams_dsp_0 -> ams_db: Set MOVEMENT_REPORT message + ams_dsp_0 -> ams_dsp_0: Flush/Invalidate L1 cache + end + + ams_dsp_0 -> ixc_service_dsp_0: Send FORWARD_AMS_MESSAGE(ams_message_slot_id) IDC to the consumer's core + activate ixc_service_dsp_0 + ixc_service_dsp_0 -> idc_dsp_0: IDC Interrupt + activate idc_dsp_0 + idc_dsp_1 -> scheduler_dsp_1: Add/unblock IDC task + return + return + end + else AMS Consumer Processor ID == Current Processor ID + ams_dsp_0 -> ams_db: Get AMS consumer callback + ams_dsp_0 -> ams_dsp_0: Call consumer AMS callback + end + end + return + + ... + + scheduler_dsp_1 -> idc_dsp_1: Execute task + activate idc_dsp_1 + idc_dsp_1 -> ixc_service_dsp_1: Process IDC message + activate ixc_service_dsp_1 + ixc_service_dsp_1 -> ams_dsp_1: FORWARD_AMS_MESSAGE(ams_message_slot_id) + activate ams_dsp_1 + ams_dsp_1 -> ams_db: Get KEY_PHRASE_DETECTED consumers + loop Until all consumer are called + ams_dsp_1 -> ams_db: Get AMS consumer Processor ID + + alt AMS Consumer Processor ID == Current Processor ID + ams_dsp_1 -> ams_db: Get AMS consumer callback + alt If Custom module consumer + ams_dsp_1 -> custom_module_dsp_1: Call AMS Custom module callback + activate custom_module_dsp_1 + return + else + ams_dsp_1 -> ams_dsp_0: Call consumer AMS callback + end + end + end + return + return + return +end + +... + +group Unregister KEY_PHRASE_DETECTED produce + kr_dsp_0 -> ams_dsp_0: am_service_unregister_producer(message_id) + activate ams_dsp_0 + return +end + +... + +group Unregister KEY_PHRASE_DETECTED consumer + custom_module_dsp_1 -> ams_dsp_1: am_service_unregister_consumer(message_id) + activate ams_dsp_1 + ams_dsp_1 -> ams_db: Remove KEY_PHRASE_DETECTED message consumer + return +end + +@enduml diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1.pu new file mode 100644 index 00000000..969188bb --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1.pu @@ -0,0 +1,34 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n100ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 100ms + LPT: 5ms +end note + +rectangle "BUF2\n\n10ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 10ms + LPT: 9ms +end note + +rectangle "BUF3\n\n15ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1_1.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1_1.pu new file mode 100644 index 00000000..b8f65e24 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1_1.pu @@ -0,0 +1,34 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n109ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 100ms + LPT: 5ms +end note + +rectangle "BUF2\n\n10ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 10ms + LPT: 9ms +end note + +rectangle "BUF3\n\n6ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1_2.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1_2.pu new file mode 100644 index 00000000..9b8798ba --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1_2.pu @@ -0,0 +1,34 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n109ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 100ms + LPT: 5ms +end note + +rectangle "BUF2\n\n0ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 10ms + LPT: 9ms +end note + +rectangle "BUF3\n\n16ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1_3.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1_3.pu new file mode 100644 index 00000000..5dd8d956 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1_3.pu @@ -0,0 +1,40 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n14ms of data\n" as buf1 +note bottom of buf1 + there was 109ms + LL1 produced 5ms + DP1 consumed 100ms + 109+5-100 = 14ms +end note + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 100ms + LPT: 5ms +end note + +rectangle "BUF2\n\n100ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 10ms + LPT: 9ms +end note + +rectangle "BUF3\n\n11ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1_4.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1_4.pu new file mode 100644 index 00000000..03ed3355 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1_4.pu @@ -0,0 +1,42 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n100ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 100ms + LPT: 5ms +end note + +rectangle "BUF2\n\n10ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 10ms + LPT: 9ms +end note + +rectangle "BUF3\n\n15ms of data\n" as buf3 + +note bottom of buf3 + there was 11ms + DP2 produced 90ms + LL2 consumed 86ms + 11+90-86 = 15ms +end note + + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1_5.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1_5.pu new file mode 100644 index 00000000..098fb792 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example1_5.pu @@ -0,0 +1,41 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n105ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 100ms + LPT: 5ms +end note + +rectangle "BUF2\n\n0ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 10ms + LPT: 9ms +end note + +rectangle "BUF3\n\n20ms of data\n" as buf3 + +note bottom of buf3 + there was 15ms + DP2 produced 10ms + LL2 consumed 5ms + 15+10-5 = 20ms +end note + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2.pu new file mode 100644 index 00000000..7677f06d --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2.pu @@ -0,0 +1,34 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n5ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n15ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 20ms + LPT: 10ms +end note + +rectangle "BUF3\n\n18ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_1.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_1.pu new file mode 100644 index 00000000..83dfc838 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_1.pu @@ -0,0 +1,40 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n2ms of data\n" as buf1 +note bottom of buf1 + there was 5ms + LL1 produced 2ms + DP1 consumed 5ms + 5-5+2 = 2ms +end note + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n20ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 20ms + LPT: 10ms +end note + +rectangle "BUF3\n\n16ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_1a.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_1a.pu new file mode 100644 index 00000000..8e1c2874 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_1a.pu @@ -0,0 +1,34 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n5ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n20ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 20ms + LPT: 10ms +end note + +rectangle "BUF3\n\n13ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_2.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_2.pu new file mode 100644 index 00000000..0e7440cf --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_2.pu @@ -0,0 +1,34 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n12ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n0ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 20ms + LPT: 10ms +end note + +rectangle "BUF3\n\n26ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_2a.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_2a.pu new file mode 100644 index 00000000..20f6e42e --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_2a.pu @@ -0,0 +1,34 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n12ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n20ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 20ms + LPT: 10ms +end note + +rectangle "BUF3\n\n6ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_3.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_3.pu new file mode 100644 index 00000000..a976be4f --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_3.pu @@ -0,0 +1,40 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n9ms of data\n" as buf1 +note bottom of buf1 + there was 12ms + LL1 produced 2ms + DP1 consumed 5ms + 12+2-5 = 9ms +end note + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n5ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 20ms + LPT: 10ms +end note + +rectangle "BUF3\n\n24ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_4.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_4.pu new file mode 100644 index 00000000..4e06b3e5 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_4.pu @@ -0,0 +1,40 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n6ms of data\n" as buf1 +note bottom of buf1 + there was 9ms + LL1 produced 2ms + DP1 consumed 5ms + 9+2-5 = 6ms +end note + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n10ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 20ms + LPT: 10ms +end note + +rectangle "BUF3\n\n22ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_5.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_5.pu new file mode 100644 index 00000000..c1efc9c0 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_5.pu @@ -0,0 +1,40 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n3ms of data\n" as buf1 +note bottom of buf1 + there was 6ms + LL1 produced 2ms + DP1 consumed 5ms + 9+2-5 = 3ms +end note + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n15ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 20ms + LPT: 10ms +end note + +rectangle "BUF3\n\n20ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_6.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_6.pu new file mode 100644 index 00000000..7677f06d --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_6.pu @@ -0,0 +1,34 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n5ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n15ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 20ms + LPT: 10ms +end note + +rectangle "BUF3\n\n18ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_7.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_7.pu new file mode 100644 index 00000000..b2a6ca71 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example2_7.pu @@ -0,0 +1,39 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n2ms of data\n" as buf1 +note bottom of buf1 + there was 5ms + LL1 produced 2ms + DP1 consumed 5ms + 5+2-5 = 2ms +end note +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n20ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 20ms + LPT: 10ms +end note + +rectangle "BUF3\n\n16ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3.pu new file mode 100644 index 00000000..92dbf045 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3.pu @@ -0,0 +1,34 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n0ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n0ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 10ms + LPT: 6ms +end note + +rectangle "BUF3\n\n0ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_1.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_1.pu new file mode 100644 index 00000000..0c83890a --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_1.pu @@ -0,0 +1,34 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n5ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n0ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 10ms + LPT: 6ms +end note + +rectangle "BUF3\n\n0ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_2.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_2.pu new file mode 100644 index 00000000..c5e7faba --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_2.pu @@ -0,0 +1,34 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n2ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n5ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 10ms + LPT: 6ms +end note + +rectangle "BUF3\n\n0ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_3.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_3.pu new file mode 100644 index 00000000..64b7accb --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_3.pu @@ -0,0 +1,34 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n5ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n5ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 10ms + LPT: 6ms +end note + +rectangle "BUF3\n\n0ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_4.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_4.pu new file mode 100644 index 00000000..858ff446 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_4.pu @@ -0,0 +1,34 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n2ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n10ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 10ms + LPT: 6ms +end note + +rectangle "BUF3\n\n0ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_5.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_5.pu new file mode 100644 index 00000000..d9ccd7e6 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_5.pu @@ -0,0 +1,34 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n9ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n10ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 10ms + LPT: 6ms +end note + +rectangle "BUF3\n\n0ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_6.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_6.pu new file mode 100644 index 00000000..f43be350 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_6.pu @@ -0,0 +1,34 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n12ms of data\n" as buf1 + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n0ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 10ms + LPT: 6ms +end note + +rectangle "BUF3\n\n10ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_7.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_7.pu new file mode 100644 index 00000000..5591eaae --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example3_7.pu @@ -0,0 +1,40 @@ +@startuml +left to right direction +(LL1) as mod1 #f6ed80 + +rectangle "BUF1\n\n9ms of data\n" as buf1 +note bottom of buf1 + there was 12ms + LL1 procuded 2ms + DP1 consumed 5ms + 12 + 2 - 5 = 9ms +end note + +(DP1) as mod2 #ADD1B2 + +note bottom of mod2 + period 5ms + LPT: 2ms +end note + +rectangle "BUF2\n\n5ms of data\n" as buf2 + +(DP2) as mod3 #ADD1B2 + +note bottom of mod3 + period 10ms + LPT: 6ms +end note + +rectangle "BUF3\n\n8ms of data\n" as buf3 + +(LL2) as mod4 #f6ed80 + + +mod1--> buf1 +buf1 --> mod2 +mod2-->buf2 +buf2 --> mod3 +mod3-->buf3 +buf3 --> mod4 +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example4.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example4.pu new file mode 100644 index 00000000..dfb6cd24 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example4.pu @@ -0,0 +1,38 @@ +@startuml +left to right direction + +package pipeline2{ + (LL3) #f6ed80 + rectangle "BUF3\n\n0ms of data\n" as buf3 + (DP2) #ADD1B2 + note bottom of DP2 + period 5ms + LPT: 1ms + end note + rectangle "BUF4\n\n0ms of data\n" as buf4 + (LL4) #f6ed80 +} + +package pipeline1{ + (LL1) #f6ed80 + rectangle "BUF1\n\n10ms of data\n" as buf1 + (DP1) #ADD1B2 + note bottom of DP1 + period 10ms + LPT: 8ms + end note + rectangle "BUF2\n\n10ms of data\n" as buf2 + (LL2) #f6ed80 + } + +LL1 --> buf1 +buf1 --> DP1 +DP1 --> buf2 +buf2 --> LL2 + +LL3 --> buf3 +buf3 --> DP2 +DP2 --> buf4 +buf4 --> LL4 + +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example4_1.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example4_1.pu new file mode 100644 index 00000000..627e730b --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example4_1.pu @@ -0,0 +1,38 @@ +@startuml +left to right direction + +package pipeline2{ + (LL3) #f6ed80 + rectangle "BUF3\n\n5ms of data\n" as buf3 + (DP2) #ADD1B2 + note bottom of DP2 + period 5ms + LPT: 1ms + end note + rectangle "BUF4\n\n0ms of data\n" as buf4 + (LL4) #f6ed80 +} + +package pipeline1{ + (LL1) #f6ed80 + rectangle "BUF1\n\n15ms of data\n" as buf1 + (DP1) #ADD1B2 + note bottom of DP1 + period 10ms + LPT: 8ms + end note + rectangle "BUF2\n\n5ms of data\n" as buf2 + (LL2) #f6ed80 + } + +LL1 --> buf1 +buf1 --> DP1 +DP1 --> buf2 +buf2 --> LL2 + +LL3 --> buf3 +buf3 --> DP2 +DP2 --> buf4 +buf4 --> LL4 + +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example4_2.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example4_2.pu new file mode 100644 index 00000000..9e5a49b0 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/example4_2.pu @@ -0,0 +1,38 @@ +@startuml +left to right direction + +package pipeline2{ + (LL3) #f6ed80 + rectangle "BUF3\n\n1ms of data\n" as buf3 + (DP2) #ADD1B2 + note bottom of DP2 + period 5ms + LPT: 1ms + end note + rectangle "BUF4\n\n5ms of data\n" as buf4 + (LL4) #f6ed80 +} + +package pipeline1{ + (LL1) #f6ed80 + rectangle "BUF1\n\n16ms of data\n" as buf1 + (DP1) #ADD1B2 + note bottom of DP1 + period 10ms + LPT: 8ms + end note + rectangle "BUF2\n\n4ms of data\n" as buf2 + (LL2) #f6ed80 + } + +LL1 --> buf1 +buf1 --> DP1 +DP1 --> buf2 +buf2 --> LL2 + +LL3 --> buf3 +buf3 --> DP2 +DP2 --> buf4 +buf4 --> LL4 + +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/pic1_chains.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/pic1_chains.pu new file mode 100644 index 00000000..0dc0256b --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/dp_scheduling/pic1_chains.pu @@ -0,0 +1,16 @@ +left to right direction +(LL1) as mod1 +(DP1) as mod2 #ADD1B2 +(DP2) as mod3 #ADD1B2 +(LL2) as mod4 +(DP3) as mod5 #7D3CFF +(DP4) as mod6 #7D3CFF +(LL3) as mod7 + + +mod1-->mod2 +mod2-->mod3 +mod3-->mod4 +mod4-->mod5 +mod5-->mod6 +mod6-->mod7 diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/lib_manager/library_manager_delete_instance.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/lib_manager/library_manager_delete_instance.pu new file mode 100644 index 00000000..6a827e38 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/lib_manager/library_manager_delete_instance.pu @@ -0,0 +1,56 @@ +@startuml + +box "Host" #LightGreen + participant "Driver" as host_driver +end box + +box "SOF" #LightSkyBlue + participant "IPC4 Handler" as ipc4_handler + participant "Component Manager" as component_manager + participant "Library Manager" as library_manager +end box + +box "Zephyr RTOS" #LightBlue + participant "Memory Management Driver" as memory_management_driver +end box + +host_driver -> ipc4_handler: SOF_IPC4_MOD_DELETE_INSTANCE + activate ipc4_handler + ipc4_handler -> component_manager: Free comp_driver + activate component_manager + alt IADK module + component_manager -> library_manager: Deinitialize comp_driver \nwith Processing Module Adapter + activate library_manager + library_manager -> component_manager: return status + deactivate library_manager + else SOF module + component_manager -> library_manager: Deinitialize comp_driver + activate library_manager + library_manager -> component_manager: return status + deactivate library_manager + end alt + component_manager -> library_manager: Free comp_driver resources + activate library_manager + library_manager -> memory_management_driver: Free/Unmap L2 memory for code and rodata + activate memory_management_driver + memory_management_driver -> library_manager + deactivate memory_management_driver + library_manager -> memory_management_driver: Free/Unmap L2 memory for bss + activate memory_management_driver + memory_management_driver -> library_manager + deactivate memory_management_driver + loop Search library for shared module + library_manager -> library_manager: Check if shared module exists and is loaded + library_manager -> memory_management_driver: Free/Unmap L2 memory for shared module + activate memory_management_driver + memory_management_driver -> library_manager + deactivate memory_management_driver + end loop + library_manager -> component_manager: return status + deactivate library_manager + component_manager -> ipc4_handler: return status + deactivate component_manager +ipc4_handler -> host_driver: Complete IPC request +deactivate ipc4_handler + +@enduml diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/lib_manager/library_manager_init_instance.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/lib_manager/library_manager_init_instance.pu new file mode 100644 index 00000000..9b16f5fd --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/lib_manager/library_manager_init_instance.pu @@ -0,0 +1,65 @@ +@startuml + +box "Host" #LightGreen + participant "Driver" as host_driver +end box + +box "SOF" #LightSkyBlue + participant "IPC4 Handler" as ipc4_handler + participant "Component Manager" as component_manager + participant "Library Manager" as library_manager +end box + +box "Zephyr RTOS" #LightBlue + participant "Memory Management Driver" as memory_management_driver +end box + +host_driver -> ipc4_handler: SOF_IPC4_MOD_INIT_INSTANCE + activate ipc4_handler + ipc4_handler -> library_manager: lib_manager_register_module() + activate library_manager + library_manager -> ipc4_handler: return status + deactivate library_manager + ipc4_handler -> component_manager: Create comp_driver + activate component_manager + component_manager -> library_manager: Allocate L2 memory for module + activate library_manager + library_manager -> memory_management_driver: Map L2 memory + deactivate library_manager + activate memory_management_driver + memory_management_driver -> library_manager + deactivate memory_management_driver + activate library_manager + library_manager -> memory_management_driver: Load module code and rodata \nfrom L3 to L2 memory + activate memory_management_driver + memory_management_driver -> library_manager + deactivate memory_management_driver + library_manager -> memory_management_driver: Initialize L2 memory for bss + activate memory_management_driver + memory_management_driver -> library_manager + deactivate memory_management_driver + loop Search library for shared module + library_manager -> library_manager: Check if shared module exists and is not loaded + library_manager -> memory_management_driver: Allocate/Map L2 memory for shared module + activate memory_management_driver + memory_management_driver -> library_manager + deactivate memory_management_driver + library_manager -> memory_management_driver: Load shared module code and rodata \nfrom L3 to L2 memory + activate memory_management_driver + memory_management_driver -> library_manager + deactivate memory_management_driver + end loop + alt IADK module + component_manager -> library_manager: Create/Initialize comp_driver \nwith IADK Module Adapter + library_manager -> component_manager: return status + else SOF module + component_manager -> library_manager: Create/Initialize comp_driver + library_manager -> component_manager: return status + deactivate library_manager + end alt + component_manager -> ipc4_handler: return status + deactivate component_manager +ipc4_handler -> host_driver: Complete IPC request +deactivate ipc4_handler + +@enduml diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/lib_manager/library_manager_load.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/lib_manager/library_manager_load.pu new file mode 100644 index 00000000..714a5de5 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/lib_manager/library_manager_load.pu @@ -0,0 +1,49 @@ +@startuml + +box "Host" #LightGreen + participant "Driver" as host_driver +end box + +box "SOF" #LightBlue + participant "IPC4 Handler" as ipc4_handler + participant "Library Manager" as library_manager + participant "MPP Memory Manager" as mpp_memory_manager +end box + +box "ACE Platform" #LightYellow + participant "ROM EXT" as rom_ext +end box + + +host_driver -> ipc4_handler: SOF_IPC4_GLB_LOAD_LIBRARY + activate ipc4_handler + ipc4_handler -> library_manager: lib_manager_load_library() + activate library_manager + library_manager -> library_manager: Parse Manifest \nPrepare Storage Memory + library_manager -> mpp_memory_manager: Allocate L3 memory for library + activate mpp_memory_manager + mpp_memory_manager -> library_manager + deactivate mpp_memory_manager + library_manager -> library_manager: Prepare HDA DMA transfer + host_driver -> library_manager: Transfer library manifest over DMA\nto L3 memory + note right: if SoC does not support L3 memory\nthen L2 memory has to be used + opt if AUTH_API_ENABLED + library_manager -> rom_ext: Verify Manifest + activate rom_ext + rom_ext -> library_manager: result + deactivate rom_ext + end opt + host_driver -> library_manager: Transfer library code over DMA\nto L3 memory + opt if AUTH_API_ENABLED + library_manager -> rom_ext: Verify whole Library + activate rom_ext + rom_ext -> library_manager: result + deactivate rom_ext + end opt + library_manager -> library_manager: Update Library \ndescriptors table + library_manager -> ipc4_handler: return status + deactivate library_manager +ipc4_handler -> host_driver: Complete IPC request +deactivate ipc4_handler + +@enduml diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_layer_diagram.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_layer_diagram.pu new file mode 100644 index 00000000..24f8c175 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_layer_diagram.pu @@ -0,0 +1,55 @@ +@startuml + +allowmixing + +scale max 1024 width + +package "SOF" { + + package "Media Processing Pipelines layer" as MEDIA_PROCESSING_PIPELINES { + package "MPP Scheduling" as MPP_SCHEDULING { + component "LL Tasks" as LL_TASKS + component "DP Tasks" as DP_TASKS + + DP_TASKS -[hidden]down- LL_TASKS + } + + package "Communication" as COMMUNICATION { + component "IPC Message Processing and common command definitions" as IPC_MESSAGE_PROCESSING + component "Async Messaging" as ASYNC_MESSAGING + + IPC_MESSAGE_PROCESSING -[hidden]right- ASYNC_MESSAGING + } + + package "Pipeline/Component Infrastructure" as PIPELINE_COMPONENT_INFRASTRUCTURE { + component "Pipeline Management" as PIPELINE_MANAGEMENT + component "Host/DAI Gateways" as HOST_DAI_GATEWAYS + component "Processing Component Management" as PROCESSING_COMPONENT_MANAGEMENT + + PIPELINE_MANAGEMENT -[hidden]right- HOST_DAI_GATEWAYS + HOST_DAI_GATEWAYS -[hidden]right- PROCESSING_COMPONENT_MANAGEMENT + } + + COMMUNICATION -[hidden]down- PIPELINE_COMPONENT_INFRASTRUCTURE + COMMUNICATION -[hidden]right- MPP_SCHEDULING + } + + package "Zephyr" as ZEPHYR { + interface "Zephyr Services, SoC HAL and Driver Interfaces" as SS + + component "SoC HAL" as SOC + component "Drivers" as DRIVERS + component "XTHAL" as XTHAL + component "Services" as SERVICES + + SS -[hidden]down- SERVICES + SERVICES -[hidden]right- SOC + SOC -[hidden]right- DRIVERS + DRIVERS -[hidden]right- XTHAL + } + + MEDIA_PROCESSING_PIPELINES -[hidden]down- ZEPHYR + PIPELINE_COMPONENT_INFRASTRUCTURE -[hidden]down- ZEPHYR +} + +@enduml diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/edf_scheduling.diag b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/edf_scheduling.diag new file mode 100644 index 00000000..b9680b22 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/edf_scheduling.diag @@ -0,0 +1,42 @@ +// FIXME: blockdiag is orphaned and not compatible with Pillow anymore: +// https://github.com/blockdiag/blockdiag/pull/171 + +blockdiag edf_scheduling { + + node_width = 250; + node_height = 120; + default_fontsize = 16; + + Comp_1 -> Comp_2 + comment_1 -> Comp_2 [style=dashed] + Comp_2 -> Comp_3 + comment_2 -> Comp_3 [style=dashed] + Comp_3 -> Comp_4 + comment_3 -> Comp_4 [style=dashed] + Comp_4 -> sink + comment_4 -> sink [style=dashed] + + Comp_1 [label="DP component 1\n + *processing period\n + *compute requirement"] + Comp_2 [label="DP component 2\n + *processing period\n + *compute requirement"] + Comp_3 [label="DP component 3\n + *processing period\n + *compute requirement"] + Comp_4 [label="DP component 4\n + *processing period\n + *compute requirement"] + + sink [label="real time sink", shape=endpoint, fontsize = 16] + + comment_1 [label="DP1 to deliver data let\n + DP2 meet its objective"] + comment_2 [label="DP2 to deliver data let\n + DP3 meet its objective"] + comment_3 [label="DP3 to deliver data let\n + DP4 meet its objective"] + comment_4 [label="DP4 to deliver data\n + to real time-sink"] +} diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/example_DP_secondary_core_timeline.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/example_DP_secondary_core_timeline.pu new file mode 100644 index 00000000..2d3e35c9 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/example_DP_secondary_core_timeline.pu @@ -0,0 +1,136 @@ +@startuml + +Title DP tasks scheduling on secondary DSP core + +legend +Assumptions: +1) 1ms scheduling +2) No LL tasks assigned to example secondary DSP core +3) DP Task B do not depend on Task A completion +(otherwise, Task B would start on next timer interrupt after A +completion) +end legend + +scale 1 as 150 pixels + +concise "Task B" as Task_B +concise "Task A" as Task_A + +concise "DP task processing" as DP_Processing +robust "DSP" as DSP +concise "Timer interrupt" as Interrupt + + +@Task_A +0 is Busy +1.5 is {-} + +4 is Busy +5.5 is {-} + +8 is Busy +9.5 is {-} + +@0 <-> @4: Task A schedule period (4ms) +@4 <-> @5.5: Task A execution time (1.5ms) + +DP_Processing@0 -[#Orange]> Task_A@0 +DP_Processing@1 -[#Orange]> Task_A@1 +DP_Processing@1.5 -[#Orange]> Task_A@1.5 + + +@Task_B +0 is Busy +2 is {-} + +6 is Busy +8 is {-} + +@0 <-> @6: Task B schedule period (6ms) +@6 <-> @8: Task B execution time (2ms) + +DP_Processing@1.5 -[#Brown]> Task_B@0 +DP_Processing@2 -[#Brown]> Task_B@0.5 +DP_Processing@3 -[#Brown]> Task_B@1.5 +DP_Processing@3.5 -[#Brown]> Task_B@2 + +DSP is Idle +DP_Processing is {-} + +@0 +DP_Processing is "A" + +@0 +Interrupt -[#DarkViolet]> DSP +DSP -> DP_Processing +DSP is "Scheduling" +DP_Processing is "A" + +@1 +Interrupt -[#DarkViolet]> DSP +DSP -> DP_Processing +DP_Processing is "A" + +@1.5 +DP_Processing -> DSP +DSP -> DP_Processing +DP_Processing is "B" + +@2 +Interrupt -[#DarkViolet]> DSP +DSP -> DP_Processing +DP_Processing is "B" + +@3 +Interrupt -[#DarkViolet]> DSP +DSP -> DP_Processing +DP_Processing is "B" + +@3.5 +DP_Processing -> DSP +DSP is Idle +DP_Processing is {-} + +@4 +Interrupt -[#DarkViolet]> DSP +DSP is "Scheduling" +DSP -> DP_Processing +DP_Processing is "A" + +@5 +Interrupt -[#DarkViolet]> DSP +DSP -> DP_Processing +DP_Processing is "A" + +@5.5 +DP_Processing -> DSP +DSP is Idle +DP_Processing is {-} + +@6.001 +Interrupt -[#DarkViolet]> DSP +DSP -> DP_Processing +DSP is "Scheduling" +DP_Processing is "B" + +@7.001 +Interrupt -[#DarkViolet]> DSP +DSP -> DP_Processing +DP_Processing is "B" + +@8.001 +Interrupt -[#DarkViolet]> DSP +DSP -> DP_Processing +DP_Processing is "A" + +@9.001 +Interrupt -[#DarkViolet]> DSP +DSP -> DP_Processing +DP_Processing is "A" + +@9.5 +DP_Processing -> DSP +DSP is Idle +DP_Processing is {-} + +@enduml diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/example_LL_DP_timeline.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/example_LL_DP_timeline.pu new file mode 100644 index 00000000..74a91cce --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/example_LL_DP_timeline.pu @@ -0,0 +1,95 @@ +@startuml + +Title Task scheduling on DSP core + +legend +Assumptions: +1) 1ms scheduling +2) 0.1ms takes LL task execution +3) 0.5ms takes execution of all DP tasks +end legend + +scale 1 as 200 pixels + +concise "DP Tasks Processing" as DP_Processing +concise "LL Tasks Processing" as LL_Processing +robust "DSP" as DSP +concise "Timer Interrupt" as Interrupt + +DSP is Idle + +@DSP +@1.2 <-> @2: Time available for\nDP tasks execution +@2.2 <-> @2.7: Actual execution time\nof DP tasks +@3 <-> @3.2: Actual execution time\nof LL tasks + +@Interrupt +@0 <-> @1 : Schedule period + +@0 +Interrupt -> DSP +DSP -> LL_Processing +DSP is "Scheduling tasks" +LL_Processing is Busy +DP_Processing is {-} + +@+0.2 +DSP -> DP_Processing +LL_Processing is {-} +DP_Processing is Busy + +@+0.5 +DP_Processing -> DSP +DP_Processing is {-} +DSP is Idle + +@1 +Interrupt -> DSP +DSP -> LL_Processing +DSP is "Scheduling tasks" +LL_Processing is Busy + +@+0.2 +DSP -> DP_Processing +LL_Processing is {-} +DP_Processing is Busy + +@+0.5 +DP_Processing -> DSP +DP_Processing is {-} +DSP is Idle + +@2 +Interrupt -> DSP +DSP -> LL_Processing +DSP is "Scheduling tasks" +LL_Processing is Busy + +@+0.2 +DSP -> DP_Processing +LL_Processing is {-} +DP_Processing is Busy + +@+0.5 +DP_Processing -> DSP +DP_Processing is {-} +DSP is Idle + +@3 +Interrupt -> DSP +DSP -> LL_Processing +DSP is "Scheduling tasks" +LL_Processing is Busy + +@+0.2 +DSP -> DP_Processing + +LL_Processing is {-} +DP_Processing is Busy + +@+0.5 +DP_Processing -> DSP +DP_Processing is {-} +DSP is Idle + +@enduml diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/example_multiple_cores_timeline.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/example_multiple_cores_timeline.pu new file mode 100644 index 00000000..1aa419e7 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/example_multiple_cores_timeline.pu @@ -0,0 +1,108 @@ +@startuml + +Title Tasks scheduling on multiple DSP cores + +legend +Assumptions: +1) 1ms system tick + +Notes: +2) Core #0 has only LL tasks assigned schedule in 1ms period +3) Core #1 has one DP task assigned that is dependent on Core #0 LL tasks data, scheduled in 1ms period +(e.g. multicore pipeline with DP module scheduled on separate core) +4) Core #2 has LL tasks scheduled in 1ms period and DP task scheduled in 2ms period +(e.g. pipeline processing with LL and DP components components where DP component has 2ms scheduling period) +end legend + +scale 1 as 300 pixels + +concise "DSP #2" as DSP_2 +concise "DSP #1" as DSP_1 +concise "DSP #0" as DSP_0 + +concise "Timer interrupt" as Interrupt + +@DSP_0 +0 is "LL proc." +0.5 is {-} + +1 is "LL proc." +1.5 is {-} + +2 is "LL proc." +2.5 is {-} + +3 is "LL proc." +3.5 is {-} + +4 is "LL proc." +4.5 is {-} + +@0 <-> @1: DSP#0 LL schedule period (1ms) + +@DSP_1 +0 is {-} + +1 is "DP proc." +1.6 is {-} + +2 is "DP proc." +2.6 is {-} + +3 is "DP proc." +3.6 is {-} + +4 is "DP proc." +4.6 is {-} +5 is {-} + +@0 <-> @1: delay one period (waiting for first DSP#0 LL data) +@1 <-> @2: DSP#1 DP schedule period (1ms) + +@DSP_2 + +0 is "LL proc." +0.3 is {-} + +1 is "LL proc." +1.3 is {-} + +2 is "LL proc." +2.3 is "DP proc." + +3 is "LL proc." +3.3 is "DP proc." +3.7 is {-} + +4 is "LL proc." +4.3 is "DP proc." + +@0 <-> @1: DSP#2 LL schedule period (1ms) +@2.3 <-> @4.3: DSP#2 DP schedule period (2ms) + +@0 +Interrupt -[#DarkViolet]> DSP_0 +Interrupt -[#DarkViolet]> DSP_1 +Interrupt -[#DarkViolet]> DSP_2 + +@1 +Interrupt -[#DarkViolet]> DSP_0 +Interrupt -[#DarkViolet]> DSP_1 +Interrupt -[#DarkViolet]> DSP_2 + +@2 +Interrupt -[#DarkViolet]> DSP_0 +Interrupt -[#DarkViolet]> DSP_1 +Interrupt -[#DarkViolet]> DSP_2 + +@3 +Interrupt -[#DarkViolet]> DSP_0 +Interrupt -[#DarkViolet]> DSP_1 +Interrupt -[#DarkViolet]> DSP_2 + +@4 +Interrupt -[#DarkViolet]> DSP_0 +Interrupt -[#DarkViolet]> DSP_1 +Interrupt -[#DarkViolet]> DSP_2 + +@enduml diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/example_task_with_budget.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/example_task_with_budget.pu new file mode 100644 index 00000000..c4b27de9 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/example_task_with_budget.pu @@ -0,0 +1,50 @@ +@startuml + +skinparam maxMessageSize 400 +skinparam BoxPadding 4 + +box "SOF Firmware" #LightBlue + participant "Firmware Manager" + participant "MPP Scheduling" + participant "Zephyr Scheduler" + participant "Zephyr Thread" +end box + +activate "Zephyr Scheduler" + +"Zephyr Scheduler"-> "Zephyr Thread": schedule IPC Task with Budget (TWB) thread\n(MEDIUM_PRIO) +activate "Zephyr Thread" + + "Zephyr Thread"-> "Zephyr Thread": run + "Zephyr Thread"-> "MPP Scheduling": on processing complete + activate "MPP Scheduling" + "MPP Scheduling"-> "Zephyr Thread": k_thread_runtime_stats_get + activate "Zephyr Thread" + return + "MPP Scheduling"-> "MPP Scheduling": update IPC Task with budget\ncycles_consumed_in_sys_tick + return + "Zephyr Thread"-> "Zephyr Thread": suspend TWB Zephyr Thread\n(k_sem_take) +return + +"Zephyr Scheduler"-> "Zephyr Thread": schedule EDF thread\n(LOW_PRIO) +activate "Zephyr Thread" + "Zephyr Thread"-> "Zephyr Thread": run + + activate "Firmware Manager" + "Firmware Manager"-> "Firmware Manager": Host IPC message received + "Firmware Manager"-> "MPP Scheduling": request IPC processing + activate "MPP Scheduling" + "MPP Scheduling"-> "Zephyr Thread": resume IPC TWB Zephyr Thread\n(k_sem_give) + "MPP Scheduling" --> "Firmware Manager" + deactivate "MPP Scheduling" + deactivate "Firmware Manager" + +"Zephyr Thread" --> "Zephyr Scheduler": EDF thread gets preempted +deactivate "Zephyr Thread" + +"Zephyr Scheduler"-> "Zephyr Thread": schedule IPC task with budget thread\n(MEDIUM_PRIO) + activate "Zephyr Thread" + "Zephyr Thread"-> "Zephyr Thread": run + return + +@enduml diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/schedulers_diagram.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/schedulers_diagram.pu new file mode 100644 index 00000000..b7e6895a --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/schedulers_diagram.pu @@ -0,0 +1,60 @@ +@startuml +allowmixing + +scale max 1280 width + +package “RTOS layer” { + + package "SOF kernel extension" as KERNEL_EXTENSION { + package "MPP Scheduling" as MPP_SCHEDULING { + component "LL Tasks" as LL_TASKS + component "DP Tasks" as DP_TASKS + component "Tasks with Budget" as TWB + component "Idle Tasks" as IDLE_TASKS + + LL_TASKS -[hidden]right- DP_TASKS + DP_TASKS -[hidden]right- TWB + TWB -[hidden]right- IDLE_TASKS + } + } + + package "Zephyr" as ZEPHYR_LAYER { + package "Services" as SERVICES { + component "Timing" as TIMING + component "Interrupts" as INTERRUPTS + } + + package "Scheduling" as SCHEDULING { + component "Threads" as THREADS + component "EDF Scheduler" as EDF + component "Time-Slice Scheduler" as TIME_SLICE_SCHEDULING + + THREADS -[hidden]right- EDF + EDF -[hidden]right- TIME_SLICE_SCHEDULING + } + + package "Drivers" as DRIVERS { + component "Timer" as TIMER_DRV + component "Watchdog" as WATCHDOG_DRV + } + + package “SoC HAL” as SOC_HAL { + component "OEM SoC 1" as OEM_SOC_1 + component "OEM SoC 2" as OEM_SOC_2 + component "Other SoCs" as OTHER_SOCS + } + + component "XTHAL" as XTHAL + + SERVICES -[hidden]right- SCHEDULING + SERVICES -[hidden]down- XTHAL + SCHEDULING -[hidden]down- SOC_HAL + SCHEDULING -[hidden]down- DRIVERS + DRIVERS -[hidden]right- SOC_HAL + DRIVERS -[hidden]right- XTHAL + } + + KERNEL_EXTENSION -[hidden]down- ZEPHYR_LAYER +} + +@enduml diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/schedulers_threads_periodic_update.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/schedulers_threads_periodic_update.pu new file mode 100644 index 00000000..5eee1041 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/schedulers_threads_periodic_update.pu @@ -0,0 +1,38 @@ +@startuml + +scale max 1280 width + +skinparam maxMessageSize 400 +skinparam BoxPadding 4 + +box "SOF Firmware" #LightBlue + participant "MPP Scheduling" + participant "Zephyr Thread" + participant "Timer" +end box + +"Timer" -> "MPP Scheduling": sys_tick callback +activate "MPP Scheduling" + +loop for each Task with Budget + "MPP Scheduling"-> "MPP Scheduling": reset task with budget\ncycles_consumed_in_sys_tick + "MPP Scheduling" -> "Zephyr Thread": k_thread_priority_set(thread, MEDIUM_PRIO) + "MPP Scheduling" -> "Zephyr Thread": k_thread_time_slice_set(thread, slice_ticks = budget) + note right: Reset priority and budget\nto default value + "MPP Scheduling"-> "Zephyr Thread": k_thread_runtime_stats_get(thread) + activate "Zephyr Thread" + return return thread_cycles - absolute number of cycles consumed + "MPP Scheduling"-> "MPP Scheduling": save thread_ref_cycles = thread_cycles as a reference +end + +loop for each DP task + opt if DP task is ready for processing + "MPP Scheduling"-> "MPP Scheduling": re-calculate task deadline + "MPP Scheduling" -> "Zephyr Thread": k_thread_deadline_set(thread, deadline) + "MPP Scheduling" -> "Zephyr Thread": resume thread + end +end + +deactivate "MPP Scheduling" + +@enduml diff --git a/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/schedulers_zephyr.pu b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/schedulers_zephyr.pu new file mode 100644 index 00000000..834b28c4 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/images/mpp_scheduling/schedulers_zephyr.pu @@ -0,0 +1,88 @@ +@startuml + +scale max 1280 width + +skinparam maxMessageSize 400 +skinparam BoxPadding 4 + +box "SOF" #LightBlue + participant "MPP Scheduling" + participant "Zephyr Scheduler" + participant "Zephyr Thread" + participant "Timer" +end box + +"Timer" -> "MPP Scheduling": sys_tick callback +activate "MPP Scheduling" + loop for each core + "MPP Scheduling"-> "Zephyr Scheduler": resume LL Zephyr Thread\n(k_sem_give) + activate "Zephyr Scheduler" + end + + "MPP Scheduling"-> "MPP Scheduling": DP and Task with Budget\nZephyr Threads update + +"Zephyr Scheduler"-> "Zephyr Thread": schedule LL Zephyr Thread\n(context switch) + deactivate "MPP Scheduling" + activate "Zephyr Thread" + "Zephyr Thread"-> "Zephyr Thread": zephyr_ll_run + activate "Zephyr Thread" + + loop for each LL pending task + note left: LL pending tasks are scheduled operations\nthat are waiting for certain circumstances\n(like data arrival) to start processing + opt if task is ready for processing + "Zephyr Thread"-> "Zephyr Thread": move task \nto LL run queue + end + end + + loop for each task in LL queues + "Zephyr Thread"-> "Zephyr Thread": run LL task callback + end + return + + "Zephyr Thread"-> "Zephyr Thread": suspend LL Zephyr Thread\n(k_sem_take) + return + +loop for each Task With Budget (TwB) Zephyr Thread + "Zephyr Scheduler"-> "Zephyr Thread": schedule TwB Zephyr Thread\n(context switch) + activate "Zephyr Thread" + "Zephyr Thread"-> "Zephyr Thread": run + + alt if time_slice (budget) timeout + "Zephyr Thread"-> "Zephyr Scheduler": time_slice timeout + "Zephyr Scheduler"-> "MPP Scheduling": time_slice callback(thread) + activate "MPP Scheduling" + "MPP Scheduling"-> "Zephyr Thread": k_thread_priority_set(thread, LOW_PRIO) + note right: when budget is consumed\nreset time_slice to default\nand lower priority + "MPP Scheduling"-> "Zephyr Thread": k_thread_time_slice_set(thread, slice_ticks = budget) + deactivate "MPP Scheduling" + + else if processing complete (no time_slice timeout) + "Zephyr Thread"-> "MPP Scheduling": on processing complete (thread) + activate "MPP Scheduling" + "MPP Scheduling"-> "Zephyr Thread": k_thread_runtime_stats_get(thread) + activate "Zephyr Thread" + return return thread_cycles - absolute number of cycles consumed by thread + "MPP Scheduling"->"MPP Scheduling": update thread\ncycles_consumed_in_sys_tick += (thread_cycles - thread_ref_cycles) + note right: thread_ref_cycles is a reference number of cycles consumed by thread\nupdated on each sys_tick start and processing complete + "MPP Scheduling"->"MPP Scheduling": update thread_ref_cycles = thread_cycles + return + deactivate "MPP Scheduling" + + "Zephyr Thread" -> "Zephyr Thread": suspend TwB Zephyr Thread\n(k_sem_take) + note left: TwB Threads are expected to be resumed when there is new data for processing\nfor example IPC TwB Thread will be resumed on IPC interrupt + "Zephyr Thread" --> "Zephyr Scheduler" + deactivate "Zephyr Thread" + end +end + +loop for each DP Zephyr Thread + "Zephyr Scheduler"-> "Zephyr Thread": schedule DP Zephyr Thread with earlieast deadline\n(context switch) + note right: TwB Threads with low priority are treated\nas threads with max deadline and will be\nscheduled after DP threads complete processing + activate "Zephyr Thread" + "Zephyr Thread"-> "Zephyr Thread": run + note right: DP thread runs till completion\nor till earlier deadline or\nhigher priority thread is available + return + deactivate "Zephyr Thread" +end + +@enduml diff --git a/architectures/firmware/sof-zephyr/mpp_layer/index.rst b/architectures/firmware/sof-zephyr/mpp_layer/index.rst new file mode 100644 index 00000000..b8542887 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/index.rst @@ -0,0 +1,17 @@ +.. _mpp_layer: + +Media Processing Pipelines Layer +################################ + +The Media Processing Pipelines (MPP) is a FW infrastructure layer independent to +the HW. The MPP components serve as kernel services extension that is available +to the Application layer. + +.. toctree:: + :maxdepth: 1 + + mpp_overview + mpp_scheduling + async_messaging + lib_manager + dp_scheduling \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/mpp_layer/lib_manager.rst b/architectures/firmware/sof-zephyr/mpp_layer/lib_manager.rst new file mode 100644 index 00000000..0bb4bccf --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/lib_manager.rst @@ -0,0 +1,58 @@ +.. _lib_manager: + +Loadable Library Manager +######################## + +The Loadable Library Manager is a MPP Layer component responsible for loading +and running loadable components provided in external libraries. It supports SOF +native components as well as IADK cAVS/ACE developed modules through +:doc:`../../intel/ace/iadk_modules`. + +Loading an external library is a feature available only for IPC4 protocol with +command: `SOF_IPC4_GLB_LOAD_LIBRARY`. + +.. uml:: images/lib_manager/library_manager_load.pu + :caption: Library Manager: Load library flow + +In the `SOF_IPC4_GLB_LOAD_LIBRARY` IPC flow the ``lib_manager_load_library()`` api +function loads binary from host driver to DSP memory and updates its internal +structure with library descriptor data. If ``AUTH_API`` Kconfig option is +selected, library manager communicates with platform ROM Extension library to +perform library image verification. In that case only trusted libraries will be +successfully loaded. + +**NOTE:** ``AUTH_API`` Kconfig option is available only for Intel platforms. + +During the `SOF_IPC4_MOD_INIT_INSTANCE` IPC4 protocol call, handler searches +for specific module among build-in components and if not found, verifies +manifests of all already loaded external libraries. When module is found in +external library, it is registered in SOF Firmware ``struct comp_driver_list`` +with ``lib_manager_register_module()`` api function and loaded from L3 memory to +L2 memory. Afterwards module is created with standard component device +operation. + +**NOTE:** If L3 memory is not available, the L2 memory has to be used and there +is no memory load operation required. + +.. uml:: images/lib_manager/library_manager_init_instance.pu + :caption: Init instance flow for loadable module + +External libraries could contain not only processing modules but also shared +library code that could be reused across several external modules. The library +manager searches external library manifest for such entities and loads them +together with first processing module loaded. + +When an external processing module is no longer needed, it could be unloaded +with the IPC4 call `SOF_IPC4_MOD_DELETE_INSTANCE`. The command performs reverse +flow to the previous one. It frees L2 SRAM memory allocated for the processing +module and if it is last one unloaded from given library, it frees also +resources used for all shared libraries loaded previously. + +.. uml:: images/lib_manager/library_manager_delete_instance.pu + :caption: Delete instance flow for loadable module + +In `SOF_IPC4_MOD_INIT_INSTANCE` and `SOF_IPC4_MOD_DELETE_INSTANCE` flows, +particular module could be loaded in more than one instance. Its `.text` and +`.rodata` memory sections are allocated only for the first instance and shared +for all other instances. Also the `.text` and `.rodata` resources are released +only for the last instance of given processing module. diff --git a/architectures/firmware/sof-zephyr/mpp_layer/mpp_overview.rst b/architectures/firmware/sof-zephyr/mpp_layer/mpp_overview.rst new file mode 100644 index 00000000..955a3781 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/mpp_overview.rst @@ -0,0 +1,94 @@ +.. _mpp_layer_overview: + +Media Processing Pipelines Overview +################################### + +The Media Processing Pipelines (MPP) layer role is to enable SOF specific use +cases that are not supported directly by Zephyr. The MPP is responsible for host +communication, tasks scheduling, pipeline and component management. + +.. uml:: images/mpp_layer_diagram.pu + :caption: Media Processing Pipelines Layer diagram + +Services in Media Processing Pipelines Layer +******************************************** + +Gateways +======== + +The gateways are a key element in SOF data exchange with host, external audio +peripherals and internally between firmware components. They serve as an +abstraction layer for multiple data protocols. + +The typical audio stream (chain of pipelines) starts and ends with I/O gateway. +I/O gateway represents a sink or a source interface that can be read or written +via DMA operations on I/O FIFO (i.e. DMIC, SNDW, etc.) or directly via memory +operations (i.e. memory buffers of IPC Gateway). Host Gateway is unique as it +exposes interface endpoint to the Host driver. + +The stream audio gateways are created as a part of Copier component +configuration. + +.. TODO: Add link to Copier detailed description + +Examples of gateways: + +- DMIC Gateway, +- SoundWire Gateway, +- I2S Gateway, +- HD/A Gateway, +- IPC Gateway, + +.. TODO: Add link to Gateways detailed specification. + +*NOTE:* Not all I/O gateways must be available in all configurations. + +Pipeline Management +=================== + +The Pipeline Management is a host IPC driven service that is used to: + +- create / delete pipeline +- switch pipeline state +- create pipeline processing tasks +- allocate pipeline buffers memory + +.. TODO: Add link to Pipeline Management IPC interface. + +Processing Component Management +=============================== + +Processing Component Management is driven by host IPC requests. It is used to: + +- instantiate / delete components +- configure components +- bind / unbind components into processing paths +- load components into ADSP memory + +.. TODO: Add link to Component Management IPC interface. + +Asynchronous Messaging +====================== + +Asynchronous Messaging Service (AMS) provides functionality to: + +- send asynchronous messages to firmware components or host, +- broadcast messages to multiple consumers, +- asynchronous message exchange between components running on different cores + +.. TODO: Add link to Asynchronous Messaging Service detailed description + +MPP Scheduling +============== + +MPP Scheduling is dedicated to support Media Processing Pipelines services tasks +scheduling. It exposes SOF specific interface that is implemented on top of +Zephyr scheduling API. + +MPP Scheduling features: + +- Low Latency tasks scheduling, +- Data Processing tasks scheduling, +- Tasks with budget scheduling + +.. TODO: Add link to MPP Scheduling detailed description diff --git a/architectures/firmware/sof-zephyr/mpp_layer/mpp_scheduling.rst b/architectures/firmware/sof-zephyr/mpp_layer/mpp_scheduling.rst new file mode 100644 index 00000000..c4ff5631 --- /dev/null +++ b/architectures/firmware/sof-zephyr/mpp_layer/mpp_scheduling.rst @@ -0,0 +1,302 @@ +.. _sof-zephyr_mpp_scheduling: + +MPP Scheduling +############## + +This section describes MPP scheduling flows, task types and their usage in SOF +based on Zephyr API. + +MPP Scheduling defines four task categories: + +- Low Latency audio data processing tasks (LL) - high priority, +- Tasks with Budget (TwB) - medium priority, +- audio Data Processing tasks (DP) - low priority, +- background (idle) priority tasks + +**NOTE:** As of today, only LL tasks has been integrated with Zephyr. TwB, DP +and idle tasks are work in progress (WIP). + +The role of MPP Scheduling is limited to task threads definition, configuration +and state management. The thread scheduling itself is handled by Zephyr. + +MPP Scheduling is designed to: + +- address strict real-time requirements, + + - i.e. to avoid under/overflows on isochronous interfaces such as + I2S, + +- provide predictable latency, +- reduce amount of buffering needed, + +MPP Scheduling defines two tasks categories: + +Task categories characteristic: + +- LL tasks for latency sensitive audio data processing, + + - LL tasks are organized in queues shared between component instances, + - there is one non-preemptive high priority LL Thread assigned to exactly + one core. For example, for HW configuration with 4 cores there will be 4 + LL Threads, + - each queue is statically linked to one LL Thread and all queue tasks will + be processed on a core that LL Thread is assigned to, + - there are multiple queues per LL Thread which represent a priority and + guarantee tasks execution order, + +.. TODO: Add LL tasks, Threads and queues relation diagram, + +- TwB for medium priority processing (e.g., IPC/IDC message handling), + + - each TwB is scheduled as a separate preemptive thread, + - TwB has assigned budget for processing that is refreshed in each sys tick + (`Zephyr Thread time slicing + `__), + - TwB priority is dropped to low when budget is consumed, + +- DP tasks for low priority audio processing, + + - DP tasks are scheduled based on earliest deadline first (EDF) algorithm, + - each DP task is scheduled as a separate preemptive thread, + - DP tasks can be assigned to one of the available cores, + +- idle tasks for background processing, + + - idle tasks are scheduled as separate preemptive threads, + - they have the lowest priority and are scheduled when all other tasks + completed their processing, + - they are used in Fast Mode. For example, in data draining from firmware to + host. + +**NOTE:** Each task is assigned by MPP Scheduling to one core. Tasks are +executed by the assigned core till termination. + +**NOTE:** For Earliest Deadline First (EDF) algorithm description, please refer +to link: +`Wikipedia `__. + +**NOTE:** For Zephyr Scheduling description, please refer to link: +`Zephyr +Scheduling `__. + +.. uml:: images/mpp_scheduling/schedulers_diagram.pu + :caption: SOF MPP Scheduling based on Zephyr + +LL Tasks +******** + +Low Latency Tasks are executed within one of the non-preemptive high priority LL +Threads that runs all ready-to-run tasks till completion during a single cycle. +There is one LL Thread scheduled per core with its own queues and LL tasks to +execute. + +MPP Scheduling adds ready tasks to LL queues at the beginning of each scheduling +period. There are a number of queues to add tasks to. LL Thread iterates over +the queues, and runs all tasks from one queue before moving to the next queue. +Therefore, it is possible to guarantee that some tasks are always run before +others during a cycle. + +There are also two special queues: pre-run queue and post-run queue. Tasks from +pre-run queue are run at the beginning of each cycle (may consider them to have +the highest priority). + +Tasks from post-run queue are run at the end of each cycle (may consider them to +have the lowest priority). + +Example of a pre-run task may be a task registered by the sink driver that +starts the sink at the very beginning of the cycle if data was supplied during +the previous cycles and link has been stopped. + +.. TODO: Evaluate option to add time slice limit for LL thread (set limit it to + 90% to not starve potential IPC communication tasks) + +DP Tasks +******** + +The data processing components are represented as a DP tasks that are scheduled as +separate preemptive threads. DP threads scheduling is done according to EDF +(Earliest Deadline First) algorithm that is part of Zephyr. + +To meet real-time processing criteria algorithm operates by choosing component task +that is closest to its deadline (time when output data is required). + +For playback case algorithm starts from sink and going backward calculates +deadline for data delivery: + + * Time required by component to process data depend on processing period and compute. + * Goal is to process data through chain before real-time sink deadline + +EDF scheduling example + +.. blockdiag:: images/mpp_scheduling/edf_scheduling.diag + +The capture pipelines operate in the same way. + +It is important to consider that EDF assumes preemptive scheduling of the DP +Tasks and lack of dependency between them. + +Task With Budget +**************** + +This is a specialized version of DP task that has pre-allocated MCPS budget +renewed with every system tick. When the task is ready to run, then depending on +the budget left in the current system tick, either MEDIUM_PRIORITY or +LOW_PRIORITY is assigned to task thread. The latter allows for opportunistic +execution if there is no other ready task with a higher priority while the +budget is already spent. + +Examples of tasks with budget: Ipc Task, Idc Task. + +Task with Budget (TWB) has two key parameters assigned: + +- *cycles granted*: the budget per system tick, +- *cycles consumed*: number of cycles consumed in a given system_tick + for task execution + +The number of cycles consumed is being reset to 0 at the beginning of each +system_tick, renewing TWB budget. When the number of cycles consumed exceed +cycles granted, the task is switched from MEDIUM to LOW priority. When the task +with budget thread is created the MPP Scheduling is responsible to set thread +time slice equal to task budget along with setting callback on time slice +timeout. Thread time slicing guarantee that Zephyr scheduler will interrupt +execution when the budget is spent, so MPP Scheduling timeout callback can +re-evaluate task priority. + +If there is a budget left in some system tick (task spent less time or started +executing close to the system tick that preempts execution), it is reset and not +carried over to the next tick. + +**NOTE** The Zephyr Scheduler track time slice budget of the TWB when preempted +and log warning if the budget is significantly exceeded (some long critical +section inside the task’s code might be responsible for this). + +**NOTE** The MPP Scheduling must be notified by TWB on processing complete and +update cycles consumed in the current system tick. This allows to schedule TWB +more than once (if necessary) in the single system tick with MEDIUM_PRIORITY. +The second TWB schedule should be done with modified time slice value, equal to +delta between budget and cycles consumed. + +Scheduling flows +**************** + +Zephyr scheduling +================= + +The presented Zephyr scheduling flow takes place on each core that has +MPP tasks scheduled. + +.. uml:: images/mpp_scheduling/schedulers_zephyr.pu + :caption: Zephyr scheduling of MPP threads flow + + +MPP Data Processing and Task with Budget threads periodic update +================================================================ + +Zoom in to Data Processing (Earliest Deadline First) and Task with Budget +Threads periodic update operations on each system tick start. + +.. uml:: images/mpp_scheduling/schedulers_threads_periodic_update.pu + :caption: DP and TWB threads sys tick update flow + + +Task with budget scheduling +=========================== + +.. uml:: images/mpp_scheduling/example_task_with_budget.pu + :caption: Task with budget example scheduling flow + + +Example timeline of MPP Scheduling on a DSP core +================================================= + +The below diagram shows how scheduling looks like on a DSP core. At the timer +interrupt, LL scheduler runs as the first one and then DP scheduler is executed. + +.. uml:: images/mpp_scheduling/example_LL_DP_timeline.pu + :caption: Example timeline of MPP Scheduling on DSP core with LL and DP tasks scheduling + + +Example timeline of DP tasks scheduling on secondary DSP core +============================================================== + +The below diagram shows a detailed example of how DP tasks are scheduled +on the secondary DSP core. + +.. uml:: images/mpp_scheduling/example_DP_secondary_core_timeline.pu + :caption: Example of DP tasks scheduling on secondary DSP core + + +Example timeline of MPP scheduling on multiple DSP cores +======================================================== + +The below diagram shows how scheduling looks like on many DSP cores. The DP task +deadlines are reevaluated on each core in Timer sys tick callback. + +.. uml:: images/mpp_scheduling/example_multiple_cores_timeline.pu + :caption: Example of MPP Scheduling on many cores - LL and DP tasks scheduling + +Fast Mode +********* + +The Fast Mode is used to process data faster than real time. The processing +faster than real time is only needed for a short time period and it happens i.e. +when firmware performs low power Wake on Voice. In such case SOF firmware is +working in low power mode, performing i.e. key phrase detection algorithm, +accumulating last few seconds of audio samples in history buffer. When a key +phrase detection happens, there is a need to stream the accumulated history to +Host as quickly as possible with optional additional processing on DSP. It is +only possible when a sink interface to Host transfer burst of data from DSP. + +The Fast Mode is an idle low priority task. The task is only executed when other +DP tasks with deadlines has completed their processing and there is still enough +DSP cycles before a next system tick. + +When the Fast Mode task is created by i.e. History Buffer, the component +instance (i.e. History Buffer) needs to provide a list of LL component instances +that will be executed within a Fast Mode thread, similar as it is done with LL +tasks queues and LL Thread. When the Fast Mode thread is executed it will +trigger processing of LL components in similar way as LL Thread does. The Fast +Mode task is executed in the critical section. It will check if there is data +available in an input queue and there is enough space in an output queue. Only +then it will execute a LL component. What is important to note is that the Fast +Mode task does not call processing on the DP components directly. + +As described in the previous sections, the processing on DP components is called +according to EDF algorithm. A periodicity of a component processing is +determined by time needed to fill an input queue using real time source of data. +When an input queue has sufficient amount of data, the processing on DP +component can be called. The input queues for DP components that are on the Fast +Mode task path will be filling much faster than real time as the side effect of +the Fast Mode task execution - LL components will move data to DP component +input queue and out of DP component output queue. As the result, DP component +can be executed much earlier than real time - a DSP task reports “ready to run” +as soon as it has sufficient amount of data in input queue and output queue has +enough space for produced frame. That can lead to starvation of other tasks and +to prevent it a Fast Mode tasks must be scheduled as idle tasks in background. + +Watchdog timer +************** + +Depending on HW configuration there can be a single watchdog timer, watchdog +available for each DSP core or none. + +All DSP cores shall enable watchdog when they are active to monitor health of +subsystem. When one of watchdogs will expire, the entire subsystem will be reset +by Host. + +Watchdog shall be enabled when: + +- DSP core is enabled, +- tasks are assigned to DSP core, + +Watchdog shall be disabled when: + +- DSP core is disabled, +- no tasks are assigned to DSP core, +- DSP core goes to low power state, + +Watchdog timer shall be programmed to value of a few scheduling periods. + +Watchdog timer when enabled shall be updated at every system tick. In case of +primary DSP core, it should be after running LL tasks. In case of secondary HP +DSP cores, it should be on system tick end. \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/overview.rst b/architectures/firmware/sof-zephyr/overview.rst new file mode 100644 index 00000000..e9969e29 --- /dev/null +++ b/architectures/firmware/sof-zephyr/overview.rst @@ -0,0 +1,12 @@ +.. _sof-zephyr-overview: + +Overview +######## + +New SOF firmware architecture is based on Zephyr RTOS and introduce new IPC4 +Host protocol ABI. In result FW has been re-organized into layers. The +interaction between the components across the layers is limited to the +internally defined interfaces. + +.. uml:: images/overview_diagram.pu + :caption: SOF with Zephyr Architecture overview diff --git a/architectures/firmware/sof-zephyr/rtos_layer/images/kernel_services.pu b/architectures/firmware/sof-zephyr/rtos_layer/images/kernel_services.pu new file mode 100644 index 00000000..f1d19987 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/images/kernel_services.pu @@ -0,0 +1,57 @@ +@startuml +allowmixing + +scale max 1280 width + +package "SOF" { + package "Kernel Infrastructure" { + interface "Zephyr System Services" as SS + + package "Services" { + component "Memory Manager" as MEMORY_MANAGER + component "Power Manager" as POWER_MANAGER + component "IPC/IDC" as IXC + component "Logging" as LOGGING + component "Debug" as DEBUG + component "Interrupt Handler" as INTERRUPT_HANDLER + } + + SS .down. MEMORY_MANAGER + SS .down. POWER_MANAGER + SS .down. IXC + SS .down. LOGGING + SS .down. DEBUG + SS .down. INTERRUPT_HANDLER + } + + package "Kernel Extension" { + interface "Extended System Services" as ESS + + component "AVS Scheduling" as AVS_Scheduling + + package "Extended Services" as EXTENDED_SERVICES { + component "Firmware Manager" as FIRMWARE_MANAGEMENT + component "Pipeline Management" as PIPELINE_MANAGEMENT + component "Async Messaging" as ASYNC_MESSAGING + component "Processing Component Management" as COMPONENT_MANAGEMENT + component "IPC Message Processing" as IPC_MESSAGE_PROCESSING + } + + ESS .down. FIRMWARE_MANAGEMENT + ESS .down. PIPELINE_MANAGEMENT + ESS .down. ASYNC_MESSAGING + ESS .down. IPC_MESSAGE_PROCESSING + ESS .down. COMPONENT_MANAGEMENT + + AVS_Scheduling -[hidden]down- EXTENDED_SERVICES + } + + package "Loadable modules" { + component "WoV" as WOV + + WOV .down. SS + WOV .down. ESS + } +} + +@enduml \ No newline at end of file diff --git a/architectures/firmware/sof-zephyr/rtos_layer/images/power/dsp_fw_power_states.pu b/architectures/firmware/sof-zephyr/rtos_layer/images/power/dsp_fw_power_states.pu new file mode 100644 index 00000000..c864c743 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/images/power/dsp_fw_power_states.pu @@ -0,0 +1,14 @@ +@startuml +hide empty description + +state "D0 / D0ix" as D0 { + [*] --> PM_STATE_ACTIVE: Initialization + PM_STATE_ACTIVE -> PM_STATE_RUNTIME_IDLE + PM_STATE_RUNTIME_IDLE -> PM_STATE_ACTIVE + PM_STATE_ACTIVE --> [*] +} + +[*] --> D0: Go to D0 / Power DSP on +D0 --> [*]: Go to D3 / Power DSP Off + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/images/power/dx_state_transitions.pu b/architectures/firmware/sof-zephyr/rtos_layer/images/power/dx_state_transitions.pu new file mode 100644 index 00000000..1a1870b2 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/images/power/dx_state_transitions.pu @@ -0,0 +1,10 @@ +@startuml + +[*] --> D3 +D3 --> D0 +D0 --> D0ix: SET_D0ix(wake = 0) +D0ix --> D0: SET_D0ix(wake = 1) +D0ix --> D3: ENTER_DX_STATE +D0 --> D3: ENTER_DX_STATE + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_disable_d0i3.pu b/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_disable_d0i3.pu new file mode 100644 index 00000000..9279b09d --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_disable_d0i3.pu @@ -0,0 +1,19 @@ +@startuml + +box "Host" #LightSkyBlue + participant "Driver" as DRIVER +end box + +box "SOF" #LightBlue + participant "Core #0: Zephyr lib" as sof_zephyr_lib + participant "Zephyr Power Manager" as zephyr_power_manager +end box + +DRIVER -> sof_zephyr_lib: SET_D0ix(prevent_power_gating = 1) IPC request +activate sof_zephyr_lib + sof_zephyr_lib -> zephyr_power_manager: pm_policy_state_lock_get\n(PM_STATE_RUNTIME_IDLE) + activate zephyr_power_manager + return +return SET_D0ix IPC response + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_dsp_idle.pu b/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_dsp_idle.pu new file mode 100644 index 00000000..123751e5 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_dsp_idle.pu @@ -0,0 +1,41 @@ +@startuml + +box "SOF" #LightBlue + participant "Core #N: Zephyr lib" as sof_zephyr_lib + participant "Zephyr Power Manager" as zephyr_power_manager + participant "Zephyr SoC HAL" as soc_hal +end box + +box "Hardware" #LightGreen + participant "Core #N: Control" as core_hw_control +end box + +opt When Core is Idle + + zephyr_power_manager -> sof_zephyr_lib: pm_policy_next_state (PID: Core #N, ticks) + activate sof_zephyr_lib + activate zephyr_power_manager + sof_zephyr_lib -> zephyr_power_manager: pm_policy_state_lock_get\n(PM_STATE_RUNTIME_IDLE) + activate zephyr_power_manager + return + alt if no lock on D0ix state + return PM_STATE_RUNTIME_IDLE + else if there is lock on D0ix state + return PM_STATE_ACTIVE + end + + zephyr_power_manager -> soc_hal: pm_power_state_set\n(power_state, PID: Core #N) + activate soc_hal + alt If power_state is PM_STATE_IDLE + soc_hal -> soc_hal: arch_clear_power_gating_prevent (Core #N) + soc_hal -> core_hw_control: Clear power gating prevent + else if PM_STATE_RUNTIME_ACTIVE + soc_hal -> soc_hal: arch_set_power_gating_prevent (Core #N) + soc_hal -> core_hw_control: Set power gating prevent + end + return + + deactivate zephyr_power_manager +end + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_enable_d0i3.pu b/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_enable_d0i3.pu new file mode 100644 index 00000000..70b3ea8b --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_enable_d0i3.pu @@ -0,0 +1,29 @@ +@startuml + +box "Host" #LightSkyBlue + participant "driver" as driver +end box + +box "SOF" #LightBlue + participant "Core #0: Zephyr lib" as sof_zephyr_lib + participant "Zephyr Power Manager" as zephyr_power_manager +end box + +driver -> sof_zephyr_lib: SET_D0ix(prevent_power_gating = 0) IPC request +activate sof_zephyr_lib + sof_zephyr_lib -> zephyr_power_manager: pm_policy_state_lock_put\n(PM_STATE_RUNTIME_IDLE) + activate zephyr_power_manager + return + sof_zephyr_lib -> zephyr_power_manager: pm_policy_state_lock_is_active\n(PM_STATE_RUNTIME_IDLE) + activate zephyr_power_manager + return + + alt if D0ix is still locked + sof_zephyr_lib --> driver: return ERROR + note right: Zephyr PM Policy can be used concurrently\nand there can be more then one lock\non D0ix state + else + sof_zephyr_lib --> driver: return SUCCESS + end + + deactivate sof_zephyr_lib +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_primary_core_power_down.pu b/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_primary_core_power_down.pu new file mode 100644 index 00000000..c904de25 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_primary_core_power_down.pu @@ -0,0 +1,56 @@ +@startuml + +scale max 1280 width + +box "Host" #LightSkyBlue + participant "driver" as driver +end box + +box "SOF" #LightBlue + participant "Core #0: Zephyr lib" as sof_zephyr_lib_0 + participant "Zephyr Power Manager" as zephyr_power_manager + participant "Zephyr SoC HAL" as soc_hal +end box + +box "Hardware" #LightGreen + participant "Core #0: Control" as core_hw_control +end box + +opt If D0ix is enabled + driver -> sof_zephyr_lib_0: SET_D0ix(prevent D0ix) IPC request + activate sof_zephyr_lib_0 + sof_zephyr_lib_0 -> zephyr_power_manager: pm_policy_state_lock_get\n(PM_STATE_RUNTIME_IDLE) + activate zephyr_power_manager + return + return +end + +== DSP FW in PM_STATE_ACTIVE == + +driver -> sof_zephyr_lib_0: SET_DX(PID: Core #0, D3) IPC request +activate sof_zephyr_lib_0 + sof_zephyr_lib_0 -> zephyr_power_manager: Read status of secondary cores + activate zephyr_power_manager + return + + alt If any secondary core is powered up + sof_zephyr_lib_0 --> driver: SET_DX(ERROR) IPC response + else else + sof_zephyr_lib_0 -> zephyr_power_manager: pm_power_state_force\n(PM_STATE_SOFT_OFF, PID: Core #0) + activate zephyr_power_manager + zephyr_power_manager -> soc_hal: pm_power_state_set\n(PM_STATE_SOFT_OFF, PID: Core #0) + activate soc_hal + soc_hal -> soc_hal: Save context + soc_hal -> soc_hal: Prepare restore vector + return + return + +return SET_DX(SUCCESS) IPC response +end + +driver -> core_hw_control: clear power register +loop Until Core #0 power is down + driver -> core_hw_control: Read Core #0 power bit +end + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_secondary_core_boot.pu b/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_secondary_core_boot.pu new file mode 100644 index 00000000..dc8704e9 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_secondary_core_boot.pu @@ -0,0 +1,48 @@ +@startuml + +box "Host" #LightSkyBlue + participant "driver" as driver +end box + +box "SOF" #LightBlue + participant "Core #0: Zephyr lib" as sof_zephyr_lib_0 + participant "Core #1: FW Init" as fw_init_1 + participant "Zephyr Power Manager" as zephyr_power_manager + participant "Zephyr SoC HAL" as soc_hal +end box + +box "Hardware" #LightGreen + participant "Core #1: Control" as core_control_1 +end box + +opt If D0ix is enabled + driver -> sof_zephyr_lib_0: SET_D0ix(prevent D0/D0ix) IPC request + activate sof_zephyr_lib_0 + sof_zephyr_lib_0 -> zephyr_power_manager: pm_policy_state_lock_get\n(PM_STATE_RUNTIME_IDLE) + activate zephyr_power_manager + return + return +end + +== DSP FW in PM_STATE_ACTIVE == + +driver -> sof_zephyr_lib_0: SET_DX(PID: Core #1, D0) IPC request +activate sof_zephyr_lib_0 + sof_zephyr_lib_0 -> soc_hal: arch_start_cpu(PID: Core #1) + activate soc_hal + soc_hal -> core_control_1: Set alternate boot vector to FW Init + note right: Cores share the \nsame FW binary\nand the firmware must be\npresent in SRAM. + soc_hal -> core_control_1: Set SPA bit + + core_control_1 -> fw_init_1: Start and jump to alternate boot vector + activate fw_init_1 + fw_init_1 -> fw_init_1: Restore context\nif any saved + + loop Until Core #1 is enabled + soc_hal -> core_control_1: read power register + end + deactivate fw_init_1 + return +return + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_secondary_core_power_down.pu b/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_secondary_core_power_down.pu new file mode 100644 index 00000000..05d6c6c8 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/images/power/flow_secondary_core_power_down.pu @@ -0,0 +1,56 @@ +@startuml + +scale max 1280 width + +box "Host" #LightSkyBlue + participant "driver" as driver +end box + +box "SOF" #LightBlue + participant "Core #0: Zephyr lib" as sof_zephyr_lib_0 + participant "Zephyr Power Manager" as zephyr_power_manager + participant "Zephyr SoC HAL" as soc_hal +end box + +box "Hardware" #LightGreen + participant "Core #1: Control" as core_1_control +end box + +opt If D0ix is enabled + driver -> sof_zephyr_lib_0: SET_D0ix(prevent D0ix) IPC request + activate sof_zephyr_lib_0 + sof_zephyr_lib_0 -> zephyr_power_manager: pm_policy_state_lock_get\n(PM_STATE_RUNTIME_IDLE) + activate zephyr_power_manager + return + return +end + +== DSP FW in PM_STATE_ACTIVE == + +driver -> sof_zephyr_lib_0: SET_DX(PID: Core #1, D3) IPC request +activate sof_zephyr_lib_0 + sof_zephyr_lib_0 -> zephyr_power_manager: pm_power_state_force\n(PM_STATE_SOFT_OFF, PID: Core #1) + activate zephyr_power_manager + zephyr_power_manager -> soc_hal: pm_power_state_set\n(PM_STATE_SOFT_OFF, PID: Core #1) + activate soc_hal + soc_hal -> soc_hal: Save context to IMR + return + deactivate zephyr_power_manager + + loop Until Core #1 transition to PM_STATE_SOFT_OFF + sof_zephyr_lib_0 -> zephyr_power_manager: pm_power_state_get(PID: Core #1) + activate zephyr_power_manager + return + end + + sof_zephyr_lib_0 -> soc_hal: arch_stop_cpu(PID: Core #1) + activate soc_hal + soc_hal -> core_1_control: clear power bit + loop Until Core #1 is disabled + soc_hal -> core_1_control: read power register + end + return + +return SET_DX(SUCCESS) IPC response + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/images/power/power_components.pu b/architectures/firmware/sof-zephyr/rtos_layer/images/power/power_components.pu new file mode 100644 index 00000000..f111ae24 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/images/power/power_components.pu @@ -0,0 +1,30 @@ +node sw_driver [ + SW Driver + * DSP power control over IPC protocol +] + +node fw [ + SOF Zephyr Library + + * Exposes interface of SOF with XTOS for Host Power IPC handling + * Executes requested sequence of Zephyr power operations + * Waits and verifies power request completion + + --- + Zephyr Power Management + Generic RTOS Power Management service + + * Manages System Power States + * Manages Power Policies + * Manages Device Runtime Power + + --- + SoC HAL + Hardware specific power control + + * Moves SoC and its resources to power state requested by Zephyr + * Interacts directly with hardware and power registers + * Suppors different power states depending on the target SoC +] + +sw_driver -down-> fw : <> Set Dx - power state transition D0/D3\n<> Set D0ix - power gating override (on/off) diff --git a/architectures/firmware/sof-zephyr/rtos_layer/images/zephyr_kernel_diagram.pu b/architectures/firmware/sof-zephyr/rtos_layer/images/zephyr_kernel_diagram.pu new file mode 100644 index 00000000..f7bf622a --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/images/zephyr_kernel_diagram.pu @@ -0,0 +1,124 @@ +@startuml +allowmixing + +scale max 1280 width + +package "Kernel space" { + + package "Media Processing Pipelines - kernel extension" as MPP_KERNEL_EXTENSION { + interface "Extended System Services" as ESS + + component "Firmware Manager" as FIRMWARE_MANAGER + + package "Communication" as COMMUNICATION { + component "IPC Message Processing" as IPC_MESSAGE_PROCESSING + component "Async Messaging" as ASYNC_MESSAGING + + IPC_MESSAGE_PROCESSING -[hidden]right- ASYNC_MESSAGING + } + + package "Pipeline/Component Infrastructure" as PIPELINE_COMPONENT_INFRASTRUCTURE { + component "Pipeline Management" as PIPELINE_MANAGEMENT + component "Host/DAI Gateways" as HOST_DAI_GATEWAYS + component "Processing Component Management" as PROCESSING_COMPONENT_MANAGEMENT + + PIPELINE_MANAGEMENT -[hidden]right- HOST_DAI_GATEWAYS + HOST_DAI_GATEWAYS -[hidden]right- PROCESSING_COMPONENT_MANAGEMENT + } + + package "AVS Scheduling" as AVS_SCHEDULING { + component "Data Processing (DP) Tasks (EDF based)" as DP_TASKS + component "Low Latency (LL) Tasks" as LL_TASKS + + DP_TASKS -[hidden]right- LL_TASKS + } + + FIRMWARE_MANAGER -[hidden]right- PIPELINE_COMPONENT_INFRASTRUCTURE + FIRMWARE_MANAGER -[hidden]down- COMMUNICATION + COMMUNICATION -[hidden]right- AVS_SCHEDULING + + ESS -[hidden]down- FIRMWARE_MANAGER + ESS -[hidden]down- PIPELINE_COMPONENT_INFRASTRUCTURE + } + + package "Zephyr" as Zephyr_RTOS { + interface "Zephyr System Services" as SS + + package "Schedulers" as SCHEDULERS { + component "RTOS Scheduling" as RTOS_SCHEDULER + } + + package "Services" as SERVICES { + component "Memory Manager" as MEMORY_MANAGER + component "Power Manager" as POWER_MANAGER + component "IPC/IDC" as IXC + component "Logging" as LOGGING + component "Debug" as DEBUG + component "Timer Manager" as TIMER_MANAGER + component "Interrupt Handler" as INTERRUPT_HANDLER + + MEMORY_MANAGER -[hidden]right- POWER_MANAGER + POWER_MANAGER -[hidden]right- IXC + IXC -[hidden]down- LOGGING + LOGGING -[hidden]right- TIMER_MANAGER + TIMER_MANAGER -[hidden]right- INTERRUPT_HANDLER + } + + package "SoC HAL" as SOC { + component "OEM SoC 1" as SOC_1 + component "OEM SoC 2" as SOC_2 + component "Other SoCs" as OTHER_SOCS + + SOC_1 -[hidden]right- SOC_2 + SOC_2 -[hidden]right- OTHER_SOCS + } + + package "Drivers" as DRIVERS { + package "Common Drivers" as COMMON_DRIVERS { + component "GPDMA" as GPDMA + component "Timer" as TIMER + component "SHA-384" as SHA384 + component "Watchdog" as WATCHDOG + component "IPC" as IPC + component "IDC" as IDC + } + + package "Audio Drivers" as AUDIO_DRIVERS{ + component "DMIC" as DMIC + component "I2S" as I2S + component "SDW" as SDW + component "HDA" as HDA + + DMIC -[hidden]right- I2S + I2S -[hidden]right- SDW + SDW -[hidden]right- HDA + } + + package "Sensing Drivers" as SENSING_DRIVERS { + component "I2C" as I2C + component "GPIO" as GPIO + component "I3C" as I3C + component "SPI" as SPI + component "UART" as UART + + I2C -[hidden]right- GPIO + GPIO -[hidden]right- I3C + I3C -[hidden]right- SPI + SPI -[hidden]right- UART + } + } + + component "XTHAL" as XTHAL + + SS -[hidden]down- SCHEDULERS + SS -[hidden]down- SERVICES + SCHEDULERS -[hidden]right- SERVICES + SERVICES -[hidden]right- SOC + SERVICES --[hidden]down-- DRIVERS + DRIVERS -[hidden]down- XTHAL + } + + MPP_KERNEL_EXTENSION --[hidden]down-- Zephyr_RTOS +} + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/index.rst b/architectures/firmware/sof-zephyr/rtos_layer/index.rst new file mode 100644 index 00000000..204b057a --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/index.rst @@ -0,0 +1,16 @@ +.. _rtos_layer: + +RTOS Layer Infrastructure +######################### + +The RTOS layer is based on Zephyr that provide generic and scalable open source +solution with options for SW partitioning of product subsystems to run audio +workloads. + +.. toctree:: + :maxdepth: 1 + + zephyr_kernel_overview + memory_management/index + power_management + io_drivers/index diff --git a/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/dmic/dmic_driver.rst b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/dmic/dmic_driver.rst new file mode 100644 index 00000000..6da57691 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/dmic/dmic_driver.rst @@ -0,0 +1,44 @@ +.. _dmic_driver: + +DMIC IO Driver +############## + +.. uml:: images/dmic_diagram.pu + :caption: DMIC IO Driver overview + +Gateway Initialization +********************** + +.. uml:: images/dmic_gateway_init.pu + :caption: DMIC Input Gateway Initialization + +DMIC HW is initialized as follows: + + 1. Mute microphones. + 2. Enable clock on microphones (also enable CIC and FIRs). + 3. Wait for clock stabilization (SoC defined delay). + 4. Unmute microphones using a curved ramp until the DC offset is gone and + replaced with the live stream. + +Configuration BLOB +****************** + +DMIC IO Driver is prepared for the configuration BLOB to come in context of any +instance of the DmicInput at any time. The configuration may be rejected if the +current state of PDM controllers and FIFOs is inappropriate. Accepting the +configuration does not always mean that it is immediately programmed to the HW. +The configuration is global, so when sent by an instance of DmicInput while +another instance is already running it is just compared with already programmed +data for the sake of consistency. + +Gateway Release +*************** + +.. uml:: images/dmic_gateway_release.pu + :caption: DMIC Input Gateway Release + +State Transitions +***************** + +.. uml:: images/dmic_gateway_state_transitions.pu + :caption: DMIC Input Gateway State Transition diff --git a/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/dmic/images/dmic_diagram.pu b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/dmic/images/dmic_diagram.pu new file mode 100644 index 00000000..6dc94a0c --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/dmic/images/dmic_diagram.pu @@ -0,0 +1,30 @@ +@startuml + +hide methods +hide attributes + +component Zephyr { + class DmicDriver + interface dai_dmic_ops + interface dai_driver_api +} + +component MPP { + interface Gateway + + interface IoDriver + class DmicManager + class DmicInput +} + +DmicDriver -up- dai_dmic_ops + +dai_dmic_ops -left-|> dai_driver_api : implements + +DmicManager -up- IoDriver +DmicManager -left-> DmicInput : manages +DmicInput -up- Gateway +DmicInput -down-> dai_dmic_ops : calls +DmicDriver --* DmicInput + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/dmic/images/dmic_gateway_init.pu b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/dmic/images/dmic_gateway_init.pu new file mode 100644 index 00000000..f8a938f4 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/dmic/images/dmic_gateway_init.pu @@ -0,0 +1,23 @@ +@startuml + +participant "DMIC Manager" as dmic_manager +participant "Zephyr PM Subsystem" as zephyr_pm +participant "DMIC Driver" as dmic_driver + +-> dmic_manager : gateway_allocate() + activate dmic_manager + dmic_manager -> zephyr_pm : pm_runtime_device_get (dmic) + + activate zephyr_pm + zephyr_pm -> zephyr_pm : increase usage count + opt if usage == 1 + zephyr_pm -> dmic_driver : pm_device_resume + activate dmic_driver + return + end + return + + deactivate dmic_manager +<-- dmic_manager + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/dmic/images/dmic_gateway_release.pu b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/dmic/images/dmic_gateway_release.pu new file mode 100644 index 00000000..9afebab9 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/dmic/images/dmic_gateway_release.pu @@ -0,0 +1,23 @@ +@startuml + +participant "DMIC Manager" as dmic_manager +participant "Zephyr PM Subsystem" as zephyr_pm +participant "DMIC Driver" as dmic_driver + +-> dmic_manager : gateway_release() + activate dmic_manager + dmic_manager -> zephyr_pm : pm_runtime_device_put (dmic) + + activate zephyr_pm + zephyr_pm -> zephyr_pm : decrease usage count + opt if usage == 0 + zephyr_pm -> dmic_driver : pm_device_suspend + activate dmic_driver + return + end + return + + deactivate dmic_manager +<-- dmic_manager + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/dmic/images/dmic_gateway_state_transitions.pu b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/dmic/images/dmic_gateway_state_transitions.pu new file mode 100644 index 00000000..ee592ed6 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/dmic/images/dmic_gateway_state_transitions.pu @@ -0,0 +1,19 @@ + +participant "Dmic Input\nGateway" as dmic_input +participant "DMA" as dma + +== Dmic Input : STOPPED == + +-> dmic_input : STOPPED + dmic_input -> dma : stop() + +== Dmic Input : PAUSED == + +-> dmic_input : PAUSED + dmic_input -> dma : init_transfer() + dmic_input -> dma : pause() + +== Dmic Input : RUNNING == + +-> dmic_input : RUNNING + dmic_input -> dma : start() diff --git a/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/hda/hda_driver.rst b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/hda/hda_driver.rst new file mode 100644 index 00000000..3165775c --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/hda/hda_driver.rst @@ -0,0 +1,50 @@ +.. _hda_driver: + +HD-A IO Driver +############## + +.. uml:: images/hda_io_driver_deps.pu + :caption: HD-A IO Driver overview + +HD-A Gateways +************* + +Gateway Node Addressing +======================= + +There are four types of HD-A gateways. Note that the naming convention +(inherited from c-spec) names the data flow direction based on the external +entity's perspective. Therefore, "output" means that data comes to FW from the +external source and "input" means that data is sent from FW to the external +sink. + +.. uml:: images/hda_playback.pu + :caption: HD-A Playback + +.. uml:: images/hda_capture.pu + :caption: HD-A Capture + +HD-A Gateway types: + - HDA-A DMA Source, + + - DMA Host Output, + - DMA Link Input, + + - HDA-A DMA Sink, + + - DMA Host Input, + - DMA Link Output + +HD-A to HDMI +============ + +There following options are available: + + 1. Legacy HD/A (not recommended), + 2. HW chaining in the DSP (depends on HW support), + 3. SW chaining in the DSP (recommended), + 4. Full Copier-...-Copier pipeline (more resources required). + +The most resource-efficient way to do a simple HD/A to HD/A playback via the DSP +is to use the "DMA Chaining" feature. FW provides an IPC command to connect two +HD/A gateways with a simple data copier task running in the LL domain. diff --git a/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/hda/images/hda_capture.pu b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/hda/images/hda_capture.pu new file mode 100644 index 00000000..37e6a371 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/hda/images/hda_capture.pu @@ -0,0 +1,15 @@ +@startuml + +component "host capture" as hc + +package FW { + component "Host Input" as hi + component "Link Output" as lo +} + +component "link capture" as lc +hc <- hi +hi <- lo +lo <- lc + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/hda/images/hda_io_driver_deps.pu b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/hda/images/hda_io_driver_deps.pu new file mode 100644 index 00000000..8cfdd590 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/hda/images/hda_io_driver_deps.pu @@ -0,0 +1,12 @@ + +@startuml +allowmixing + +component "hd-a io driver" as io_drv +component "hd-a gateway" as gateway +component "hd-a dma" as dma + +io_drv -right-> gateway : provides +gateway -down-> dma : use + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/hda/images/hda_playback.pu b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/hda/images/hda_playback.pu new file mode 100644 index 00000000..7988d2b3 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/hda/images/hda_playback.pu @@ -0,0 +1,15 @@ +@startuml + +component "host playback" as hp + +package FW { + component "Host Output" as ho + component "Link Input" as li +} + +component "link playback" as lp +hp -> ho +ho -> li +li -> lp + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/i2s/i2s_driver.rst b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/i2s/i2s_driver.rst new file mode 100644 index 00000000..ef17ecae --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/i2s/i2s_driver.rst @@ -0,0 +1,123 @@ +.. _i2s_driver: + +I2S IO Driver +############# + +.. uml:: images/i2s_diagram.pu + :caption: I2S IO Driver overview + +Configuration BLOB +****************** + +The Configuration Blob is a build of block structures: + - TDM slot Map, + - I2S base registers, + - MCLK configuration that allows for specifying the ratio for multiple + dividers, + - Aggregation configuration + +The ``I2sConfigurationBlobHeader`` begins with a signature followed by the BLOB +version and size. + +.. code-block:: text + + I2sConfigurationBlobHeader + { + signature and version { 0xEE, BLOB version } + size in bytes + } + +Blob Configuration structure that follows the header depends on the BLOB version. +Currently, only v2.5 is supported with the structure as follows: + +.. code-block:: text + + I2sConfigurationBlob2 + { + I2sConfigurationBlobHeader + TDM slot map ver.2 [I2S_TDM_MAX_SLOT_MAP_COUNT] + I2S base registers + MCLK configuration ver.2 + { + 2.5: Aggregation configuration + } + } + +TDM Time Slots +============== + +TDM time slots are statically assigned to streams by definition coming from +ACPI. A single stream transmits data through time slots of a single time slot +group. For example, 8 TDM time slots may be grouped by the following definition +from ACPI: + +.. code-block:: text + + tsd[0] = 0xFFFFFF43, tsd[1] = 0xFFFFFF01, ... + +where: + - Stream 0 specifies time_slot_group_index = 1, + - Stream 1 uses time_slot_group_index = 0 + +that would mean that the 1st TDM slot is mapped to S0 Ch0; the 0th TDM slot is +mapped to S0 Ch1; the 3rd TDM slot is mapped to S1 Ch0, and 4th TDM slot is +mapped to S1 Ch1. + +.. graphviz:: images/i2s_tdm.dot + :caption: I2S TDM + +Configuring BCLK Clock Input Source +=================================== + +The I2S Link BCLK may be configured to use on the SoC available clock sources. + +Example BCLK clock sources: + + - XTAL Oscillator clock, + - Audio Cardinal clock, + - Audio PLL fixed clock, + - MCLK + +Clock selection is programmed using values provided in the I2S Configuration +BLOB for the MCDSS and MNDSS fields of the MDIVCTRL register. + +Link Synchronization (and Aggregation) +====================================== + +Applies to sync of the streams started together as well as to synchronizing new +stream with already running ones. + +.. note:: The same configuration must be set to all involved I2S ports. Specifically, + all the ports must be driven by the same clock source. Moreover, there might + be clock source SoC limitations. For example, in the TGL the M/N divider has + to be selected for aggregation case. + +.. list-table:: + :widths: 25 25 50 + :header-rows: 1 + + * - Synchronized + - Provider Mode + - Consumer Mode + * - Stream start + - Yes + - Yes + * - BCLK, SFRM + - Yes + - By hooking up to the same I2S provider + +"Single" I2S links may be synchronized and aggregated by sending I2sSyncData to +the I2S IO Driver. + +Loopback mode +====================================== + +The I2S transmitter and receiver share data pins at the IP level. The Tx pin of the transmitter +is connected to the Rx pin of the receiver. This may be used for easy creation of digital +loopbacks (LBM, loopback mode) - the receiver always does see what the sender is sending. + +Please note the following: + + - all the parameters of transmitter and receiver, like number of channels, data rates, and format must match each other + - the lines are connected internally, so LBM mode may be used even if the I2S pins are not physically available + diff --git a/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/i2s/images/i2s_diagram.pu b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/i2s/images/i2s_diagram.pu new file mode 100644 index 00000000..d49b4d50 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/i2s/images/i2s_diagram.pu @@ -0,0 +1,18 @@ +@startuml + +hide methods +hide attributes + +class I2sSink --() Gateway +class I2sSource --() Gateway +class I2sDriver --() IoDriver +class I2sChannel +class I2sInputChannel + +I2sChannel --* I2sDriver +I2sInputChannel --|> I2sChannel +I2sOutputChannel --|> I2sChannel +I2sSink --o I2sOutputChannel +I2sSource --o I2sInputChannel + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/i2s/images/i2s_tdm.dot b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/i2s/images/i2s_tdm.dot new file mode 100644 index 00000000..db699bbd --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/i2s/images/i2s_tdm.dot @@ -0,0 +1,38 @@ +digraph G { + node [fontsize=10,shape=record,height=.1]; + splines=false + + subgraph clusterAcpi { + label="tdm_ts_group[8]"; fontsize=10; + tdm_acpi [label="FFFFFF43 |FFFFFF01 |..."]; + } + + subgraph clusterStr0 { + label="Stream 0"; fontsize=10; color="#C4D600"; + + str0_cfg [label="\{ time_slot_group_index=1\}"]; + str0_cfg -> tdm_acpi:acpi1 [style=dotted]; + + str0 [label="L |R |... |

" color="#C4D600"]; + } + + subgraph clusterStr1 { + label="Stream 1"; fontsize=10; color="#FFA300" + + str1_cfg [label="\{ time_slot_group_index=0\}"] + str1_cfg -> tdm_acpi:acpi0 [style=dotted] + + str1 [label="L |R |..." color="#FFA300"] + } + + str [label="<0>R |<1>L |<2> |<3>L |<4>R |<5> |<6> |<7> "] + + str0:l -> str:1 + str0:r -> str:0 + + str1:l -> str:3 + str1:r -> str:4 + + {rank=min; tdm_acpi} + {rank=max; str} +} diff --git a/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/images/io_drivers_diagram.pu b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/images/io_drivers_diagram.pu new file mode 100644 index 00000000..37ce38ce --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/images/io_drivers_diagram.pu @@ -0,0 +1,16 @@ +frame "SOF" { + component Gateway + component GatewayExtension <> +} + +frame "Zephyr" { + component IoDriver <> + component DMA +} + +Gateway *-right- GatewayExtension + +Gateway -down- IoDriver +Gateway -down- DMA + +GatewayExtension ..> IoDriver diff --git a/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/index.rst b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/index.rst new file mode 100644 index 00000000..52562049 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/io_drivers/index.rst @@ -0,0 +1,31 @@ +.. _io_drivers: + +IO Drivers +########## + +The IO Drivers provide access to an IO HW Interfaces connected to the DSP, e.g. +I2S, DMIC, etc. and are managed as a part of the Zephyr RTOS. The Audio IO +Drivers share generic `Zephyr DAI interface `__. +For a full list of IO drivers available on the specific platform, refer to +:ref:`platforms`. HW IO is accessed via the `Gateway` interface inside the FW. +The actual implementation of that interface depends on the underlying HW IO +mechanism. Gateways use the Zephyr DMA interface to transmit the data to/from +the represented HW IO. DMA interface implementation depends on the underlying +DMA method (HDA-DMA, GPDMA, etc.). + +**NOTE:** The introduction of Gateways concept to SOF with Zephyr is a work in +progress. In existing implementation the SOF Host and DAI implementation is +still in use as a substitute of Gateways. + +.. uml:: images/io_drivers_diagram.pu + :caption: IO Drivers diagram + +Drivers +******* + +.. toctree:: + :maxdepth: 1 + + hda/hda_driver + i2s/i2s_driver + dmic/dmic_driver diff --git a/architectures/firmware/sof-zephyr/rtos_layer/memory_management/heap_sharing.rst b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/heap_sharing.rst new file mode 100644 index 00000000..1b7d0347 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/heap_sharing.rst @@ -0,0 +1,58 @@ +Heap sharing +############ + +The memory heap can be: + +- local - used exclusively by a single DSP core, +- shared - higher level memory shared across all DSP cores + +.. uml:: images/heaps.pu + :caption: Memory Heaps + +.. note:: Introduction of MMU will require a separate local application heap per + isolated domain. + +L1 Cache Coherency +****************** + +NOTE: This section applies to Intel systems without L1 cache coherency + +A local heap is used exclusively by a single DSP core. Therefore operations on +the allocated memory buffers do not require explicit L1 cache operations nor +data cache alignment. + +All operations performed on a local heap can be executed by the associated DSP +core only. The *move-to-another-core* operation is not permitted for allocated +buffers. + +A shared heap can be configured in two ways: + +1. To provide uncache aliases of buffer addresses to the clients, +2. To provide cacheable addresses to the clients. + +Option #1 is preferred, since does not require explicit L1 cache operations +when memory is accessed by a DSP core. However, all operations directly access +L2+ memory therefore it is not suitable for a low latency high performance data +processing case. + +Option #2 provides better performance but requires explicit L1 cache operations, +which are difficult to maintain and validate, as well as data cache alignment +for both client buffers and their descriptors, which creates an overhead. This +configuration should be avoided if possible unless a coherent API is available +to share the data. + +However, a one important exception to the shared memory accessed through uncached +alias is a data buffer connected between processing components running on +different cores. Locking and cache operations price could be payed to get much +better performance of accessing the data in the buffer which may be a +significant part of light weight LL processing modules DSP cycle budget. + +Accessing Shared Memory Pool +**************************** + +The data structures needed to manage shared memories are initialized by the +primary core, structure location in memory map is known at the build time and +API is protected by the mutex. + +The mutex uses atomic operation behind and all processors co-managing this +memory heap must support atomics. diff --git a/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/dynamic_module_load.pu b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/dynamic_module_load.pu new file mode 100644 index 00000000..02c386d0 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/dynamic_module_load.pu @@ -0,0 +1,77 @@ +@startuml + +box "Host" #LightGreen + participant "Driver" as host_driver +end box + +box "Media Processing Pipelines Layer" #LightSkyBlue + participant "Component Manager" as component_manager + participant "Library Manager" as lib_manager + participant "MPP Memory Manager" as mpp_memory_manager +end box + +box "Zephyr RTOS" #LightBlue + participant "Memory Management Driver" as memory_management_driver +end box + +box "Hardware" #LightGrey + participant "Memory" as hw_memory +end box + +host_driver -> lib_manager: Load Library + activate lib_manager + lib_manager -> mpp_memory_manager: rmalloc(MEM_ZONE_RUNTIME, flags=NULL, MEM_CAPS_LOADABLE_LIBRARY, size) + activate mpp_memory_manager + return address to store library + lib_manager --> host_driver + deactivate lib_manager + +host_driver -> lib_manager: Transfer library over DMA\nto given address + +host_driver -> component_manager: Instantiate Component + activate component_manager + + opt if Component is Loadable and it is first instance + component_manager -> lib_manager: Load component + activate lib_manager + + loop repeat for Component TEXT, RODATA + lib_manager -> lib_manager: read Component virtual address and size from manifest + + lib_manager -> memory_management_driver: sys_mm_drv_map_region(virt*, phys=NULL, size, flags=NULL) + activate memory_management_driver + memory_management_driver -> memory_management_driver: allocate free phys pages + opt power up memory banks for allocated phys pages + memory_management_driver -> hw_memory: power up memory banks + end + memory_management_driver --> lib_manager + deactivate memory_management_driver + + lib_manager -> lib_manager: read Component address offset from library manifest + lib_manager -> lib_manager: mem_copy(virt*, library_store_addr + offset, size) + lib_manager -> memory_management_driver: sys_mm_drv_update_region(virt*, size, flags= CODE / RODATA) + activate memory_management_driver + note right: update region flags to prevent overwrite + return + + end + + opt if Component has BSS + lib_manager -> memory_management_driver: sys_mm_drv_map_region(virt*, phys=NULL, bss_size, flags) + activate memory_management_driver + memory_management_driver -> memory_management_driver: allocate free phys pages + opt power up memory banks for allocated phys pages + memory_management_driver -> hw_memory: power up memory banks + end + memory_management_driver --> lib_manager + deactivate memory_management_driver + end + + lib_manager --> component_manager + deactivate lib_manager + end + + component_manager -> component_manager: Instantiate Component + component_manager --> host_driver + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/heaps.pu b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/heaps.pu new file mode 100644 index 00000000..582b21bd --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/heaps.pu @@ -0,0 +1,31 @@ +scale max 1024 width + +node "DSP Core #0 Memory Block" as core_0 { + node "Application Heap (local)" as app_0 #lightgreen { + component "Pipelines @Core #0" as ppl_0 + component "LL Modules & Tasks @Core #0" as ll_0 + component "DP Modules & Tasks @Core #0" as dp_0 + } + + node "Application Heap (shared)" as app_shared_0 #lightyellow { + component "Shared buffers" + } + + node "System Heap (shared)" as sys_0 #lightblue { + component "Devices" + } +} + +ppl_0 -[hidden]down-> ll_0 +ll_0 -[hidden]down-> dp_0 + +node "DSP Core #1 Memory Block" as core_1 { + node "Application Heap (local)" as app_1 #lightgreen { + component "Pipelines @Core #1" as ppl_1 + component "LL Modules & Tasks @Core #1" as ll_1 + component "DP Modules & Tasks @Core #1" as dp_1 + } +} + +ppl_1 -[hidden]down-> ll_1 +ll_1 -[hidden]down-> dp_1 diff --git a/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/memory_allocation.pu b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/memory_allocation.pu new file mode 100644 index 00000000..82d84bf0 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/memory_allocation.pu @@ -0,0 +1,21 @@ +@startuml + +box "SOF" #LightBlue + participant "Component Management" as component_management + participant "MPP Memory Manager" as mpp_memory_manager +end box + +box "Zephyr" #LightGreen + participant "Zephyr Memory Manager" as zephyr_memory_manager +end box + +activate component_management +component_management -> mpp_memory_manager: rmalloc(mem_zone, flags, caps, size) + activate mpp_memory_manager + + mpp_memory_manager -> mpp_memory_manager: find memory heap that\nmatch zone and caps + mpp_memory_manager -> zephyr_memory_manager: k_heap_alloc (heap, size) + activate zephyr_memory_manager + return + mpp_memory_manager --> component_management +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/memory_allocation_from_memory_driver.pu b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/memory_allocation_from_memory_driver.pu new file mode 100644 index 00000000..a9d10fd7 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/memory_allocation_from_memory_driver.pu @@ -0,0 +1,26 @@ +@startuml + +box "SOF" #LightBlue + participant "Library Manager" as library_manager +end box + +box "Zephyr" #LightGreen + participant "Memory Management Driver" as memory_management_driver +end box + +box "Hardware" #LightGrey + participant "Memory" as hw_memory +end box + +activate library_manager + +library_manager -> memory_management_driver: sys_mm_drv_map_region\n(virt*, phys=NULL, size, flags) + activate memory_management_driver + memory_management_driver -> memory_management_driver: allocate memory phys pages + opt if phys memory pages require power up + memory_management_driver -> hw_memory: power up memory banks + end + + return + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/memory_initialization.pu b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/memory_initialization.pu new file mode 100644 index 00000000..666e68b1 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/memory_initialization.pu @@ -0,0 +1,42 @@ +@startuml + +box "SOF" #LightBlue + participant "MPP Memory Manager" as mpp_memory_manager +end box + +box "Zephyr" #LightGreen + participant "Memory Manager" as zephyr_memory_manager + participant "Memory Management Driver" as memory_management_driver +end box + +box "Hardware" #LightGrey + participant "Memory" as hw_memory +end box + + +-> memory_management_driver: sys_mm_drv_mm_init + activate memory_management_driver + memory_management_driver -> memory_management_driver: read unused_main_mem_start_marker\nfrom linker + note right: The marker is used to\n identify where base firmware\n ends in memory (text, data, bss) + + memory_management_driver -> memory_management_driver: sys_mm_drv_unmap_region(unused_main_mem_start, unused_size) + activate memory_management_driver + opt If architecture support granular memory banks power control + memory_management_driver -> hw_memory: power down unused memory banks + deactivate memory_management_driver + end + + deactivate memory_management_driver + +-> mpp_memory_manager: mpp_mem_init + activate mpp_memory_manager + mpp_memory_manager -> mpp_memory_manager: read memory zones\nbase address and size + loop for each memory region create heap + mpp_memory_manager -> zephyr_memory_manager: k_heap_init\n(heap, mem*, size) + activate zephyr_memory_manager + return + end + + deactivate mpp_memory_manager + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/memory_management_layers.pu b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/memory_management_layers.pu new file mode 100644 index 00000000..a2218c96 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/images/memory_management_layers.pu @@ -0,0 +1,60 @@ +@startuml + +allowmixing + +scale max 1024 width + +component SOF { + + package "Zephyr" as ZEPHYR_RTOS { + interface "Zephyr Memory Service interface" as ZMSI + hide ZMSI methods + hide ZMSI attributes + + package "Drivers" as DRIVERS { + component "Memory Management Driver" as MEMORY_MGMT_DRIVER + } + + package "Memory Manager" as ZEPHYR_MEM_MANAGER { + component "Multi Heap" as MULTI_HEAP + component "Memory Heaps" as MEM_HEAPS + component "Memory Blocks Allocator" as MEM_BLOCK_ALLOCATOR + component "Demand Paging" as DEMAND_PAGING + + MULTI_HEAP .[hidden]right. MEM_HEAPS + MEM_HEAPS .[hidden]right. MEM_BLOCK_ALLOCATOR + MEM_BLOCK_ALLOCATOR .[hidden]right. DEMAND_PAGING + } + + component "Device Tree" as DEV_TREE + + ZMSI -[hidden]down- MEM_BLOCK_ALLOCATOR + ZEPHYR_MEM_MANAGER -[hidden]down- DRIVERS + DRIVERS -[hidden]right- DEV_TREE + } + + package "Media Processing Pipelines layer" as MPP_LAYER { + component "Pipeline Manager" as PIPELINE_MANAGER + component "Communication" as COMMUNICATION + component "Component Manager" as COMPONENT_MANAGER + component "MPP Memory Manager" as MPP_MEM_MANAGER + + PIPELINE_MANAGER -[hidden]right- COMMUNICATION + COMMUNICATION -[hidden]right- MPP_MEM_MANAGER + MPP_MEM_MANAGER -[hidden]right- COMPONENT_MANAGER + + } + + package "Application layer" as APP_LAYER { + component "Loadable Components" as LOADABLE_COMPONENTS + component "Built-in Components" as BUILT_IN_COMPONENTS + + BUILT_IN_COMPONENTS -[hidden]right- LOADABLE_COMPONENTS + } + + APP_LAYER -[hidden]down- MPP_LAYER + MPP_LAYER -[hidden]down- ZEPHYR_RTOS + +} + +@enduml diff --git a/architectures/firmware/sof-zephyr/rtos_layer/memory_management/index.rst b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/index.rst new file mode 100644 index 00000000..68d4e180 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/index.rst @@ -0,0 +1,43 @@ +.. _memory_mgmt: + +Memory Management +################# + +Memory Management role is to provide service API for dynamic memory mapping and +allocation from available memory zones. + +Overview +******** + +The memory support functionality is delivered at two levels: + + - Zephyr Memory Management Service, which provides memory drivers, demand + paging, allocators, and heap management, + + - MPP Memory Management - SOF extension, which provides heaps for virtual + memory mapped to physical memory on demand, and declaration of SOF specific + heaps instantiated for various memory zones, + +.. uml:: images/memory_management_layers.pu + :caption: Example of Memory Management layers and interfaces + +Read More +********* + +.. toctree:: + :maxdepth: 1 + + memory_zones + mpp_memory_management + heap_sharing + memory_management_driver + memory_management_flows + +External Links +============== + +- `Zephyr Memory Management Service `__ +- `Memory Blocks Allocator `__ +- `Memory Management driver `__ +- `Heaps Management `__ +- `Demand Paging `__ diff --git a/architectures/firmware/sof-zephyr/rtos_layer/memory_management/memory_management_driver.rst b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/memory_management_driver.rst new file mode 100644 index 00000000..097c450f --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/memory_management_driver.rst @@ -0,0 +1,21 @@ +Memory Management Driver +######################## + +The Memory Management Driver (MMD) is part of the Zephyr distributed drivers. +Each SoC may require unique Memory Management driver implementation. The MMD +shall implement common MMD interface that is exposed to kernel services. This +allows for explicit allocation and mapping of individual memory hardware pages +within the physical environment. + +All operations within Memory Management Driver are explicit. Hardware page IDs +represent real physical blocks of hardware memory. + +The MMD is responsible for identification what part of the SoC memory is used by +the base firmware (code, data, bss) and unmap the unused blocks. The unused +memory will be available for dynamic allocation. Base firmware code, read only +data and BSS are mapped in the TLB automatically with corresponding flags (CODE, +RODATA) to prevent incidental modification. + +Memory Management Driver can maintain memory power at a granular level if the +architecture support it. It has possibility to power up selected memory banks on +map requests and power down on unmap, which is a recommended flow. diff --git a/architectures/firmware/sof-zephyr/rtos_layer/memory_management/memory_management_flows.rst b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/memory_management_flows.rst new file mode 100644 index 00000000..aa90ebb2 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/memory_management_flows.rst @@ -0,0 +1,41 @@ +Flows +##### + +Memory initialization +********************* + +Main goal of Memory initialization is to unmap unused memory after firmware load +and create heaps for supported memory zones. + +.. uml:: images/memory_initialization.pu + :caption: Memory initialization flow + +Memory allocation +***************** + +The common memory allocation is expected to use one of the available memory +zones via Zephyr Heap that was created during initialization. + +.. uml:: images/memory_allocation.pu + :caption: Memory allocation example flow + +Memory allocation directly using Memory Management Driver +********************************************************* + +In specific use cases (e.g. Dynamic Component Load) it may be required to +allocate memory directly using Memory Management Driver to control what virtual +address will be mapped to physical memory. + +.. uml:: images/memory_allocation_from_memory_driver.pu + :caption: Example memory allocation using Memory Management Driver + +Dynamic Component Load +********************** + +The loadable components are stored in Loadable Library memory zone and can be +loaded on instantiate request to System memory. The components load to System +memory is optional and integrator can indicate if the components can be executed +directly from the Loadable Library memory zone. + +.. uml:: images/dynamic_module_load.pu + :caption: Dynamic component load and instantiation flow diff --git a/architectures/firmware/sof-zephyr/rtos_layer/memory_management/memory_zones.rst b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/memory_zones.rst new file mode 100644 index 00000000..5be17be8 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/memory_zones.rst @@ -0,0 +1,11 @@ +Memory Zones +############ + +Depending on the memory use case a different memory zone can be used for +allocation. Application and MPP layer components are using memory zones and +capabilities to identify a target memory. The memory zones mapping on physical +addresses is SoC specific. If the SoC support multiple memory types with +different characteristics, then it is up to SoC integrator to decide which +memory will be most suitable for zone mapping. For example, if SoC has access to +slow but large capacity memory then it can map it for Loadable Library memory +zone. diff --git a/architectures/firmware/sof-zephyr/rtos_layer/memory_management/mpp_memory_management.rst b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/mpp_memory_management.rst new file mode 100644 index 00000000..2f079186 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/memory_management/mpp_memory_management.rst @@ -0,0 +1,19 @@ +MPP Memory Management +##################### + +MPP Memory Management (MPP MM) is a SOF extension running on top of Zephyr +Memory Manager. The reason to create MPP MM was to add support for memory zones, +which are not natively supported by Zephyr. Zephyr by default initialize single +System Heap. + +The MPP MM roles: + + - initialization of Memory Heaps for supported memory zones, + - provide allocator API for memory allocation from different memory zones, + +Memory Heaps initialization is done based on SoC Memory Map that identify start +and end addresses of memory zones. + +.. note:: + Memory zones are expected to be defined as memory sections in a SoC linker script. + diff --git a/architectures/firmware/sof-zephyr/rtos_layer/power_management.rst b/architectures/firmware/sof-zephyr/rtos_layer/power_management.rst new file mode 100644 index 00000000..c394f52c --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/power_management.rst @@ -0,0 +1,158 @@ +.. _power_mgmt: + +Power Management +################ + +The Power Manager is responsible for system and device power management. The +power management behavior can be customized by power policy configuration and +direct power API requests which allows you to adjust system power savings to the +current firmware activity. + +.. uml:: images/power/power_components.pu + :caption: Participants of the Firmware power management. + +`Zephyr Power Management +documentation `__ + +DSP Cores +********* + +Each DSP core can be separately powered up and down. + +The assumption is that DSP #0 is a primary core and is responsible for powering +up all secondary cores. The primary core powers up the secondary cores on Set Dx +IPC request. + +The secondary core shall be powered up prior to any task allocated to it by the SW +driver. + +Power Transitions +***************** + +There are three DSP core power states: + +.. list-table:: + :widths: 5 10 20 + :header-rows: 1 + + * - DSP Power State + - Zephyr Power State + - Notes + * - D0 + - PM_STATE_ACTIVE + - built-in state, no extra mapping required + * - D0i3 + - PM_STATE_RUNTIME_IDLE + - custom mapping in the Device Tree + *d0i3: idle { power-state-name = "runtime-idle" }* + * - D3 + - PM_STATE_SOFT_OFF + - custom mapping in the Device Tree + *d3: off { power-state-name = "soft-off" }* + +A major consumer of power related to the main part of the DSP subsystem +is a source of the clock that is wired to the DSP core and the DSP core itself. +Transitions to lower power states focus on this part. Another power consumer, +a bit less significant, is the L2 SRAM memory embedded in the DSP subsystem. + +The clock source and clock gating is managed by the Power Manager according to +Power Policy configuration settings. + +Memory power is controlled by the Memory Management Driver that is responsible +for memory setup on power state transitions and memory banks power gating on +map/unmap requests (if it is supported by the SoC). + +Other power-related settings are clock gating and power gating of I/Os (I2C, +I3C, GPIO, SPI, UART, DMIC, etc.) and external DSP accelerators (if supported by +the hardware). + +The low power state transition can be triggered either by Zephyr (on CPU idle) +or on the Host IPC request through the Zephyr force power state set request. The +entrance to D0i3 power state can be dynamically locked on SetD0ix IPC request +that configures the Zephyr Power Policy to prevent a selected power state transition. + +More details are in the `Zephyr Power Management +documentation `__ + +.. uml:: images/power/dsp_fw_power_states.pu + :caption: DSP and FW Power States + +.. uml:: images/power/dx_state_transitions.pu + :caption: D3, D0 and D0ix state transitions + +Power Up of Secondary Core (D3 to D0 transition) +================================================ + +The below diagram shows secondary core boot flow: + +.. uml:: images/power/flow_secondary_core_boot.pu + :caption: DSP Secondary Core Boot flow + +Power down of DSP core (D0 to D3 transition) +============================================ + +The below diagram shows a primary core power down flow: + +.. uml:: images/power/flow_primary_core_power_down.pu + :caption: DSP Primary Core Power Down flow + +Power down of Secondary Core (D0 to D3 transition) +================================================== + +The below diagram shows a secondary core power down flow: + +.. uml:: images/power/flow_secondary_core_power_down.pu + :caption: DSP Secondary Core Power Down flow + +Enable D0ix (D0 to D0ix) +======================== + +D0ix is enabled on explicit `SET_D0ix` IPC message with prevent_power_gating bit +set to 0. + +.. uml:: images/power/flow_enable_d0i3.pu + :caption: Enable D0i3 flow + +Disable D0ix (D0ix to D0) +========================= + +D0ix is disabled on explicit `SET_D0ix` IPC message with prevent_power_gating +bit set to 1. + +.. uml:: images/power/flow_disable_d0i3.pu + :caption: Disable D0i3 flow + +DSP idle state +============== + +.. uml:: images/power/flow_dsp_idle.pu + :caption: DSP idle state flow + +DSP Cores Clock Gating +====================== + +DSP clocks, similar to DSP cores, can be separately gated as well. Clock gating +shall be enabled by default for all DSP cores unless there is request to prevent +it. + +.. TODO: Create diagram with DSP power state transitions when either DSP clock + is gate or DSP power is gate. + +**NOTE:** Power and clock gating is controlled via `Set D0ix` IPC message. + +I/O Power and Clock Gating Management +************************************* + +Zephyr is responsible for I/O devices power and clock management. + +The I/O device power is controlled based on usage count. More details can be +found in `Zephyr Device Runtime Power Management +documentation `__ + +The I/O clock gating is configurable in driver power policy. Each driver shall +request the desired clock and clock power gating if it is necessary for I/O, +accelerator, etc. to work correctly. + +For instance, audio I/Os such as I2S associated with audio domain require a high +accuracy XTAL clock and may request it. This clock shall be used for as long as +audio I/Os are active. diff --git a/architectures/firmware/sof-zephyr/rtos_layer/zephyr_kernel_overview.rst b/architectures/firmware/sof-zephyr/rtos_layer/zephyr_kernel_overview.rst new file mode 100644 index 00000000..e8e9ada2 --- /dev/null +++ b/architectures/firmware/sof-zephyr/rtos_layer/zephyr_kernel_overview.rst @@ -0,0 +1,372 @@ +.. _kernel_overview: + +Zephyr based kernel +################### + +Zephyr has been introduced as an IP agnostic solution that replaced existing SOF +audio specific kernel. The Zephyr base kernel has been complemented with SOF Low +Level Drivers, SoC HAL and kernel extensions. The new solution continues +scalable kernel concept and it serves as a generic part of infrastructure that +can be statically and dynamically customized based on usage, compute, and memory +constrains, HW configuration etc. + +As a result of the kernel customization, a firmware infrastructure is produced. +This firmware infrastructure can run on a given processor type and it is tuned +for specified usage. + +For more Zephyr kernel details, see `Zephyr Introduction +documentation `__ + +The Zephyr based kernel consists of the following components: + +- Hardware integration layer: XTHAL, +- Low Level Drivers, + + - DMIC, + - I2S, + - SNDW, + - GPIO, + - I2C, + - I3C, + - timers, + - GPDMA, + - IDC, + - IPC, + - watchdog, + - etc. + +- SoC HAL, + + - OEM SoC specific code, + +- Services: shared resource services, communication services, memory manager, + power manager, interrupt manager, system service, etc. +- Kernel extensions: + + - AVS schedulers, + - Firmware Manager, + - Media Processing Pipeline Components, + +The Zephyr base kernel expectations: + +- it can scale down to meet all KPIs via static and dynamic scaling options, +- Zephyr itself is IP agnostic and shared across other SW and FW projects, +- it is available and maintain under open source license, + +.. uml:: images/zephyr_kernel_diagram.pu + :caption: Zephyr Kernel diagram + +Scaling Options +''''''''''''''' + +Zephyr kernel offers scaling options to adjust to selected HW configuration, +scale down to meet aggressive KPIs on a given platform, scale up to meet +functional requirements. + +The scaling is achieved in two ways: + +- static, kernel components can be selectively enabled in the build process + + - Drivers selected depending on SoC Configuration + - Services and execution frameworks chosen in Zephyr + +- dynamic, not used parts can be unloaded and saved in "backup storage" memory, + that typically has large capacity and high access latency. They will be + loaded again once a specific event will happen + + - It is only applicable to SoCs that support it. + - It is achieved via one of the following mechanisms: + + - Firmware Paging (if present) - Only currently executing modules are in + SRAM. + - Split Firmware into modules - Modules are loaded from "backup storage" + or unloaded on explicit request. No runtime dynamism. + +Handling Project Configuration +'''''''''''''''''''''''''''''' + +Zephyr is prepared to be configured via device tree that describe given SoC +board audio hardware configuration. + +A SoC board device tree allows configuring: + +* HW configuration + + * number of HP DSP cores, + * types of memories available per cores, + * supported clocks, + * number of I/Os, + * number of IPC and IDC interfaces for DSP cores, + * etc. + + * DSP memory space, + * IPC mailbox address, + * etc. + +Low Level Drivers +''''''''''''''''' + +SOF is capable to support hardware with several audio I/Os, sensor I/Os, DSP +accelerators and DMAs which count can be customized per architcture. + +HW resources with low level drivers: + +* Audio I/Os: I2S, DMIC, SNDW, HD/A, +* Sensor I/Os: I2C, I3C, GPIO, UART, SPI, ADC, PWM, +* Common resources: HP GPDMA, IPC, IDC, Timers, SHA-384, Watchdog + +**NOTE:** Not all I/Os are supported in each SoC board. + +.. TODO: add link to supported audio architectures + +Zephyr based firmware provides low level drivers for all these resources. A +specific driver can be enabled during build process. + +SoC HAL +''''''' + +The SoC HAL include implementation and configuration details specific for +selected SoC architecture. The SoC HAL abstraction allow to seamlesly switch +between target SoC configuration builds. + +More details can be found in Zephyr documentation: + +* `Zephyr Board Porting Guide `__ +* `Zephyr Architecture Porting Guide `__ + +Services +'''''''' + +.. uml:: images/kernel_services.pu + :caption: Example of kernel services + +The base Zephyr services provide generic system management functionality for +memory, interrupts, autonomous power control (clock and power gating, clock +management). + +The SOF specific functionality is exposed in a form of an extended kernel +services. The extended services utilize Zephyr base services infrastructure and +low level drivers to supply user space interface for the firmware application +layer components. The user space separation from hardware and low level drivers +significantly increase the firmware security and stability. + +Firmware Management +------------------- + +The firmware manager is a core service that is responsible for: + +- reading HW capabilities (number of cores, memory available, etc.), +- firmware initialization, +- instantiation and initialization of Low Level drivers for the existing HW + components, + + - memory type drivers initialization with size read form capability + registers + - audio drivers for supported interfaces + +- instantiate and initialize Extended Kernel Services + + - component manager + - pipeline manager + - IPC/IDC communication service + - async messaging service + - debug service + +.. TODO: add other components that require initialization by the firmware manager + +Interrupt Management +-------------------- + +The interrupt handler service allows to: + +- enable and disable an interrupt for DSP core, +- register a callback that will be called once a specified interrupt occur, + +For more details, see `Zephyr Interrupts +documentation `__ + +Memory Management +----------------- + +The Memory Manager provides a service to other FW components to allocate a block +out of available memory pools, it provides high level API, scans for unused +memory areas, handles physical memory defragmentation, prefetch and cache +policies. Most of the memory is expected to be paged. + +All allocation requests refer to virtual memory address space, which shall be +continuous. This also applies to DMA buffer allocations, where continuous memory +is guaranteed by either continuous physical memory or VA/PA translation. + +The map of available memory resources is passed to the Memory Manager during +initialization of Memory Manager via firmware infrastructure. + +For more details, see `Zephyr Memory Management +documentation `__. + +Power Management +---------------- + +The power management behavior highly depends on platform that firmware runs on, +and it can be configured during build time. There are platforms that only allow +clock gating and power gating is not applicable. + +The power management interface provides the following functionality: + +- allow and prevent power gating, +- allow and prevent clock gating, +- allow and prevent slower clock, +- allow and prevent XTAL shutdown, + +In all cases, the implementation relies on atomic counter which is incremented +every time when prevent function is called and decremented when allow function +is called. + +.. TODO: Add link to SOF Power Management detailed description with flows + +`Zephyr Power Management documentation +`__. + +IPC and IDC Service +------------------- + +The IPC and IDC Service provides communication channel over IPC or IDC. IPCs are +used for the external communication with Host, other processors within SoC or +other subsystems within PCH. IDCs are used for the internal communication +between processors within SOF subsystem. + +The introduction of SOF with Zephyr is followed with new IPC4 interface and +message formats that replaced IPC3. + +The following types of sequences are supported: + +- request-response initiated by Host, + + - it is synchronous sequence, + - long-running operations shall queue request and send response immediately. + The actual completion information should be sent via one-way asynchronous + notification, + +- one-way asynchronous notification, + +.. TODO: Add link to Communication section (when ready) + +Debugging +--------- + +The Zephyr based kernel provides a few services that helps with debugging FW. + +Logging +~~~~~~~ + +The Logger Service provides a lightweight mechanism to push log entries to all +firmware modules that are based on Zephyr logging infrastructure. + +It is a very useful mechanism to do a first level of debugging. + +.. TODO: Add link to Logger Service section (when ready) +.. TODO: Add link to SOF Enable Logs interface +.. TODO: Add link to SOF status and error codes registers + +Zephyr related documentation: + +- `Zephyr + Logging `__ + +Probes +~~~~~~ + +SOF supports injection and extraction probes. The probes are mainly used to +extract audio data from queues between components. + +The other probe use cases include: + +- injection of audio data to a component input queue - useful during testing + and debugging, +- injection of data to internal probes, +- extraction of data from internal probes i.e. internal component states, + intermediate data, debug information, +- logging - probes can be used as transport for firmware logs, + +.. TODO: Add link to Probe configuration interface (when ready) + +Performance Measurements +~~~~~~~~~~~~~~~~~~~~~~~~ + +The firmware infrastructures support performance measurements to collect +information about DSP cycles or amount of data moved via interfaces. + +.. TODO: Add link to Performance Measurements State firmware interface +.. TODO: Add link to firmware Global Performance Data description + + +Telemetry +~~~~~~~~~ + +Firmware infrastructure supports collection of telemetry events which then can +be read by the Host Software. The modules running in FW infrastructure can push +telemetry events via System Services. + +If the telemetry collection is started, the telemetry events will be written to +a common circular buffer. + +If the telemetry collection is stopped/disabled, the telemetry events will be +dropped at telemetry service level and they will not be written to the telemetry +circular buffer. During transition from started to stopped state, the telemetry +events that are already in the circular buffer will be dropped. + +.. TODO: Add link to SOF Telemetry interface documentation + +.. _schedulers_zephyr: + +Schedulers +---------- + +The scheduling method depends on compute and memory available for firmware +running on processor as well as type of workloads executed on given domain. + +There are following types of schedulers supported in SOF + +- AVS scheduling, + +.. TODO: Add link to Scheduling detailed section + +Async Messaging Service +----------------------- + +Asynchronous Messaging Service (AMS) is mechanism to exchange asynchronous +events between components running in the same firmware infrastructure or running +on the another processor (e.g. between HiFi and Fusion cores). + +The Async Messages can be also injected and extracted via Host Async Message +Gateway module by Host SW. + +.. TODO: Add link to Asynchronous Messaging detailed section + +System Services +--------------- + +The FW components do not know location of driver and service functions in base +firmware library, so they need to access base firmware services via System +Services. + +In SOF with Zephyr the `Zephyr interfaces for +drivers `__ +were adopted. All newly developed drivers must be compliant to this standard and +the legacy ones must be ported to it. + +In Zephyr based firmware, a driver instance is obtained via +``device_get_binding`` function call with a name of a driver instance. There is +no explicit driver initialization call as a driver instance is initialized with +the first call. + +A driver implementation must be ready for using the same hardware instance from +many modules and from many cores (it must be thread-safe implementation). There +can be more than one device instance if there is more than 1 instance of a +hardware (i.e. 2 I2C owner controllers). + +The example functionalities that should be exposed via system services: + +- IPC and IDC, +- Logger Service, +- RTOS scheduler functionalities, like yield, +- Async Messaging Service, diff --git a/architectures/firmware/sof-zephyr/zephyr_api_integration.rst b/architectures/firmware/sof-zephyr/zephyr_api_integration.rst new file mode 100644 index 00000000..fe351051 --- /dev/null +++ b/architectures/firmware/sof-zephyr/zephyr_api_integration.rst @@ -0,0 +1,86 @@ +.. _zephyr-api-integration: + +Zephyr API Integration +###################### + +Most of the interfaces between the application (audio) layer and the kernel are +aggregated inside the part of the legacy SOF architecture called "lib". The +interfaces are exposed by the *lib*, declared in header files in +*src/include/sof/lib* directory. Implementation is located in the *src/lib* +except for platform and architecture specific functions that are delegated to +*platform* and *arch* parts respectively. + +.. uml:: images/sof_lib.pu + :caption: Legacy SOF Lib + +Zephyr replaces *lib* and other architecture and platform specific code, +everything below the *app* & *mpp* layers. + +In order to unify the access to the lower parts from the *app* and *mpp*, the +library header files provides now a definition of unified interface but some +changes are introduced to the original set of APIs and/or the implementation. + +Let's have a look at possible cases. + +**Case #1: New Zephyr API replaces 1:1 legacy SOF lib API** + +If there is a Zephyr version of a SOF legacy API which provides exactly the same +functionality as the original function but has a different name, the Zephyr +function name is used as a replacement in the SOF *app* and *mpp* code. It +causes direct linking and call into the Zephyr code optimizing FW size and +performance when SOF is built with Zephyr. Building with legacy SOF *lib* +requires an implementation or just a simple adapter for the new Zephyr API. It +may or may not slightly increase the size and decrease the performance of the +legacy SOF. + +.. code-block:: c + + // src/include/sof/lib.cpu.h + #ifdef __ZEPHYR__ + #include + #else + // was: static inline int cpu_is_core_enabled(int id) + static inline bool arch_cpu_active(int id) + { + arch_cpu_is_core_enabled(id); + } + #endif /* __ZEPHYR__ */ + +**Case #2: Legacy SOF lib API requires multi-step implementation for Zephyr +configuration** + +There may be a case when SOF legacy API is implemented by a single function +provided by the *arch* or another package and there is no 1:1 API available in +Zephyr to replace that. In this case, the API is implemented in the *lib-zephyr* +part based on the native Zephyr APIs. + +.. code-block:: c + + // src/include/sof/lib/cpu.h + #ifdef __ZEPHYR__ + void cpu_disable_core(int id); + #else + static inline void cpu_disable_core(int id) + { + arch_cpu_disable_core(id); + } + #endif /* __ZEPHYR__ */ + + // src/lib-zephyr/cpu.c + void cpu_disable_core(int id) + { + // ... calls to Zephyr APIs + } + +**Case #3: Legacy SOF lib API is implemented completely inside the lib and does +not have any replacement in Zephyr** + +The agent code might be an example of the library functions that are common and +must be compiled and linked together with either legacy SOF *lib* or +*lib-zephyr*. + +The dependencies between the SOF *lib*, *lib-zephyr*, and *zephyr* are +illustrated in the below figure. + +.. uml:: images/sof_lib_zephyr.pu + :caption: SOF Lib + Zephyr diff --git a/architectures/host/index.rst b/architectures/host/index.rst index 30d8bb2a..a7a3cd13 100644 --- a/architectures/host/index.rst +++ b/architectures/host/index.rst @@ -3,64 +3,7 @@ Host Architecture ################# -SOF Driver Architecture -======================= - -|SOF| can either operate as a standalone firmware or alongside a host OS -driver for configuration and control. The |SOF| OS driver is responsible for -loading firmware, loading configuration and managing firmware use cases. -Currently |SOF| has a driver for the Linux OS. - -The |SOF| driver code is dual licensed GPLv2 and BSD and this means the user -can choose which licence they want to use (either BSD or GPLv2). The driver -stack is designed with maximum resuse so that large portions of it can be -taken and integrated into other OSs or RTOSs. - -.. seealso:: - - Refer to the indepth :ref:`sof_driver_arch` document for more information. - -Linux Driver ------------- - -The Linux ASoC driver is upstream in the Linux kernel from v5.2 onwards. The -architecture for |SOF| is shown in the diagram below. The driver -architecture is split into four layers, like a protocol stack, each with a -different purpose. - -#. **Machine driver.** The ASoC machine driver does all the - machine/board audio hardware integration. It also glues the platform - driver and drivers for any codec(s) together so they appear as a single - ALSA sound card. |SOF| can reuse existing upstream machine drivers (as - only the platform name needs to be changed) or can have bespoke machine - drivers. *Linux OS specific - GPLv2 only.* - -#. **Generic PCM Driver.** The PCM driver creates ALSA PCMs, DAPM, and - kcontrols based on the topology data loaded at run time. The PCM driver - also allocates buffers for DMA and registers with run time PM. It is - architecture and platform generic code. Generic for all **platforms**, - but OS specific - GPLv2 only.* - -#. **Generic IPC driver.** The IPC driver is the messaging bridge - between the host and DSP and defines the messaging ABI and protocol. It - is architecture and platform generic code. *Generic OS - BSD or GPLv2.* - -#. **DSP Platform Driver.** The platform driver is a platform specific - driver that abstracts the low level platform DSP hardware into a common - generic API that is used by the upper layers. This includes code that - will initialize the DSP and boot the firmware. *Generic OS - BSD or GPLv2.* - - - .. figure:: ../images/driver-arch-diag.png - :align: center - :alt: SOF Driver Architecture - :width: 800px - - `Sound Open Firmware Linux Driver Architecture. The right-hand side of - the diagram shows the mailbox/doorbell mechanism and the DSP. - The Linux PCM and IPC drivers can be reused without modification on every - platform. Runtime differentiation can be achived by regenerating - topology data to match device use cases whilst static hardware - differentiation is achieved via the machine driver and/or ACPI / Device - Tree configuration.` +.. toctree:: + :maxdepth: 1 + linux_driver/architecture/sof_driver_arch.rst diff --git a/developer_guides/linux_driver/architecture/images/sof-driver-arch-1.png b/architectures/host/linux_driver/architecture/images/sof-driver-arch-1.png similarity index 100% rename from developer_guides/linux_driver/architecture/images/sof-driver-arch-1.png rename to architectures/host/linux_driver/architecture/images/sof-driver-arch-1.png diff --git a/developer_guides/linux_driver/architecture/images/sof-driver-arch-2.png b/architectures/host/linux_driver/architecture/images/sof-driver-arch-2.png similarity index 100% rename from developer_guides/linux_driver/architecture/images/sof-driver-arch-2.png rename to architectures/host/linux_driver/architecture/images/sof-driver-arch-2.png diff --git a/developer_guides/linux_driver/architecture/sof_driver_arch.rst b/architectures/host/linux_driver/architecture/sof_driver_arch.rst similarity index 97% rename from developer_guides/linux_driver/architecture/sof_driver_arch.rst rename to architectures/host/linux_driver/architecture/sof_driver_arch.rst index a307b1d7..61f774f9 100644 --- a/developer_guides/linux_driver/architecture/sof_driver_arch.rst +++ b/architectures/host/linux_driver/architecture/sof_driver_arch.rst @@ -1,7 +1,17 @@ .. _sof_driver_arch: -SOF Driver Architecture -####################### +SOF Linux Driver Architecture +############################# + +|SOF| can either operate as a standalone firmware or alongside a host OS +driver for configuration and control. The |SOF| OS driver is responsible for +loading firmware, loading configuration and managing firmware use cases. +Currently |SOF| has a driver for the Linux OS. + +The |SOF| driver code is dual licensed GPLv2 and BSD and this means the user +can choose which licence they want to use (either BSD or GPLv2). The driver +stack is designed with maximum resuse so that large portions of it can be +taken and integrated into other OSs or RTOSs. .. contents:: :local: diff --git a/architectures/index.rst b/architectures/index.rst index 246cb14c..a82a0be0 100644 --- a/architectures/index.rst +++ b/architectures/index.rst @@ -1,6 +1,6 @@ .. _architectures: -Supported Architectures +Architecture ####################### SOF is intended to run on many different hardware architectures and is therefore @@ -8,11 +8,13 @@ not coupled to any particular DSP or host hardware architecture. The SOF |TSC| ensures that any DSP or host architecture specific code is partitioned to reside in architecture-specific directories with generic APIs to common code. -This section outlines the architecture at a high level, however the source code +This section outlines the architecture at a high level; however, the source code should always be consulted for the low level details. .. toctree:: :maxdepth: 2 host/index - dsp/index + firmware/index + + diff --git a/conf.py b/conf.py index 574a1455..c64f3493 100755 --- a/conf.py +++ b/conf.py @@ -30,8 +30,13 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. + + +# FIXME: blockdiag is orphaned and not compatible with Pillow anymore: +# https://github.com/thesofproject/sof-docs/issues/472 extensions = ['breathe', 'sphinx.ext.graphviz', 'sphinxcontrib.plantuml', - 'sphinx.ext.todo', 'sphinx.ext.extlinks', + 'sphinx.ext.todo', 'sphinx.ext.extlinks', 'sphinxcontrib.blockdiag', + 'sphinxcontrib.jquery' ] @@ -45,13 +50,24 @@ plantuml = 'java -jar ' + os.path.join(os.path.abspath('.'), 'scripts/plantuml.jar') \ + ' -config ' + os.path.join(os.path.abspath('.'), 'scripts/plantuml.cfg') -# Temporarily set this to "none" for a build without diagrams but ~= 15 -# times faster from scratch. +# More than half of the time building from scratch is consumed by the +# sphinx extension "breathe" that converts doxygen XML. Most of the rest +# is consumed by plantUML here. So you can set the variable below to +# 'none' for an _almost instant_ sphinx build! (with zero UML diagram +# and no doxygen). 'none' requires sphinxcontrib.plantuml>=0.11 but +# pre-0.11 errors can be ignored. (of course don't disable UML when +# you're touching UML stuff) plantuml_output_format = 'svg' # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] +# Fixes "WARNING: Error when parsing function declaration." +c_id_attributes = ["__sparse_cache"] +# Not clear why Sphinx thinks some C files are C++ +cpp_id_attributes = c_id_attributes +# cpp_paren_attributes = ["_ALIAS_OF", "__printf_like"] + # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # @@ -63,14 +79,14 @@ # General information about the project. project = u'SOF Project' -copyright = u'2021, SOF Project' +copyright = u'2024, SOF Project' author = u'SOF Project developers' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. -version = release = "0.1" +version = release = "2.11.0" # # The short X.Y version. @@ -83,7 +99,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -116,12 +132,10 @@ sys.stderr.write('Warning: sphinx_rtd_theme missing. Use pip to install it.\n') else: html_theme = "sphinx_rtd_theme" - html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] html_theme_options = { 'canonical_url': '', 'analytics_id': 'GTM-M4BL5NF', 'logo_only': False, - 'display_version': True, 'prev_next_buttons_location': 'None', # Toc options 'collapse_navigation': False, @@ -168,13 +182,13 @@ # as required. extlinks = { 'git-sof-mainline': - (SOF_GIT + '/sof/tree/master/%s', ""), + (SOF_GIT + '/sof/tree/master/%s', None), 'git-sof-docs-mainline': - (SOF_GIT + '/sof-docs/tree/master/%s', ""), + (SOF_GIT + '/sof-docs/tree/master/%s', None), 'git-sof-kconfig': - (SOF_GIT + '/kconfig/tree/master/%s', ""), + (SOF_GIT + '/kconfig/tree/master/%s', None), 'git-alsa': - ('https://git.alsa-project.org/?p=%s.git', ""), + ('https://git.alsa-project.org/?p=%s.git', None), } # Add any paths that contain custom static files (such as style sheets) here, diff --git a/contribute/doc_guidelines.rst b/contribute/doc_guidelines.rst index f2aa0d96..caee341b 100644 --- a/contribute/doc_guidelines.rst +++ b/contribute/doc_guidelines.rst @@ -386,7 +386,7 @@ the first non-white space in the preceding line. For example: 1. And for numbered list items, the continuation line should align with the text of the line above. - .. code-block:: + .. code-block:: none The text within a directive block should align with the first character of the directive name. diff --git a/contribute/process/docbuild.rst b/contribute/process/docbuild.rst index 43f4998b..06570e03 100644 --- a/contribute/process/docbuild.rst +++ b/contribute/process/docbuild.rst @@ -124,6 +124,11 @@ creating drawings: drawing syntax into an image. You need to have a Java runtime environment (JRE) installed when generating documentation. +There is a sof-docs Docker image recipe that can be used as an alternative to +installing the documentation tools on local OS. If you choose to use Docker then +please skip the tools installation steps and go directly to +:ref:`run_documentation_processors` + Depending on your Linux version, install the following tools: * For Ubuntu use: @@ -158,6 +163,20 @@ tools: PIP_IGNORE_INSTALLED=0 pip3 install --user -r scripts/requirements-lax.txt + The hardcoded package versions might need additional libraries installed + in order to compile them. For example, to resolve the following error: + + .. code-block:: bash + + ERROR: Could not build wheels for pillow, which is required to install pyproject.toml-based projects + + you should install: + + .. code-block:: bash + + sudo apt install libjpeg-dev zlib1g-dev + + For Windows, install the needed tools manually: * Python (3.7+) from https://www.python.org/downloads/ @@ -202,20 +221,25 @@ another ``make html`` and the output layout and style is changed. The ``read-the-docs`` theme is installed as part of the ``requirements.txt`` list above. +.. _run_documentation_processors: + Run documentation processors **************************** The sof-docs directory contains all the .rst source files, extra tools, and Makefile for generating a local copy of the SOF technical documentation. -* Generate the HTML output by using the following commands: +You can generate the HTML documentation by using local build tools (1) or by +Docker image (2) + +1. Generate the HTML output by using the following commands (**local build**): .. code-block:: bash cd thesofproject # API documentation (Doxygen) - cmake -S sof/doc -B sof/doc -GNinja - ninja -C sof/doc -v doc + cmake -S sof/doc -B sof/build_doxygen -GNinja + ninja -C sof/build_doxygen -v doc # UML and reStructuredText make -C sof-docs VERBOSE=1 html @@ -228,6 +252,28 @@ If your changes are not related to any UML diagram, you can build more than 10 times faster from scratch by temporarily changing the ``plantuml_output_format`` line in :git-sof-docs-mainline:`conf.py`. +2. Generate the HTML output by using the following commands (**Docker build**): + + .. code-block:: bash + + cd thesofproject + # Build both sof (Doxygen) and sof-docs UML and reStruredText + ./sof-docs/scripts/docker_build/docker-build.sh + +The docker build script will copy the sof and sof-docs source code from host +working directory to image, build the documentation and when completed copy back +output to the host (./sof-docs/_build) + +The first docker build run will take more time due to image creation and +installation of all the necessary build tools. Each next build is much faster +and can additionally be speed up by selecting only sof-docs to build: + + .. code-block:: bash + + cd thesofproject + # Re-build only sof-docs + ./sof-docs/scripts/docker_build/docker-build.sh docs + Publish content *************** @@ -259,7 +305,7 @@ publishing. .. note:: In some situations it is necessary to clean all the files and build from - the very beginning. To do this, use the ``make clean`` command. + the very beginning. To do this, use the ``make -C sof-docs clean`` command. Installation troubleshooting **************************** diff --git a/developer_guides/add_new_arch.rst b/developer_guides/add_new_arch.rst new file mode 100644 index 00000000..b0ba708c --- /dev/null +++ b/developer_guides/add_new_arch.rst @@ -0,0 +1,33 @@ +.. _add_new_arch: + +Adding a new DSP architecture to SOF +==================================== + +This is not yet a guide for architecure porting, but in general, you can add +support for a new DSP architectures to SOF in the following two ways: + +- Write a new Hardware Abstraction Layer (HAL) for your DSP. +- Use an existing RTOS that supports your DSP architecture as a HAL for SOF. + +Both methods require a working compiler for the new DSP architecture and +preferrably an emulation environment or hardware debugger to help with the +bringup and debug. + +Method 1 - New HAL +------------------ + +The main work in adding the new architecture HAL is duplicating and porting the +src/arch directory to your new architecture. The code in the architecture +directory mainly deals with architecture abstraction and initialization of any +architecture IP like MMU, IRQs and caches alongside providing optimized +versions of some common C functions (memcpy, memset, etc) for that architecture. +Adding a new architecture also usually means adding a new host platform too. + +Method 2 - Use existing RTOS +---------------------------- + +This method involves creating a HAL by wrapping the RTOS functions used by SOF +as thinly as possible (i.e. to compile out). It also means removing unused code +from the SOF build in order to use the RTOS version if desireable i.e. +allocator, schedulers, messaging etc. The final stage is to link the SOF audio +code to the RTOS. diff --git a/developer_guides/debugability/coredump-reader/index.rst b/developer_guides/debugability/coredump-reader/index.rst index 1400a073..1ca6d5d2 100644 --- a/developer_guides/debugability/coredump-reader/index.rst +++ b/developer_guides/debugability/coredump-reader/index.rst @@ -3,6 +3,10 @@ Coredump-reader ############### +NOTE: These instructions do not work with SOF running on Zephyr, +please refer to +https://docs.zephyrproject.org/latest/services/debugging/coredump.html + Tool for processing FW stack dumps. In verbose mode it prints the stack leading to the core dump including DSP registers and function calls. It outputs unwrapped gdb command function call addresses to human readable @@ -30,3 +34,53 @@ We read from dump file into sof-coredump-reader.py, then we pipe its output to x .. code-block:: bash ./sof-coredump-to-gdb.sh sof-apl dump_file + +Usage with Linux SOF Driver +*************************** + +If a core dump occurs after a DSP error, the Linux SOF driver allows +accessing the dump via debugfs. Consider the following example of capturing +the dump file and processing it with coredump-reader: + +.. code-block:: bash + + dut> cat /sys/kernel/debug/sof/exception >dsp-coredump + # transfer file to host + host> sof/tools/coredumper/sof-coredump-reader.py -v -l 4 -i dsp-coredump -o dsp-coredump.gdb + host> xt-gdb sof/build_tlg_xcc/sof --command=dsp-coredump.gdb + [cut] + $1 = "Exception location:" + 0xbe02fb29 is in ipc_glb_debug_message (/home/user/sof/src/ipc/handler-ipc3.c:1371). + [cut] + $2 = "backtrace" + #0 0xbe051b00 in literals () + #1 0xbe04e277 in dump_stack (p=3187705884, addr=0x1cc6c29b, offset=3270769662, limit=380, stack_ptr=0x1) at /home/user//sof/src/arch/xtensa/include/arch/lib/cache.h:79 + #2 0xbe04e2f7 in panic_dump (p=233492486, panic_info=0x0, data=0xbe0a4130) at /home/user/sof/src/arch/xtensa/include/arch/debug/panic.h:45 + #3 0xbe02dfd9 in exception () at /home/user/sof/src/arch/xtensa/init.c:115 + #4 0xbe050a28 in _GeneralException () + #5 0xbe02fb29 in ipc_glb_debug_message (header=394016) at /home/user/sof/src/ipc/handler-ipc3.c:1373 + [cut] + (xt-gdb) info all-registers + pc 0xbe051b00 0xbe051b00 + ar0 0x0 0 + ar1 0xbe00a044 -1107255228 + ar2 0x10000 65536 + +Notes: + +- Coredump-reader only works with the xcc toolchain. + +- If the Linux kernel fails to probe, the exception file cannot be read. + +- To prevent runtime suspend from powering off the DSP and erasing + the exception data, perform one of the following steps: + + - Set the ``CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT`` option in the + kernel to ensure DSP is left powered on if a DSP crash occurs. + + - Disable runtime power management (PM) with a module parameter. + For example, for PCI devices:: + options sof_pci_dev sof_pci_debug=1 + +- The DSP core dump information is also printed to kernel dmesg, but + sof-coredump-reader.py cannot parse this core dump format. diff --git a/developer_guides/debugability/index.rst b/developer_guides/debugability/index.rst index 8c8f5d2a..ed686043 100644 --- a/developer_guides/debugability/index.rst +++ b/developer_guides/debugability/index.rst @@ -11,3 +11,5 @@ Debugability coredump-reader/index probes/index ri-info/index + perf-counters/index + shell/index diff --git a/developer_guides/debugability/logger/index.rst b/developer_guides/debugability/logger/index.rst index fd53b7dd..17e41d1c 100644 --- a/developer_guides/debugability/logger/index.rst +++ b/developer_guides/debugability/logger/index.rst @@ -129,7 +129,7 @@ Examples .. note:: - debugfs files used by ``sof-logger`` + debugfs files used by sof-logger: - ``etrace``: direct access to the shared TRACE window of the SOF firmware - ``trace``: using DMA to stream debug trace information from SOF firmware (on @@ -150,6 +150,9 @@ Examples file and start reading from position 0 and thus be in sync with the firmware when it is resumed. + Sometimes error messages about dropped logs are printed. If that is a problem, + increasing DMA_TRACE_LOCAL_SIZE in the relevant platform.h file can be helpful. + Trace filtering *************** @@ -204,56 +207,68 @@ Instance descriptions can have one of the following forms: - ``X.*`` - each component on selected pipeline *X* - ``X.Y`` - component on pipeline *X* with id *Y* -Trace level changes works in the same order as options given in a command line, and a new set overwrites old values. It allows you to easily enable verbose logs only for selected components and keep the lowest possible log level (critical) for others, as shown in the following example: +Trace level changes work in the same order as options given in a command line, and a new set overwrites old values. +It allows you to easily enable verbose logs only for selected components and keep the lowest possible log level (critical) for +others, as shown in the following example: sof-logger -l ldc_file -t -Fcritical=* -Fverbose="dai*, volume1.1" A similar example may be prepared for components on a particular pipeline: - sof-loggerr -l ldc_file -t -Fc=* -Fv=*1.* + sof-logger -l ldc_file -t -Fc=* -Fv=*1.* -.. note:: - To track a verbose message, select the "Trace verbose" option under the "Trace" menu from the firmware build. +Verbose and debug log levels +---------------------------- + +To enable verbose and debug trace messages, select the "Trace->Trace verbose" option in the firmware build +menuconfig (in addition to setting the proper log levels as described above). + +Disabling DSP power gating +-------------------------- -Active trace filters are stored in the firmware runtime memory, so after a firmware restart (such as after power gating in sleep mode) filters settings will be reset. +After a firmware reset (such as after power gating in suspend mode) custom filter settings will be lost. +Thus consider disabling power gating during your debug session. The way this is done is slightly different on every platform, +two examples follow: -Consider disabling power gating during your debug session by entering the following: +1. Intel PCI based: -.. code:: bash +.. code-block:: bash sudo su echo on >/sys/devices/pci0000\:00/0000\:$(lspci -nn | grep "audio contoller" | awk '{print $1;}')/power/control -.. note:: - The current device power status can be read by entering this command: +2. NXP imx8mp: + +.. code-block:: bash - .. code:: bash + sudo su + echo on>/sys/class/devlink/platform:power-domains:audiomix-pd--platform:3b6e8000.dsp/consumer/power/control - cat /sys/devices/pci0000\:00/0000\:$(lspci -nn | grep "audio controller" | awk '{print $1;}')/power/runtime_status +To re-enable automatic suspend use ``echo auto``, the current status can be read from the runtime_status file in these sysfs directories. -The logger trace filtration affects only traces sent after the filter setup, -so traces already stored on the kernel side are not affected. +Trace filtering details +----------------------- -Filters are set up incrementally, so when loggers are run twice with -different settings, then filters from the first run will not be restored to -the default state but will be replaced by a new one. To reset filters to the -default state, a firmware reset is needed. +* The filtering mechanism occurs on the firmware side so, after changing the + log level to verbose for each component, the DSP can be overwhelmed by + tracing. -Detailed description --------------------- +* Core functionality is provided by the DSP, so filtering does not work in + offline mode - during conversion in a previously saved input file. -The filtration mechanism occurs on the firmware side so, after changing the -log level to verbose for each component, the DSP can be overhelmed by -tracing. +* The trace filtering affects only traces sent after the filter setup, + so traces already stored on the kernel side are not affected. If a certain log level is needed before a filter has been setup the DECLARE_TR_CTX() + macro at the beginning of the respective component's source file can be adapted. -Core functionality is provided by the DSP, so filtration does not work in -offline mode - during conversion in a previously saved input file. +* Filters are set up incrementally, so when loggers are run twice with + different settings, then filters from the first run will not be restored to + the default state but will be replaced by a new one. Active trace filters are stored in the firmware runtime memory. To reset the filters to the + default state, a firmware reset is needed. -Communication between the firmware and logger is occurs through driver -debug file systems. The logger writes new trace settings to ``sys/kernel/debug/sof/filter``. These will be used to create *IPC* messages with new -trace levels. A simple text data format is used: +* Communication between the firmware and logger occurs through the kernel debugfs. The logger writes new trace settings to ``sys/kernel/debug/sof/filter``. + These will be used to create *IPC* messages with new trace levels. A simple text data format is used: -``log1_level uuid1_id pipe1_id comp1_id; [log2_level uuid2_id pipe2_id comp2_id;]\n`` + ``log1_level uuid1_id pipe1_id comp1_id; [log2_level uuid2_id pipe2_id comp2_id;]\n`` -Any unused uuid_id should be set here to 0; other unused fields should be -set to -1. ``log_level`` must always be set to a valid value that represents ``LOG_LEVEL_*`` defined values. + Any unused uuid_id should be set here to 0; other unused fields should be + set to -1. ``log_level`` must always be set to a valid value that represents ``LOG_LEVEL_*`` defined values. diff --git a/developer_guides/debugability/perf-counters/index.rst b/developer_guides/debugability/perf-counters/index.rst new file mode 100644 index 00000000..4e1ea77b --- /dev/null +++ b/developer_guides/debugability/perf-counters/index.rst @@ -0,0 +1,63 @@ +.. _dbg-perf-counters: + +Performance Counters +#################### + +Firmware can be configured to trace performance counters for each processing +component. Each performance trace entry includes: + +- component UUID + +- peak platform and cpu timer ticks consumed during component's copy processing + +.. note:: + Performance timestamp macros use both the platform timer and cpu timer in case + the latter is not always running. + +Performance Counters usage +************************** + +Currently, you can only enable performance counters statically during FW build in +one of two ways: + +- Select **Performance counter** from **Debug** menu using ``make menuconfig``. + +- Add ``CONFIG_PERFORMANCE_COUNTERS=y`` to specific FW config, for + example, tigerlake_defconfig. + + +After you enable the performance counters, they are logged periodically for each +active component with the pipeline period frequency. + +Example +******* + +Performance counter trace example: + + .. code-block:: bash + + [ 8481257.031250] ( 51.562500) c0 demux 1.2 src/audio/pipeline.c:206 perf comp_copy peak plat 782 cpu 8136 + +``demux 1.2`` - processing component + +``plat 782`` - peak platform cycles consumed + +``cpu 8136`` - peak CPU cycles consumed + +MCPS calculation +---------------- + +The equation below illustrates how to calculate component MCPS (million cycles +per second) consumption. + + .. code-block:: bash + + MCPS = cpu_ticks / (pipeline_period[s] * 10^6) + + // for common pipeline_period = 1ms it can be simplified to + MCPS = cpu_ticks / 1000 + +In the trace example above, cpu_ticks = 8136, the pipeline_period is 1ms so the +demux consumption equals 8,136 MCPS + + diff --git a/developer_guides/debugability/probes/index.rst b/developer_guides/debugability/probes/index.rst index c05bd91a..98e6dedc 100644 --- a/developer_guides/debugability/probes/index.rst +++ b/developer_guides/debugability/probes/index.rst @@ -12,26 +12,84 @@ from each buffer. Requirements ************ +.. _install-tinycompress: + - Install `tinycompress `_ (crecord tool) Enabling Probes *************** -- Enable the following Linux kernel configuration options: +.. _kernel-side: + +Kernel side +=========== + +- The probes support is enabled by Kconfig on supported platforms as a SOF client + driver, check the kernel config for ``SND_SOC_SOF_DEBUG_PROBES``. + The debugfs also needs to be enabled for the probes to be usable. .. code-block:: bash CONFIG_DEBUG_FS=y - CONFIG_SND_SOC_SOF_DEBUG_PROBES=y - CONFIG_SND_SOC_SOF_HDA_PROBES=y -- Enable the Probe module in the SOF firmware ``kconfig`` using this command: +- The probes client needs to be enabled via the 'enable' module parameter (e.g. ``/etc/modprobe.d/sof.conf``): + + .. code-block:: bash + + options snd_sof_probes enable=1 + + To make sure that the sound card for the probes is consistent between boots, a + card slot can be forced for the module. + For example to use card3, this can be added to the sof.conf file: + + .. code-block:: bash + + options snd slots=,,,snd_sof_probes + + Remove and re-load the driver: + + .. code-block:: bash + + rmmod snd_sof_probes + modprobe snd_sof_probes + + Verify that the card is available (if not, try to reboot): + + .. code-block:: bash + + cat /proc/asound/cards | grep sofprobes + +.. _firmware-side: + +Firmware side +============= + +- The Probe module can be enabled under the 'Probe' menu's 'Probes enabled' prompt (``PROBES``) + To edit the ``kconfig`` use this command: .. code-block:: bash make menuconfig -- Refer to **Step 3 Build firmware binaries** in :ref:`Build SOF from Scratch ` for reference. + The following options available + + Required for audio probes: + + .. code-block:: bash + + CONFIG_PROBE=y # enable probes + CONFIG_PROBE_POINTS_MAX=16 # max probepoints + + Required for logging through probes interface: + + .. code-block:: bash + + CONFIG_LOG_BACKEND_SOF_PROBE=y + CONFIG_ZEPHYR_LOG=y + + Refer to :ref:`Simple logging case` for quick guide to use probes logging interface. + +- Refer to **Step 3 Build firmware binaries** in :ref:`Build SOF from Scratch ` for reference on how to build SOF FW. Note that you do not need to modify the audio topology file. @@ -49,13 +107,14 @@ the last stage of extraction. .. code-block:: bash - crecord -c0 -d23 -b8192 -f4 -FS32_LE -R48000 -C4 /tmp/extract.dat + crecord -c3 -d0 -b8192 -f4 -FS32_LE -R48000 -C4 /tmp/extract.dat Usage: .. code-block:: none - -d : device ID; equals 23 in the above example. + -c : card number; 3 in the above example if a slot is forced + -d : device ID; equals 0 in the above example (probes card only have 1 compressed capture stream). -b : buffer size. For probes, this is part of the probe initialization IPC and denotes the extraction stream buffer size on the host side. -f : fragments is basically number of periods for compress stream. @@ -66,7 +125,8 @@ the last stage of extraction. - Pause the playback stream. (optional) - Add probe points via the ``debugfs`` "probe_points" entry in ``/sys/kernel/debug/sof`` - For example, to add a buffer with 7 probe points: + + For example, to add buffer 7 with a probe point (IPC3): .. code-block:: bash @@ -75,38 +135,89 @@ the last stage of extraction. Refer to the host side struct sof_probe_point_desc defined in ``sound/soc/sof/probe.h`` or struct probe_point in ``/src/include/ipc/probe.h`` from sof for the meaning of the triplets: - .. code-block:: c + .. code-block:: c + + /** + * Description of probe point + */ + struct probe_point { + uint32_t buffer_id; /**< ID of buffer to which probe is attached */ + uint32_t purpose; /**< PROBE_PURPOSE_EXTRACTION or PROBE_PURPOSE_INJECTION */ + uint32_t stream_tag; /**< Stream tag of DMA via which data will be provided for injection. + * For extraction purposes, stream tag is ignored when received, + * but returned actual extraction stream tag via INFO function. + */ + } __attribute__((packed)); + + In the above example, 7 stands for the ``buffer_id`` which is a monolithic + counter value that follows a component instantiation order. + + One way to find out the right instance of ``buffer_id`` is to enable + dev_dbg in ``sound/sound/soc/sof/topology.c`` and search for the widget id + from the following messages: + + .. code-block:: c + + dev_dbg(scomp->dev, + "tplg: widget %d (%s) is ready [type: %d, pipe: %d, pins: %d / %d, stream: %s]\n", + swidget->comp_id, w->name, swidget->id, index, + swidget->num_input_pins, swidget->num_output_pins, + strnlen(w->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 ? w->sname : "none"); + + On a booted system the list can be acquired with + + .. code-block:: bash + + dmesg | grep "tplg: widget " + ... + snd_sof:sof_widget_ready: sof-audio-pci-intel-tgl 0000:00:1f.3: tplg: widget 2 (gain.1.1) is ready [type: 6, pipe: 1, pins: 1 / 1, stream: none] + snd_sof:sof_widget_ready: sof-audio-pci-intel-tgl 0000:00:1f.3: tplg: widget 3 (mixin.1.1) is ready [type: 4, pipe: 1, pins: 1 / 3, stream: none] + snd_sof:sof_widget_ready: sof-audio-pci-intel-tgl 0000:00:1f.3: tplg: widget 4 (pipeline.1) is ready [type: 32, pipe: 1, pins: 0 / 0, stream: none] + snd_sof:sof_widget_ready: sof-audio-pci-intel-tgl 0000:00:1f.3: tplg: widget 5 (codec0_in) is ready [type: 0, pipe: 1, pins: 0 / 0, stream: none] + snd_sof:sof_widget_ready: sof-audio-pci-intel-tgl 0000:00:1f.3: tplg: widget 6 (iDisp2 Tx) is ready [type: 7, pipe: 1, pins: 0 / 0, stream: none] + snd_sof:sof_widget_ready: sof-audio-pci-intel-tgl 0000:00:1f.3: tplg: widget 7 (dai-copier.HDA.Analog.playback) is ready [type: 27, pipe: 2, pins: 1 / 0, stream: Analog] + ... + + For IPC4 system, the above example looks like this (extraction from gain.1.1): + + .. code-block:: bash + + echo 2,0,0 > probe_points + + The semantics of the buffer_id are quite different on IPC4 system: + + .. code-block:: c + + typedef union probe_point_id { + uint32_t full_id; + struct { + uint32_t module_id : 16; /**< Target module ID */ + uint32_t instance_id : 8; /**< Target module instance ID */ + uint32_t type : 2; /**< Probe point type as specified by ProbeType enumeration */ + uint32_t index : 6; /**< Queue index inside target module */ + } fields; + } __attribute__((packed, aligned(4))) probe_point_id_t; + + .. code-block:: c /** * Description of probe point */ struct probe_point { - uint32_t buffer_id; /**< ID of buffer to which probe is attached */ - uint32_t purpose; /**< PROBE_PURPOSE_EXTRACTION or PROBE_PURPOSE_INJECTION */ + probe_point_id_t buffer_id; /**< ID of buffer to which probe is attached */ + uint32_t purpose; /**< PROBE_PURPOSE_xxx */ uint32_t stream_tag; /**< Stream tag of DMA via which data will be provided for injection. * For extraction purposes, stream tag is ignored when received, * but returned actual extraction stream tag via INFO function. */ - } __attribute__((packed)); - - In the above example, 7 stands for the ``buffer_id`` which is a monolithic - counter value that follows a component instantiation order. - - One way to find out the right instance of ``buffer_id`` is to enable - dev_dbg in ``sound/sound/soc/sof/topology.c`` and search for the widget id - from the following messages: - - .. code-block:: c - - dev_dbg(scomp->dev, "tplg: ready widget id %d pipe %d type %d name : %s stream %s\n", - swidget->comp_id, index, swidget->id, tw->name, - strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 - ? tw->sname : "none"); + } __attribute__((packed, aligned(4))); 2. Unpause the playback stream. (optional) #. Close the playback stream when done. #. Close the crecord tool. +.. _data-parsing: + Data parsing ************ @@ -124,4 +235,31 @@ Usage and ouput: sof-probes: done As a result, ``buffer_7.wav`` is generated in the *tools/build_tools/probes* folder. The wave file can then be examined with your tool of choice -such as ``Audacity``. \ No newline at end of file +such as ``Audacity``. + +.. _simple-logging-case: + +Simple logging case +******************* + +With the :ref:`crecord` and :ref:`sof-probes` in path, FW built with :ref:`probes logging enabled`, and probes enabled from :ref:`Linux side`, it should be possible to extract the logs with following steps: + +#. crecord has to be started first: + +.. code-block:: bash + + crecord -c3 -d0 -b8192 -f4 -FS32_LE -R48000 -C4 | sof-probes -l + +#. then to enable logs through probes sysfw interface use following commands as root, + + IPC3 system: + +.. code-block:: bash + + echo 0,1,0 > /sys/kernel/debug/sof/probe_points + + IPC4 system: + +.. code-block:: bash + + echo 0,0,0 > /sys/kernel/debug/sof/probe_points diff --git a/developer_guides/debugability/shell/index.rst b/developer_guides/debugability/shell/index.rst new file mode 100644 index 00000000..4f0b943c --- /dev/null +++ b/developer_guides/debugability/shell/index.rst @@ -0,0 +1,119 @@ +.. _dbg-zephyr-shell: + +Zephyr Shell +############ + +Zephyr provides a shell subystem for interactive debugging and a channel +to run custom test sequences. SOF supports use of the Zephyr shell. + +The Zephyr shell is documented at: +https://docs.zephyrproject.org/latest/services/shell/index.html + +Requirements +************ + +- SOF target platform must have Zephyr support. + +- At least one shell backend (DSP memory window, serial port, RTT, ...) compatible + with target platform. + +Build SOF with Shell Support +**************************** + +Shell is typically disabled by default and the firmware needs to be +rebuilt. For common SOF targets, a build overlay is provided in SOF +upstream to easily enable shell suppot in build. + + .. code-block:: bash + + # example build for Intel Tiger Lake platform + build-sh> sof/scripts/xtensa-build-zephyr.py tgl -o app/shell_overlay.conf + +Using Shell with Intel cavstool.py +********************************** + +This section covers use with SOF targets compatible with +CONFIG_SHELL_BACKEND_ADSP_MEMORY_WINDOW backend (for example Audio DSPs +on Intel Tiger Lake and Meteor Lake). + +Running the tool with "-p" to create a pseudo terminal for the shell: + + .. code-block:: bash + + dut-sh> sudo ./cavstool.py -l -p + INFO:cavs-fw:Existing driver "snd_sof_pci_intel_tgl" found + INFO:cavs-fw:Mapped PCI bar 0 of length 16384 bytes. + INFO:cavs-fw:Selected output stream 15 (GCAP = 0xffffffff) + INFO:cavs-fw:Mapped PCI bar 4 of length 1048576 bytes. + INFO:cavs-fw:Detected cAVS 1.8+ hardware + INFO:cavs-fw:Waiting forever for firmware handoff, ROM_STATUS = 0xffffffff + INFO:cavs-fw:FW alive, ROM_STATUS = 0x5 + INFO:cavs-fw:shell PTY at: /dev/pts/4 + +The Zephyr shell is now available at pseudo terminal /dev/pts/4 (see log above) +and can be attached with any terminal program: + + .. code-block:: bash + + dut-sh> sudo minicom -p /dev/pts/4 + Welcome to minicom 2.8 + + OPTIONS: I18n + Port /dev/modem + + Press CTRL-A Z for help on special keys + + ~$ kernel uptime + Uptime: 31600 ms + ~$ kernel stacks + 0x9e0a4e78 ll_thread0 (real size 8192): unused 6752 usage 1440 / 8192 (17 %) + 0x9e0a34b8 (real size 4096): unused 4008 usage 88 / 4096 ( 2 %) + 0x9e0a3400 (real size 4096): unused 4008 usage 88 / 4096 ( 2 %) + 0x9e0a3348 (real size 4096): unused 4008 usage 88 / 4096 ( 2 %) + 0x9e0a3290 (real size 4096): unused 4008 usage 88 / 4096 ( 2 %) + 0x9e0a37d0 edf_workq (real size 8192): unused 6304 usage 1888 / 8192 (23 %) + 0x9e0a3c48 sysworkq (real size 1024): unused 728 usage 296 / 1024 (28 %) + 0x9e0a3180 shell_adsp_memory_window (real size 2048): unused 760 usage 1288 / 2048 (62 %) + 0x9e0a3080 logging (real size 4096): unused 3488 usage 608 / 4096 (14 %) + 0x9e0a38b0 idle 00 (real size 1024): unused 824 usage 200 / 1024 (19 %) + 0xbe09df80 IRQ 00 (real size 2048): unused 1712 usage 336 / 2048 (16 %) + 0xbe09e780 IRQ 01 (real size 2048): unused 0 usage 2048 / 2048 (100 %) + 0xbe09ef80 IRQ 02 (real size 2048): unused 0 usage 2048 / 2048 (100 %) + 0xbe09f780 IRQ 03 (real size 2048): unused 0 usage 2048 / 2048 (100 %) + ~$ kernel threads + Scheduler: 1 since last call + Threads: + 0x9e0a4e78 ll_thread0 + options: 0x0, priority: -16 timeout: 0 + state: pending, entry: 0xbe02e060 + stack size 8192, unused 6752, usage 1440 / 8192 (17 %) + + 0x9e0a34b8 + options: 0x0, priority: -16 timeout: 0 + state: prestart, entry: 0xbe0154cc + stack size 4096, unused 4008, usage 88 / 4096 (2 %) + + [cut] + *0x9e0a3180 shell_adsp_memory_window + options: 0x0, priority: 14 timeout: 0 + state: , entry: 0xbe01969c + stack size 2048, unused 760, usage 1288 / 2048 (62 %) + + 0x9e0a3080 logging + options: 0x0, priority: 14 timeout: 0 + state: pending, entry: 0xbe016710 + stack size 4096, unused 3488, usage 608 / 4096 (14 %) + + 0x9e0a38b0 idle 00 + options: 0x1, priority: 15 timeout: 0 + state: , entry: 0xbe054298 + stack size 1024, unused 824, usage 200 / 1024 (19 %) + ~$ + +The memory window backend does not rely on IPC, so the shell is not +dependent on the IPC version implementation. The cavstool.py is also +implemented to handle cases where the DSP is suspended to lower power +state and the memory window is not accessible to host. When the DSP +is in such state, the shell terminal will appear inactive, but it will +resume immediately after DSP resumes to active state, without need +to rerun the cavstool.py script. diff --git a/developer_guides/firmware/async_messaging_best_practices.rst b/developer_guides/firmware/async_messaging_best_practices.rst new file mode 100644 index 00000000..efc49c1b --- /dev/null +++ b/developer_guides/firmware/async_messaging_best_practices.rst @@ -0,0 +1,651 @@ +.. _async_messaging_best_practices: + +Async Messaging Best Practices +############################## + +This section provides best practices and point out issues that developers should +be aware of when using asynchronous messages in their components. + +Message Type IDs +**************** + +The only unique value that is guaranteed to not change is UUID. The message type +IDs can change every time when a component is registering as a message +consumer/producer. In fact it depends on initialization order of components and +it may seem to be static. However it can change i.e. with addition of a new +component to pipeline and the entire mechanism will stop working. + +The components must not hardcode this value and they must use a runtime value of +component instance ID returned during producer/consumer registration. + +.. _message_handling: + +Message Handling +**************** + +The asynchronous messages consumers must be prepared to handle the messages +asynchronously. A message can be received while a component is processing data +and it can lead to undefined behavior when internal state is changed +immediately. The recommended way of handling asynchronous messages is to save a +message and apply the changes during a next processing time i.e. at the +beginning of processing. + +- When a processing of asynchronous message is done at the beginning of + component processing (Process Data), only then component processing is + deterministic. + +If an asynchronous message cannot be processed immediately by a consumer, it is +a good practice to implement a queue of incoming asynchronous messages in a +component or at least count asynchronous messages since last processing to +detect this kind of situation. + +A consumer component cannot assume that it can save a message pointer and +dereference is later. The message memory is released as soon as Asynchronous +Messaging Service will finish processing, so a consumer component must copy a +content of asynchronous message. + +Example - the pseudo code on a consumer side: + +.. code:: cpp + + queue_t request_queue; + + struct request_t { + uint8_t new_state; + }; + + struct message_context_t { + int32_t error; + queue_t *request_queue; + }; + + message_context_t message_context; + + void callback(const ams_message_payload_s * const ams_message_payload, void *ctx) { + if(ams_message_payload->message_length != sizeof(request_t)) { + ((message_context_t *)ctx)->error = 1; + return; + } + + queue_push(((message_context_t *)ctx)->request_queue, (request_t *)(ams_message_payload->message)); + } + + error_code componentA::Init(Pipeline* parent_ppl, const ModuleACfg* cfg) { + //getting Message Type ID + error = am_service_get_message_type_id(MESSAGE_A, &message_type_id); + if(error != 0) { + //error handling + } + + //registering consumer + message_context.error = 0; + message_context.request_queue = &request_queue; + error = am_service_register_consumer(message_type_id, GetcomponentID(), GetInstanceID(), callback, &message_context); + if(error != 0) { + //error handling + } + } + + error_code componentA::ProcessData(size_t max_output_data_size, uint32_t* custom_error_code) { + while(queue_size(message_context.request_queue) > 0) { + if(message_context.error != 0) { + //error handling + } + + request_t *r = queue_pop(message_context.request_queue); + //handling of async message + process_request(r); + } + + //regular processing + } + +.. _processing_in_a_consumer_callback: + +Processing in a consumer callback +********************************* + +The consumer callbacks must not do any heavy processing. Best if the callback +only saves information and a component will process it in the next processing +slot. + +- The asynchronous message callbacks are called in the context of a message + producer or in the context of IDC task. +- If a heavy processing is done in a message, then a producer MPCS or IDC task + budget needs to take into account this heavy processing. While it may be + possible to take into account additional budget for simple cases, it is + impossible to accommodate MCPS requirements in the general case (i.e. large + number of consumers with heavy processing). + +The example described in :ref:`message_handling` is also applicable for this issue. + +.. _message_filtering_mechanism: + +Message Filtering Mechanism +*************************** + +1. If a consumer is interested in async messages from one particular producer, + it needs to register for that particular producer using component ID and + instance ID. A component ID and instance ID of producer should be passed as + ``LARGE_CONFIG_SET`` parameter to the consumer. +2. If a producer wants to target a specific component instance, then it should + use send function that is parametrized with component ID and instance ID. + +Passing Pointers In Asynchronous Messages +***************************************** + +The asynchronous messages do not prevent to pass pointers between components. It +seems like a good idea at the beginning when a developer wants to return a +result. While it is simple solution, it may lead into the following issues: + +- there can be more than one consumer of a message and each of them needs to + have an allocated slot in the memory, +- the firmware framework cannot guarantee that component memory will be still + available when async message is processed i.e. a component can be subject of + firmware paging and the firmware infrastructure can decide to evict component + memory, + +The recommended method is to not pass pointers in the asynchronous messages. + +One-way Messages +**************** + +The asynchronous messages are one-way messages and there is no explicit feedback +whether a message was received or processed. The ``send`` functions return only +information whether the async messaging service return an error. + +Two-way Messages - Example #1 +***************************** + +The asynchronous messages are One-way Messages. Sometimes there is a need to +implement “function call” like functionality where a component instance wants +another component instance to take an action and return a result. This +functionality should be implemented with following issues in mind: + +- the result will not be returned immediately - :ref:`message_handling`, +- avoiding heavy processing in a consumer callback - :ref:`processing_in_a_consumer_callback`, +- 1:1 vs. M:N communication - :ref:`message_filtering_mechanism`, +- blocking vs. non-blocking execution: + + - If a producer depends on a result, it has to be handled as a blocking call + and the producer has to block its execution until result is received. To + do that, a blockade should be used when ``send`` functions return. + + - the task blockade must be removed when a result is received (in a + result callback), it will allow to continue a component execution, + - when the task blockade is set, the component execution is preempted and + the component with the highest priority is called, + +- one vs. two messages for handling action and result + + - the “function call” can be implemented as two separate messages: one for + triggering action from component A to component B and then second one for + passing result from component B to component A, it increases amount of + asynchronous messages, + - the recommended way is to implement it as one asynchronous message where + component A and B are both consumer and producer of the same asynchronous + message + + - it is important to note that filtering mechanism must be used to break + recursion - component A must discard a message from itself, + +Example - 1:1 function call: + +Consumer (component instance A) code: + +.. code:: cpp + + uint32_t message_type_id; + + queue_t request_queue; + + struct message_context_t { + int32_t error; + queue_t *request_queue; + }; + + message_context_t message_context; + + queue_t request_queue; + + struct request_t { + uint8_t message_type; //1 - request, 2 - response + uint8_t new_state; + }; + + void consumer_callback(const ams_message_payload_s * const payload, void *ctx) { + if(payload->message_length != sizeof(request_t)) { + ((message_context_t *)ctx)->error = 1; + return; + } + + //only requests are supported by a consumer + if((request_t *)(payload->message)->message_type != 1) { + ((message_context_t *)ctx)->error = 2; + return; + } + + queue_push(((message_context_t *)ctx)->request_queue, (request_t *)(payload->message)); + } + + error_code componentB::Init(Pipeline* parent_ppl, const ModuelCfg* cfg) { + //getting Message Type ID + error = am_service_get_message_type_id(MESSAGE_A, &message_type_id); + if(error != 0) { + //error handling + } + + //registering consumer + message_context.error = 0; + message_context.request_queue = &request_queue; + error = am_service_register_consumer_mi(message_type_id, GetcomponentID(), GetInstanceID(), component_A_id, component_A_instance_id, callback, &message_context); + if(error != 0) { + //error handling + } + } + + error_code componentB::ProcessData(size_t max_output_data_size, uint32_t* custom_error_code) { + while(queue_size(request_queue) > 0) { + if(message_context.error != 0) { + //error handling + } + + request_t *r = queue_pop(request_queue); + + //handling of async message + process_request(r); + + //message response + request_t response; + response.message_type = 2; + + error_code error = am_service_send_mi(message_type_id, GetcomponentID(), GetInstanceID(), component_A_id, component_A_instance_id, sizeof(request_t), &response); + if(e != 0) { + //error handling + } + } + + //regular processing + } + +Producer code: + +.. code:: cpp + + uint32_t message_type_id; + + queue_t request_queue; + + struct message_requestor_context_t { + int32_t error; + queue_t *request_queue; + uint32_t blockade; + }; + + message_requestor_context_t message_context; + + struct request_t { + uint8_t message_type; //1 - request, 2 - response + uint8_t new_state; + }; + + void consumer_callback(const ams_message_payload_s * const payload, void *ctx) { + if(payload->message_length != sizeof(request_t)) { + (message_requestor_context_t *)ctx->error = 1; + return; + } + + //only responses are supported by a producer + if((request_t *)(payload->message)->message_type != 2) { + (message_requestor_context_t *)ctx->error = 2; + return; + } + + queue_push(((message_context_t *)ctx)->request_queue, (request_t *)(payload->message)); + (message_requestor_context_t *)ctx->blockade = 0; //unblock a producer component execution + } + + error_code componentA::Init(Pipeline* parent_ppl, const ModuleACfg* cfg) { + //getting Message Type ID + error = am_service_get_message_type_id(MESSAGE_A, &message_type_id); + if(error != 0) { + //error handling + } + + //registering consumer + message_context.error = 0; + message_context.blockade = 0; + message_context.request_queue = &request_queue; + error = am_service_register_consumer_mi(message_type_id, GetcomponentID(), GetInstanceID(), component_B_id, component_B_instance_id, callback, &message_context); + if(error != 0) { + //error handling + } + + //registering as a producer + error = am_service_register_producer(message_type_id); + if(error != 0) { + //error handling + } + } + + error_code componentA::ProcessData(size_t max_output_data_size, uint32_t* custom_error_code) { + ... + SystemServiceInternal const* services = get_system_services(); + ... + //message request + request_t response; + response.message_type = 1; + + message_context.blockade = 1; //initialize blockade + error_code error = am_service_send_mi(message_type_id, GetcomponentID(), GetInstanceID(), component_B_id, component_B_instance_id, sizeof(request_t), &response); + if(e != 0) { + //error handling + } + + //block a component execution until a consumer will reply with a result + _AdspCurrentTaskBlockade blockade; + services->SetTaskRunCondition(&blockade, (uint32_t*)(&message_context.blockade), 0 /*unblocking value*/, 0xffffffff); + services->RemoveTaskRunCondition(&blockade); + + while(queue_size(request_queue) > 0) { + if(message_context.error != 0) { + //error handling + } + + request_t *r = queue_pop(request_queue); + + //handling of async message + process_request(r); + } + ... + //regular processing + } + +Two-way Messages - Example #2 +***************************** + +The below example shows a real use case where multiple control interfaces are +supported (IPC and I2C). Control application needs to produce an async message +and when async message response is received, it needs to respond to the correct +requestor IPC vs. I2C. To make it happen, the unique async message ID needs to +be introduced. The unique ID can be generated globally or locally when source +component is tracked. In the below pseudo-code, the ID is generated locally and +component B needs to respond to the correct component. + +Example - 1:1 function call: + +Consumer (component instance B) code: + +.. code:: cpp + + uint32_t message_request_id; + uint32_t message_response_id; + uint32_t current_state; + + queue_t request_queue; + queue_t requestor_info_queue; + + struct unique_message_id { + uint16_t component_id; + uint16_t instance_id; + uint32_t message_id; + }; + + struct message_context_t { + int32_t error; + queue_t *request_queue; + queue_t *requestor_info_queue; + }; + + message_context_t message_context; + + struct request_t { + unique_message_id uid; + uint32_t requested_state; + }; + + struct requestor_info_t { + unique_message_id uid; + uint16_t component_id; + uint16_t instance_id; + }; + + struct response_t { + unique_message_id uid; + uint32_t current_state; + }; + + void consumer_callback(const ams_message_payload_s * const payload, void *ctx) { + if(payload->message_length != sizeof(request_t)) { + ((message_context_t *)ctx)->error = 1; + return; + } + + queue_push(((message_context_t *)ctx)->request_queue, (request_t *)(payload->message)); + + requestor_info_t info; + info.uid = (request_t *)(payload->message)->uid; + info.component_id = payload->producer_component_id; + info.instance_id = payload->producer_instance_id; + queue_push(((message_context_t *)ctx)->requestor_info_queue, info); + } + + error_code componentB::Init(Pipeline* parent_ppl, const ModuelCfg* cfg) { + //getting Message Type ID for requests + error = am_service_get_message_type_id(MESSAGE_REQUEST, &message_request_id); + if(error != 0) { + //error handling + } + + //registering consumer + message_context.error = 0; + message_context.request_queue = &request_queue; + message_context.requestor_info_queue = &requestor_info_queue; + error = am_service_register_consumer(message_request_id, GetcomponentID(), GetInstanceID(), callback, &message_context); + if(error != 0) { + //error handling + } + + //getting Message Type ID for responses + error = am_service_get_message_type_id(MESSAGE_RESPONSE, &message_response_id); + if(error != 0) { + //error handling + } + + //registering producer + error = am_service_register_producer(message_response_id, GetcomponentID(), GetInstanceID()); + if(error != 0) { + //error handling + } + } + + void process_request(request_t *r) { + current_state = r->requested_state; + } + + uint32_t get_current_state() { + return current_state; + } + + error_code componentB::ProcessData(size_t max_output_data_size, uint32_t* custom_error_code) { + while(queue_size(request_queue) > 0) { + if(message_context.error != 0) { + //error handling + } + + request_t *r = queue_pop(request_queue); + + //handling of async message + process_request(r); + + //message response + response_t response; + response.uid = r->uid; + response.current_state = get_current_state(); + + //find requestor information + requestor_info_t *ri = find(requestor_info_queue, r->uid); + if(ri == NULL) { + //error handling + } + queue_pop(requestor_info_queue, ri); + + error_code error = am_service_send_mi(message_type_id, GetcomponentID(), GetInstanceID(), ri->component_id, ri->instance_id, sizeof(response_t), &response_t); + if(e != 0) { + //error handling + } + } + + //regular processing + ... + } + +Producer code: + +.. code:: cpp + + uint32_t message_request_id; + uint32_t message_response_id; + uint32_t message_id_counter; + + queue_t response_queue; + queue_t request_source_queue; + + struct unique_message_id { + uint16_t component_id; + uint16_t instance_id; + uint32_t message_id; + }; + + struct message_requestor_context_t { + int32_t error; + queue_t *response_queue; + uint32_t blockade; + }; + + message_requestor_context_t message_context; + + struct request_source_t { + unique_message_id uid; + uint32_t source; //0 - IPC, 1 - I2C + }; + + struct request_t { + unique_message_id uid; + uint32_t requested_state; + }; + + struct response_t { + unique_message_id uid; + uint32_t current_state; + }; + + void consumer_callback(const ams_message_payload_s * const payload, void *ctx) { + if(payload->message_length != sizeof(response_t)) { + (message_requestor_context_t *)ctx->error = 1; + return; + } + + queue_push(((message_context_t *)ctx)->response_queue, (request_t *)(payload->message)); + } + + error_code componentA::Init(Pipeline* parent_ppl, const ModuleACfg* cfg) { + message_id_counter = 0; + + //getting Message Type ID for response + error = am_service_get_message_type_id(MESSAGE_RESPONSE, &message_response_id); + if(error != 0) { + //error handling + } + + //registering consumer + message_context.error = 0; + message_context.blockade = 0; + message_context.response_queue = &response_queue; + error = am_service_register_consumer(message_response_id, GetcomponentID(), GetInstanceID(), callback, &message_context); + if(error != 0) { + //error handling + } + + //getting Message Type ID for request + error = am_service_get_message_type_id(MESSAGE_REQUEST, &message_request_id); + if(error != 0) { + //error handling + } + + //registering as a producer + error = am_service_register_producer(message_request_id, GetcomponentID(), GetInstanceID()); + if(error != 0) { + //error handling + } + } + + Message::IxcStatus componentA::LargeConfigSet(uint32_t large_param_id, + bool init_block, + bool final_block, + uint32_t data_off_size, + const ByteArray* data, + ByteArray* response) + { + ... + //message request + request_t request; + response.uid = {GetcomponentID(), GetInstanceID(), message_id_counter++}; + response.requested_state = state_from_request; + + request_source_t source; + source.uid = response.uid; + source.source = 0; //IPC + queue_push(request_source_queue, source); + + error_code error = am_service_send_mi(message_type_id, GetcomponentID(), GetInstanceID(), component_B_id, component_B_instance_id, sizeof(request_t), &response); + if(e != 0) { + //error handling + } + ... + } + + void process_request(response_t *r) { + ... + request_source_t *rs = find(request_source_queue, r->uid); + if(rs == NULL) { + //error handling + } + + if(rs->source == 0) { + //send response over IPC + } + + queue_pop(request_source_queue, rs); + ... + } + + error_code componentA::ProcessData(size_t max_output_data_size, uint32_t* custom_error_code) { + ... + while(queue_size(response_queue) > 0) { + if(message_context.error != 0) { + //error handling + } + + response_t *r = queue_pop(request_queue); + + //handling of async message + process_request(r); + } + ... + //regular processing + } + +Max message size +**************** + +The asynchronous message size is limited by size of an async message slot in the +AM queue, which is currently 4KB and should not be exceeded. + +Queue is Full +************* + +The queue of asynchronous messages is used when there are customers of messages +registered on other core than producer’s core. This queue has limited size and +it can happen that ``send`` function will fail. In such case, the best strategy +is to retry ``send`` function call in the next execution period. diff --git a/developer_guides/firmware/index.rst b/developer_guides/firmware/index.rst index 9584ee4f..ee2e75cd 100644 --- a/developer_guides/firmware/index.rst +++ b/developer_guides/firmware/index.rst @@ -9,12 +9,7 @@ Developer guides and information for firmware development. :maxdepth: 1 component-tutorial/tut-intro - mem-mgmt - pm-runtime/index - schedulers - drivers/index - components/index - pipelines/index porting - kd_integration/index cmake + async_messaging_best_practices + llext_modules diff --git a/developer_guides/firmware/llext_modules.rst b/developer_guides/firmware/llext_modules.rst new file mode 100644 index 00000000..e4040d54 --- /dev/null +++ b/developer_guides/firmware/llext_modules.rst @@ -0,0 +1,108 @@ +.. _llext_modules: + +LLEXT Modules +############# + +|SOF| support for loadable modules, using Zephyr LLEXT API. + +Zephyr LLEXT API +**************** + +Please refer to https://docs.zephyrproject.org/latest/services/llext/index.html +for detailed documentation. In short, the Zephyr Linkable Loadable Extensions +(LLEXT) API implements support for run-time loading and unloading of ELF-format +executable code and data. + +SOF use of the LLEXT API +************************ + +SOF has multiple ways to implement loadable modules. LLEXT is one of them. +With it modules are built as shared or relocatable ELF objects with an addition +of a cryptographic signature, using any user-supplied key, and a manifest. When +loaded and instantiated, Zephyr LLEXT functionality is used to dynamically +resolve module internal as well as SOF and Zephyr external code and data +references. In the future support for inter-module linking will be added. + +Accessing the base firmware from LLEXT modules +********************************************** + +LLEXT modules can access all code and data from the base firmware exported, +using the ``EXPORT_SYMBOL()`` macro. Therefore writing LLEXT modules isn't very +different from built-in ones. + +Implementing LLEXT modules +************************** + +At the moment only modules, implementing the Module Adapter API +:ref:`apps-comp-world` are supported. + +.. _multiple-adapter-modules: + +It is possible to implement multiple Module Adapter modules with a common code +base, i.e. sharing a set of source files and functions. Then a single LLEXT +object would be created, implementing multiple Module Adapter interfaces. In +that case an array of ``struct sof_module_api_build_info`` objects is needed and +the TOML file should contain those multiple module entries too. +src/audio/mixin_mixout/mixin_mixout.c is an example of such a case. + +As explained above, LLEXT modules in general look very similar to native SOF +code, with the only restriction of having no access to not-exported symbols. + +LLEXT modules should also contain a ``.buildinfo`` section, containing a +``struct sof_module_api_build_info`` object and a ``.module`` section, +containing a ``struct sof_man_module_manifest`` object. The latter should also +contain a pointer to a module entry point function, returning a pointer to the +module's ``struct module_interface`` instance. All these additions can be +performed, using ``SOF_LLEXT_MOD_ENTRY()``, ``SOF_LLEXT_MODULE_MANIFEST()`` and +``SOF_LLEXT_BUILDINFO`` helper macros. See src/audio/eq_iir/eq_iir.c for an +example. + +A TOML configuration file is needed for building of LLEXT modules too. It is +generated by the C preprocessor at build time from the same components, as would +be used for a monolithic build. For this preprocessor run a small header file is +added. It mostly just includes ``platform.toml`` and ``${module}.toml``, similar +to src/samples/audio/smart_amp_test_llext/llext.toml.h. + +Finally an additional CMakeLists.txt is needed similar to +src/samples/audio/smart_amp_test_llext/CMakeLists.txt. It contains a single call +to ``sof_llext_build()``, which is an SOF helper function, using Zephyr LLEXT +cmake support by calling ``add_llext_target()`` and ``add_llext_command()``. + +With that in place, it is also possible to switch between monolithic and modular +builds by specifying the module as "tristate" in its Kconfig and selecting "m" +for modular builds. Note, that it is possible to implement third party Module +Adapter drivers, that would be built exclusively as loadable modules. Such +modules don't have to use "tristate" in their Kconfig entries. + +Installation +************ + +As specified in +:ref:`Firmware look-up paths per Intel platform ` +the |SOF| Linux kernel driver loads SOF modules by their UUIDs, +specified in the topology. For SOF in-tree modules the process of creation and +installation of modules in a deployment tree is automated by the +xtensa-build-zephyr.py script. It copies modules to the deployment tree as +files with a "llext" extension and creates symbolic links to them named as +``${UUID}.bin``. E.g. + +.. code-block:: cfg + + B36EE4DA-006F-47F9-A06D-FECBE2D8B6CE.bin -> drc.llext + +Note, that as described :ref:`above ` multiple UUIDs +can be associated with a single module, in such cases multiple symbolic links +will be created, e.g. + +.. code-block:: cfg + + 39656EB2-3B71-4049-8D3F-F92CD5C43C09.bin -> mixin_mixout.llext + 3C56505A-24D7-418F-BDDC-C1F5A3AC2AE0.bin -> mixin_mixout.llext + +See :ref:`apps-component-overview` for more information on UUID use by SOF +component and module adapter drivers. + +It is also possible to avoid using the script by running ``west build`` to build +an SOF image and any modules, then using the cross-compiler to preprocess TOML +files and finally by running rimage to sign them. This would generate the same +result but figuring out all the command-line arguments would be rather difficult. diff --git a/developer_guides/index.rst b/developer_guides/index.rst index 3ef80cdd..5ac976e5 100644 --- a/developer_guides/index.rst +++ b/developer_guides/index.rst @@ -24,6 +24,7 @@ terminology before reading further. virtualization/running fuzzing/index testbench/index + add_new_arch Technical Notes *************** diff --git a/developer_guides/linux_driver/index.rst b/developer_guides/linux_driver/index.rst index 4082c00b..c6534d70 100644 --- a/developer_guides/linux_driver/index.rst +++ b/developer_guides/linux_driver/index.rst @@ -6,6 +6,5 @@ SOF Linux Driver .. toctree:: :maxdepth: 1 - architecture/sof_driver_arch third_party/index diff --git a/developer_guides/testbench/build_testbench.rst b/developer_guides/testbench/build_testbench.rst index b371757d..c6173507 100644 --- a/developer_guides/testbench/build_testbench.rst +++ b/developer_guides/testbench/build_testbench.rst @@ -3,6 +3,13 @@ Build and Run Testbench ####################### +First, you'll need to install some dependencies to run the testbench: + +.. code-block:: bash + + sudo apt install valgrind bc # For Ubuntu/Debian + sudo dnf install valgrind bc # For Fedora + Retrieve the required firmware from the ``thesofproject`` repository in Github as described in :ref:`build-from-scratch`. Start a shell at the firmware repository top level in the ``$SOF_WORKSPACE/sof`` directory as also described. @@ -108,7 +115,7 @@ it can be launched to an audio editor tool such as mhWaveEdit: .. code-block:: bash paplay audio_out.wav - mhWaveEdit audio_out.wav + mhwaveedit audio_out.wav .. figure:: fig_mhwaveedit.png diff --git a/developer_guides/topology/topology.rst b/developer_guides/topology/topology.rst index d2f7a4ab..3e2a23af 100644 --- a/developer_guides/topology/topology.rst +++ b/developer_guides/topology/topology.rst @@ -217,7 +217,7 @@ DAI_ADD macro defined as follows: | **dai_index**: index of the dai in the firmware. Please note that the DAI’s of different types can have the same dai_index. The dai_index information can be found by looking in platform-specific dai array - definitions in the firmware. For example, for apollolake these are + definitions in the firmware. For example, for Apollo Lake these are defined in src/platform/apollolake/dai.c. | **dai_be**: name of CPU DAI as defined in DAI array in the platform driver. | **buffer**: Source/sink buffer the DAI is connected to. This completes the @@ -303,7 +303,7 @@ be scheduled. To specify the DSP core for a pipeline, use the SOF_TKN_SCHED_CORE token located in tools/topology/m4/pipeline.m4: -.. code-block:: +.. code-block:: none W_PIPELINE(stream, period, priority, core, initiator, platform) ... @@ -313,14 +313,14 @@ located in tools/topology/m4/pipeline.m4: Then specify this 'core' in your pipeline definition, such as in tools/topology/sof/pipe-dai-playback.m4: -.. code-block:: +.. code-block:: none W_PIPELINE(N_DAI_OUT, SCHEDULE_PERIOD, SCHEDULE_PRIORITY, SCHEDULE_CORE, SCHEDULE_TIME_DOMAIN, pipe_dai_schedule_plat) To specify the DSP core for a component/widget, use the SOF_TKN_COMP_CORE_ID token located in tools/topology/m4/pga.m4: -.. code-block:: +.. code-block:: none dnl W_PGA(name, format, periods_sink, periods_source, core, kcontrol0. kcontrol1...etc) ... diff --git a/developer_guides/topology2/topology2.rst b/developer_guides/topology2/topology2.rst index 26958c6f..86b5db62 100644 --- a/developer_guides/topology2/topology2.rst +++ b/developer_guides/topology2/topology2.rst @@ -6,10 +6,10 @@ Topology 2.0 This is a high-level keyword extension on top of the existing ALSA conf topology format designed to: -* Simplify the ALSA conf topology definitions by providing high level "classes" so topology - designers need to write less config for commonly defined objects. +* Simplify the ALSA conf topology definitions by providing high level "classes". In this way, topology + designers can write less configurations for commonly defined objects. -* Allow simple reuse of objects. Define once and reuse (like M4) with the ability to alter objects +* Allow simple reuse of objects. Define once and reuse (like M4) with the ability to alter object configuration attributes from defaults. * Allow data type and value verification. This is not done today and frequently crops up in FW bug @@ -17,44 +17,44 @@ to: .. contents:: -1. Ingredients -************** +Ingredients +*********** -A typical 2.0 configuration file consists of the following: +A typical 2.0 configuration file consists of the following components: * Classes * Objects * Arguments * Conditional includes -1.1 Classes ------------ +Classes +------- -Topology today has some common definitions that are often reused throughout with slightly altered -configurations such as widgets (components), pipelines, dais, pcm and controls. Topology 2.0 -introduces the concept of reusable "class" like definitions that can be used to create commonly -used topology objects. Classes are defined with a new keyword “Class”. +Topology today has some common definitions that are often reused with slightly altered +configurations, such as widgets (components), pipelines, dais, pcm, and controls. Topology 2.0 +introduces the concept of reusable class-like definitions that you can use to create commonly +used topology objects. Classes are defined with a new keyword ``Class``. -A class definition always starts with the "Class" keyword followed by 2 nodes. The first node contains -the class group and the second node contains the class name. For example: +A class definition always starts with the ``Class`` keyword followed by two nodes. The first node contains +the class group, and the second node contains the class name. For example: .. code-block:: bash Class.Base.data {} -Note that '.' is the node separator in the alsaconf syntax. In the above line, "Base" is the class -group and "data" is the class name. Currently, the alsatplg compiler supports the following class groups: +Note that '.' is the node separator in the alsaconf syntax. In the above line, ``Base`` is the class +group and ``data`` is the class name. Currently, the alsatplg compiler supports the following class groups: widget, pipeline, DAI, control and base. Most of the commonly used topology objects can be classified into -one of these groups. If there's need for a new class group, the alsatplg compiler should be updated to add +one of these groups. If a new class group is required, the alsatplg compiler should be updated to add support for it. -1.1.1 Class Ingredients -''''''''''''''''''''''' +Class Ingredients +''''''''''''''''' A minimalistic class definition should consist of the following: -* One or more attributes declared with the keyword "DefineAttribute". Attributes are parameters that - are used to describe the object. For ex: +* One or more attributes declared with the keyword ``DefineAttribute``. Attributes are parameters that + are used to describe the object. For example: .. code-block:: bash @@ -62,11 +62,11 @@ A minimalistic class definition should consist of the following: type "string" } -"name" is an attribute of type string. + "name" is an attribute of type string. * Basic attribute qualifiers with the constructor array and unique attribute name. Attribute qualifiers - should be declared within the "attributes {}" node in the class definition. + should be declared within the ``attributes {}`` node in the class definition. .. code-block:: bash @@ -87,10 +87,10 @@ A minimalistic class definition should consist of the following: unique "name" } -1.1.2 A Simple Class -'''''''''''''''''''' +A Simple Class +'''''''''''''' -An example of a simple class definition with 2 attributes and qualifiers is as follows: +The following example demonstrates a simple class definition with two attributes and qualifiers: .. code-block:: bash @@ -124,27 +124,27 @@ An example of a simple class definition with 2 attributes and qualifiers is as f } } -The "data" class definition belonging to the "base" class group, contains 2 attributes namely, -name and bytes, both of type "string". By default, all attributes are give the type "integer" unless -specified otherwise like above. Currently, topology 2.0 supports only "integer" and "string" types for -attributes. +The ``data`` class definition belonging to the ``base`` class group contains two attributes, +name and bytes, both of type ``string``. By default, all attributes have the ``integer`` type, unless +specified otherwise, like in the example above. Currently, topology 2.0 supports only ``integer`` and +``string`` types for attributes. The attribute qualifiers are used to describe how to instantiate an object from the class definition and validate the attribute values. -In the above definition, the "constructor" array tells the compiler how to build the object's name. -A data object instantiated with the name "EQIIR-Coefficients" will be given the name, -"data.EQIIR-Coefficients" i.e. the class name followed by '.' followed by the constructor attribute +In the above definition, the ``constructor`` array tells the compiler how to build the object's name. +A data object instantiated with the name ``EQIIR-Coefficients`` will be given the name +``data.EQIIR-Coefficients``, that is the class name followed by '.' followed by the constructor attribute values separated by '.'. -The "unique" qualifier indicates that two data objects instantiated within the same alsaconf node should -have unique values for their "name" attribute. If two data objects are instantiated within the same alsaconf -node with the same "name" attribute, there be no errors but the two object instances with be merged -with the second instance overriding the attribute values in the first one. Therefore, it is the topology -writer's responbility to ensure that two instances within the same parent node have different unique attribute -values. +The ``unique`` qualifier indicates that multiple data objects instantiated within the same alsaconf node should +have unique values for their ``name`` attribute. If two data objects are instantiated within the same alsaconf +node with the same ``name`` attribute, errors will not occur, but the two object instances will be merged. +Additionally, the attribute values in the second instance will override the attribute values in the first one. +Therefore, it is the topology writer's responsibility to ensure that multiple instances within the same parent +node have different unique attribute values. -Let's consider another class definition example for the "pga" widget belonging to the class group "Widget". +Let's consider another class definition example for the ``pga`` widget belonging to the class group ``Widget``: .. code-block:: bash @@ -178,16 +178,18 @@ Let's consider another class definition example for the "pga" widget belonging t } } -Note that the pga object names are constructed with the class name "pga" followed by 2 attribute values, index -and instance, ex: pga.1.1. Also note that both the attributes wil be given the type "integer" by default because -the definitions do not specify the type. Also, note that in practice, the unique instance attribute should also be -part of the constructor. +Note that the pga object names are constructed with the class name +``pga`` followed by two attribute values, index and instance. For +example, ``pga.1.1``. Both attributes will have the ``integer`` type +by default because the definitions do not specify the type. In +practice, the unique instance attribute should also be part of the +constructor. -1.1.3 Attribute default values -'''''''''''''''''''''''''''''' +Attribute default values +'''''''''''''''''''''''' Optionally, class definitions can be extended to give default values for their attributes. Let's add a -"uuid" attribute of type string to the pga class above and give it a default value. +``uuid`` attribute of type ``string`` to the ``pga`` class and give it a default value: .. code-block:: bash @@ -231,14 +233,14 @@ Optionally, class definitions can be extended to give default values for their a All pga objects will automatically be given the default uuid as specified above in the class definition. -1.1.4 Advanced attribute qualifiers -''''''''''''''''''''''''''''''''''' +Advanced attribute qualifiers +''''''''''''''''''''''''''''' -Apart from the mandatory basic attribute qualifiers, attributes in the class definition can be qualified +Apart from the mandatory basic attribute qualifiers, you can qualify attributes in the class definition using the following advanced keywords: * **Mandatory:** Attributes qualified as mandatory should be provided with a value in the object - instance, failing which the alsatplg compiler will emit and error. Objects with default values in the class + instance, failing which the alsatplg compiler will emit an error. Objects with default values in the class definition need not be qualified as mandatory. Also, note that attributes in the constructor array are mandatory by default as they are required for building the object's name. @@ -307,11 +309,13 @@ Let's add some extra attributes and advanced qualifers into the pga class defini uuid "7e:67:7e:b7:f4:5f:88:41:af:14:fb:a8:bd:bf:86:82" } -1.1.5 Automatic attributes -'''''''''''''''''''''''''' -In some cases, an attribute's value depends on other attribute values and need to be computed during -build time. Such attributes are qualified with the "automatic" keyword in the class definition. Please -refer to buffer_ for the complete class definition. +Automatic attributes +'''''''''''''''''''' + +In some cases, an attribute value depends on other attribute values +and need to be computed during build time. Such attributes are +qualified with the ``automatic`` keyword in the class definition. +Refer to buffer_ for the complete class definition. .. code-block:: bash @@ -337,15 +341,19 @@ refer to buffer_ for the complete class definition. } } -In the above, case the buffer's size attribute value will be computed based on the pipeline parameters to which the buffer -belongs. Currently, the alsatplg compiler only has support for computing the automatic attribute "size" for the buffer objects. -If needed, support for automatic attributes in new class definitions should be added in the alsatplg compiler. +In the example above, the ``size`` attribute value of ``buffer`` is +computed based on the pipeline parameters, to which the buffer +belongs. Currently, the alsatplg compiler only has support for +computing the automatic attribute ``size`` for the buffer objects. +Support for automatic attributes in new class definitions +should be added in the alsatplg compiler if necessary. + +Attribute Constraints +''''''''''''''''''''' -1.1.6 Attribute Constraints -''''''''''''''''''''''''''' One of the key features of Topology 2.0 is validation of the values provided for objects. This is achieved with the help of constraints added to the attribute definition. Constraints can be added to an attribute using -the "constraints" keyword as follows: +the ``constraints`` keyword: .. code-block:: bash @@ -353,12 +361,12 @@ the "constraints" keyword as follows: constraints {} } -Currently, 3 types of constraints are supported: +Currently, three types of constraints are supported: -* min: min value for attribute, applicable only to integer type attributes -* max: max value for attribute, applicable only to integer type attributes +* **min:** The minimum value for an attribute, applicable only to integer type attributes. +* **max:** The maximum value for an attribute, applicable only to integer type attributes. - For example, the pga class definition can be expanded with an attribute for "ramp_step_ms" with min and + For example, the pga class definition can be expanded with an attribute for ``ramp_step_ms`` with min and max values as follows: .. code-block:: bash @@ -370,9 +378,9 @@ Currently, 3 types of constraints are supported: } } -* valid values: an array of acceptable human-readable values, applicable only to string type attributes. +* **valid values:** an array of acceptable human-readable values, applicable only to string type attributes. - For example, the pga class can have an attribue for "ramp_step_type" with pre-defined values as follows: + For example, the pga class can have an attribue for ``ramp_step_type`` with pre-defined values as follows: .. code-block:: bash @@ -388,17 +396,23 @@ Currently, 3 types of constraints are supported: } } -When the pga is class is instantiated with a value that doesn't belong in the valid_values array for ramp_step_type, -the alsatplg compiler will emit an error along with the list of permitted values. +When the pga class is instantiated with a value that does not belong in +the ``valid_values`` array for ``ramp_step_type``, the alsatplg compiler emits +an error along with the list of valid values. -1.1.7 Attributes with token references -'''''''''''''''''''''''''''''''''''''' -Typically, a lot of objects contain a private data section that is composed of sets of tuple arrays. Some of the attributes in -a class definition may need to be packed into the tuple array. Such attributes are identified with the "token_ref" node -which contains the name of the tuple array that the attribute should be built into. For example, both the ramp_step_ms and -ramp_step_type attributes in the pga class need to be added to the tuple array. So, they are contain the token_ref node -with the value "sof_tkn_volume.word" indicating that the attributes should be packed with the "sof_tkn_volume tuple" array -of type "word" as shown below. +Attributes with token references +'''''''''''''''''''''''''''''''' + +Typically, a lot of objects contain a private data section that is +composed of sets of tuple arrays. Some of the attributes in a class +definition may need to be packed into the tuple array. Such attributes +are identified with the ``token_ref`` node which contains the name of +the tuple array that the attribute should be built into. For example, +both the ``ramp_step_ms`` and ``ramp_step_type`` attributes in the pga +class need to be added to the tuple array. So, they contain the +token_ref node with the value ``sof_tkn_volume.word`` indicating that +the attributes should be packed with the ``sof_tkn_volume tuple`` +array of type ``word``: .. code-block:: bash @@ -427,10 +441,12 @@ of type "word" as shown below. } } -Sometimes, valid_values for attributes might need to be translated from the human readable values to integer tuple values so -that it can be parsed correctly by the kernel driver. In the example above, valid values for ramp_step_type are defined -as human readable string values such as linear, log etc. which are translated to tuple values 0, 1, etc respectively before -getting added to the tuple array. +Sometimes, ``valid_values`` for attributes might need to be translated +from the human readable values to integer tuple values so that it can +be parsed correctly by the kernel driver. In the example above, valid +values for ``ramp_step_type`` are defined as human readable string +values, such as linear and log. These values are translated to tuple +values (0, 1, etc) before getting added to the tuple array. .. code-block:: bash @@ -454,10 +470,12 @@ getting added to the tuple array. } } -1.1.8 A complete class definition -''''''''''''''''''''''''''''''''' +.. _complete_class_definition: + +A complete class definition +''''''''''''''''''''''''''' -Puting it all together, the complete defintiion for the pga widget class is as follows: +Putting it all together, the following example demonstrates the complete definition for the pga widget class: .. code-block:: bash @@ -549,24 +567,27 @@ Puting it all together, the complete defintiion for the pga widget class is as f ramp_step_ms 200 } -1.2 Objects ------------ +Objects +------- + Objects are used to instantiate multiple instances of the same class to avoid duplicating -common attribute definitions. Objects are instantiated with the new keyword "Object" followed by -3 nodes in order as follows: +common attribute definitions. Objects are instantiated with the new keyword ``Object`` followed by +three nodes: .. code-block:: bash Object.Widget.pga."1" {} -The nodes refer to the following: +The nodes refer to the following elements: -* Class group to which the object's class belongs i.e. "Widget" -* Class name i.e. "pga" -* Unique attribute value: This is the value for the attribute that is qualified as "unique" in the - class definition i.e. "instance" +* Class group to which the object class belongs. In this case, the class belongs to ``Widget``. +* Class name. That is ``pga``. +* Unique attribute value. This is the value for the attribute that is qualified as ``unique`` in the + class definition. That is ``instance``. -Using the pga class definition in section 1.1.8, a pga widget object can be instantiated as follows: +Using the pga class definition as described in +:ref:`complete_class_definition`, you can instantiate a pga widget +object in the following way: .. code-block:: bash @@ -574,16 +595,21 @@ Using the pga class definition in section 1.1.8, a pga widget object can be inst index 5 } -where 1 is the value for the unique attribute ("instance") in the pga class definition and the -"index" attribute is given the value 5. Since, there are no other mandatory attributes in the -class defintion, the above instance is fully valid. The key thing to notice in the instantiation -is that there is no need to duplicate commonly used attribute values in the object instantiation. -Objects automatically inherit the default values for attributes from their class definition. +where ``1`` is the value for the unique attribute ``instance`` in the pga class definition and the +``index`` attribute is given the value of 5. As the class definition contains no other mandatory +attributes, the above instance is fully valid. + +.. important:: + + You do not need to duplicate commonly used attribute values in the + object instantiation. Objects automatically inherit the default + values for attributes from their class definition. + +Modifying default attributes +'''''''''''''''''''''''''''' -1.2.1 Modifying default attributes -'''''''''''''''''''''''''''''''''' Attributes that have default values in the class definition can be overwritten by specifying the -new value in the object instance as follows: +new value in the object instance: .. code-block:: bash @@ -592,11 +618,12 @@ new value in the object instance as follows: ramp_step_ms 300 } -The above object overrides the ramp_step_ms default value of 200ms set in the class definition with the -new value of 300ms. +The above object overrides the ``ramp_step_ms`` default value of 200 |_| ms set in the class definition with the +new value of 300 |_| ms. + +Objects within classes +'''''''''''''''''''''' -1.2.2 Objects within classes -'''''''''''''''''''''''''''' Class definitions can optionally also include child objects that need to be instantiated for every instance of the class object. For example, a pga widget typically always contains a volume mixer control. The mixer control class definition is as follows: @@ -695,13 +722,13 @@ The mixer control class definition is as follows: mute_led_direction 0 } -A mixer conrol object can be added to the pga widget class definition as below: +You can add a mixer control object to the pga widget class definition: .. code-block:: bash Class.Widget."pga" { # Attributes, qualifiers and default values are skipped for simplicity. - # Please refer to the complete class definition in Section 1.1.8 above for details + # Refer to the complete class definition in "Complete Class Definition" for details # volume control for pga widget Object.Control.mixer."1" { @@ -711,14 +738,15 @@ A mixer conrol object can be added to the pga widget class definition as below: } } -The mixer control "My Volume Control" will be programmatically added to all pga objects. +The mixer control ``My Volume Control`` will be programmatically added to all pga objects. -1.2.3 Object attribute inheritance -'''''''''''''''''''''''''''''''''' -One thing to note in the above object instantiation is that the mixer object has 2 mandatory attributes, -index and instance but the index attribute value is missing in the instance. This is because the mixer control -object inherits the index attribute value from it's parent pga object when it gets instantiated. For ex, lets take -a pga object instance. +Object attribute inheritance +'''''''''''''''''''''''''''' + +One thing to note in the above object instantiation is that the mixer object has two mandatory attributes, +index and instance. But the index attribute value is missing in the instance. This is because the mixer control +object inherits the index attribute value from its parent pga object when it gets instantiated. For example, +consider the following pga object instance: .. code-block:: bash @@ -726,12 +754,15 @@ a pga object instance. index 5 } -The index value "5" will be inherited by the mixer control object in the pga class definition. Inheritance is -implied only when a child object's class definition shares an attribute of the same name with its parent class -definition. In the case of mixer control class and pga widget class, the shared attribute is "index". +The mixer control object in the pga class definition inherits the index value of ``5``. Inheritance occurs +only when a child object's class definition shares an attribute of the same name with its parent class +definition. In the case of mixer control class and pga widget class, the shared attribute is ``index``. + +.. _setting_child_object_attributes: + +Setting child object attributes +''''''''''''''''''''''''''''''' -1.2.4 Setting child object attributes -''''''''''''''''''''''''''''''''''''' Let's consider the pga class definition with the mixer control object again: .. code-block:: bash @@ -748,8 +779,8 @@ Let's consider the pga class definition with the mixer control object again: } } -Note that the mixer control object has it's name set in the pga widget class definition. But, ideally we want to -give the mixer control a new name whenever a new pga widget object is instantiated. This can be achieved as follows: +Note that the mixer control object has its name set in the pga widget class definition. But, ideally, we want to +give the mixer control a new name whenever a new pga widget object is instantiated. You can do it like this: .. code-block:: bash @@ -763,13 +794,14 @@ give the mixer control a new name whenever a new pga widget object is instantiat } } -Now, the mixer control object is assigned the name "My Control Volume 5". +Now, the mixer control object is assigned the name ``My Control Volume 5``. -1.2.5 Nested Objects -'''''''''''''''''''' +Nested Objects +'''''''''''''' + Objects can also be instantiated as child objects within other object instances. For example, a -switch control can be added to pga widget objects during instantiation as follows: +switch control can be added to pga widget objects during instantiation: .. code-block:: bash @@ -790,12 +822,13 @@ switch control can be added to pga widget objects during instantiation as follow } } -Note how the "unique" attribute for the two mixer control objects differ to keep the mixer instances unique. +Note how the ``unique`` attribute for the two mixer control objects differs to keep the mixer instances unique. + +Recursive object attribute inheritance +'''''''''''''''''''''''''''''''''''''' -1.2.6 Recursive object attribute inheritance -'''''''''''''''''''''''''''''''''''''''''''' Objects can be nested within objects that are nested within other objects themselves. In this case, the attribute -values cam be inherited all the way from the top-level parent object. For example, consider the following class +values can be inherited all the way from the top-level parent object. For example, consider the following class definition for volume-playback pipeline: .. code-block:: bash @@ -827,14 +860,15 @@ class is instantiated as: } This ensures that all child objects within the volume-playback object will inherit the -index attribute value from it. So the pga widget object will have the same index and by the same +index attribute value from it. So the pga widget object will have the same index. By the same rule, the mixer control object within the pga widget object will also have the same index attribute -value of "1". +value of 1. + +Setting child object attributes deep down in the parent object tree +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -1.2.7 Setting child object attributes deep down in the parent object tree -''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' -In section 1.2.4, we saw that we can set child attribute values from its parent object instance. -For example, the mixer control object's name can be set from the pga widget object instace. This +In :ref:`setting_child_object_attributes`, we saw that we can set child attribute values from its parent object instance. +For example, you can set the mixer control object's name from the pga widget object instance. This can be extended further and it is possible to set the mixer control name from the parent object of the pga object. Consider the volume playback object instance in the previous section. We can set the mixer control name for the pga object as follows: @@ -852,11 +886,12 @@ mixer control name for the pga object as follows: } -1.3. Arguments in top-level configuration files ------------------------------------------------ +Arguments in top-level configuration files +------------------------------------------ + Arguments are used to pass build-time parameters that can be used for building multiple binaries from the same configuration file. Consider the following top-level topology configuration file -with 2 pipelines: +with two pipelines: .. code-block:: bash @@ -902,19 +937,24 @@ with 2 pipelines: } } -The value for the "dynamic_pipeline" attribute in the volume-playback objects in the above example -will be expanded from the provided value for the DYNAMIC_PIPELINE argument when building the -topology binary with the -DDYNAMIC_PIPELINE=1 or -DDYNAMIC_PIPELINE=0 option. +In this example, the value for the ``dynamic_pipeline`` attribute in the volume-playback objects +is expanded from the provided value for the ``DYNAMIC_PIPELINE`` argument when building the +topology binary with the ``-DDYNAMIC_PIPELINE=1`` or ``-DDYNAMIC_PIPELINE=0`` option. + +.. note:: -Note that the alsatplg compiler only parses the arguments that are defined at the top-level node in the -machine topology file. + The alsatplg compiler only parses the arguments that are defined at + the top-level node in the machine topology file. -1.4 Includes ------------- -When building a top-level configuration file, it should include all the class definitions for the objects -being instantiated, failing which the compiler will emit errors calling out missing class definitions. The -include paths for searching for dependencies can be specified as below. All paths are relative to the -directory specified by the environment variable "ALSA_CONFIG_DIR". +Includes +-------- + +When building a top-level configuration file, it should include all +class definitions for the objects being instantiated, failing which +the compiler will emit errors calling out missing class definitions. +All paths are relative to the directory specified by the environment +variable ``ALSA_CONFIG_DIR``. You can specify the include paths for +dependencies as follows: .. code-block:: bash @@ -922,7 +962,7 @@ directory specified by the environment variable "ALSA_CONFIG_DIR". -and the class definitions can be included as follows: +Include the class definitions as follows: .. code-block:: bash @@ -931,8 +971,11 @@ and the class definitions can be included as follows: -3. Simple machine topology -************************** +.. _simple_machine_topology: + +Simple machine topology +*********************** + A machine topology typically consists of the following: * Include paths pointing to the search directory for class definitions includes @@ -943,8 +986,8 @@ A machine topology typically consists of the following: * PCM objects * Top-level pipeline connections -Let's look at a simple machine topology configuration file that includes a volume-playback pipeline, -a HDA type DAI link, a playback PCM and the top-level connection. +Let's consider a simple machine topology configuration file that includes a volume-playback pipeline, +a HDA type DAI link, a playback PCM, and the top-level connection: .. code-block:: bash @@ -1038,11 +1081,11 @@ a HDA type DAI link, a playback PCM and the top-level connection. } Note that the above configuration file only includes the top-level route between the buffer widget -"buffer.1.1" in the volume-playback pipeline and the dai widget "dai.HDA.1.playback". The connections +``buffer.1.1`` in the volume-playback pipeline and the dai widget ``dai.HDA.1.playback``. The connections between the widgets in the volume-playback pipeline are defined in the class definition. Let's peek into the volume-playback pipeline class definition to look at the route objects contained within -the class definition. Please refer to volume-playback_ for the complete class definition. +the class definition. Refer to volume-playback_ for the complete class definition. .. code-block:: bash @@ -1126,7 +1169,7 @@ the class definition. Please refer to volume-playback_ for the complete class de mips 5000 } -The pipeline class definition is fairly straight-forward to follow except for the route object instances. +The pipeline class definition is fairly easy to follow except for the route object instances. Let's analyze it a bit further. The route class definition is defined as follows: .. code-block:: bash @@ -1171,9 +1214,9 @@ Let's analyze it a bit further. The route class definition is defined as follows } } -Note that a route object is expected to have instance, source and sink attributes. +Note that a route object is expected to have instance, source, and sink attributes. -Let's look at the route objects in the volume-playback class again: +Let's consider the route objects in the volume-playback class again: .. code-block:: bash @@ -1194,14 +1237,14 @@ Let's look at the route objects in the volume-playback class again: } } -Notice that the source and sink attributes are defined for all of the routes. For ex: the second route object, -"Object.Base.route.2" has a sink attribute value of "pga..1". Referring back to the pga widget class definition -in Section 1.1.8, we know that a pga widget object's constructor has 2 attributes, namely, index and instance. +Notice that the source and sink attributes are defined for all of the routes. For example, the second route object +``Object.Base.route.2`` has a sink attribute value of ``pga..1``. Referring back to the pga widget class definition +in :ref:`complete_class_definition`, we know that a pga widget object's constructor has two attributes, ``index`` and ``instance``. We know the instance of the pga widget in the volume-playback class is 1 by looking at the list of widgets. But the index attribute value for the pga widget in the pipeline is unknown. It will only be set from a top-level -topology config file as in Section 3. Therefore, the index attribute is left empty in the class definition -and it will populated with the appropriate value by the alsatplg compiler when the route object is built. For the -machine topology above, the route object "Object.base.route.2" will be built with the right pipeline ID's as follows: +topology config file as in :ref:`simple_machine_topology`. Therefore, the index attribute is left empty in the class definition. +The alsatplg compiler will populate the index attribute with the appropriate value when the route object is built. For the +machine topology above, the route object ``Object.base.route.2`` will be built with the right pipeline IDs as follows: .. code-block:: bash @@ -1210,13 +1253,14 @@ machine topology above, the route object "Object.base.route.2" will be built wit sink "pga.1.1" } -Currently, the alsatplg supports the feature of filling in attribute values only for the route object source +Currently, alsatplg can fill in attribute values only for the route object source and sink attributes. If needed, this feature can be extended for other types of objects. -4. Conditional includes -*********************** +Conditional includes +******************** + Conditional includes allow building multiple topology binaries from the same input configuration file. -For example, let's consider the HDA generic machine topology. The number of DMIC's determines wether +For example, let's consider the HDA generic machine topology. The number of DMICs determines whether the DMIC configuration file should be included or not. This can be achieved as follows: .. code-block:: bash @@ -1231,19 +1275,23 @@ the DMIC configuration file should be included or not. This can be achieved as f "[1-4]" "include/platform/intel/dmic-generic.conf" } -The regular expression "[1-4]" indicates that the dmic-generic.conf file should be included if +The regular expression ``[1-4]`` indicates that the dmic-generic.conf file should be included if the DMIC_COUNT argument value is between 1 and 4. Assuming the top-level file is called -"sof-hda-generic.conf", two separate topology binaries can be built as follows: +``sof-hda-generic.conf``, you can build two separate topology binaries with the following commands: -**`alsatplg -p -c sof-hda-generic.conf -o sof-hda-generic.tplg`** for machines with no DMIC's +* For machines with no DMICs: -**`alsatplg -D DMIC_COUNT=2 -p -c sof-hda-generic.conf -o sof-hda-generic-2ch.tplg`** for machines with 2 DMIC's. + ``alsatplg -p -c sof-hda-generic.conf -o sof-hda-generic.tplg`` -Conditional includes are not limited to top-level configuration files. They can be added to any node -in the configuration file to include the configuration at the specified node. For example, we conditionally -include the right filter coefficients for the byte controls in a EQIIR widget as follows: +* For machines with two DMICs: -Define the argument for the coefficients in the top-level topology file as follows: + ``alsatplg -D DMIC_COUNT=2 -p -c sof-hda-generic.conf -o sof-hda-generic-2ch.tplg`` + +Conditional includes are not limited to top-level configuration files. You can add them to any node +in the configuration file to include the configuration at the specified node. For example, we can conditionally +include the right filter coefficients for the byte controls in the EQIIR widget. + +Define the argument for the coefficients in the top-level topology file: .. code-block:: bash @@ -1252,7 +1300,7 @@ Define the argument for the coefficients in the top-level topology file as follo default "highpass_40hz_0db_48khz" } -And then the coefficients can be included as follows: +And then include the coefficients: .. code-block:: bash @@ -1267,49 +1315,108 @@ And then the coefficients can be included as follows: } } -5. Building 2.0 configuration files -*********************************** -Topology 2.0 configuration files can be compiled to produce the topology binary files using the -alsatplg compiler as follows: +Building 2.0 configuration files +******************************** -alsatplg <-D args=values> -p -c input.conf -o output.tplg +You can use alsatplg to compile Topology 2.0 configuration files and produce the topology binary files: -The -D switch is used to pass comma-separated argument values to the top-level configuration file. +.. code-block:: bash -The -P switch can be used to convert a 2.0 configuration file to the 1.0 configuration file as -follows: + alsatplg <-D args=values> -p -c input.conf -o output.tplg -alsatplg <-D args=values> -P input.conf -o output.conf +The ``-D`` switch is used to pass comma-separated argument values to the top-level configuration file. -6. Topology reminders -********************* +You can use the ``-P`` switch to convert a 2.0 configuration file to the 1.0 configuration file: + +.. code-block:: bash -1. "index" refers to the pipeline ID in pipeline, widget and control class groups + alsatplg <-D args=values> -P input.conf -o output.conf + +Split topologies +**************** + +Linux kernel can load multiple topologies, a topology for a single function. +This feature is useful to support SDCA setups with standardized components. And no need to create topologies +for every new product. To achieve this, you need to split the topology into multiple tplg files. +The split topology files should be named as follows: + +.. code-block:: bash -2. "id" in the DAI class group objects refers to the link ID as defined in the machine driver in the kernel + sof---id.tplg -7. Alsaconf reminders -********************* +Currently is only needed for the DMIC function and not needed for SDCA functions in general. +It should be mtl, lnl, etc. -1. "." refers to a node separator. "foo.bar value" is quivalent to +Where should be one of .. code-block:: bash + sdca-jack: SDCA headphone and headset. + sdca-amp: SDCA amp, where n is the amp link numbers. + sdca-mic: SDCA host mic. + dmic-ch: PCH DMIC, where n is the number of supported channels. Currently, only 2ch and 4ch are supported. + hdmi-pcm: HDMI with PCM id starts from . The is 3 for the "sof-hda-dsp" card and 5 for other cards. + + +For example + +.. code-block:: bash + + sof-sdca-2amp-id2.tplg + sof-sdca-mic-id4.tplg + sof-arl-dmic-2ch-id5.tplg + sof-hdmi-pcm5-id7.tplg + +The split topologies are the subset of the monolithic topology. Usually, you just need to add a description with proper +macro settings to disable the features that you don't need and set the first BE ID that in the topology in the cmake file +to generate the split topologies. + +For example + +.. code-block:: bash + + "cavs-sdw\;sof-arl-sdca-2amp-id2\;PLATFORM=mtl,NUM_SDW_AMP_LINKS=2,SDW_JACK=false,\ + SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,NUM_HDMIS=0" + + +Topology reminders +****************** + +Review the following topology considerations: + +- "index" refers to the pipeline ID in pipeline, widget, and control class groups. + +- "id" in the DAI class group objects refers to the link ID as defined in the machine driver in the kernel. + +Alsaconf reminders +****************** + +Review the following alsaconf considerations: + +- "." refers to a node separator. "foo.bar value" is quivalent to the following: + + .. code-block:: bash + foo { bar value } -2. Arrays are defined with [] as below +- Arrays are defined with []. For example: -.. code-block:: bash + .. code-block:: bash !constructor [ "foo" "bar" ] -It is recommended to use the "!" in the array definitions in the class definition. This is to ensure that if the class -configuration file is included more than once from different sources, the array items will not be duplicated. + We recommend to use the exclamation mark (!) in array definitions + within the class definition. Use it to ensure that the array items + are not duplicated if the class configuration file is included more + than once from different sources. .. _volume-playback: https://github.com/thesofproject/sof/blob/main/tools/topology/topology2/include/pipelines/volume-playback.conf .. _buffer: https://github.com/thesofproject/sof/blob/main/tools/topology/topology2/include/components/buffer.conf + +.. |_| unicode:: 0xA0 + :trim: diff --git a/developer_guides/unit_tests.rst b/developer_guides/unit_tests.rst index 3b1008dd..93e0e0e7 100644 --- a/developer_guides/unit_tests.rst +++ b/developer_guides/unit_tests.rst @@ -35,6 +35,28 @@ and re-use to build unit tests. Like this: ``-DINIT_CONFIG`` and a new build directory - Build and run the tests with ``make test`` or ``ninja test``. +.. note:: + + Use -DTOOLCHAIN=xt option. + + As of December 2021, -DTOOLCHAIN=xtensa--elf is not + supported. You can use a native toolchain, see below. + +If you get this double ``uintptr_t`` definition error: + +.. code-block:: bash + + [ 2%] Building C object test/cmocka/CMakeFiles/common_mock.dir/src/common_mocks.c.o + In file included from sof/test/cmocka/src/common_mocks.c:29: + sof/but/cmocka_git/src/cmocka_git/include/cmocka.h:132: + error: redefinition of typedef ‘uintptr_t’ + xcc/install/builds/RG-2017.8-linux/X4H3I16w2D48w3a_2017_8/xtensa-elf/include/stdint.h:252: + error: previous declaration of ‘uintptr_t’ was here + +... then append this to your cmake invocation: ``-DEXTRA_CFLAGS=-D_UINTPTR_T_DEFINED=1`` + +Additional unit tests options can be found in :ref:`cmake`. + Example: Running tests for APL ============================== @@ -45,12 +67,6 @@ Example: Running tests for APL -DROOT_DIR=/xcc/install/builds/RG-2017.8-linux/X4H3I16w2D48w3a_2017_8/xtensa-elf .. make -j4 && ctest -j8 -.. note:: - - Use -DTOOLCHAIN=xt option, -DTOOLCHAIN=xtensa--elf is not supported - -Additional unit tests options can be found in :ref:`cmake`. - Compiling unit tests without a cross-compilation toolchain ========================================================== diff --git a/getting_started/build-guide/build-from-scratch.rst b/getting_started/build-guide/build-from-scratch.rst old mode 100755 new mode 100644 index 286d4f4f..4c0519af --- a/getting_started/build-guide/build-from-scratch.rst +++ b/getting_started/build-guide/build-from-scratch.rst @@ -12,10 +12,9 @@ Intel platforms include: |BYT|, |CHT|, |HSW|, |BDW|, |APL|, |CNL|, |ICL|, |JSL|, Support also exists for NXP i.MX8/i.MX8X/i.MX8M platforms. -The following steps describe how to install the SOF development -environment on Ubuntu 16.04, 18.04, 18.10, and 20.04. They should work on -19.04, 19.10 and other Linux distributions with minor or no -modifications. +The following steps describe how to install the SOF development environment on +Ubuntu 16.04, 18.04, 18.10, and 20.04, and Fedora 36. They should work on Ubuntu +19.04, 19.10 and other Linux distributions with minor or no modifications. .. note:: @@ -50,7 +49,7 @@ Install package dependencies ============================ .. note:: - This guide uses Ubuntu as an example but any modern distribution can be + This guide uses Ubuntu/Fedora as an example but any modern distribution can be used for SOF development. Due to continuous default package updates in distributions, SOF @@ -58,39 +57,42 @@ documentation may not include explicit instructions for possible missing tools and packages. When you encounter missing dependencies, refer to your distribution's documentation on how to install them. -Make sure that ``build-essential`` and ``git`` are installed: +* For Fedora (tested with v36, other recent versions should work fine): -.. code-block:: bash + .. code-block:: bash - sudo apt-get install build-essential git + sudo dnf group install "Development Tools" "C Development Tools and Libraries" + sudo dnf install ncurses-devel gtk3-devel gettext-devel texinfo help2man \ + glibc-static libstdc++-static openssl-devel tree * For Ubuntu 20.04: .. code-block:: bash - sudo apt install autoconf flex bison texinfo help2man gawk libtool-bin \ - libncurses5 libncurses5-dev libssl-dev libgtk-3-dev tree \ - ninja-build gettext libasound2-dev + sudo apt install build-essential git autoconf flex bison texinfo help2man \ + gawk libtool-bin libncurses5 libncurses5-dev libssl-dev libgtk-3-dev \ + tree ninja-build gettext libasound2-dev * For Ubuntu 18.10: .. code-block:: bash - sudo apt-get install libgtk-3-dev libsdl1.2-dev libspice-protocol-dev \ - libspice-server-dev libusb-1.0-0-dev libusbredirhost-dev libtool-bin \ - acpica-tools valgrind texinfo virt-manager qemu-kvm \ - libvirt-daemon-system libvirt-clients virtinst libfdt-dev libssl-dev \ - pkg-config help2man gawk libncurses5 libncurses5-dev + sudo apt-get install build-essential git libgtk-3-dev libsdl1.2-dev \ + libspice-protocol-dev libspice-server-dev libusb-1.0-0-dev \ + libusbredirhost-dev libtool-bin acpica-tools valgrind texinfo \ + virt-manager qemu-kvm libvirt-daemon-system libvirt-clients virtinst \ + libfdt-dev libssl-dev pkg-config help2man gawk libncurses5 \ + libncurses5-dev * For Ubuntu 16.04 and 18.04: .. code-block:: bash - sudo apt-get install libgtk-3-dev libsdl1.2-dev libspice-protocol-dev \ - libspice-server-dev libusb-1.0-0-dev libusbredirhost-dev libtool-bin \ - iasl valgrind texinfo virt-manager qemu-kvm libvirt-bin virtinst \ - libfdt-dev libssl-dev pkg-config help2man gawk libncurses5 \ - libncurses5-dev + sudo apt-get install build-essential git libgtk-3-dev libsdl1.2-dev \ + libspice-protocol-dev libspice-server-dev libusb-1.0-0-dev \ + libusbredirhost-dev libtool-bin iasl valgrind texinfo virt-manager \ + qemu-kvm libvirt-bin virtinst libfdt-dev libssl-dev pkg-config help2man \ + gawk libncurses5 libncurses5-dev If you are using Ubuntu 16.04, the gcc version must be updated to gcc 7.3+ in order for the Advanced Linux Sound Architecture (ALSA) to build. @@ -105,11 +107,12 @@ in order for the Advanced Linux Sound Architecture (ALSA) to build. Install CMake ============= -If you use Ubuntu 18.04+ you can install CMake with apt: +If you use Ubuntu 18.04+ or Fedora you can install CMake with apt/dnf: .. code-block:: bash - sudo apt-get install cmake + sudo apt-get install cmake # Ubuntu + sudo dnf install cmake # Fedora For Ubuntu 16.04, CMake from apt is outdated and you must install CMake from sources. Refer to this short guide: https://cmake.org/install/. @@ -143,7 +146,8 @@ before you configure alsa-utils. .. code-block:: bash - sudo apt-get install libfftw3-dev libfftw3-doc + sudo apt-get install libfftw3-dev libfftw3-doc # Ubuntu + sudo dnf install fftw3-devel # Fedora Clone, build, and install alsa-utils. @@ -157,7 +161,9 @@ Clone, build, and install alsa-utils. # To install alsa-utils locally ./gitcompile --prefix=$HOME/local \ --with-alsa-inc-prefix=$HOME/local/include \ - --with-alsa-prefix=$HOME/local/lib + --with-alsa-prefix=$HOME/local/lib \ + --with-systemdsystemunitdir=$HOME/local/lib/systemd \ + --with-udev-rules-dir=$HOME/local/lib/udev sudo make install If you run into alsa-lib linking errors, try to re-build it with the libdir @@ -206,15 +212,14 @@ Clone both repos and check out the ``sof-gcc10.2`` and ``sof-gcc10x`` branch. cd "$SOF_WORKSPACE" git clone https://github.com/thesofproject/xtensa-overlay git clone https://github.com/thesofproject/crosstool-ng - cd xtensa-overlay - git checkout sof-gcc10.2 - cd ../crosstool-ng - git checkout sof-gcc10x + git -C xtensa-overlay/ checkout sof-gcc10.2 + git -C crosstool-ng/ checkout sof-gcc10x Build crosstool-ng and install it in its own source directory. .. code-block:: bash + cd crosstool-ng/ ./bootstrap ./configure --prefix=$(pwd) make @@ -226,31 +231,33 @@ Toolchains The config files provided refer to ``../xtensa-overlay/`` and point at different ``./builds/xtensa-*-elf`` subdirectories. Copy the ones you want to ``.config`` and build the cross-compiler(s) for your target -platform(s). Note that ``./ct-ng build`` requires an network connection to -download gcc components. +platform(s). Note that ``./ct-ng build`` requires an network connection +to download gcc components. While other steps take minutes at most, +building all toolchains may last about an hour depending on your network +connection and the performance of your system. .. code-block:: bash unset LD_LIBRARY_PATH - - # Baytrail/Cherrytrail - cp config-byt-gcc10.2-gdb9 .config - ./ct-ng build - # Haswell/Broadwell - cp config-hsw-gcc10.2-gdb9 .config - ./ct-ng build - # Apollo Lake - cp config-apl-gcc10.2-gdb9 .config - ./ct-ng build - # Cannon Lake, Ice Lake, Jasper Lake and Tiger Lake - cp config-cnl-gcc10.2-gdb9 .config - ./ct-ng build - # i.MX8/i.MX8X - cp config-imx-gcc10.2-gdb9 .config - ./ct-ng build - # i.MX8M - cp config-imx8m-gcc10.2-gdb9 .config - ./ct-ng build + + # byt = Bay Trail / Cherry Trail + # hsw = Haswell/Broadwell + # apl = Apollo Lake + # cnl = Cannon Lake, Ice Lake, Jasper Lake, and Tiger Lake + # imx = i.MX8/i.MX8X + # imx8m = i.MX8M + + # Omit the toolchains you don't want to save (a lot of) time + time for i in byt hsw apl cnl imx imx8m; do + cp config-$i-gcc10.2-gdb9 .config && + time ./ct-ng build || break + done + + # ... or just build all toolchains + time for i in config*gcc10.2-gdb9; do + cp "$i" .config && time ./ct-ng build || break + done + ``./ct-ng`` is a Linux kernel style Makefile; so the sample commands below can be used to fix some out of date ``config-*-gcc10.2-gdb9`` file or find @@ -263,18 +270,6 @@ default values missing from it: ./ct-ng oldconfig V=1 diff -u config-apl-gcc10.2-gdb9 .config -While other steps take minutes at most, building all toolchains may last -about an hour depending on the performance of your system. Run this loop -to build all toolchains without interruption: - -.. code-block:: bash - - unset LD_LIBRARY_PATH; - time for i in config*gcc10.2-gdb9; do - cp "$i" .config && ./ct-ng build || break ; - done - - "Install" toolchains in the expected location by linking from ``$SOF_WORKSPACE`` to them: @@ -316,9 +311,11 @@ switch to the `xtensa` branch. git checkout -b xtensa origin/xtensa Temporarily add toolchains to your PATH variable. This is *not* required -when using high-level scripts described below; it's only required here or -when invoking CMake manually. In other words, you don't need to adjust your -PATH permanently because no risk of interfere with non-SOF tasks exists. +when using the high-level, "every day" build scripts described in the +next sections. It's only required for this once-off ``newlib`` headers +step or when invoking CMake manually. In other words, you don't need to +change your PATH permanently which would interfere with other, non-SOF +work. .. code-block:: bash @@ -329,6 +326,7 @@ Build and install the newlib headers for each toolchain: .. code-block:: bash XTENSA_ROOT="${SOF_WORKSPACE}"/xtensa-root + cd "${SOF_WORKSPACE}"/newlib-xtensa time for toolchain in ../xtensa-*-elf; do ./configure --target="${toolchain#../}" --prefix="$XTENSA_ROOT" && make && make install || break; @@ -357,7 +355,7 @@ After the SOF environment is set up, clone the *sof* repo: .. code-block:: bash cd "$SOF_WORKSPACE" - git clone https://github.com/thesofproject/sof + git clone --recursive https://github.com/thesofproject/sof cd sof @@ -367,7 +365,10 @@ optional target hostname in the latter file. Then run the installer: .. code-block:: bash - make -C installer/ + make -C installer/ [ -j 4 ] + +Adjust the ``-j 4`` example to your number of CPU cores or remove it +when the build fails. This builds multiple platforms in parallel and deploys firmware and topologies to ``/lib/firmware/intel/`` on the local or remote diff --git a/getting_started/build-guide/build-with-docker.rst b/getting_started/build-guide/build-with-docker.rst index 62831f71..de972829 100644 --- a/getting_started/build-guide/build-with-docker.rst +++ b/getting_started/build-guide/build-with-docker.rst @@ -120,9 +120,9 @@ To build the SOF binaries for one or more platforms: .. code-block:: bash cd "${SOF_WORKSPACE}"/sof/ - # Baytrail + # Bay Trail ./scripts/docker-run.sh ./scripts/xtensa-build-all.sh byt - # Baytrail and Apollo Lake + # Bay Trail and Apollo Lake ./scripts/docker-run.sh ./scripts/xtensa-build-all.sh byt apl Build inside container diff --git a/getting_started/build-guide/build-with-zephyr.rst b/getting_started/build-guide/build-with-zephyr.rst old mode 100755 new mode 100644 index 303282ce..e3eb035d --- a/getting_started/build-guide/build-with-zephyr.rst +++ b/getting_started/build-guide/build-with-zephyr.rst @@ -12,84 +12,205 @@ This guide describes how to build and run |SOF| as a Zephyr application. .. note:: The following example uses ``$ZEPHYR_WORKSPACE`` as the working - directory. + directory for both SOF and Zephyr projects. Prepare ******* -The easiest way to build Zephyr is to use its recommended toolchain. Follow -instructions in `Install a Toolchain `_ for details. +- The easiest way to build Zephyr is to use its recommended toolchain which is included in its SDK. Refer to `Install Zephyr SDK `_ for details. -Check out and build -******************* +- Install **west**. Zephyr uses west as a source management and building system. Follow + the Zephyr `Getting Started `_ guide for dependencies and for the west installation. + +Clone and initialize SOF project +******************************** + +Initialize the west manifest ``$ZEPHYR_WORKSPACE/sof/west.yml`` using the ``west tool``: + + - Clone the SOF repository: + + .. code-block:: bash + + mkdir $ZEPHYR_WORKSPACE && cd $ZEPHYR_WORKSPACE + west init -m https://github.com/thesofproject/sof + + - Or initialize the west manifest from the existing SOF clone. Note that when using the Python convenience script, as described in the next section, this is not mandatory. + + .. code-block:: bash + + cd $ZEPHYR_WORKSPACE + west init -l ./sof -#. Install **west**. - Zephyr uses west as a source management and building system. Follow - the Zephyr `Getting Started `_ guide for dependencies and for the west installation. .. note:: + | Since the Zephyr project also uses the west manifest, your west tool might already be initialized to manifest Zephyr. In this case, west issues the following error during initialization: + | *"FATAL ERROR: already initialized in $ZEPHYR_WORKSPACE, aborting."* + | + | To verify that the manifest is currently used by the west tool, execute the following command from the ``$ZEPHYR_WORKSPACE`` directory: + | ``west config -l``. + | + | If command output shows the following, remove the ``$ZEPHYR_WORKSPACE/.west`` directory and reinitialize the west manifest using one of the two methods described above: + | *manifest.path=zephyr* + | *manifest.file=west.yml* + + .. important:: + The SOF project **must** be cloned to the ``sof`` directory because this name is hardcoded in the west manifest file. Failure to do so may result in SOF dependencies being cloned into a newly created ``$ZEPHYR_WORKSPACE/sof/rimage`` directory along with other undesirable consequences. - If you need a different SOF version than the one that west - automatically checks out, change to ``modules/audio/sof`` and use git - to select your preferred version. You need at least version 1.6 to use - it with Zephyr. Make sure you branch or tag your code in git; - otherwise, a future ``west update`` may lose it. See the west user - guide. + **All commands described in the guide from this point should be executed from the $ZEPHYR_WORKSPACE directory.** -#. Initialize a new ``west`` repository. This checks out all Zephyr sources, - including SOF: + +Check out and build using Python convenience script +*************************************************** + +The SOF project offers a Python convenience script, ``./sof/scripts/xtensa-build-zephyr.py``, that provides a friendly build process for the end user. It is a wrapper for a **west tool** that performs steps described in the `Check out and build using west tool directly`_ section below. + +This script can be used on both Windows and Linux operating systems. Note that it will be removed when the SOF project creates better integration with west tool commands. + +The script automates the following steps that are required to build firmware for the SOF platform: + - Initializes your west tool to SOF's west manifest. + - Clones and checks out SOF and Zephyr dependencies. + - Builds a firmware ``.elf`` file for the requested platform. + - Builds a **rimage tool**. + - Uses the **rimage tool** and a **private key** to sign the ``.elf`` file. It produces a final firmware image file with the ``.ri`` extension. + - Uses the **smex tool** to generate debugging symbols file with the ``.ldc`` extension. + +| A list of platforms that can be built with the script is shown in this help message: +| ``./sof/scripts/xtensa-build-zephyr.py --help`` + +Usage example 1: + You cloned the SOF project and you want to build firmware for the *Tigerlake* platform. .. code-block:: bash - mkdir $ZEPHYR_WORKSPACE - cd $ZEPHYR_WORKSPACE - west init - # Significantly smaller and faster than a full "west update" - west update hal_xtensa sof + ./sof/scripts/xtensa-build-zephyr.py -u tgl + + Running this command will: + + - Initialize west to the ``./sof/west.yml`` manifest if it is not already initialized. + - Clone and check out projects to the revision defined in the ``./sof/west.yml`` file: -#. Build and sign a firmware image: + - SOFs submodules (Rimage and Tomlc99) + - Zephyr project + - Zephyr project dependencies needed by SOF in ``$ZEPHYR_WORKSPACE/modules`` directory + + - Build a signed firmware image ``./build-tgl/zephyr/zephyr.ri`` and debug symbols file ``./build-sof-staging/sof/sof-tgl.ldc``. + + .. note:: + You may wish to rebuild all files from scratch. To do this, add a ``-p`` flag to the script invocation. To provide better build verbosity, use the ``-v`` flag. Make sure to check ``--help`` to see all build options. + +Usage example 2: + Your environment is set up as a cloned SOF project and you are working on a fork/branch of the Zephyr and Rimage submodules. You want to build a *Tigerlake* platform with your changes. .. code-block:: bash - cd $ZEPHYR_WORKSPACE - ./modules/audio/sof/scripts/xtensa-build-zephyr.sh -h # shows usage - ./modules/audio/sof/scripts/xtensa-build-zephyr.sh $your_platforms - ls build-*/zephyr/zephyr.* - => build-*/zephyr/zephyr.ri ... + ./sof/scripts/xtensa-build-zephyr.py tgl + + Running this command will: -#. Fetch and switch to the latest SOF code + - Initialize west to the ``./sof/west.yml`` manifest if it is not already initialized. + - Build a signed firmware image ``./build-tgl/zephyr/zephyr.ri`` and debug symbols file ``./build-sof-staging/sof/sof-tgl.ldc``. + - Skip cloning dependencies and check them out to revisions from the ``./sof/west.yml`` manifest. - By policy, zephyr modules are carefully versioned with west and not - automatically synchronized with the latest code. To switch to the - latest: +Usage example 3: + Your environment is set up as a cloned SOF project and you are working on a fork/branch of the Zephyr and Rimage submodules. You want to restore default revisions for SOF dependencies from the ``./sof/west.yml`` manifest. .. code-block:: bash - cd modules/audio/sof/ - git remote add sof https://github.com/thesofproject/sof - git fetch sof - git switch --track sof/main + ./sof/scripts/xtensa-build-zephyr.py -u - You can also delete the ``sof`` clone downloaded by ``west`` and - replace it with an older clone; west will automatically adjust. + Running this command will: -Run -*** + - Initialize west to the ``./sof/west.yml`` manifest if it is not already initialized. + - Clone and checkout projects to revisions defined in the ``./sof/west.yml`` file. + - Skip building the firmware image. + +Output directory + For convenience, the ``xtensa-build-zephyr.py`` script copies all + firmware files into a single, staging directory: + + .. code-block:: bash -For convenience, the ``xtensa-build-zephyr.sh`` script copies all -firmware files into a single, "staging" directory: + $ tree build-sof-staging/ + + build-sof-staging/ + ├── sof + │   ├── community + │   │   ├── sof-apl.ri + │   │   ├── sof-imx8.ri + │   │   └── sof-tgl-h.ri + + +Check out and build using west tool directly +******************************************** + +#. Clone and check out SOF dependencies such as submodules, the Zephyr project, and some of its modules needed by SOF: .. code-block:: bash - $ tree build-sof-staging/ + west update - build-sof-staging/ - ├── sof - │   ├── community - │   │   ├── sof-apl.ri - │   │   ├── sof-imx8.ri - │   │   └── sof-tgl-h.ri + .. important:: + This command will check out revisions specified in the ``$ZEPHYR_WORKSPACE/sof/west.yml`` file for the following projects: + - Rimage (SOF submodule) + - Tomlc99 (Rimage submodule) + - Zephyr + - projects in ``$ZEPHYR_WORKSPACE/modules`` directory. + + **Make sure you back up your work before changing revisions!** + This will not affect your SOF project revision. + +#. Build a board. Make sure to use the appropriate Zephyr SDK or other toolchain of your choice. Boards to build are listed in the ``$ZEPHYR_WORKSPACE/sof/app/boards`` directory. + + .. code-block:: bash + west build --build-dir build-tgl --board intel_adsp/cavs25 ./sof/app + + + Note that the SOF project defines platform names that have Zephyr board counterparts. In the above example, the *Tigerlake* platform matches the ``intel_adsp/cavs25`` Zephyr board target (see `Zephyr HWMv2 board terminology `_). This is why the output directory is named ``build-tgl``; however, you may use any name you wish. + + .. note:: + To add verbosity to the build output use the -v -v flags. Example: + ``west -v -v build --build-dir build-tgl --board intel_adsp/cavs25 ./sof/app`` + + To perform a complete clean rebuild, use the --pristine flag. Example: + ``west -v -v build --build-dir build-tgl --pristine always --board intel_adsp/cavs25 ./sof/app`` + + The ``.elf`` file produced by the ``west build`` is missing a + manifest and signature. A a result, you must sign the file using the **rimage tool** + and a **private key** to generate the final firmware image (``.ri`` file). + +#. Build the rimage tool by running the following: + + .. code-block:: bash + + cmake -B ./build-rimage -S ./sof/rimage + cmake --build ./build-rimage + +#. Sign the firmware using the rimage tool and a private key by running the following: + + .. code-block:: bash + + west sign --build-dir ./build-tgl -t rimage --tool-path ./build-rimage/rimage --tool-data ./sof/rimage/config -- -k ./sof/keys/otc_private_key_3k.pem + + **The signed output firmware image file is** ``./build-tgl/zephyr/zephyr.ri`` **.** + + .. note:: + The SOF project provides some pre-generated key pairs of different lengths: + - ``./sof/keys/otc_private_key_3k.pem`` + ``./sof/keys/otc_public_key_3k.pem`` + - ``./sof/keys/otc_private_key.pem`` + ``./sof/keys/otc_public_key.pem`` + + You may wish to generate your own set of keys for firmware signing. + +#. (Optional) Generate debug symbols. + + .. code-block::bash + + ./build-tgl/zephyr/smex_ep/build/smex -l ./build-tgl/zephyr/zephyr.ldc ./build-tgl/zephyr/zephyr.elf + + The output file ``./build-tgl/zephyr/zephyr.ldc`` may be used for reading firmware logs. + +Run +*** #. Copy the firmware image(s) to the usual location on all your target systems. Example: @@ -98,16 +219,14 @@ firmware files into a single, "staging" directory: sudo rsync -a build-sof-staging/sof/ testsystemN.local:/lib/firmware/intel/sof/ - ``rsync`` also works locally and unlike ``cp -R`` it is always - idempotent. You may want to use the ``rsync -a --delete`` option to - make absolutely sure you're not running some older version but only - after backing up your original ``sof/`` directory first. The - ``--delete`` option is dangerous, use it only in very well tested + Note that ``rsync`` also works locally and, unlike ``cp -R``, it is always + idempotent. You may want to use the ``rsync -a --delete`` option to + make absolutely sure you're not running some older version, **but do so + only after first backing up your original sof/ directory**. The + ``--delete`` option is dangerous; use it only in very well-tested scripts. - Also make sure nothing in ``/lib/firmware/updates`` takes precedence, - see - https://www.kernel.org/doc/html/v5.5/driver-api/firmware/fw_search_path.html + Also make sure nothing in ``/lib/firmware/updates`` takes precedence. Refer to `Firmware search paths `_. #. Reboot the system. Note that the location and name of your SOF firmware image may vary by system. Search your kernel logs with @@ -131,3 +250,18 @@ For firmware log extraction, use You might also need to build and update your system audio topology file. For details see :ref:`build-from-scratch`. + + +Troubleshoot +************ + +#. The west tool version is older than the minimal version requirement defined in the ``./sof/west.yml`` manifest. + + | The manifest file defines the minimal yaml schema version that sets compatibility with west tool according to `Zephyr documentation `_. If your west tools version is not sufficient to process the manifest file, west raises an exception (reference to west 0.12.0 for Windows): + + .. code-block:: bash + + west.manifest.ManifestVersionError: ('0.13', WindowsPath('$ZEPHYR_WORKSPACE/.west/manifest-tmp/west.yml')) + + | In this example, ``./sof/west.yml`` defines minimal version as ``0.13`` while the west tool used has version ``0.12.0``. Update your west tool to a newer version. + diff --git a/getting_started/index.rst b/getting_started/index.rst old mode 100755 new mode 100644 index a9511ef1..3d585a7c --- a/getting_started/index.rst +++ b/getting_started/index.rst @@ -21,18 +21,36 @@ current distro release is always preferred. build-guide/build-3rd-party-toolchain build-guide/build-with-zephyr -Set up SOF on hardware -********************** +Set up SOF on a Linux machine +***************************** -SOF runs on a variety of devices with varying audio capabilities so -instructions may differ between devices. +You can build the Linux kernel with the latest SOF code and install it locally or remotely with ktest. + +Do this first: .. toctree:: :maxdepth: 1 - setup/setup_minnowboard_turbot - setup/setup_up_2_board - setup/setup_ktest_environment + setup_linux/prepare_build_environment + +Then proceed based on if you are installing locally or through ktest: + +.. toctree:: + :maxdepth: 1 + + setup_linux/install_locally + setup_linux/setup_ktest_environment + +Set up SOF on a special device +****************************** + +SOF also runs on the MinnowBoard Turbot and the Up Squared board with Hifiberry Dac+. + +.. toctree:: + :maxdepth: 1 + + setup_special_device/setup_minnowboard_turbot + setup_special_device/setup_up_2_board Debug Audio issues on Intel platforms ************************************* @@ -57,3 +75,12 @@ This section provides guides for integrators and for users working with i.MX pla nxp/sof_imx_user_guide +Building loadable modules using LMDK +************************************ + +This section descibes process of building loadable modules using LMDK. + +.. toctree:: + :maxdepth: 1 + + loadable_modules/lmdk_user_guide diff --git a/getting_started/intel_debug/introduction.rst b/getting_started/intel_debug/introduction.rst index 7260602b..11e8ca55 100644 --- a/getting_started/intel_debug/introduction.rst +++ b/getting_started/intel_debug/introduction.rst @@ -6,14 +6,14 @@ Overview of Intel hardware platforms ACPI platforms (introduced before and up to 2015) ************************************************* -On Baytrail, Cherrytrail, Braswell, and Broadwell devices (also referred to +On Bay Trail, Cherry Trail, Braswell, and Broadwell devices (also referred to as `legacy` devices), the DSP enumeration is handled by the ACPI subsystem. 1. Local audio accessories (mics, speakers, headset) ---------------------------------------------------- -On Baytrail, Cherrytrail, Braswell, and Broadwell, the BIOS can either +On Bay Trail, Cherry Trail, Braswell, and Broadwell, the BIOS can either enable or disable the DSP: * Enable the DSP. In this case, a DSP driver is required. This mode is @@ -28,7 +28,7 @@ enable or disable the DSP: On Broadwell, HDMI/DP is handled by an HDaudio controller. -On Baytrail/Cherrytrail and Braswell, the BIOS can enable two modes: +On Bay Trail/Cherry Trail and Braswell, the BIOS can enable two modes: * HDAudio-based solution (similar to Broadwell). @@ -55,12 +55,12 @@ exposes PCM devices and no audio processing capabilities. When OEM platforms integrate digital microphones attached directly to the Intel chipset (aka DMIC), or they use I2C/I2S or SoundWire interfaces, the DSP must be enabled by the BIOS. There is, however, one -more option. On Skylake and Kabylake platforms, the Intel DSP is handled by +more option. On Skylake and Kaby Lake platforms, the Intel DSP is handled by the ``snd-soc-skl`` module which relies on closed-source firmware. -SOF is available on Intel PCI devices starting with GeminiLake, and +SOF is available on Intel PCI devices starting with Gemini Lake, and has since been the only solution provided by Intel for the following -platforms: CometLake, IceLake, and TigerLake. +platforms: Comet Lake, Ice Lake, and Tiger Lake. Since multiple drivers can register for the same PCI ID, it was (until recently) common for users and distributions to use the wrong @@ -71,7 +71,7 @@ The ``snd-intel-dspcfg`` module introduced in early 2020 exposes an API used by all drivers, and the user can now override default choices by setting the ``dsp_driver`` parameter. For example, setting -.. code-block:: +.. code-block:: cfg options snd-intel-dspcfg dsp_driver=1 @@ -83,7 +83,7 @@ Conversely, when a platform does not require a DSP-based platform, but the DSP is still enabled by the OEM, the user or integration can force the SOF Linux driver to be used. -.. code-block:: +.. code-block:: cfg options snd-intel-dspcfg dsp_driver=3 @@ -94,20 +94,23 @@ User space and filesystem requirements Selecting the SOF driver is not enough. Audio is properly configured only if the following elements are present on the file system. -1. Firmware binary +1. Firmware +----------- + +1.1. Base firmware ------------------ -The firmware file, ``/lib/firmware/intel/sof/sof-tgl.ri``, contains -all DSP code and tables. On PCI devices, the firmware can only be -signed by an Intel production key which prevents community users from -installing their own firmware. Notable exceptions include Google -Chromebooks and Up2/Up-Extreme boards, where the *community key* is -used. +The firmware file, ``/lib/firmware/intel/sof/sof-tgl.ri`` (example +location for Intel Tiger Lake), contains all DSP code and tables. On +PCI devices, the firmware can only be signed by an Intel production +key which prevents community users from installing their own firmware. +Notable exceptions include Google Chromebooks and Up2/Up-Extreme +boards, where the *community key* is used. The Intel ME (Management Engine) is responsible for authentication of the firmware, whether it is signed by an Intel production key (consumer products), a community key (open development systems and Chromebooks -since GeminiLake) or an OEM key. If the Intel ME is disabled by an +since Gemini Lake) or an OEM key. If the Intel ME is disabled by an OEM, or disabled by user-accessible BIOS options, the firmware authentication will fail and the firmware boot will not complete. If the ME is disabled by the OEM, the only solution is to fall-back @@ -117,6 +120,98 @@ Linux kernel to query whether or not the firmware authentication is enabled, which means `dmesg` logs cannot be provided to alert the user to an ME configuration issue. +.. _loadable-libraries: + +1.2. Loadable libraries +----------------------- + +An IPC4 library is a container of a single or multiple modules (bundle) which +can be loaded to the firmware after it is booted up. +Library loading is supported on Meteor Lake (ACE1) or newer platforms. + +Background information: the base firmware always resides in DSP SRAM while the +loaded library is stored in DRAM memory and only the needed code is copied to +SRAM for execution. By moving modules out from the base firmware to a library +can reduce the overall SRAM use depending on the device configuration and +topology. + +See :ref:`llext_modules` for technical details. + +1.3. Non-modular and modular firmware releases +---------------------------------------------- + +SOF project releases for Intel platforms are either a single firmware or modular firmware based. + +1.3.1. Non-modular firmware releases +------------------------------------ + +The release contains single a firmware image: **sof-PLAT.ri** + +1.3.2. Modular firmware releases +-------------------------------- + +Modular SOF release is technically supported with IPC4 on Meteor Lake (MTL) or newer platforms since it depends on Loadable Library support (see :ref:`loadable-libraries` for details). + +Description of files provided by a modular release: + - **sof-PLAT.ri** : The base firmware + - **sof-PLAT-openmodules.ri** : the bundle contains modules for audio processing not included in the base firmware + - **sof-PLAT-debug.ri** : the bundle contains modules that are needed for firmware debugging and profiling. Used by developers and for bug reporting if needed + - **UUID.bin** : On demand loadable library identified by UUID. If the library contains multiple modules then a UUID symlink must be provided for each one. + +The main firmware can be shipped as a + - single binary (**sof-PLAT.ri**) + - split release when the base firmware (**sof-PLAT.ri**), processing modules (**sof-PLAT-openmodules.ri**) and debug/developer modules (**sof-PLAT-debug.ri**) are provided as separate binaries. + + - After the base firmware boot, the kernel will load the **sof-PLAT-openmodules.ri** and **sof-PLAT-debug.ri** bundles to the firmware to provide equivalent functionality as the single binary release. + +Notes: + - additional libraries referenced by topology files or drivers will be loaded based on the UUID of the module from the library path (**UUID.bin**). + +1.4 Firmware lookup paths +------------------------- + +Linux SOF will look up firmware files at the following paths. + +Look-up paths per Intel platform for **non-modular firmware releases** + +.. _intel_non_modular_firmware_paths: + ++-----------------------------------------------------------+--------+------------------------------------------------+-----------+-----------------------------------+ +|Platform |IPC type|Load path |File name |Notes | ++===========================================================+========+================================================+===========+===================================+ +|Raptor Lake and older |IPC3 |/lib/firmware/intel/sof/ |sof-PLAT.ri|PLAT = glk, cml, ..., rpl | ++-----------------------------------------------------------+ +------------------------------------------------+ | | +|Raptor Lake and older (community signed) | |/lib/firmware/intel/sof/community/ | | | ++-----------------------------------------------------------+--------+------------------------------------------------+ +-----------------------------------+ +|Tiger Lake and newer |IPC4 |/lib/firmware/intel/sof-ipc4/PLAT/ | |PLAT = tgl, adl, rpl, mtl, lnl, ...| ++-----------------------------------------------------------+ +------------------------------------------------+ | | +|Tiger Lake and newer (community signed) | |/lib/firmware/intel/sof-ipc4/PLAT/community/ | | | ++-----------------------------------------------------------+--------+------------------------------------------------+-----------+-----------------------------------+ + +Look-up paths per Intel platform for **modular firmware releases (IPC4 only)** + +.. _intel_modular_firmware_paths: + ++-----------------------------------------------------------+------------------------------------------------+-----------------------------+----------------------+ +|Platform |Load path |File name |Notes | ++===========================================================+================================================+=============================+======================+ +|Meteor Lake and newer |/lib/firmware/intel/sof-ipc4/PLAT/ || || PLAT = mtl, lnl, ...| +| | || sof-PLAT.ri || [*] PLAT = ptl, ... | +| | || sof-PLAT-openmodules.ri [*]| | +| | || sof-PLAT-debug.ri [*]| | ++-----------------------------------------------------------+------------------------------------------------+ | | +|Meteor Lake and newer (community signed) |/lib/firmware/intel/sof-ipc4/PLAT/community/ | | | ++-----------------------------------------------------------+------------------------------------------------+-----------------------------+ | +|Meteor Lake and newer Loadable libraries |/lib/firmware/intel/sof-ipc4-lib/PLAT/ |UUID.bin | | ++-----------------------------------------------------------+------------------------------------------------+ | | +|Meteor Lake and newer Loadable libraries (community signed)|/lib/firmware/intel/sof-ipc4-lib/PLAT/community/| | | ++-----------------------------------------------------------+------------------------------------------------+-----------------------------+----------------------+ + +Important notices: + - The standard Linux firmware search path and order is followed. The above table covers the base "/lib/firmware" case. See https://docs.kernel.org/driver-api/firmware/fw_search_path.html for more information. + - The firmware folder and filename can be overridden with "fw_path" and "fw_filename" SOF kernel parameters. + - The loadable module library path can be overridden with "lib_path" SOF kernel parameter. + 2. Topology file ---------------- @@ -124,6 +219,28 @@ The topology file, such as ``/lib/firmware/intel/sof-tplg/sof-hda-generic-2ch.tp be instantiated by the SOF driver. The topology can be regenerated and reconfigured with tools but requires expert knowledge of the ALSA/ASoC/topology frameworks. +.. list-table:: Firmware topology file look-up paths per Intel platform + :widths: 50 5 50 25 + :header-rows: 1 + + * - Platform + - IPC type + - Topology load path + - Notes + * - Raptor Lake and older + - IPC3 + - /lib/firmware/intel/sof-tplg/sof-CONFIG.tplg + - CONFIG = topology variant needed for detected hardware configuration + * - Tiger Lake and newer + - IPC4 + - /lib/firmware/intel/sof-ipc4-tplg/sof-CONFIG.tplg + - CONFIG = topology variant needed for detected hardware configuration + +Important notices: + - For compatibility reasons with respect to **Meteor Lake** ``/lib/firmware/intel/sof-ace-tplg`` must be symlinked to ``/lib/firmware/intel/sof-ipc4-tplg`` + - The standard Linux firmware search path and order is followed. The above table covers the base "/lib/firmware" case. See https://docs.kernel.org/driver-api/firmware/fw_search_path.html for more information. + - The topology folder and filename can be overridden with "tplg_path" and "tplg_filename" `snd_sof_pci` kernel parameters. + 3. UCM file ----------- diff --git a/getting_started/intel_debug/suggestions.rst b/getting_started/intel_debug/suggestions.rst index 9b9c9b3c..5a01e805 100644 --- a/getting_started/intel_debug/suggestions.rst +++ b/getting_started/intel_debug/suggestions.rst @@ -22,24 +22,41 @@ snd-intel-dspcfg dsp_driver=1" to ``/etc/modprobe.d/alsa-base.conf``. If no sound can be heard and jack detection is not functional, an HDaudio external codec configuration is likely. In some cases, the Linux drivers are missing configuration information and may only -enable two of the four speakers present. All of these cases are orthogonal -to SOF issues in that the SOF driver cannot compensate for codec driver -problems on its own. +enable two of the four speakers present. + +All of these cases are orthogonal to SOF issues in that the SOF driver +cannot compensate for codec driver problems on its own. The HDaudio +codec configuration is handled by the legacy HDAudio driver +(snd-hda-intel), which is not maintained directly by SOF developers. Try booting into Windows first, then reboot into Linux ****************************************************** -On some platforms, such as with an HDaudio codec connected to amplifiers -over an I2C/I2S link, the codec driver needs to perform a set of -amplifier configurations. This is often handled in Windows but not in -Linux codec drivers. A classic example of such issues is when +On some platforms, such as with an HDaudio codec connected to +amplifiers over an I2C/I2S link, the codec driver needs to perform a +set of amplifier configurations. This is often handled in Windows but +not in Linux codec drivers. A classic example of such issues is when headphone playback works, but speaker playback does not (or not on all -speakers). +speakers). Booting first in Windows then rebooting in Linux may help +setup the right configuration, but additional work is needed to patch +the Linux kernel. + +Reverse-engineer the Windows audio driver +***************************************** + +The HDaudio driver configures the codec with 'verb' commands to +e.g. setup the 'pins' or a coefficient. The exact values used are +device-specific, and in the absence of any documentation from the +codec vendor need to be reverse-engineered by snooping HDAudio +commands in a Windows environment. + +The following links provide additional information on snooping the +commands and determining what needs to be added to the Linux +kernel. These links are not maintained by SOF developers. -These types of issues also occur with the HDaudio legacy driver -and are not part of SOF bugs proper. To fix such issues, either obtain -direct support from the codec vendor, or reverse-engineer the missing -configuration by snooping HDaudio commands in a Windows environment. +* `ASUS Linux blog `_ + +* `How to sniff verbs from a Windows sound driver `_ Make sure the ME is enabled *************************** @@ -58,7 +75,7 @@ issues are possible. Use the following commands to check if the SOF driver is functional at the hardware device level: -.. code-block:: +.. code-block:: console speaker-test -Dhw:0,0 -c2 -r48000 -f S16_LE arecord -Dhw:0,0 -c2 -r48000 -f S16_LE -d 10 test.wav @@ -95,25 +112,49 @@ may not be enough to debug a specific issue, and the recommendation is to add the following options to the ``/etc/modprobe.d/sof-dyndbg.conf`` file: -.. code-block:: - - options snd_sof_intel_byt dyndbg=+p - options snd_sof_intel_bdw dyndbg=+p - options snd_sof_intel_ipc dyndbg=+p - options snd_sof_intel_hda_common dyndbg=+p - options snd_sof_intel_hda dyndbg=+p - options snd_sof dyndbg=+p - options snd_sof_pci dyndbg=+p - options snd_sof_acpi dyndbg=+p - options snd_sof_of dyndbg=+p - options snd_sof_nocodec dyndbg=+p - options soundwire_bus dyndbg=+p - options soundwire_generic_allocation dyndbg=+p - options soundwire_cadence dyndbg=+p - options soundwire_intel_init dyndbg=+p - options soundwire_intel dyndbg=+p - options snd_soc_skl_hda_dsp dyndbg=+p - options snd_intel_dspcfg dyndbg=+p +.. code-block:: cfg + + # ACPI + options snd_sof_acpi dyndbg=+pmf + options snd_sof_acpi_intel_byt dyndbg=+pmf + options snd_sof_acpi_intel_bdw dyndbg=+pmf + options snd_sof_intel_byt dyndbg=+pmf + options snd_sof_intel_bdw dyndbg=+pmf + + # PCI + options snd_sof_pci dyndbg=+pmf + options snd_sof_pci_intel_apl dyndbg=+pmf + options snd_sof_pci_intel_cnl dyndbg=+pmf + options snd_sof_pci_intel_icl dyndbg=+pmf + options snd_sof_pci_intel_tgl dyndbg=+pmf + options snd_sof_pci_intel_mtl dyndbg=+pmf + options snd_sof_pci_intel_lnl dyndbg=+pmf + + # DSP selection + options snd_intel_dspcfg dyndbg=+pmf + options snd_intel_sdw_acpi dyndbg=+pmf + + # SOF internals + options snd_sof_intel_hda_common dyndbg=+pmf + options snd_sof_intel_hda_generic dyndbg=+pmf + options snd_sof_intel_hda_mlink dyndbg=+pmf + options snd_sof_intel_hda dyndbg=+pmf + options snd_sof dyndbg=+pmf + options snd_sof_nocodec dyndbg=+pmf + + # HDA + options snd_hda_intel dyndbg=+pmf + options snd-hda-codec-realtek dyndbg=+pmf + options snd-hda-codec-generic dyndbg=+pmf + options snd-hda-codec-hdmi dyndbg=+pmf + options snd-hda-codec dyndbg=+pmf + + # SoundWire core + options soundwire_bus dyndbg=+pmf + options soundwire_generic_allocation dyndbg=+pmf + options soundwire_cadence dyndbg=+pmf + options soundwire_intel_init dyndbg=+pmf + options soundwire_intel dyndbg=+pmf Note that this list is only an example. @@ -137,6 +178,163 @@ Trace support might need to be enabled on distribution kernels in case the ``/sys/kernel/debug/sof/trace`` file is not present by adding sof_debug=1 option to snd_sof module: -.. code-block:: +.. code-block:: cfg options snd_sof sof_debug=1 + + +Digital mic issues +****************** + +The SOF driver and firmware have limited information related to the +number of digital microphones and their physical location. + +On devices designed for Windows, the presence of the microphone is +reported as an NHLT endpoint (ACPI table in the BIOS). The SOF Linux +driver will report this information with a 'dmesg' log such as + +.. code-block:: none + + [ 4.301490] sof-audio-pci-intel-tgl 0000:00:1f.3: DMICs detected in NHLT tables: 2 + +Recent versions of the ACPICA tools (acpica-tools package) can also be +used to visualize the ACPI tables. + +In some instances the number of DMICs reported by the NHLT does not +match the hardware layout. The SOF driver provides a means to alter +the value with a kernel parameter which can be added in +/etc/modprobe.d/alsa-base.conf (or any other configuration file with +this .conf extension). A reboot is necessary after changing the value + +.. code-block:: cfg + + options snd_sof_intel_hda_common dmic_num=4 + +The following command can then be used to check if the microphones are active at the lowest level + +.. code-block:: bash + + arecord -Dhw:0,6 -c4 -r48000 -fS32_LE -d 10 test.wav + +In 99% of the cases, hardware designers connect the two microphones on +the PDM0 controller. Some platforms use PDM1, which cannot really be +detected by the OS. By capturing in 4ch mode, it's possible that +channel3 and 4 capture data while channel0 and channel1 only show +signs of transitions and DC-removal. Simply talking or recording music +in this 10s test, then visualizing the recorded file with Audacity is +often enough to diagnose the presence of 2 microphones on the 'wrong' +PDM controller. + +In that case, a different topology file needs to be used, typically +sof-hda-generic-2ch-pdm1.tplg. On older distributions, it will be +necessary to override the file installed in +/lib/firmware/intel/sof-tplg/sof-hda-generic-2ch.tplg. On kernels +5.20+ a kernel parameter will be enough with no need to change and +override installed topology files, e.g. + +.. code-block:: cfg + + options snd-sof-pci tplg_filename=sof-hda-generic-2ch-pdm1.tplg + +These PDM1 issues are tracked in GitHub with the label 'DMIC-PDM1' in the +`firmware issues `_ +and in the `Linux issues `_. + +Users running Linux distributions on Chromebooks routinely experience +issues with digital microphones. In the Chrome environment, the +topology always exposes 4 channels, and UCM files for specific +platforms specify which of the 4 channels are valid. A plugin will +then drop the useless/non-populated channels. This capability does not +exist yet in upstream UCM/Linux. Capturing with the 'arecord; command +above will help understand which channels are valid and configure UCM +files. + +ES8336 support +************** + +Since 2021, a number of OEMs relied on the ES8336 codec from Everest +Audio on platforms as varied as AppoloLake, GeminiLake, JasperLake, +CometLake, AlderLake. + +End-users can verify if the hardware uses this configuration by +running the 'alsa-info' command and checking for the presence an ACPI +_HID, e.g. + +.. code-block:: none + + /sys/bus/acpi/devices/ESSX8336:00/status 15 + +.. code-block:: none + + /sys/bus/acpi/devices/ESSX8326:00/status 15 + +Support for this platform only stated upstream with the kernel +5.19-rc1. Any attempts with earlier kernels will require backports and +experimental patches to be added. In the case of the 8326, the codec +vendor submitted a driver to the ALSA/ASoC maintainers, which was not +merged as of July 2022. In this specific case end-users will be forced +to compile their own kernel. + +The SOF driver implemented an automatic detection of the SSP/I2S port +used by hardware and the presence of digital microphones based on +platform firmware/NHLT. + +There are however a number of hardware configurations that cannot be +detected from platform firmware. To work-around this limitation, the +'sof-es8336' machine driver exposes a 'quirk' kernel parameter which +can be used for modify GPIO and jack detection settings. Existing +quirks are listed in the sound/soc/intel/boards/sof_es8336.c machine +driver: + +.. code-block:: c + + #define SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK BIT(4) + #define SOF_ES8336_JD_INVERTED BIT(6) + #define SOF_ES8336_HEADPHONE_GPIO BIT(7) + #define SOC_ES8336_HEADSET_MIC1 BIT(8) + + +The default and actual quirk values for the platform can be obtained +from the kernel logs in the line as follows: + +.. code-block:: none + + ... + sof-essx8336 sof-essx8336: quirk mask 0x1a0 + ... + +for the unchanged mask, or: + +.. code-block:: none + + ... + sof-essx8336 sof-essx8336: Overriding quirk 0x1a0 => 0x120 + ... + +for the quirk overriding. + +The overridden quirk value can also be obtained from the +/sys/module/snd_soc_sof_es8336/parameters/quirk (the value is reported +as a plain integer, not hexadecimal). If the quirk is not overridden, +the `-1` value is returned. + +Changes to the default can be added with the following option in +e.g. /etc/modprobe.d/alsa-base.conf. Only the bits listed above can be +modified; others need to remain as is. + +.. code-block:: cfg + + options snd_soc_sof_es8336 quirk= + +Changing quirk values is an extremely experimental endeavor that +should only attempted by users with working knowledge of the Linux +audio subsystem and an understanding that playing with hardware +settings MAY DAMAGE HARDWARE or generate extremely loud sounds that +MAY DAMAGE YOUR HEARING. + +In rare cases, some platforms use the MCLK1 signal instead of +MCLK0. As of July 2022, there is no turn-key solution for those +platforms. + +These ES8336 issues are tracked in GitHub with the label 'codec +ES8336' in the `Linux ES8336 issues `_. diff --git a/getting_started/loadable_modules/lmdk_user_guide.rst b/getting_started/loadable_modules/lmdk_user_guide.rst new file mode 100644 index 00000000..b6085e01 --- /dev/null +++ b/getting_started/loadable_modules/lmdk_user_guide.rst @@ -0,0 +1,25 @@ +.. _lmdk_user_guide: + +Loadable modules build guide using LMDK +####################################### + +What is LMDK +************ + +LMDK(Loadable Module Development Kit) is a standalone package required to build loadable module. It is independent from SOF FW but contains necessary data structures to interact with it. + +How to build +************ + +To build example loadable library execute: +.. code-block:: bash + + $ cd libraries/example + $ mkdir build + $ cd build + + $ cmake -DRIMAGE_COMMAND="/path/to/rimage" -DSIGNING_KEY="/path/to/signing/key.pem" .. + $ cmake --build . + +Here RIMAGE_COMMAND is path to rimage executable binary, SIGNING_KEY is path to +signing key for rimage. `LMDK ` diff --git a/getting_started/nxp/sof_imx_user_guide.rst b/getting_started/nxp/sof_imx_user_guide.rst old mode 100755 new mode 100644 diff --git a/getting_started/setup/setup_ktest_environment.rst b/getting_started/setup/setup_ktest_environment.rst deleted file mode 100644 index 41ed55b1..00000000 --- a/getting_started/setup/setup_ktest_environment.rst +++ /dev/null @@ -1,383 +0,0 @@ -.. _setup-ktest-environment: - -Set up a Ktest-based environment -################################ - -.. contents:: - :local: - :depth: 3 - -Introduction -************ -These instructions explain how a target device can be configured to -update the kernel over SSH. The use of ktest.pl and git worktrees -allow for simultaneous configs to be tested on multiple platforms, -though only one branch can be checked out at a time. Wired Ethernet -access is assumed as wireless is unreliable. If there is no Ethernet -port, use a USB-Ethernet dongle supported in the kernel. - -Prerequisites on the target device -********************************** - -The target device can be any of the SOF-supported platforms, -e.g. MinnowBoard, Up^2, Asus T100, Chromebooks) - -1. Install OS on target ------------------------ - -Install ubuntu or debian (fedora is possible with a minor change -in the *initrd* generation) - -2. Enable root password ------------------------ - -.. code-block:: bash - - sudo su (enter your password) - passwd (enter new root password) - exit - -3. Create test kernel ---------------------- - -Copy your existing known-to-work kernels/initrd - -.. code-block:: bash - - cp /boot/vmlinuz-4.13.0-16-generic /boot/vmlinuz-test - cp /boot/initrd.img-4.13.0-16-generic /boot/initrd.img-test - -Change the extensions as needed to create an initial grub entry -for a test kernel. You will never override the default -Ubuntu/Debian stuff, so you will always have the ability to boot a -working kernel if your changes fail to boot. - -4. Edit grub default --------------------- - -.. code-block:: bash - - # Use your text editor of choice. - sudo emacs /etc/default/grub - sudo update-grub - -Add ``GRUB_DISABLE_SUBMENU=y`` to the end and save. -Sub-menus confuse ktest. - -5. Get familiar with grub-reboot --------------------------------- - -ktest relies on grub-reboot. grub-reboot lets you try a freshly built -kernel *only once* and then boot immediately a "safe" kernel again -without interacting with the boot menu: a simple power cycle is -enough. It's a must have for testing development kernels that may not -fully boot. - -In case something goes wrong with ktest, being familiar with grub-reboot -may save you interacting with the boot menu or even better: it may save -you making your system unbootable by accident. Understanding how -grub-reboot works is required to fully understand ktest -configuration. It's much easier to discover grub-reboot alone than when -entangled with ktest. - -There's a lot of grub-reboot documentation online and offline but -apparently no good and very short cheat sheet so here is one below. For -more details search the documentation of your Linux distribution. The -commands below have been tested on Ubuntu 20.04; they should be nearly -identical for most Linux distributions. - -.. code-block:: bash - - # Add/remove entries in grub.cfg after making changes in /boot/ - # grub.cfg is generated, don't edit it! - update-grub - - # See which GRUB entry was booted - cat /proc/cmdline - - # grub-reboot requires "unharcoding" GRUB_DEFAULT - printf 'GRUB_DEFAULT=saved\n' >> /etc/default/grub - update-grub - -Warning: ``update-grub`` does not care about menuentry order and will -mess up what the numbers below point to! - -.. code-block:: bash - - # Show the currently selected menuentry - grub-editenv list - => saved_entry=6 - - # Show all, numbered kernel choices without (re)booting - awk '/^menuentry/ { print i++, '\t', $0 }' /boot/grub/grub.cfg - => 5 menuentry ... - => 6 menuentry 'Ubuntu, with Linux 5.4.0-53-generic' --class ubuntu ... - => 7 menuentry ... - - # Attempt to boot menuentry 4 only once - grub-reboot 4; grub-editenv list - => saved_entry=6 - => next_entry=4 - reboot - - # Switch to menuentry number 4 as the new "safe" kernel - grub-set-default 4; grub-editenv list - => saved_entry=4 - - -Fedora and derived distributions have a more elaborate system to manage -"installed" kernels. Instead of extracting ``menuentry`` lines from -``/boot/grub/grub.cfg`` with the ``awk`` command above, to list all -installed kernels use: ``grubby --info=ALL``. - -After copying it to ``/boot``/, "install" a new kernel with: -``grubby --add-kernel /boot/vmlinuz-softest --title=softest``. Check -``grubby``'s documentation for more details. - -6. Install openssh-server -------------------------- - -.. code-block:: bash - - sudo apt-get install openssh-server - # Use your editor of choice. - sudo emacs /etc/ssh/sshd_config - -Replace ``PermitRootLogin without-password`` with ``PermitRootLogin yes`` -and save. - -7. reboot target ----------------- - -Configure SSH without password -****************************** - -1. Check SSH connection ------------------------ - -.. code-block:: bash - - ssh root@ - -2. Generate an SSH key for the target -------------------------------------- - -.. code-block:: bash - - cd ~/.ssh - ssh-keygen -f sshktest - # Enter a 5+ character passphrase. - ssh-copy-id -i ~/.ssh/sshktest root@ - # This will prompt you for the root password. - -3. Test the key ---------------- - -.. code-block:: bash - - ssh -i ~/.ssh/sshktest root@ - # Ubuntu unlocks the key so the -i option is not necessary. - -4. Disable root access ----------------------- - -Disable the root password on the target device if you -are concerned about access control. - -.. code-block:: bash - - # Use your editor of choice. - sudo emacs /etc/ssh/sshd_config - -Replace ``PermitRootLogin yes`` by ``PermitRootLogin without-password``, save, and exit. - -Create a linux development environment -************************************** - -1. Create a main working GIT tree ---------------------------------- - -.. code-block:: bash - - git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git linux-ref.git - cd linux-ref.git - -2. Add a set of useful remotes ------------------------------- - -.. code-block:: bash - - git remote add sof https://github.com/thesofproject/linux.git - git remote add takashi git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git - git remote add broonie git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git - git remote add liam git://git.kernel.org/pub/scm/linux/kernel/git/lrg/asoc.git - git remote add keyon git://github.com/keyonjie/linux.git - git remote add vinod git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/sound.git - git remote add plb git://github.com/plbossart/sound.git - git fetch sof - git fetch takashi - git fetch broonie - git fetch liam - git fetch keyon - git fetch vinod - git fetch plb - -All of these branches will be accessible and can be updated from any -worktree. Clone once and use fetch to update the main working tree. - -3. Create a worktree for SOF in ~/ktest ---------------------------------------- - -.. note:: - Change the location of your ktest directory and which branch you use - as needed. - -.. code-block:: bash - - git worktree add ~/ktest/sof-dev sof/topic/sof-dev - -4. Set-up worktree ------------------- - -.. code-block:: bash - - cd ~/ktest/sof-dev - mkdir sof-dev-build - mkfifo sof-dev-cat - cp sof-dev/tools/testing/ktest/ktest.pl . - -5. Save your kernel config as ~/ktest/sof-dev-defconfig -------------------------------------------------------- - -If you don't know what options are needed, you can start using configurations maintained by SOF developers. - -.. code-block:: bash - - git clone https://github.com/thesofproject/kconfig.git - cd linux - make defconfig - scripts/kconfig/merge_config.sh .config ../kconfig/base-defconfig ../kconfig/sof-defconfig ../kconfig/sof-mach-driver-defconfig ../kconfig/hdaudio-codecs-defconfig - cp .config ../sof-dev-defconfig - make mrproper - cd .. - -.. note:: - - Use make proper since ktest.pl requires the source directory - to be clean. All compilation happens in the -build directory. - -6. Edit ktest configuration as needed -------------------------------------- - -Save the following in sof-dev.conf. - -.. code-block:: perl - - # The difference between config variables (:=) and ktest options (=) and a - # few other things are explained in tools/testing/ktest/examples/sample.conf - - MACHINE = 192.168.1.205 - CLEAR_LOG = 1 - SSH_USER = root - THIS_DIR := ${PWD} - # BUILD_DIR is the source directory - BUILD_DIR = ${THIS_DIR}/sof-dev - # OUTPUT_DIR is the actual build directory - OUTPUT_DIR = ${THIS_DIR}/sof-dev-build - BUILD_TARGET = arch/x86/boot/bzImage - - # ktest requires LOCALVERSION. This is normally a '-something' suffix like - # in 'vmlinuz-5.10-rc5-something'. Let's (ab)use it as the full version so - # we have a constant 'vmlinuz-something' filename and we don't have to - # make changes in /boot/ all the time. - # update-grub will complain but work anyway. - LOCALVERSION = test - TARGET_IMAGE = /boot/vmlinuz-${LOCALVERSION} - - BUILD_OPTIONS = -j8 - LOG_FILE = ${OUTPUT_DIR}/sof-dev.log - CONSOLE = cat ${THIS_DIR}/sof-dev-cat - POWER_CYCLE = echo Power cycle the machine now and press ENTER; read a - #set below to help ssh connection to close after sending reboot command - REBOOT = ssh -o 'ProxyCommand none' $SSH_USER@$MACHINE 'sudo reboot > /dev/null &' - - # This how ktest finds which menuentry number to pass to grub-reboot - GRUB_FILE = /boot/grub/grub.cfg - GRUB_MENU = Ubuntu, with Linux ${LOCALVERSION} - #GRUB_MENU = ubilinux GNU/Linux, with Linux ${LOCALVERSION} - #GRUB_MENU = GalliumOS GNU/Linux, with Linux ${LOCALVERSION} - GRUB_REBOOT = grub-reboot - REBOOT_TYPE = grub2 - - # update-initramfs does not support any "version-less" 'vmlinuz-test' because it - # does not tell where to find modules like '/lib/modules/5.10.0-rc5test+' - # So we have to use a lower level, more explicit command like: - # mkinitramfs -o initrdfile 5.10.0-rc5test+ - # ktest finds the real KERNEL_VERSION thanks to "make O=${OUTPUT_DIR} - # kernelrelease" - POST_INSTALL = ssh -o 'ProxyCommand none' $SSH_USER@$MACHINE sudo /usr/sbin/mkinitramfs -o /boot/initrd.img-${LOCALVERSION} $KERNEL_VERSION - - #REBOOT_TYPE = script - #REBOOT_SCRIPT = ssh $SSH_USER@$MACHINE "sed -i 's|^default.*$|default test|' /boot/loader/loader.conf" - - TEST_START - # TEST_TYPE can be: build, install, boot, ... - TEST_TYPE = boot - BUILD_TYPE = useconfig:${THIS_DIR}/sof-dev-defconfig - BUILD_NOCLEAN = 1 - - -For Fedora and derived distributions, make the following changes: - -.. code-block:: perl - - GRUB_MENU = "title" of the kernel entry as displayed by: 'grubby --info=ALL' - GRUB_REBOOT = grub2-reboot - REBOOT_TYPE = grub2bls - POST_INSTALL = ssh -o 'ProxyCommand none' $SSH_USER@$MACHINE sudo dracut --hostonly --force --kver ${LOCALVERSION} - -7. Build and test ------------------ - -.. code-block:: bash - - ./ktest.pl sof-dev.conf - -If this does not work, make sure you have all the following files in the -local directory: - -* ktest.pl -* sof-dev-cat -* sof-dev -* sof-dev-build -* sof-dev.conf -* sof-dev-defconfig - -Ktest will compile, install the new kernel, and reboot. Prompt -detection only works with a UART, not over SSH, so you will have to -``Control-C`` manually when the console is not enabled. - -8. Enjoy! ---------- - -9. Enjoy even more! -------------------- - -By having multiple worktrees and configs, you can run tests in parallel -on different machines on the same kernel or different branches. - -10. Clean up /lib/modules -------------------------- - -Ktest creates a separate module directory per kernel version. -User needs to clean up old module directory periodically. - -.. code-block:: bash - - $ ls -al /lib/modules - drwxrwxr-x 3 ubuntu ubuntu 4096 Sep 28 15:07 5.9.0-rc4-test+ - drwxrwxr-x 3 ubuntu ubuntu 4096 Sep 24 11:06 5.9.0-rc5-test+ - drwxrwxr-x 3 ubuntu ubuntu 4096 Oct 5 16:39 5.9.0-rc6-test+ - drwxrwxr-x 3 ubuntu ubuntu 4096 Oct 14 21:42 5.9.0-rc7-test+ - drwxrwxr-x 3 ubuntu ubuntu 4096 Nov 2 12:16 5.9.0-rc8-test+ - diff --git a/getting_started/setup_linux/install_locally.rst b/getting_started/setup_linux/install_locally.rst new file mode 100644 index 00000000..ce50ec8f --- /dev/null +++ b/getting_started/setup_linux/install_locally.rst @@ -0,0 +1,134 @@ +.. _install-locally: + +Install the Kernel Locally +########################## + +.. contents:: + :local: + :depth: 3 + +Introduction +************ + +Make sure you have `set up your development environment `_ before following these steps. This page will guide you through the process of installing the kernel locally on your machine. It will be installed in addition to your distro's default kernel so that you can always change back to that in case something goes wrong. If you are interested in learning more about this process, there are lots of online guides available, for example `Fedora* Quick Docs `_, `Arch Linux documentation `_ or `this wiki page `_. + + +Build and install the kernel +**************************** + +1. Change directory to ``~/work/sof/linux`` that you created on the setup page. + +#. Load the base kernel configuration. + + The following command copies the configuration of the booted kernel so that it will be used as a base: + + .. code-block:: bash + + cp /boot/config-$(uname -r)* .config + + +#. Apply the SOF-specific configuration. + + + The following scripts update your base configuration so that it uses the latest SOF modules. Run only one of them depending on your needs. If it prompts you with any questions, just press **Enter** to accept the default value. Note that, by default, these scripts will set the configuration to only compile modules that are currently loaded in order to lower compile times. This means that when you've booted from the custom kernel, some external devices may not work if they were not connected while running this script. If you want to compile all modules, delete the line ``make localmodconfig`` from the script you will run in this step. + + - For most users: + + .. code-block:: bash + + ../kconfig/kconfig-distro-sof-update.sh + + + - For additional logging and experimental device support: + + .. code-block:: bash + + ../kconfig/kconfig-distro-sof-dev-update.sh + + .. _compile-kernel-step: + +#. Compile the kernel. + + The first time you run this command, it can take a while (over 30 minutes on some machines), so grab a coffee or take an exercise break while it runs. + + .. code-block:: bash + + make -j$(nproc --all) + + .. _install-kernel-step: + +#. Install the kernel. + + .. code-block:: bash + + sudo make modules_install + sudo make install + +If all went well, your freshly-built kernel will be installed and available at next boot. Restart your computer, and you should have the option to pick a kernel when it turns on. Select the kernel which name has ``-sof`` at the end of it, and your computer should boot as normal using the kernel you just built. On Ubuntu*, the kernel option may be hidden behind the **Advanced options for Ubuntu** submenu. + +Update and rebuild +****************** + +If you need to try some new changes, download the updated code and rebuild the kernel. + +Update the kernel cloned with git +--------------------------------- + +If you originally cloned the repo using git, perform the following steps to update and rebuild the kernel: + +1. Pull the changes. + + .. code-block:: bash + + git pull + +#. Clean the directory. + + .. note:: You should clean up after switching branches or configuration or any other major code change. If you just pulled some minor updates, it's likely unnecessary and will increase your build time. + + .. code:: bash + + make clean + +#. Repeat :ref:`steps 4` :ref:`and 5` to rebuild and reinstall the kernel. + +#. Reboot your computer, and select the kernel with ``-sof`` at the end of its name to test it. + +Update the kernel downloaded via zip +------------------------------------ + +Unfortunately, if you downloaded via zip, the entire process has to be restarted from the :ref:`Get the kernel source` step. There is no good way to incrementally update. However, the kernel build should be faster now as part of it will be cached. + +Make sure you delete the old folder before starting over: + +.. code-block:: bash + + cd .. + rm -rf linux + + +Remove the kernel +***************** + +If you run into issues or no longer need the custom kernel, you can remove it. + +- Ubuntu: + + .. code-block:: bash + + cd ~/work/sof/linux + sudo rm /boot/*-$(make kernelversion) + sudo rm -rf /lib/modules/$(make kernelversion) + sudo update-grub + +- Fedora: + + .. code-block:: bash + + cd ~/work/sof/linux + sudo rm /boot/*-$(make kernelversion)* + sudo rm -rf /lib/modules/$(make kernelversion) + sudo grubby --remove-kernel=/boot/vmlinuz-$(make kernelversion) + + +After rebooting, you should be back to your old kernel with all traces of the custom kernel installation gone. If you'd like, you can also delete the ``~sof`` directory to save disk space. diff --git a/getting_started/setup_linux/prepare_build_environment.rst b/getting_started/setup_linux/prepare_build_environment.rst new file mode 100644 index 00000000..d86cb6aa --- /dev/null +++ b/getting_started/setup_linux/prepare_build_environment.rst @@ -0,0 +1,79 @@ +.. _prepare-build-environment: + +Set up a Development Environment to Build the Kernel +#################################################### + +These instructions will help you set up a development environment for the SOF branch of the Linux kernel. If you have dedicated test hardware, you can use ktest to install it over ssh. Otherwise, you can install it locally on your device in addition to your default kernel. + +Review the following prerequisites: + +- **Development device:** PC running Fedora* 35+ or Ubuntu* 20.04+. + +- **Target device:** PC running Fedora 35+ or Ubuntu 20.04+, with secure boot disabled. If the target device is different than the development device, you must be able to ssh into the target, which is typically on the same local network/VPN. + +1. Create a working directory. + + This directory can be located anywhere. Simply change the ``SOF_WORKSPACE`` variable if you would like to store your sources somewhere else. + + .. code-block:: bash + + export SOF_WORKSPACE=~/work/sof + mkdir -p $SOF_WORKSPACE + cd $SOF_WORKSPACE + +#. Install kernel build dependencies. + + - Fedora (see `their guide `_ for details): + + .. code-block:: bash + + sudo dnf install fedpkg + fedpkg clone -a kernel + cd kernel + sudo dnf builddep kernel.spec + sudo dnf install ccache + cd .. + + - Ubuntu (see `their page `_ for details): + + .. code-block:: bash + + sudo apt update + sudo apt install git libncurses-dev gawk flex bison openssl libssl-dev dkms libelf-dev libudev-dev libpci-dev libiberty-dev autoconf dwarves zstd + +#. Download the configuration scripts. + + .. code-block:: bash + + git clone https://github.com/thesofproject/kconfig.git + + .. _get-kernel-source: + +#. Get the kernel source. + + There are two ways to get the kernel source. We strongly recommend using git as it makes updates **much** easier, but the zip download may be more successful if you have an unstable connection. + + - Option 1: Clone with git. + + .. code-block:: bash + + git clone https://github.com/thesofproject/linux.git --depth=1 + cd linux + + .. note:: + + If a maintainer requests that you check out a different branch to test a bug fix, add ``-b [branch]`` to the end of this command, where `[branch]` is the branch name. + + - Option 2: Download via zip. + + Visit the SOF Linux fork at https://github.com/thesofproject/linux. If a maintainer asks you to test a specific branch, click the dropdown with the text "topic/sof-dev" and select the branch they asked you to test. Then, click the green **Code** dropdown and select **Download ZIP**. Once it is downloaded, extract it to the directory you created in the previous step: + + .. code-block:: bash + + cd ~/Downloads + unzip linux-*.zip -d $SOF_WORKSPACE + cd $SOF_WORKSPACE + mv linux-* linux + cd linux + +Your device should now be ready to configure and build the kernel. How to proceed depends on if you are installing :ref:`locally` or on :ref:`dedicated test hardware`. diff --git a/getting_started/setup_linux/setup_ktest_environment.rst b/getting_started/setup_linux/setup_ktest_environment.rst new file mode 100644 index 00000000..2836890c --- /dev/null +++ b/getting_started/setup_linux/setup_ktest_environment.rst @@ -0,0 +1,405 @@ +.. _setup-ktest-environment: + +Set up a Ktest-based Environment +################################ + +.. contents:: + :local: + :depth: 3 + +Introduction +************ + +These instructions explain how a target device can be configured to +update the kernel over SSH. The use of ktest.pl and git worktrees +allow for simultaneous configs to be tested on multiple platforms. +Wired Ethernet access is assumed as wireless is unreliable. If there +is no Ethernet port, use a USB-Ethernet dongle supported in the kernel. + +The target device can be any of the SOF-supported platforms, +such as MinnowBoard, Up^2, Asus T100, Chromebooks. + +Set up a target +*************** + +1. Install Ubuntu*, Debian*, or Fedora* on the target. + +#. Enable root password. + + .. code-block:: bash + + sudo su (enter your password) + passwd (enter new root password) + exit + +#. Create a test kernel. + + Copy your existing known-to-work kernels/initrd. + + .. code-block:: bash + + sudo cp /boot/vmlinuz-$(uname -r) /boot/vmlinuz-test + + # On Ubuntu: + sudo cp /boot/initrd.img-$(uname -r) /boot/initrd.img-test + + # On Fedora: + sudo cp /boot/initramfs-$(uname -r).img /boot/initramfs-test.img + sudo grubby --add-kernel /boot/vmlinuz-test --title=test + +#. Edit grub settings. + + Perform these steps only on Ubuntu and Debian. Fedora has the proper settings by default. + + a) Open the grub configuration file in your editor of choice as a super user: + + .. code-block:: bash + + sudo emacs /etc/default/grub + + b) Change ``GRUB_DEFAULT=[n]`` to ``GRUB_DEFAULT=saved``. + + c) You must disable GRUB submenus because they confuse ktest: + + .. code-block:: console + + echo 'GRUB_DISABLE_SUBMENU=y' | sudo tee -a /etc/default/grub.d/disable-submenu.cfg + + d) Update the grub configuration. + + .. code-block:: console + + # Better safe than _very_ sorry + sudo cp /boot/grub/grub.cfg /boot/grub/saved_grub.cfg + + sudo update-grub + + # Make sure submenus are actually disabled + grep submenu /boot/grub/grub.cfg + +#. Set the default kernel. + + You will never override the default + distro kernel, so you will always have the ability to boot a + working kernel if your changes cause issues. + By setting the default kernel, you can return your system to a stable + state with just a power cycle, no grub menus involved. + + - On Ubuntu: + + .. code-block:: bash + + # Print your currently booted (and known-safe) option + cat /proc/cmdline + # List the grub entries + awk '/^menuentry|submenu/ { print i++, '\t', $0 }' /boot/grub/grub.cfg + # Find the entry that matches the output of the + # first command you ran, and take note of its number + sudo grub-set-default [n] # Where [n] is that number + # This should print saved_entry=[n] + grub-editenv list + + - On Fedora: + + .. code-block:: bash + + sudo grubby --set-default /boot/vmlinuz-$(uname -r) + +6. Get familiar with grub-reboot. + + ktest relies on grub-reboot. grub-reboot lets you try a freshly built + kernel *only once* and then boot immediately a "safe" kernel again + without interacting with the boot menu: a simple power cycle is + enough. It's a must have for testing development kernels that may not + fully boot. + + In case something goes wrong with ktest, being familiar with grub-reboot + may save you interacting with the boot menu or even better: it may save + you making your system unbootable by accident. Understanding how + grub-reboot works is required to fully understand ktest + configuration. It's much easier to discover grub-reboot alone than when + entangled with ktest. + + Here is a quick cheat sheet for grub-reboot on Ubuntu/Debian. For + more details, search the documentation of your Linux distribution. The + commands below have been tested on Ubuntu 20.04. They should be nearly + identical for most Debian-derived Linux distributions. + + .. warning:: + + ``update-grub`` does not care about menuentry order and will mess up what the numbers below point to! After running update-grub, make sure the default kernel index is correct and points towards a known-safe kernel. + + .. code-block:: bash + + # Add/remove entries in grub.cfg after making changes in /boot/ + # grub.cfg is generated, don't edit it! + update-grub + + # See which GRUB entry was booted + cat /proc/cmdline + + # Show the default menuentry + grub-editenv list + #=> saved_entry=6 + + # Show all, numbered kernel choices without (re)booting + awk '/^menuentry|submenu/ { print i++, '\t', $0 }' /boot/grub/grub.cfg + #=> 5 menuentry ... + #=> 6 menuentry 'Ubuntu, with Linux 5.4.0-53-generic' --class ubuntu ... + #=> 7 menuentry ... + + # Attempt to boot menuentry 4 only once + grub-reboot 4 + # Run this to see the updated settings + grub-editenv list + #=> saved_entry=6 + #=> next_entry=4 + reboot + + # Switch to menuentry number 4 as the new "safe" kernel + grub-set-default 4 + + + Fedora and derived distributions have a more elaborate system to manage + "installed" kernels. Instead of extracting ``menuentry`` lines from + ``/boot/grub/grub.cfg`` with the ``awk`` command above, to list all + installed kernels use ``grubby --info=ALL``. + Check ``grubby`` documentation for more details. + To boot a different kernel just once, use ``grub2-reboot [n]``, where ``[n]`` is the index of the menu entry you'd like to boot. + +#. Install and configure openssh-server. + + a) Install or enable openssh-server: + + - On Ubuntu, install the server: + + .. code-block:: bash + + sudo apt-get install openssh-server + + - On Fedora, enable the server: + + .. code-block:: bash + + sudo systemctl enable sshd + + b) Update the openssh-server configuration using your editor of choice. + + .. code-block:: bash + + sudo emacs /etc/ssh/sshd_config + + Replace ``#PermitRootLogin prohibit-password`` with ``PermitRootLogin yes`` and save the file. Make sure to remove the hash character (#). + + This is just temporary, you will change this back once you have copied over your ssh key. + +#. Reboot the target. + + Make sure it boots automatically to your safe kernel. We also recommend to test using grub-reboot to boot the test kernel, then rebooting again to make sure it goes back to the safe kernel. + +Configure SSH without password +****************************** + +1. Check the SSH connection. + + You must be able to ssh into the target device, which is typically on the same local network/VPN. Run ``ip addr`` on the target to get its IP address. All other commands should be run on your dev machine, unless specified otherwise. + + .. code-block:: bash + + # Make sure that you can connect and login to the target + ssh root@ + +#. Generate an SSH key for the target. + + If you already have an ssh key you'd prefer to use, you can skip this step. + + .. code-block:: bash + + ssh-keygen -f ~/.ssh/sshktest + # This will prompt you for the target's root password. + ssh-copy-id -i ~/.ssh/sshktest root@ + +#. Test the key. + + .. code-block:: bash + + ssh root@ + + .. note:: + + In most cases `ssh-agent` should automatically manage your password(s) and key(s). If you are still prompted for a password, it's likely your distro hasn't configured `ssh-agent`. You can either figure out how to enable it, or you can manually update your config. + To do this, put the following in ``~/.ssh/config`` (make sure to update ````) and then use ``ktest-target`` instead of the actual target's IP for ssh connections (for example, ``ssh root@ktest-target``). + + .. code-block:: text + + Host ktest-target + HostName + IdentityFile ~/.ssh/sshktest + +#. Disable root access. + + Run this on the target device to disable root password, + you do not need it now that you have copied the key. + + .. code-block:: bash + + # Use your editor of choice. + sudo emacs /etc/ssh/sshd_config + + Replace ``PermitRootLogin yes`` by ``PermitRootLogin without-password``, save, and exit. + +Build and install the kernel with ktest +*************************************** + +Follow the `prepare build environment `_ instructions before proceeding. + +1. Prepare the ktest environment. + + If you run this in a different terminal than you used for the `prepare build environment `_ instructions, you need to re-set the SOF_WORKSPACE variable by running ``export SOF_WORKSPACE = ~/work/sof``. + + .. code-block:: bash + + cd $SOF_WORKSPACE + mkdir sof-dev-build + mkfifo sof-dev-cat + cp linux/tools/testing/ktest/ktest.pl . + +#. Save your kernel configuration as ``sof-dev-defconfig``. + + If you do not know what options are needed, you can start using configurations maintained by SOF developers. + + .. code-block:: bash + + cd linux + make O=../sof-dev-build olddefconfig + echo test > ../sof-dev-build/localversion + bash ../kconfig/kconfig-sof-default.sh + cp .config ../sof-dev-defconfig + make mrproper + cd .. + + .. note:: + + Use make proper since ktest.pl requires the source directory + to be clean. All compilation happens in the -build directory. + + .. note:: + + The options provided in kconfig/sof-dev-defconfig should not be used for a distro's production kernel. + +#. Edit ktest configuration as needed. + + Save the following in ``sof-dev.conf``. Make sure to update the ``MACHINE=`` line with your target device's IP (or ``ktest-target`` if you had to do the additional ssh config). + + .. code-block:: perl + + # The difference between config variables (:=) and ktest options (=) and a + # few other things are explained in tools/testing/ktest/examples/sample.conf + + MACHINE = 192.168.1.205 + CLEAR_LOG = 1 + SSH_USER = root + THIS_DIR := ${PWD} + # BUILD_DIR is the source directory + BUILD_DIR = ${THIS_DIR}/linux + # OUTPUT_DIR is the actual build directory + OUTPUT_DIR = ${THIS_DIR}/sof-dev-build + BUILD_TARGET = arch/x86/boot/bzImage + + # ktest requires LOCALVERSION. This is normally a '-something' suffix like + # in 'vmlinuz-5.10-rc5-something'. Let's (ab)use it as the full version so + # we have a constant 'vmlinuz-something' filename and we don't have to + # make changes in /boot/ all the time. + # update-grub will complain but work anyway. + LOCALVERSION = test + TARGET_IMAGE = /boot/vmlinuz-${LOCALVERSION} + + BUILD_OPTIONS = -j8 + LOG_FILE = ${OUTPUT_DIR}/sof-dev.log + CONSOLE = cat ${THIS_DIR}/sof-dev-cat + POWER_CYCLE = echo Power cycle the machine now and press ENTER; read a + #set below to help ssh connection to close after sending reboot command + REBOOT = ssh $SSH_USER@$MACHINE 'sudo reboot > /dev/null &' + + # This how ktest finds which menuentry number to pass to grub-reboot + GRUB_FILE = /boot/grub/grub.cfg + GRUB_MENU = Ubuntu, with Linux ${LOCALVERSION} + #GRUB_MENU = ubilinux GNU/Linux, with Linux ${LOCALVERSION} + #GRUB_MENU = GalliumOS GNU/Linux, with Linux ${LOCALVERSION} + GRUB_REBOOT = grub-reboot + REBOOT_TYPE = grub2 + + # update-initramfs does not support any "version-less" 'vmlinuz-test' because it + # does not tell where to find modules like '/lib/modules/5.10.0-rc5test+' + # So we have to use a lower level, more explicit command like: + # mkinitramfs -o initrdfile 5.10.0-rc5test+ + # ktest finds the real KERNEL_VERSION thanks to "make O=${OUTPUT_DIR} + # kernelrelease" + POST_INSTALL = ssh $SSH_USER@$MACHINE sudo /usr/sbin/mkinitramfs -o /boot/initrd.img-${LOCALVERSION} $KERNEL_VERSION + + #REBOOT_TYPE = script + #REBOOT_SCRIPT = ssh $SSH_USER@$MACHINE "sed -i 's|^default.*$|default test|' /boot/loader/loader.conf" + + TEST_START + # TEST_TYPE can be: build, install, boot, ... + TEST_TYPE = boot + BUILD_TYPE = useconfig:${THIS_DIR}/sof-dev-defconfig + BUILD_NOCLEAN = 1 + + + For targets running Fedora and derived distributions, make the following changes: + + .. code-block:: perl + + # GRUB_MENU should be the title of the custom kernel entry you added, + # which will match LOCALVERSION ("test") if you followed the previous steps + # You can view all your kernel entries with `grubby --info=ALL` + GRUB_MENU = ${LOCALVERSION} + GRUB_REBOOT = grub2-reboot + REBOOT_TYPE = grub2bls + POST_INSTALL = ssh $SSH_USER@$MACHINE sudo dracut --hostonly --force /boot/initramfs-${LOCALVERSION}.img $KERNEL_VERSION + +#. Build and test. + + .. code-block:: bash + + # This can take a while, so don't kill it if it appears to freeze + ./ktest.pl sof-dev.conf + + If this does not work, make sure you have all the following files in the + local directory: + + * ktest.pl + * sof-dev-cat + * linux + * sof-dev-build + * sof-dev.conf + * sof-dev-defconfig + + Ktest will compile and install the new kernel, then reboot the target device. Check which kernel is booted by running ``uname -r`` on the target. + + .. note:: + + KTest expects a UART connection to verify that the boot was successful. If you do not have a UART connection you will get some errors at the end of the ``ktest.pl`` script's execution, but you can ignore them as long as the custom kernel was installed and booted on the target device. + +#. Enjoy! + +#. Enjoy even more! + + By having multiple `Git worktrees `_ and configs, you can run tests in parallel + on different machines on the same kernel or different branches. + +#. Clean up `/lib/modules`. + + Ktest creates a separate module directory per kernel version. + User needs to clean up old module directory periodically on the target device. + + .. code-block:: bash + + $ ls -al /lib/modules + drwxrwxr-x 3 ubuntu ubuntu 4096 Sep 28 15:07 5.9.0-rc4-test+ + drwxrwxr-x 3 ubuntu ubuntu 4096 Sep 24 11:06 5.9.0-rc5-test+ + drwxrwxr-x 3 ubuntu ubuntu 4096 Oct 5 16:39 5.9.0-rc6-test+ + drwxrwxr-x 3 ubuntu ubuntu 4096 Oct 14 21:42 5.9.0-rc7-test+ + drwxrwxr-x 3 ubuntu ubuntu 4096 Nov 2 12:16 5.9.0-rc8-test+ + diff --git a/getting_started/setup/images/minnow_turbot.png b/getting_started/setup_special_device/images/minnow_turbot.png similarity index 100% rename from getting_started/setup/images/minnow_turbot.png rename to getting_started/setup_special_device/images/minnow_turbot.png diff --git a/getting_started/setup/setup_minnowboard_turbot.rst b/getting_started/setup_special_device/setup_minnowboard_turbot.rst similarity index 100% rename from getting_started/setup/setup_minnowboard_turbot.rst rename to getting_started/setup_special_device/setup_minnowboard_turbot.rst diff --git a/getting_started/setup/setup_up_2_board.rst b/getting_started/setup_special_device/setup_up_2_board.rst similarity index 100% rename from getting_started/setup/setup_up_2_board.rst rename to getting_started/setup_special_device/setup_up_2_board.rst diff --git a/introduction/index.rst b/introduction/index.rst index 40a78904..6b007c57 100644 --- a/introduction/index.rst +++ b/introduction/index.rst @@ -49,7 +49,7 @@ there can be more than once choice for other ingredients as shown in the diagram :alt: SDK Overview :width: 1000px - `SDK example configuration showing development flow for SOF on the Intel Apollolake platform running Linux OS. Note the choice of compiler toolchains and choice of optional DSP emulators.` + `SDK example configuration showing development flow for SOF on the Intel Apollo Lake platform running Linux OS. Note the choice of compiler toolchains and choice of optional DSP emulators.` SOF source code, tools, and topologies diff --git a/maintainers/admin.rst b/maintainers/admin.rst index 209858f9..450bc783 100644 --- a/maintainers/admin.rst +++ b/maintainers/admin.rst @@ -13,13 +13,11 @@ to multiple contributors: +---------------+-------------------+---------------+ | Intel | Marcin Maka | @mmaka1 | +---------------+-------------------+---------------+ -| Intel | Pierre Bossart | @plbossart | -+---------------+-------------------+---------------+ | Intel | Ranjani Sridharan | @ranj063 | +---------------+-------------------+---------------+ | NXP | Daniel Baluta | @dbaluta | +---------------+-------------------+---------------+ -| Google | Curtis Malainey | @cujomalainey | +| Google | Johny Lin | @johnylin76 | +---------------+-------------------+---------------+ Administrators may override specific merge rules, for example merge a diff --git a/platforms/index.rst b/platforms/index.rst index d968bf9d..a582511d 100644 --- a/platforms/index.rst +++ b/platforms/index.rst @@ -9,32 +9,53 @@ Supported Platforms Platform and board specific support is continually added to the SOF project as documented below. .. csv-table:: Supported Platforms - :header: "Platform", "Architecture", "Cores/Clocks", "Memory", "Audio Interfaces" - :widths: 20, 20, 10, 10, 20 - - "Host Testbench", "PC command line", "N/A", "N/A", "N/A Files are used to simulate audio interfaces" - "Qemu", "All supported SOF HW platforms", "N/A", "N/A", "WiP Files will be used to simulate audio interfaces" - "Intel Baytrail / Merrifield", "Xtensa HiFi2 EP", "1 @ 50 - 400MHz", "96KB IRAM / 192KB DRAM", "3 x SSP (I2S, PCM)" - "Intel Cherrytrail / Braswell", "Xtensa HiFi2 EP", "1 @ 50 - 400MHz", "96KB IRAM / 192KB DRAM", "6 x SSP (I2S, PCM)" - "Intel Broadwell", "Xtensa HiFi2 EP", "1 @ 50 - 400MHz", "320KB IRAM / 640KB DRAM", "2 x SSP (I2S, PCM)" - "Intel Apollolake / Geminilake", "Xtensa HiFi3", "2 @ 100 - 400MHz", "128KB LP SRAM / 512KB HP SRAM", "6 x SSP (I2S, PCM), HDA, DMIC" - "Intel Cannonlake / Whiskeylake / Cometlake", "Xtensa HiFi3", "4 @ 120 - 400MHz", "64KB LP / 3008KB HP SRAM", "3 x SSP (I2S, PCM), HDA, DMIC, Soundwire" - "Intel Suecreek", "Xtensa HiFi3", "2 @ 120 - 400MHz", "64KB LP SRAM / 4096KB HP SRAM", "6 x SSP (I2S, PCM), DMIC" - "Intel Icelake", "Xtensa HiFi3", "4 @ 120 - 400MHz", "64KB LP SRAM / 3008KB HP SRAM", "6 x SSP (I2S, PCM), HDA, DMIC, Soundwire" - "Intel Jasperlake", "Xtensa HiFi3", "2 @ 120 - 400MHz", "64KB LP SRAM / 1024KB HP SRAM", "3 x SSP (I2S, PCM), HDA, DMIC, Soundwire" - "Intel Tigerlake", "Xtensa HiFi3", "4 @ 120 - 400MHz", "64KB LP SRAM / 2944KB HP SRAM", "6 x SSP (I2S, PCM), HDA, DMIC, Soundwire" - "Intel Alderlake", "Xtensa HiFi3", "4 @ 120 - 400MHz", "64KB LP SRAM / 2944KB HP SRAM", "6 x SSP (I2S, PCM), HDA, DMIC, Soundwire" - "NXP i.MX8", "Xtensa HiFi4", "1 @ 666MHz", "64 KB TCM / 448 KB OCRAM / 8MB SDRAM", "1 x ESAI, 1 x SAI" - "NXP i.MX8X", "Xtensa HiFi4", "1 @ 640MHz", "64 KB TCM / 448 KB OCRAM / 8MB SDRAM", "1 x ESAI, 1 x SAI" - "NXP i.MX8M", "Xtensa HiFi4", "1 @ 800MHz", "64 KB TCM / 256 KB OCRAM / 8MB SDRAM", "1 x SAI, MICFIL" - "NXP i.MX8ULP", "Xtensa HiFi4", "1 @ 520MHz", "64 KB TCM / 256 KB OCRAM / 8MB SDRAM", "1 x SAI" - "AMD Renoir", "Xtensa HiFi3", "1 @ 600MHz", "20 KB LP SRAM / 1152 KB IRAM/DRAM", "1 x SP (I2S, PCM), 1 x BT (I2S, PCM), DMIC" - "Mediatek mt8195", "Xtensa HiFi4", "1 @ 220 - 720MHz", "256 KB SRAM / 16 MB DRAM", "2 x TDM Out, 1 x TDM In, DMIC" + :header: "Platform", "Architecture", "Cores/Clocks", "Platform Clock", "Memory", "Audio Interfaces" + :widths: 20, 20, 10, 10, 10, 20 + + "Host Testbench", "PC command line", "N/A", "N/A", "N/A", "N/A Files are used to simulate audio interfaces" + "Qemu", "All supported SOF HW platforms", "N/A", "N/A", "N/A", "WiP Files will be used to simulate audio interfaces" + "Intel Tiger Lake with IPC4", "Xtensa HiFi3", "4 @ 120 - 400MHz", "38.4MHz", "64KB LP SRAM / 2944KB HP SRAM", "6 x SSP (I2S, PCM), HDA, DMIC, Soundwire" + "Intel Alder Lake with IPC4", "Xtensa HiFi3", "4 @ 120 - 400MHz", "38.4MHz", "64KB LP SRAM / 2944KB HP SRAM", "6 x SSP (I2S, PCM), HDA, DMIC, Soundwire" + "NXP i.MX8", "Xtensa HiFi4", "1 @ 666MHz", "TBD", "64 KB TCM / 448 KB OCRAM / 8MB SDRAM", "1 x ESAI, 1 x SAI" + "NXP i.MX8X", "Xtensa HiFi4", "1 @ 640MHz", "TBD", "64 KB TCM / 448 KB OCRAM / 8MB SDRAM", "1 x ESAI, 1 x SAI" + "NXP i.MX8M", "Xtensa HiFi4", "1 @ 800MHz", "TBD", "64 KB TCM / 256 KB OCRAM / 8MB SDRAM", "1 x SAI, MICFIL" + "NXP i.MX8ULP", "Xtensa HiFi4", "1 @ 520MHz", "TBD", "64 KB TCM / 256 KB OCRAM / 8MB SDRAM", "1 x SAI" + "AMD Renoir", "Xtensa HiFi3", "1 @ 200-600MHz", "TBD", "20 KB LP SRAM / 1152 KB IRAM/DRAM", "1 x SP (I2S, PCM), 1 x BT (I2S, PCM), DMIC" + "AMD Rembrandt", "Xtensa HiFi5", "1 @ 200-800MHz", "TBD", "1.75 MB HP SRAM / 512 KB IRAM/DRAM", "1 x SP (I2S, PCM), 1 x BT (I2S, PCM), 1 x HS(I2S, PCM), DMIC" + "Mediatek mt8195", "Xtensa HiFi4", "1 @ 220 - 720MHz", "TBD", "256 KB SRAM / 16 MB DRAM", "2 x TDM Out, 1 x TDM In, DMIC" + "Mediatek mt8186", "Xtensa HiFi5", "1 @ 300 - 800MHz", "TBD", "512 KB SRAM / DRAM", "2 x I2S Out, 1 x I2S In, DMIC" + "Mediatek mt8188", "Xtensa HiFi5", "1 @ 26 - 800MHz", "TBD", "512 KB SRAM / 17 MB DRAM", "2 x TDM Out, 1 x TDM In, DMIC" When support for a new platform is being added, certain interfaces required by SOF infrastructure must be implemented. Refer to Platform API documentation for details. +Some platforms have been supported by SOF in the past, but are no longer +supported in SOF mainline ("main" branch). Below table lists such platforms, +the last SOF major release that had support for the platform and the stable +branch to use. For every SOF release, a stable branch is created and critical +bugfixes can be submitted and released via these stable branches. + +.. csv-table:: Platforms No Longer Supported in Mainline + :header: "Platform", "Last Release", "Branch", "Architecture", "Cores/Clocks", "Platform Clock", "Memory", "Audio Interfaces" + :widths: 20, 10, 10, 20, 10, 10, 10, 20 + + "Intel Bay Trail / Merrifield", "2.2", "stable-v2.2", "Xtensa HiFi2 EP", "1 @ 50 - 400MHz", "25MHz", "96KB IRAM / 192KB DRAM", "3 x SSP (I2S, PCM)" + "Intel Cherry Trail / Braswell", "2.2", "stable-v2.2", "Xtensa HiFi2 EP", "1 @ 50 - 400MHz", "19.2MHz", "96KB IRAM / 192KB DRAM", "6 x SSP (I2S, PCM)" + "Intel Broadwell", "2.2", "stable-v2.2", "Xtensa HiFi2 EP", "1 @ 50 - 400MHz", "24MHz", "320KB IRAM / 640KB DRAM", "2 x SSP (I2S, PCM)" + "Intel Apollo Lake / Gemini Lake", "2.2", "stable-v2.2", "Xtensa HiFi3", "2 @ 100 - 400MHz", "19.2MHz", "128KB LP SRAM / 512KB HP SRAM", "6 x SSP (I2S, PCM), HDA, DMIC" + "Intel Cannon Lake / Whiskey Lake / Comet Lake", "2.2", "stable-v2.2", "Xtensa HiFi3", "4 @ 120 - 400MHz", "24MHz", "64KB LP / 3008KB HP SRAM", "3 x SSP (I2S, PCM), HDA, DMIC, Soundwire" + "Intel Sue Creek", "2.2", "stable-v2.2", "Xtensa HiFi3", "2 @ 120 - 400MHz","24MHz", "64KB LP SRAM / 4096KB HP SRAM", "6 x SSP (I2S, PCM), DMIC" + "Intel Ice Lake", "2.2", "stable-v2.2", "Xtensa HiFi3", "4 @ 120 - 400MHz", "38.4MHz", "64KB LP SRAM / 3008KB HP SRAM", "6 x SSP (I2S, PCM), HDA, DMIC, Soundwire" + "Intel Jasper Lake", "2.2", "stable-v2.2", "Xtensa HiFi3", "2 @ 120 - 400MHz", "38.4MHz", "64KB LP SRAM / 1024KB HP SRAM", "3 x SSP (I2S, PCM), HDA, DMIC, Soundwire" + "Intel Tiger Lake with IPC3", "2.2", "stable-v2.2", "Xtensa HiFi3", "4 @ 120 - 400MHz", "38.4MHz", "64KB LP SRAM / 2944KB HP SRAM", "6 x SSP (I2S, PCM), HDA, DMIC, Soundwire" + "Intel Alder Lake with IPC3", "2.2", "stable-v2.2", "Xtensa HiFi3", "4 @ 120 - 400MHz", "38.4MHz", "64KB LP SRAM / 2944KB HP SRAM", "6 x SSP (I2S, PCM), HDA, DMIC, Soundwire" + +The periodic sof-bin releases + +contain latest binaries for all platforms, both from SOF main and +latest binaries from "stable-vX.YY" branches. + Minimum Platform Requirements ***************************** @@ -42,14 +63,14 @@ Footprint ========= DSP platforms can vary from vendor to vendor but in general SOF can run on -small platforms like Intel Baytrail DSP with 96kb of instruction RAM and 168kb +small platforms like Intel Bay Trail DSP with 96kb of instruction RAM and 168kb of data RAM. The SOF footprint can be shrunk to approximately 50kb of TEXT and DATA by fine-tuning runtime features via Kconfig. DSP Clock Speed =============== -Required DSP clock speed depends on the DSP processing load, so it can vary greatly depending on pipeline topology and the algorithm design that is running. SOF can run several volume passthrough pipelines on the Intel Baytrail DSP at 50MHz using unoptimized C code (SIMD disabled and compiled with GCC). +Required DSP clock speed depends on the DSP processing load, so it can vary greatly depending on pipeline topology and the algorithm design that is running. SOF can run several volume passthrough pipelines on the Intel Bay Trail DSP at 50MHz using unoptimized C code (SIMD disabled and compiled with GCC). Toolchain ========= diff --git a/platforms/intel-cavs/commons/work-queue.rst b/platforms/intel-cavs/commons/work-queue.rst old mode 100755 new mode 100644 diff --git a/platforms/intel-cavs/icelake/icl-memory.rst b/platforms/intel-cavs/icelake/icl-memory.rst index 689a316f..19e3e313 100644 --- a/platforms/intel-cavs/icelake/icl-memory.rst +++ b/platforms/intel-cavs/icelake/icl-memory.rst @@ -3,4 +3,4 @@ ICL Memory ########## -Memory map is the same as on Cannonlake. See :ref:`cnl-memory`. +Memory map is the same as on Cannon Lake. See :ref:`cnl-memory`. diff --git a/platforms/intel-cavs/index.rst b/platforms/intel-cavs/index.rst index 62950e1f..cc2b7bd1 100644 --- a/platforms/intel-cavs/index.rst +++ b/platforms/intel-cavs/index.rst @@ -15,7 +15,7 @@ Intel CAVS platforms supported by the |SOF|. | |ver. 2.5 | Tiger Lake | +---------+----------+-----------------------------------------+ -.. note:: While the Sky Lake and Kaby Lake platforms are also based on the +.. note:: While the Skylake and Kaby Lake platforms are also based on the cAVS 1.5 architecture, they are not supported at this time due to differences in boot flow and memory architecture. diff --git a/platforms/intel-legacy/baytrail/index.rst b/platforms/intel-legacy/baytrail/index.rst index 92bfa102..8b5040ca 100644 --- a/platforms/intel-legacy/baytrail/index.rst +++ b/platforms/intel-legacy/baytrail/index.rst @@ -1,20 +1,20 @@ .. _platform-baytrail: -Intel Baytrail/CherryTrail -########################## +Intel Bay Trail / Cherry Trail +############################## -Intel Baytrail platform is based on an Atom CPU and a Tensilica HiFi2 +Intel Bay Trail platform is based on an Atom CPU and a Tensilica HiFi2 EP DSP. It relies on both internal memory and caches to access DDR -memory. The Baytrail processor relies on a 25 MHz oscillator. +memory. The Bay Trail processor relies on a 25 MHz oscillator. Supported commercially-available platforms include the MinnowBoard Turbot, tablets and laptops built for Windows (SOF requires a Linux installation). -The Cherrytrail platform is similar to Baytrail but it relies on a +The Cherry Trail platform is similar to Bay Trail but it relies on a 19.2 MHz osciilator. Supported commercially-available platforms include the Up board and devices built for Windows (SOF requires a Linux installation). -Baytrail and Cherrytrail Chromebooks can support SOF but the official +Bay Trail and Cherry Trail Chromebooks can support SOF but the official images are still based on the closed-source firmware solution. diff --git a/platforms/intel-legacy/index.rst b/platforms/intel-legacy/index.rst index 0e257ef3..ccc590e8 100644 --- a/platforms/intel-legacy/index.rst +++ b/platforms/intel-legacy/index.rst @@ -8,7 +8,7 @@ Intel platforms based on the Tensilica Hifi2-EP DSP supported by the |SOF|. +------------+--------------------------------------------------+ | Atom/PCI | Merrifield (Edison) | +------------+--------------------------------------------------+ -| Atom/ACPI | Baytrail, Cherrytrail, Braswell | +| Atom/ACPI | Bay Trail, Cherry Trail, Braswell | +------------+--------------------------------------------------+ | Core/ACPI | Broadwell (Chromebook Pixel 2015, Dell XPS) | +------------+--------------------------------------------------+ diff --git a/platforms/intel-legacy/merrifield/index.rst b/platforms/intel-legacy/merrifield/index.rst index 0575d848..b6a7311d 100644 --- a/platforms/intel-legacy/merrifield/index.rst +++ b/platforms/intel-legacy/merrifield/index.rst @@ -4,8 +4,8 @@ Intel Merrifield ################ Intel Merrifield platform is based on an Atom CPU and a Tensilica HiFi2 -EP DSP. It is very similar to Baytrail but uses a PCI-based -enumeration and has a clocking structure similar to Cherrytrail. +EP DSP. It is very similar to Bay Trail but uses a PCI-based +enumeration and has a clocking structure similar to Cherry Trail. This platform is no longer commercially available, but the Edison platform is supported by the open-source community. diff --git a/release.rst b/release.rst old mode 100755 new mode 100644 index 0ff6939e..ee119d71 --- a/release.rst +++ b/release.rst @@ -26,7 +26,7 @@ kernel, and documentation. Download the source code as a zip or tar.gz file: Source and Binary Releases -------------------------- -The latest SOF release is v1.9 (October 2021). +The latest SOF release is v2.11.0 (Sept 2024). View new feature information and release downloads for the latest and previous releases on GitHub. Firmware and SDK tool source code and binary diff --git a/scripts/docker_build/Dockerfile b/scripts/docker_build/Dockerfile new file mode 100644 index 00000000..070f7209 --- /dev/null +++ b/scripts/docker_build/Dockerfile @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2023 Intel Corporation. All rights reserved. +# +# Defines a docker image that can build Sound Open Firmware documentation +# +# Usage: +# create parent directory for sof and sof-docs repository (e.g. thesofproject) +# clone sof repository to thesofproject\sof folder +# clone sof-docs repository to thesofproject\sof-docs folder +# build docker image from parent directory .\thesofproject: +# > docker build -t ubuntu-sofdocs -f ./sof-docs/scripts/docker_build/Dockerfile ./ +# run the image container: +# > docker run -d --name sofdocs_container ubuntu-sofdocs sleep infinity +# copy build output from container to host: +# > docker cp sofdocs_container:/home/thesofproject/sof/doc ./sof/ +# > docker cp sofdocs_container:/home/thesofproject/sof-docs/_build ./sof-docs/ +# stop the container: +# docker stop sofdocs_container +# +# Note: The first build can take time to setup ubuntu and install tools, +# but each next one will repeat only copy and build steps. +# + +FROM dokken/ubuntu-22.04 + +# Set image working directory +WORKDIR /home/thesofproject + +RUN apt-get update + +# Install sof-docs build tools +RUN apt-get install -y python3.6 +RUN apt-get install -y doxygen python3-pip python3-wheel make \ + default-jre graphviz cmake ninja-build + +# Copy sof-docs file with dependency tools list +COPY ./sof-docs/scripts/requirements.txt /home/thesofproject/sof-docs/scripts/requirements.txt + +# Install sof-docs requirements tools +RUN pip3 install --user -r /home/thesofproject/sof-docs/scripts/requirements.txt + +# Directly install sphinx to add 'sphinx-build' to the system +RUN apt-get install -y python3-sphinx + +# Copy sof source code from host to image +COPY ./sof/ /home/thesofproject/sof/ + +# Build API documentation from SOF source (Doxygen) +RUN cmake -S sof/doc -B sof/doc -GNinja +RUN ninja -C sof/doc -v doc + +# Copy sof-docs source code from host to image +COPY ./sof-docs/ /home/thesofproject/sof-docs/ + +# Build sof-docs, ignore eventual errors to complete image creation +RUN make -C sof-docs VERBOSE=1 html; exit 0 diff --git a/scripts/docker_build/docker-build.sh b/scripts/docker_build/docker-build.sh new file mode 100644 index 00000000..e16e7507 --- /dev/null +++ b/scripts/docker_build/docker-build.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2023 Intel Corporation. All rights reserved. + +build_docs_only="FALSE" +if [ $# -eq 1 ] && [[ $1 = "docs" ]]; then + build_docs_only="TRUE" + echo "Re-build sof-docs only." +fi + +# Build documentation using docker image +docker build -t ubuntu-sofdocs -f ./sof-docs/scripts/docker_build/Dockerfile ./ + +# Run image container to copy output. +# Add sleep infinity to keep container running. +docker run -d --rm --name sofdocs_container ubuntu-sofdocs sleep infinity + +if [ $build_docs_only = "FALSE" ]; then + echo "Copy SOF Doxygen generated documentation from container to host ./sof/doc/" + docker cp sofdocs_container:/home/thesofproject/sof/doc ./sof/ +fi + +echo "Copy SOF-DOCS generated documentation from container to host ./sof-docs/_build .." +docker cp sofdocs_container:/home/thesofproject/sof-docs/_build ./sof-docs/ + +echo "Stop the sofdocs_container" +docker stop sofdocs_container + +# It is required to prevent stacking of images for each build run +echo "Remove dangling docker images" +docker image prune --force + +echo "Press key to exit..." +read -n 1 k <&1 diff --git a/scripts/plantuml.cfg b/scripts/plantuml.cfg index ec0fc4db..2d1574e5 100644 --- a/scripts/plantuml.cfg +++ b/scripts/plantuml.cfg @@ -56,3 +56,17 @@ skinparam note { backgroundColor #f6ed80 borderColor #d6d6de } + +skinparam activity { + borderColor #33335b + backgroundColor #ffffff +} + +skinparam activityDiamond { + borderColor #33335b + backgroundColor #ffffff +} + +skinparam arrowColor #f05772 +skinparam maxMessageSize 400 +skinparam BoxPadding 4 diff --git a/scripts/requirements-lax.txt b/scripts/requirements-lax.txt index 64c9b91c..42077b41 100644 --- a/scripts/requirements-lax.txt +++ b/scripts/requirements-lax.txt @@ -9,12 +9,24 @@ # PIP_IGNORE_INSTALLED=0 pip3 install --user -r scripts/requirements-lax.txt # See https://github.com/pypa/pip/issues/4222 -breathe>=4.7.3 -sphinx>=1.6.7 -docutils>=0.14 +breathe>=4.29.2 +sphinx>=4.5.0 +docutils>=0.17.1 sphinx_rtd_theme>=0.2.4 -sphinxcontrib-plantuml - +sphinxcontrib-blockdiag>=3.0.0 +sphinxcontrib-jquery + +# - Version 0.11 is the first version that supports +# `plantuml_output_format=none` which is required for instant builds. +# https://pypi.org/project/sphinxcontrib-plantuml/0.11/ +# +# - Note 0.9 is the minimum to fix this fatal import failure: +# +# sphinx.util.compat.Directive class is now deprecated. Please +# use instead docutils.parsers.rst.Directive +# +# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=896485#12 +sphinxcontrib.plantuml>=0.11 # Differences between these "lax" version requirements and the official # ones in requirements.txt: @@ -44,3 +56,8 @@ sphinxcontrib-plantuml # - Downgrade if successfully tested. # - Test with plantum set to "none" in conf.py. We don't want small # typo fixes to depend on UML diagrams. + +# Workaround for warning "'ImageDraw' object has no attribute 'textsize'" +# with pillow 10.0.0, see +# https://github.com/thesofproject/sof-docs/issues/472 +pillow<10 diff --git a/scripts/requirements.txt b/scripts/requirements.txt index 516d4e06..17aff9e6 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -1,7 +1,15 @@ # This file hardcodes validated versions with '==', # see requirements-lax.txt for an alternative. -breathe==4.14.1 -sphinx==2.4.4 -docutils==0.16 + +sphinx>=7 +breathe +docutils sphinx_rtd_theme sphinxcontrib-plantuml +sphinxcontrib-applehelp + + +# blockdiag is orphaned and not compatible with pillow>=10, +# see https://github.com/thesofproject/sof-docs/issues/472 +sphinxcontrib-blockdiag +pillow<10 diff --git a/tsc/representatives.rst b/tsc/representatives.rst index 9b1916da..66b7ff4d 100644 --- a/tsc/representatives.rst +++ b/tsc/representatives.rst @@ -19,11 +19,11 @@ The TSC is currently made of the following contributors +---------------+----------------------+------------------+ | NXP | Daniel Baluta | @dbaluta | +---------------+----------------------+------------------+ -| Google | Curtis Malainey | @cujomalainey | +| Google | Johny Lin | @johnylin76 | +---------------+----------------------+------------------+ -| Google | Dylan Reid | @dgreid | +| Google | Unseated | | +---------------+----------------------+------------------+ -| Google | Ben Zhang | @bzhg | +| Google | Unseated | | +---------------+----------------------+------------------+ | AMD | Carl Wakeland | @cwakeland | +---------------+----------------------+------------------+