Repository navigation
docs: iio: ad9088: Document FSRC #3581
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,395 @@ | ||
| .. _ad9088 fsrc: | ||
|
|
||
| Fractional Sample Rate Converter | ||
| """""""""""""""""""""""""""""""" | ||
|
|
||
| This document describes the Fractional Sample Rate Converter (FSRC) support for | ||
| AD9084 Apollo device, including the FPGA AXI FSRC sequencer, the device tree | ||
| configuration, and the dynamic reconfiguration flows. AD9088 does not support | ||
| FSRC. | ||
|
|
||
| Overview | ||
| ======== | ||
|
|
||
| The FSRC changes the ratio between the JESD204 link sample rate and the | ||
| converter data path sample rate by a fractional factor N/M. The JESD204 link | ||
| keeps running at the profile lane rate, and the rate change is carried by | ||
| invalid samples (holes): | ||
|
|
||
| * **TX**: the FPGA inserts invalid samples in the stream it sends to Apollo, | ||
| so only M of every N link samples are valid. The Apollo JRx rate match FIFO | ||
| discards the invalid samples, and the Apollo TX FSRC interpolates the | ||
| valid samples back to the full data path rate. | ||
| * **RX**: the Apollo RX FSRC decimates the data path rate by N/M and fills | ||
| the link with invalid samples, sent as -FS. The FPGA removes them, so the | ||
| DMA only receives valid samples. | ||
|
|
||
| For a ratio N/M, a fraction (N-M)/N of the link samples are invalid. For | ||
| example, 15625/12288 gives 21.36% invalid samples. | ||
|
|
||
| The supported ratios are 1 < N/M < 2. N = M selects the FSRC 1x mode, where | ||
| the FSRC passes the samples unchanged. | ||
|
|
||
| With the Apollo FSRC active, -FS data samples are mapped to -FS+1 before the | ||
| invalid sample insertion. | ||
|
|
||
| The FSRC is reconfigured at runtime, with the JESD204 links up, either over | ||
| SPI or with a SYSREF timed trigger driven by the FPGA sequencer, see | ||
| :ref:`ad9088 fsrc reconfig`. | ||
|
|
||
| System Architecture | ||
| =================== | ||
|
|
||
| Data Paths | ||
| ---------- | ||
|
|
||
| :: | ||
|
|
||
| TX: | ||
| +-----+ +-----------+ JESD204 +-------------+ +----------+ +-----+ | ||
| | DMA |--->| FPGA TX |----------->| Apollo JRx |--->| Apollo |--->| DAC | | ||
| | | | FSRC | M valid of | rate match | | TX FSRC | | | | ||
| +-----+ | (holes) | N samples | FIFO (drops | | (interp. | +-----+ | ||
| +-----------+ | invalids) | | M -> N) | | ||
| +-------------+ +----------+ | ||
|
|
||
| RX: | ||
| +-----+ +----------+ +-----------+ JESD204 +-----------+ +-----+ | ||
| | ADC |--->| Apollo |--->| Apollo |----------->| FPGA RX |--->| DMA | | ||
| | | | RX FSRC | | JTx | -FS holes | FSRC | | | | ||
| +-----+ | (N -> M) | | | | (removes | +-----+ | ||
| +----------+ +-----------+ | -FS) | | ||
| +-----------+ | ||
|
|
||
| The Apollo JRx rate match FIFO takes each converter clock worth of samples, | ||
| NS of them, as all valid or all invalid. The FPGA therefore inserts the | ||
| invalid samples in groups of NS samples, NS being the JRx samples per | ||
| converter clock (``ns_minus1 + 1`` of the JRx link). | ||
|
|
||
| HDL | ||
| --- | ||
|
|
||
| The FPGA side is the ``axi_fsrc`` IP from the HDL ``library/axi_fsrc``: | ||
|
|
||
| * ``axi_fsrc_tx``: inserts the invalid samples in the TX stream, with a | ||
| programmable N/M accumulator. | ||
| * ``axi_fsrc_rx``: removes the -FS invalid samples from the RX stream. | ||
| * ``axi_fsrc_sequencer``: counts SYSREF periods and drives the Apollo | ||
| trigger pins and the TX data start, for SYSREF timed reconfigurations. | ||
|
|
||
| In the :git+hdl:`AD9084-EBZ <projects/ad9084_ebz>` reference design, the | ||
| FSRC is built with the ``FSRC_ENABLE=1`` project parameter. The sequencer | ||
| then drives the Apollo trigger pins (``trig_a``/``trig_b``) instead of the | ||
| AION trigger IP. | ||
|
|
||
| Linux Drivers | ||
| ------------- | ||
|
|
||
| * :git+linux:`ad9088_fsrc.c <main:drivers/iio/trx-rf/ad9088/ad9088_fsrc.c>` - | ||
| Apollo FSRC configuration and reconfiguration sequences. | ||
| * :git+linux:`axi_fsrc_sequencer.c <main:drivers/iio/jesd204/axi_fsrc_sequencer.c>` - | ||
| FPGA AXI FSRC TX, RX and sequencer driver (``CONFIG_AXI_FSRC_SEQUENCER``). | ||
|
|
||
| The ``axi_fsrc_sequencer`` driver registers an IIO device, ``axi_fsrc``, | ||
| with one channel per FSRC core. The Apollo driver consumes them as the | ||
| ``fsrc_tx`` and ``fsrc_rx`` IIO channels. | ||
|
|
||
| Device Tree | ||
| =========== | ||
|
|
||
| AXI FSRC Sequencer | ||
| ------------------ | ||
|
|
||
| The sequencer node holds the sequencer registers, and links the TX and RX | ||
| FSRC cores through ``fsrc-topology``. Each core node sets its role with one | ||
| of ``adi,fsrc_tx``, ``adi,fsrc_rx``, ``adi,fsrc_tx_a`` or ``adi,fsrc_rx_a``. | ||
|
|
||
| .. code:: dts | ||
|
|
||
| axi_fsrc_sequencer: axi-fsrc-sequencer@a4540000 { | ||
| compatible = "adi,axi-fsrc-sequencer"; | ||
| reg = <0xa4540000 0x10000>; | ||
|
|
||
| fsrc-topology = <&axi_fsrc_tx &axi_fsrc_rx>; | ||
| #io-channel-cells = <1>; | ||
| }; | ||
|
|
||
| axi_fsrc_tx: axi-fsrc-sequencer@a4510000 { | ||
| reg = <0xa4510000 0x10000>; | ||
| adi,fsrc_tx; | ||
| }; | ||
|
|
||
| axi_fsrc_rx: axi-fsrc-sequencer@a4500000 { | ||
| reg = <0xa4500000 0x10000>; | ||
| adi,fsrc_rx; | ||
| }; | ||
|
|
||
| * ``fsrc-topology``: phandles to the FSRC cores. Each role can only be | ||
| assigned once. | ||
| * ``#io-channel-cells``: 1, the channel index: ``0`` the TX core, ``1`` | ||
| the RX core. | ||
|
|
||
| Apollo | ||
| ------ | ||
|
|
||
| The ``fsrc_tx`` and ``fsrc_rx`` IIO channels enable the FSRC support in the | ||
| Apollo driver: | ||
|
|
||
| .. code:: dts | ||
|
|
||
| trx0_ad9084: ad9084@0 { | ||
| compatible = "adi,ad9084"; | ||
| /* ... other properties ... */ | ||
|
|
||
| /* SYSREF timed reconfiguration, see below */ | ||
| adi,fsrc-gpio-trig; | ||
|
|
||
| io-channels = <&adf4030 5>, <&adf4382 0>, | ||
| <&axi_fsrc_sequencer 0>, <&axi_fsrc_sequencer 1>; | ||
| io-channel-names = "bsync", "clk", "fsrc_tx", "fsrc_rx"; | ||
| }; | ||
|
|
||
| * ``io-channels``/``io-channel-names``: with an ``fsrc_tx`` or ``fsrc_rx`` | ||
| channel, the driver keeps the Apollo FSRC in the data path. Without | ||
| either, the profile is used as is. The TX configure and reconfig debugfs | ||
| attributes require ``fsrc_tx``, the RX ones ``fsrc_rx``, else -ENODEV. | ||
| * ``adi,fsrc-gpio-trig``: optional, asserts that the FPGA sequencer trigger | ||
| output is routed to the Apollo trigger pin A0, and selects the SYSREF timed | ||
| TX reconfiguration. Without it, the reconfigurations are done over SPI. | ||
|
|
||
| With an FSRC channel present, the driver modifies the device profile | ||
| before loading it: | ||
|
|
||
| * RX and TX FSRC not bypassed, ``enable0`` and ``enable1`` set, in 1x mode. | ||
| * ``split_4t4r`` set on 4T4R profiles, so the second stream of each side | ||
| (FSRC0_1) is enabled. | ||
| * FSRC gain reduction at ``0xFFF``, profiles without FSRC may set it at 0. | ||
| * RX rate match FIFO invalid samples enabled, sample repeat and DDC dither | ||
| disabled. | ||
|
|
||
| So the device boots at 1:1 with the FSRC in the path, ready for a runtime | ||
| reconfiguration. | ||
|
|
||
| AXI FSRC IIO Device | ||
| =================== | ||
|
|
||
| The ``axi_fsrc`` device exposes one channel per FSRC core, the output | ||
| channel 0 for the TX core and the input channel 1 for the RX core, plus the | ||
| sequencer control shared by both: | ||
|
|
||
| .. shell:: | ||
|
|
||
| /sys/bus/iio/devices/iio:device4 | ||
| $ cat name | ||
| axi_fsrc | ||
| $ ls | ||
| in_altvoltage1_enable out_altvoltage0_ratio_set | ||
| name out_altvoltage0_transmit | ||
| of_node seq_start | ||
| out_altvoltage0_enable ... | ||
|
|
||
| Both channels are always present, so the ``io-channels`` indexes are fixed. | ||
| The attributes of a core that is not in the topology return -ENODEV. | ||
|
|
||
| - ``in_altvoltage1_enable``: Enable the FPGA RX FSRC, which removes the | ||
| -FS invalid samples. | ||
|
|
||
| | ``0``: Disable. | ||
| | ``1``: Enable. | ||
|
|
||
| - ``out_altvoltage0_enable``: Enable the FPGA TX FSRC. Disabling it also | ||
| clears ``out_altvoltage0_transmit``. | ||
|
|
||
| | ``0``: Disable. | ||
| | ``1``: Enable. | ||
|
|
||
| - ``out_altvoltage0_transmit``: Start or stop the TX data. When stopped, the | ||
| FPGA sends only invalid samples. Requires ``out_altvoltage0_enable``, else | ||
| -EINVAL. | ||
|
|
||
| | ``0``: Stop, send only invalid samples. | ||
| | ``1``: Start sending valid samples at the configured ratio. | ||
|
|
||
| - ``out_altvoltage0_ratio_set``: Program the TX hole pattern as | ||
| ``<N> <M> [NS]``, with NS the invalid sample group size (default 1). Reads | ||
| back the last values. | ||
|
|
||
| | Range: ``M <= N < 2M`` | ||
| | NS: a divisor of the core samples per beat, or a multiple of it spanning | ||
| at most 256 beats. | ||
|
|
||
| The new hole pattern takes effect at once, while the FPGA TX is active. | ||
|
|
||
| .. shell:: | ||
| :no-path: | ||
|
|
||
| $ cat out_altvoltage0_ratio_set | ||
| 1 1 4 | ||
|
|
||
| - ``seq_start``: Write ``1`` to arm the TX FSRC on the sequencer data start, | ||
| reseed the hole pattern, and start the sequencer. | ||
|
|
||
| The Apollo driver drives these attributes during the reconfiguration | ||
| sequences; they are only needed directly to test the FPGA side. | ||
|
|
||
| Sequencer Timing | ||
| ---------------- | ||
|
|
||
| All sequencer counts are in SYSREF periods from the sequencer start, 4 bits | ||
| each: | ||
|
|
||
| * Apollo trigger: at count 2. | ||
| * TX data start: at count 4, the FPGA TX FSRC starts sending valid samples. | ||
|
|
||
| Register Access | ||
| --------------- | ||
|
|
||
| The ``direct_reg_access`` debugfs attribute reads and writes the core | ||
| registers, with the core selected by bits [23:16] of the address: ``0`` | ||
| sequencer, ``1`` RX, ``2`` TX, ``3`` RX A, ``4`` TX A. A core that is not in | ||
| the topology returns -ENODEV, an index past the last core -EINVAL. | ||
|
|
||
| .. shell:: | ||
|
|
||
| /sys/kernel/debug/iio/iio:device4 | ||
| # Read the TX FSRC enable register | ||
| $ echo 0x20010 > direct_reg_access | ||
| $ cat direct_reg_access | ||
| 0x1 | ||
|
|
||
| Apollo Debugfs Attributes | ||
| ========================= | ||
|
|
||
| The FSRC is configured through the Apollo device debugfs: | ||
|
|
||
| .. shell:: | ||
|
|
||
| /sys/kernel/debug/iio/iio:device8 | ||
| $ ls | grep fsrc | ||
| fsrc_inspect | ||
| fsrc_rx_configure | ||
| fsrc_rx_reconfig | ||
| fsrc_tx_configure | ||
| fsrc_tx_reconfig | ||
|
|
||
| - ``fsrc_tx_configure``: Set the TX ratio as ``<N> <M>``. Programs the FPGA | ||
| TX hole pattern, with NS from the JRx link, which takes effect at once, the | ||
| JRx invalid sample handling, and the Apollo TX FSRC rate, or the 1x mode | ||
| for N = M, which takes effect at the next ``fsrc_tx_reconfig``. | ||
| - ``fsrc_rx_configure``: Set the RX ratio as ``<N> <M>``. Programs the | ||
| Apollo RX FSRC rate, or the 1x mode for N = M, which takes effect at the | ||
| next ``fsrc_rx_reconfig``. | ||
| - ``fsrc_tx_reconfig``: Write ``1`` to apply the TX configuration, see | ||
| :ref:`ad9088 fsrc reconfig`. | ||
| - ``fsrc_rx_reconfig``: Write ``1`` to apply the RX configuration. | ||
| - ``fsrc_inspect``: Read-only, reads the configuration of all RX and TX FSRC | ||
| blocks. | ||
|
|
||
| The configure attributes require two arguments. The TX configure and reconfig | ||
| attributes require the ``fsrc_tx`` IIO channel, the RX ones the ``fsrc_rx`` IIO | ||
| channel. Supported ratios are 1 < N/M < 2. | ||
|
|
||
| The FSRC rate is ``fsrc_rate_int + fsrc_rate_frac_a / fsrc_rate_frac_b`` | ||
| = 2^48 M/N, and the gain reduction is floor(4096 M/N): | ||
|
|
||
| .. shell:: | ||
| :no-path: | ||
|
|
||
| $ echo "15625 12288" > fsrc_tx_configure | ||
| $ echo 1 > fsrc_tx_reconfig | ||
| $ cat fsrc_inspect | ||
| Rx FSRC: | ||
| A0: | ||
| enable0: 1 | ||
| ... | ||
| Tx FSRC: | ||
| A0: | ||
| enable0: 1 | ||
| enable1: 0 | ||
| mode_1x: 0 | ||
| split_4t4r: 1 | ||
| fsrc_bypass: 0 | ||
| fsrc_rate_int: 0xc9539b888722 | ||
| fsrc_rate_frac_a: 0x25ce | ||
| fsrc_rate_frac_b: 0x3d09 | ||
| gain_reduction: 0xc95 | ||
| fsrc_delay: 0x0 | ||
| ... | ||
| FSRC ratio (N/M) = 2^48 / (fsrc_rate_int + fsrc_rate_frac_a/fsrc_rate_frac_b) | ||
|
|
||
| At 1:1, the blocks yields ``mode_1x: 1`` and ``gain_reduction: 0xfff``. | ||
|
|
||
| .. _ad9088 fsrc reconfig: | ||
|
|
||
| Dynamic Reconfiguration | ||
| ======================= | ||
|
|
||
| A reconfiguration is set with the configure attributes, then applied with | ||
| the reconfig attributes, TX and RX independently. Write the reconfig right | ||
| after the configure: the FPGA TX hole pattern changes at the configure, the | ||
| Apollo TX FSRC only at the reconfig, and the TX data is not valid in | ||
| between. | ||
|
|
||
| .. shell:: | ||
| :no-path: | ||
|
|
||
| # TX and RX at 15625/12288 | ||
| $ echo "15625 12288" > fsrc_tx_configure | ||
| $ echo "15625 12288" > fsrc_rx_configure | ||
| $ echo 1 > fsrc_tx_reconfig | ||
| $ echo 1 > fsrc_rx_reconfig | ||
|
|
||
| # Back to 1:1 | ||
| $ echo "1 1" > fsrc_tx_configure | ||
| $ echo "1 1" > fsrc_rx_configure | ||
| $ echo 1 > fsrc_tx_reconfig | ||
| $ echo 1 > fsrc_rx_reconfig | ||
|
|
||
| TX over SPI | ||
| ----------- | ||
|
|
||
| Without ``adi,fsrc-gpio-trig``, ``fsrc_tx_reconfig``: | ||
|
|
||
| #. Enables the FPGA TX FSRC. | ||
| #. Enables the Apollo DSP reset on trigger, and runs the manual dynamic | ||
| reconfiguration sync, applying the new configuration. | ||
| #. Disarms the trigger resets. | ||
| #. Starts the FPGA TX data at the new ratio. | ||
| #. Resets the JRx rate match FIFOs of links A0 and B0. | ||
|
|
||
| The new rate is applied at an SPI write, so the FPGA hole pattern and the | ||
| Apollo FSRC start at an arbitrary time relative to each other and to SYSREF. | ||
|
|
||
| TX with the SYSREF Timed Trigger | ||
| -------------------------------- | ||
|
|
||
| With ``adi,fsrc-gpio-trig``, ``fsrc_tx_reconfig``: | ||
|
|
||
| #. Enables the FPGA TX FSRC and stops the TX data, the FPGA sends only | ||
| invalid samples. | ||
| #. Forces invalid samples on the Apollo JTx links, and waits for the invalid | ||
| samples to flow through. | ||
| #. Resets the JRx rate match FIFOs of links A0 and B0. | ||
| #. Maps the trigger pin A0 to all RX and TX blocks, enables the DSP reset on | ||
| trigger, and arms the trigger sync. | ||
| #. Starts the FPGA sequencer, at the trigger count it triggers the Apollo | ||
| reconfiguration, and at the data start count the FPGA FSRC TX starts sending | ||
| distributed valid and invalid samples. | ||
| #. Clears the trigger sync and disarms the trigger resets. | ||
|
|
||
| The JRx rate match FIFOs start empty, and the Apollo reconfiguration and the | ||
| FPGA data start happen at fixed SYSREF counts from the sequencer start. There | ||
| is no rate match FIFO reset after the trigger. The JTx forced invalid samples | ||
| clear when the reconfiguration completes. | ||
|
|
||
| RX | ||
| -- | ||
|
|
||
| ``fsrc_rx_reconfig`` reconfigures over SPI: | ||
|
|
||
| #. Enables the FPGA RX FSRC, removing -FS invalid samples. | ||
| #. Enables the Apollo DSP reset on trigger, and runs the dynamic | ||
| reconfiguration sync. | ||
| #. Disarms the trigger resets. | ||
|
|
||
| The RX needs no alignment with the FPGA. | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In theory it looks like this FSRC stuff could be a IIO backend cascaded with the axi_adc and axi_dac. But well, apollo is not using it anyways
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would work, requires extending drivers/iio/industrialio-backend.c with at least
but migrating apollo to use the backend first you be better, no?
also the sequencer is bizarre; if we had more time the fsrc sequencer core should be replaced with a generic sequencer, it does not do anything but counting til X after Y.