* [PATCH v3 0/4] media: synopsys: hdmirx: add HDMI audio capture support
@ 2026-07-18 8:57 Igor Paunovic
2026-07-18 8:57 ` [PATCH v3 1/4] dt-bindings: media: snps,dw-hdmi-rx: add #sound-dai-cells Igor Paunovic
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: Igor Paunovic @ 2026-07-18 8:57 UTC (permalink / raw)
To: Dmitry Osipenko, Mauro Carvalho Chehab
Cc: Sebastian Reichel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Heiko Stuebner, linux-media, linux-rockchip, linux-arm-kernel,
kernel, devicetree, linux-kernel, Igor Paunovic
This series adds audio capture support to the Synopsys DesignWare HDMI
RX controller used on the Rockchip RK3588: the controller's audio FIFO
is exposed through an ASoC hdmi-codec device, with a periodic worker
that keeps the local audio clock locked to the incoming stream by
tracking the FIFO fill level. Together with the two new dts patches
this yields a capture-only ALSA card fed by the HDMI input.
Validated on the Orange Pi 5 Plus against multiple HDMI sources:
capture follows the source sample rate (44.1/48 kHz switches
included), survives repeated stream start/stop cycles and SIGKILL of
the capturing process, and stays free of FIFO under/overruns via the
clock tracking.
Changes in v3:
- Restored the v1 audio teardown in remove(): the worker is only
armed while a capture stream is active and audio_shutdown() already
stops it, so the extra flag clear and trailing cancel added in v2
were redundant (Dmitry Osipenko's review; the v2 change came from
an incorrect automated-review finding)
- Renamed the ACR read locals and added a comment documenting the
register byte packing that makes the swap correct
- Dropped the get_dai_id stub so OF-graph cards resolve the DAI index
from the reg property naturally
- New patches 3 and 4: dts enablement, so the series is testable end
to end (requested by Dmitry). Patch 3 adds #sound-dai-cells to the
RK3588 hdmi_receiver node, patch 4 wires up the Orange Pi 5 Plus
hdmiin sound card. Both can go through the rockchip tree instead if
preferred.
Link to v2: https://lore.kernel.org/linux-media/20260715200834.8486-1-royalnet026@gmail.com/
Link to v1 (RFC): https://lore.kernel.org/linux-media/20260715051939.64652-1-royalnet026@gmail.com/
Igor Paunovic (4):
dt-bindings: media: snps,dw-hdmi-rx: add #sound-dai-cells
media: synopsys: hdmirx: add HDMI audio capture support
arm64: dts: rockchip: add #sound-dai-cells to the RK3588 HDMI receiver
arm64: dts: rockchip: enable HDMI RX audio capture on Orange Pi 5 Plus
.../bindings/media/snps,dw-hdmi-rx.yaml | 9 +
.../arm64/boot/dts/rockchip/rk3588-extra.dtsi | 1 +
.../dts/rockchip/rk3588-orangepi-5-plus.dts | 20 ++
.../platform/synopsys/hdmirx/snps_hdmirx.c | 271 ++++++++++++++++++
.../platform/synopsys/hdmirx/snps_hdmirx.h | 8 +
5 files changed, 309 insertions(+)
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3 1/4] dt-bindings: media: snps,dw-hdmi-rx: add #sound-dai-cells
2026-07-18 8:57 [PATCH v3 0/4] media: synopsys: hdmirx: add HDMI audio capture support Igor Paunovic
@ 2026-07-18 8:57 ` Igor Paunovic
2026-07-18 8:57 ` [PATCH v3 2/4] media: synopsys: hdmirx: add HDMI audio capture support Igor Paunovic
` (2 subsequent siblings)
3 siblings, 0 replies; 10+ messages in thread
From: Igor Paunovic @ 2026-07-18 8:57 UTC (permalink / raw)
To: Dmitry Osipenko, Mauro Carvalho Chehab
Cc: Sebastian Reichel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Heiko Stuebner, linux-media, linux-rockchip, linux-arm-kernel,
kernel, devicetree, linux-kernel, Igor Paunovic
The HDMI RX controller can expose the audio embedded in the incoming
HDMI stream as an ALSA capture device. Document the #sound-dai-cells
property so that a sound card can reference the HDMI RX audio DAI.
Signed-off-by: Igor Paunovic <royalnet026@gmail.com>
---
Changes in v3:
- no changes
Changes in v2 (all suggested by Sebastian Reichel):
- reworded the commit message to describe the hardware
- property description now documents the DAI indexes (0 = I2S,
1 = S/PDIF)
- moved the consumer reference into the binding example
.../devicetree/bindings/media/snps,dw-hdmi-rx.yaml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.yaml b/Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.yaml
index b7f6c87..fa6cd0d 100644
--- a/Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.yaml
+++ b/Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.yaml
@@ -78,6 +78,13 @@ properties:
The phandle of the syscon node for the Video Output GRF register
to enable EDID transfer through SDAIN and SCLIN.
+ "#sound-dai-cells":
+ const: 1
+ description:
+ The HDMI RX controller has two digital audio interfaces, one for
+ I2S and one for S/PDIF. The DAI cell selects the interface, 0 for
+ I2S and 1 for S/PDIF.
+
required:
- compatible
- reg
@@ -129,4 +136,6 @@ examples:
pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_5v_detection>;
pinctrl-names = "default";
hpd-gpios = <&gpio1 22 GPIO_ACTIVE_LOW>;
+ /* referenced by a sound card as <&hdmi_receiver 0> (0: I2S, 1: S/PDIF) */
+ #sound-dai-cells = <1>;
};
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 2/4] media: synopsys: hdmirx: add HDMI audio capture support
2026-07-18 8:57 [PATCH v3 0/4] media: synopsys: hdmirx: add HDMI audio capture support Igor Paunovic
2026-07-18 8:57 ` [PATCH v3 1/4] dt-bindings: media: snps,dw-hdmi-rx: add #sound-dai-cells Igor Paunovic
@ 2026-07-18 8:57 ` Igor Paunovic
2026-07-18 9:09 ` sashiko-bot
2026-07-18 8:57 ` [PATCH v3 3/4] arm64: dts: rockchip: add #sound-dai-cells to the RK3588 HDMI receiver Igor Paunovic
2026-07-18 8:57 ` [PATCH v3 4/4] arm64: dts: rockchip: enable HDMI RX audio capture on Orange Pi 5 Plus Igor Paunovic
3 siblings, 1 reply; 10+ messages in thread
From: Igor Paunovic @ 2026-07-18 8:57 UTC (permalink / raw)
To: Dmitry Osipenko, Mauro Carvalho Chehab
Cc: Sebastian Reichel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Heiko Stuebner, linux-media, linux-rockchip, linux-arm-kernel,
kernel, devicetree, linux-kernel, Igor Paunovic
The Synopsys DesignWare HDMI RX controller extracts the audio stream
embedded in the incoming HDMI signal and feeds it to an on-SoC I2S
controller. Expose it as an ALSA capture device by registering the
generic hdmi-codec as a child of the controller, so that a
simple-audio-card in the device tree can bind the HDMI RX audio DAI.
The sample rate is recovered from the ACR N/CTS values together with the
measured TMDS character rate. A periodic worker keeps the local audio
reference clock locked to the source by nudging it in small ppm steps to
hold the audio FIFO fill level near its target, which avoids FIFO
under/overflow and the resulting dropped samples.
Signed-off-by: Igor Paunovic <royalnet026@gmail.com>
---
Changes in v3:
- restore the v1 audio teardown in remove(): audio_shutdown() already
stops the worker when the stream closes, so the extra flag clear
and trailing cancel added in v2 were redundant (Dmitry Osipenko)
- rename the ACR read locals and add a comment documenting the
register byte packing
- drop the get_dai_id stub so OF-graph cards resolve the DAI index
from the reg property
Changes in v2:
- register the S/PDIF DAI so the indexes match the binding and reject
it with -EOPNOTSUPP until wired up (Sebastian Reichel)
- use platform_device_register_data() and drop the fixed 32-bit DMA
mask (Dmitry Osipenko)
- don't leave an ERR_PTR in audio_pdev on registration failure
- fix teardown ordering in remove()
- stop the worker before reprogramming shared state in hw_params()
- look up the "audio" clock by name instead of indexing clks[1]
- keep the worker on system_unbound_wq when re-arming
.../platform/synopsys/hdmirx/snps_hdmirx.c | 271 ++++++++++++++++++
.../platform/synopsys/hdmirx/snps_hdmirx.h | 8 +
2 files changed, 279 insertions(+)
diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c
index 9cceffa..8636944 100644
--- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c
+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c
@@ -41,6 +41,8 @@
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-v4l2.h>
+#include <sound/hdmi-codec.h>
+
#include "snps_hdmirx.h"
#include "snps_hdmirx_cec.h"
@@ -132,6 +134,13 @@ struct snps_hdmirx_dev {
struct delayed_work delayed_work_hotplug;
struct delayed_work delayed_work_res_change;
struct hdmirx_cec *cec;
+ struct platform_device *audio_pdev;
+ struct clk *audio_clk;
+ struct delayed_work audio_work;
+ u32 audio_clkrate;
+ u32 audio_fs;
+ int audio_pre_state;
+ bool audio_streaming;
struct mutex phy_rw_lock; /* to protect phy r/w configuration */
struct mutex stream_lock; /* to lock video stream capture */
struct mutex work_lock; /* to lock the critical section of hotplug event */
@@ -2283,6 +2292,13 @@ static int hdmirx_parse_dt(struct snps_hdmirx_dev *hdmirx_dev)
if (hdmirx_dev->num_clks < 1)
return -ENODEV;
+ for (int i = 0; i < hdmirx_dev->num_clks; i++) {
+ if (!strcmp(hdmirx_dev->clks[i].id, "audio")) {
+ hdmirx_dev->audio_clk = hdmirx_dev->clks[i].clk;
+ break;
+ }
+ }
+
hdmirx_dev->resets[HDMIRX_RST_A].id = "axi";
hdmirx_dev->resets[HDMIRX_RST_P].id = "apb";
hdmirx_dev->resets[HDMIRX_RST_REF].id = "ref";
@@ -2650,6 +2666,253 @@ static int hdmirx_register_cec(struct snps_hdmirx_dev *hdmirx_dev,
return 0;
}
+#define HDMIRX_AUDIO_INIT_FIFO_STATE 128
+#define HDMIRX_AUDIO_INIT_STATE (HDMIRX_AUDIO_INIT_FIFO_STATE * 4)
+
+static const int hdmirx_supported_fs[] = {
+ 32000, 44100, 48000, 88200, 96000, 176400, 192000, 768000, -1
+};
+
+static int hdmirx_audio_closest_fs(int fs)
+{
+ int i = 0, fs_t = hdmirx_supported_fs[0];
+
+ while (fs_t > 0) {
+ if (abs(fs - fs_t) <= 2000)
+ return fs_t;
+ fs_t = hdmirx_supported_fs[++i];
+ }
+ return 0;
+}
+
+/* Recover the incoming audio sample rate from the ACR N/CTS + TMDS clock. */
+static u32 hdmirx_audio_fs(struct snps_hdmirx_dev *hdmirx_dev)
+{
+ u64 tmds_clk, fs_audio = 0;
+ u32 acr_cts, acr_n, tmdsqpclk_freq;
+ u32 acr_pb3_0, acr_pb7_4;
+
+ tmdsqpclk_freq = hdmirx_readl(hdmirx_dev, CMU_TMDSQPCLK_FREQ);
+ hdmirx_readl(hdmirx_dev, PKTDEC_ACR_PH2_1);
+ acr_pb3_0 = hdmirx_readl(hdmirx_dev, PKTDEC_ACR_PB3_0);
+ acr_pb7_4 = hdmirx_readl(hdmirx_dev, PKTDEC_ACR_PB7_4);
+ /*
+ * The packet decoder stores the ACR subpacket bytes with packet byte
+ * 0 in register bits [7:0], so byte-swap each word to line the bytes
+ * up: CTS is packet bytes 1-3 (PKTDEC_ACR_PB3_0) and N is packet
+ * bytes 4-6 (PKTDEC_ACR_PB7_4), 20 bits each.
+ */
+ acr_cts = be32_to_cpu((__force __be32)acr_pb3_0) & 0xfffff;
+ acr_n = (be32_to_cpu((__force __be32)acr_pb7_4) & 0x0fffff00) >> 8;
+ tmds_clk = tmdsqpclk_freq * 4 * 1000U;
+ if (acr_cts != 0) {
+ fs_audio = div_u64((tmds_clk * acr_n), acr_cts);
+ fs_audio /= 128;
+ fs_audio = hdmirx_audio_closest_fs(fs_audio);
+ }
+ return (u32)fs_audio;
+}
+
+/* Nudge the audio reference clock by +/- ppm to keep the FIFO balanced. */
+static void hdmirx_audio_clk_ppm_inc(struct snps_hdmirx_dev *hdmirx_dev, int ppm)
+{
+ int delta, inc;
+ long rate = hdmirx_dev->audio_clkrate;
+
+ if (ppm < 0) {
+ ppm = -ppm;
+ inc = -1;
+ } else {
+ inc = 1;
+ }
+ delta = (int)div64_u64((u64)rate * ppm + 500000, 1000000);
+ delta *= inc;
+ rate = hdmirx_dev->audio_clkrate + delta;
+ clk_set_rate(hdmirx_dev->audio_clk, rate);
+ hdmirx_dev->audio_clkrate = rate;
+}
+
+static int hdmirx_audio_clk_adjust(struct snps_hdmirx_dev *hdmirx_dev,
+ int total_offset, int single_offset)
+{
+ int schedule_time = 500;
+ int ppm = 10;
+ u32 offset_abs = abs(total_offset);
+
+ if (offset_abs > 200) {
+ ppm += 200;
+ schedule_time -= 100;
+ }
+ if (offset_abs > 100) {
+ ppm += 200;
+ schedule_time -= 100;
+ }
+ if (offset_abs > 32) {
+ ppm += 20;
+ schedule_time -= 100;
+ }
+ if (offset_abs > 16)
+ ppm += 20;
+ if (total_offset > 16 && single_offset > 0)
+ hdmirx_audio_clk_ppm_inc(hdmirx_dev, ppm);
+ else if (total_offset < -16 && single_offset < 0)
+ hdmirx_audio_clk_ppm_inc(hdmirx_dev, -ppm);
+ return schedule_time;
+}
+
+static void hdmirx_audio_fifo_reinit(struct snps_hdmirx_dev *hdmirx_dev)
+{
+ hdmirx_writel(hdmirx_dev, AUDIO_FIFO_CONTROL, 1);
+ usleep_range(200, 210);
+ hdmirx_writel(hdmirx_dev, AUDIO_FIFO_CONTROL, 0);
+}
+
+/*
+ * Periodic worker that locks the local audio clock to the source by keeping
+ * the audio FIFO fill level close to its target, avoiding under/overflow.
+ */
+static void hdmirx_audio_work(struct work_struct *work)
+{
+ struct snps_hdmirx_dev *hdmirx_dev =
+ container_of(to_delayed_work(work), struct snps_hdmirx_dev, audio_work);
+ unsigned long delay = 200;
+ int cur, total, single;
+ u32 fifo, fs;
+
+ fs = hdmirx_audio_fs(hdmirx_dev);
+ fifo = hdmirx_readl(hdmirx_dev, AUDIO_FIFO_STATUS2);
+
+ if (fifo & (AFIFO_UNDERFLOW_ST | AFIFO_OVERFLOW_ST)) {
+ if (fs) {
+ clk_set_rate(hdmirx_dev->audio_clk, fs * 128);
+ hdmirx_dev->audio_clkrate = fs * 128;
+ hdmirx_dev->audio_fs = fs;
+ }
+ hdmirx_audio_fifo_reinit(hdmirx_dev);
+ hdmirx_dev->audio_pre_state = 0;
+ goto out;
+ }
+
+ cur = fifo & 0xffff;
+ total = cur - HDMIRX_AUDIO_INIT_STATE;
+ single = cur - hdmirx_dev->audio_pre_state;
+
+ if (fs && abs((int)fs - (int)hdmirx_dev->audio_fs) > 1000) {
+ clk_set_rate(hdmirx_dev->audio_clk, fs * 128);
+ hdmirx_dev->audio_clkrate = fs * 128;
+ hdmirx_dev->audio_fs = fs;
+ hdmirx_audio_fifo_reinit(hdmirx_dev);
+ hdmirx_dev->audio_pre_state = 0;
+ goto out;
+ }
+
+ if (cur != 0)
+ delay = hdmirx_audio_clk_adjust(hdmirx_dev, total, single);
+ hdmirx_dev->audio_pre_state = cur;
+out:
+ /* Only re-arm while streaming; avoids a self-reschedule race with
+ * the cancel_delayed_work_sync() callers (hw_params and
+ * audio_shutdown).
+ */
+ if (READ_ONCE(hdmirx_dev->audio_streaming))
+ queue_delayed_work(system_unbound_wq, &hdmirx_dev->audio_work,
+ msecs_to_jiffies(delay));
+}
+
+static int hdmirx_audio_hw_params(struct device *dev, void *data,
+ struct hdmi_codec_daifmt *fmt,
+ struct hdmi_codec_params *hparms)
+{
+ struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev);
+ u32 fs;
+
+ /* Only the I2S interface (DAI 0) is wired up so far. */
+ if (fmt->fmt == HDMI_SPDIF)
+ return -EOPNOTSUPP;
+
+ /*
+ * Stop the worker before touching the shared audio state; it is
+ * re-armed below once the new parameters are in place.
+ */
+ WRITE_ONCE(hdmirx_dev->audio_streaming, false);
+ cancel_delayed_work_sync(&hdmirx_dev->audio_work);
+
+ fs = hdmirx_audio_fs(hdmirx_dev);
+ if (!fs)
+ fs = hparms ? hparms->sample_rate : 48000;
+ if (!fs)
+ fs = 48000;
+
+ hdmirx_dev->audio_fs = fs;
+ hdmirx_dev->audio_clkrate = fs * 128;
+ clk_set_rate(hdmirx_dev->audio_clk, fs * 128);
+
+ hdmirx_audio_fifo_reinit(hdmirx_dev);
+ hdmirx_writel(hdmirx_dev, AUDIO_FIFO_THR_PASS, HDMIRX_AUDIO_INIT_FIFO_STATE);
+ hdmirx_writel(hdmirx_dev, AUDIO_FIFO_THR,
+ AFIFO_THR_LOW_QST(0x20) | AFIFO_THR_HIGH_QST(0x160));
+ hdmirx_writel(hdmirx_dev, AUDIO_FIFO_MUTE_THR,
+ AFIFO_THR_MUTE_LOW_QST(0x8) | AFIFO_THR_MUTE_HIGH_QST(0x178));
+
+ hdmirx_update_bits(hdmirx_dev, AUDIO_PROC_CONFIG0, I2S_EN, I2S_EN);
+ hdmirx_update_bits(hdmirx_dev, GLOBAL_SWENABLE, AUDIO_ENABLE, AUDIO_ENABLE);
+
+ hdmirx_dev->audio_pre_state = 0;
+ WRITE_ONCE(hdmirx_dev->audio_streaming, true);
+ mod_delayed_work(system_unbound_wq, &hdmirx_dev->audio_work,
+ msecs_to_jiffies(200));
+
+ dev_dbg(dev, "audio hw_params: fs=%u\n", fs);
+ return 0;
+}
+
+static void hdmirx_audio_shutdown(struct device *dev, void *data)
+{
+ struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev);
+
+ WRITE_ONCE(hdmirx_dev->audio_streaming, false);
+ cancel_delayed_work_sync(&hdmirx_dev->audio_work);
+ hdmirx_update_bits(hdmirx_dev, GLOBAL_SWENABLE, AUDIO_ENABLE, 0);
+}
+
+static const struct hdmi_codec_ops hdmirx_audio_codec_ops = {
+ .hw_params = hdmirx_audio_hw_params,
+ .audio_shutdown = hdmirx_audio_shutdown,
+};
+
+static int hdmirx_register_audio_device(struct snps_hdmirx_dev *hdmirx_dev)
+{
+ struct hdmi_codec_pdata codec_data = {
+ .ops = &hdmirx_audio_codec_ops,
+ .i2s = 1,
+ .no_i2s_playback = 1,
+ .max_i2s_channels = 8,
+ /*
+ * The controller also has an S/PDIF audio interface (DAI 1 in
+ * the binding). Register it so DAI indexes match the binding,
+ * but reject its use in hw_params() until it is wired up.
+ */
+ .spdif = 1,
+ .no_spdif_playback = 1,
+ .data = hdmirx_dev,
+ };
+ struct platform_device *audio_pdev;
+
+ if (!hdmirx_dev->audio_clk)
+ return -ENODEV;
+
+ audio_pdev = platform_device_register_data(hdmirx_dev->dev,
+ HDMI_CODEC_DRV_NAME,
+ PLATFORM_DEVID_AUTO,
+ &codec_data, sizeof(codec_data));
+ if (IS_ERR(audio_pdev))
+ return PTR_ERR(audio_pdev);
+
+ hdmirx_dev->audio_pdev = audio_pdev;
+
+ return 0;
+}
+
static int hdmirx_probe(struct platform_device *pdev)
{
struct snps_hdmirx_dev *hdmirx_dev;
@@ -2701,6 +2964,7 @@ static int hdmirx_probe(struct platform_device *pdev)
hdmirx_delayed_work_hotplug);
INIT_DELAYED_WORK(&hdmirx_dev->delayed_work_res_change,
hdmirx_delayed_work_res_change);
+ INIT_DELAYED_WORK(&hdmirx_dev->audio_work, hdmirx_audio_work);
hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_BGR24;
hdmirx_dev->timings = cea640x480;
@@ -2769,6 +3033,10 @@ static int hdmirx_probe(struct platform_device *pdev)
V4L2_DEBUGFS_IF_AVI, hdmirx_dev,
hdmirx_debugfs_if_read);
+ ret = hdmirx_register_audio_device(hdmirx_dev);
+ if (ret)
+ dev_warn(dev, "failed to register HDMI audio codec: %d\n", ret);
+
return 0;
err_unreg_video_dev:
@@ -2788,6 +3056,9 @@ static void hdmirx_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev);
+ if (hdmirx_dev->audio_pdev)
+ platform_device_unregister(hdmirx_dev->audio_pdev);
+
v4l2_debugfs_if_free(hdmirx_dev->infoframes);
debugfs_remove_recursive(hdmirx_dev->debugfs_dir);
diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h
index 31b887e..a99f54f 100644
--- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h
+++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h
@@ -81,6 +81,7 @@
#define DATAPATH_ENABLE BIT(12)
#define PKTFIFO_ENABLE BIT(11)
#define AVPUNIT_ENABLE BIT(8)
+#define AUDIO_ENABLE BIT(9)
#define MAIN_ENABLE BIT(0)
#define GLOBAL_TIMER_REF_BASE 0x0028
#define CORE_CONFIG 0x0050
@@ -177,20 +178,27 @@
#define VPROC_FMT_OVR_VALUE(x) UPDATE(x, 6, 4)
#define VPROC_FMT_OVR_EN BIT(0)
+#define AUDIO_FIFO_CONFIG 0x0460
#define AFIFO_FILL_RESTART BIT(0)
+#define AUDIO_FIFO_CONTROL 0x0464
#define AFIFO_INIT_P BIT(0)
+#define AUDIO_FIFO_THR_PASS 0x0468
+#define AUDIO_FIFO_THR 0x046c
#define AFIFO_THR_LOW_QST_MASK GENMASK(25, 16)
#define AFIFO_THR_LOW_QST(x) UPDATE(x, 25, 16)
#define AFIFO_THR_HIGH_QST_MASK GENMASK(9, 0)
#define AFIFO_THR_HIGH_QST(x) UPDATE(x, 9, 0)
+#define AUDIO_FIFO_MUTE_THR 0x0470
#define AFIFO_THR_MUTE_LOW_QST_MASK GENMASK(25, 16)
#define AFIFO_THR_MUTE_LOW_QST(x) UPDATE(x, 25, 16)
#define AFIFO_THR_MUTE_HIGH_QST_MASK GENMASK(9, 0)
#define AFIFO_THR_MUTE_HIGH_QST(x) UPDATE(x, 9, 0)
+#define AUDIO_FIFO_STATUS2 0x0478
#define AFIFO_UNDERFLOW_ST BIT(25)
#define AFIFO_OVERFLOW_ST BIT(24)
+#define AUDIO_PROC_CONFIG0 0x0480
#define SPEAKER_ALLOC_OVR_EN BIT(16)
#define I2S_BPCUV_EN BIT(4)
#define SPDIF_EN BIT(2)
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 3/4] arm64: dts: rockchip: add #sound-dai-cells to the RK3588 HDMI receiver
2026-07-18 8:57 [PATCH v3 0/4] media: synopsys: hdmirx: add HDMI audio capture support Igor Paunovic
2026-07-18 8:57 ` [PATCH v3 1/4] dt-bindings: media: snps,dw-hdmi-rx: add #sound-dai-cells Igor Paunovic
2026-07-18 8:57 ` [PATCH v3 2/4] media: synopsys: hdmirx: add HDMI audio capture support Igor Paunovic
@ 2026-07-18 8:57 ` Igor Paunovic
2026-07-18 11:12 ` Igor Paunovic
2026-07-18 8:57 ` [PATCH v3 4/4] arm64: dts: rockchip: enable HDMI RX audio capture on Orange Pi 5 Plus Igor Paunovic
3 siblings, 1 reply; 10+ messages in thread
From: Igor Paunovic @ 2026-07-18 8:57 UTC (permalink / raw)
To: Dmitry Osipenko, Mauro Carvalho Chehab
Cc: Sebastian Reichel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Heiko Stuebner, linux-media, linux-rockchip, linux-arm-kernel,
kernel, devicetree, linux-kernel, Igor Paunovic
The Synopsys HDMI RX controller exposes two digital audio interfaces,
one for I2S (0) and one for S/PDIF (1). Add the #sound-dai-cells
property so audio cards can reference them as a codec, as documented
by the snps,dw-hdmi-rx binding.
Signed-off-by: Igor Paunovic <royalnet026@gmail.com>
---
New in v3.
| 1 +
1 file changed, 1 insertion(+)
--git a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi
index a264001..fa100e3 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi
@@ -338,6 +338,7 @@
reset-names = "axi", "apb", "ref", "biu";
rockchip,grf = <&sys_grf>;
rockchip,vo1-grf = <&vo1_grf>;
+ #sound-dai-cells = <1>;
status = "disabled";
};
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 4/4] arm64: dts: rockchip: enable HDMI RX audio capture on Orange Pi 5 Plus
2026-07-18 8:57 [PATCH v3 0/4] media: synopsys: hdmirx: add HDMI audio capture support Igor Paunovic
` (2 preceding siblings ...)
2026-07-18 8:57 ` [PATCH v3 3/4] arm64: dts: rockchip: add #sound-dai-cells to the RK3588 HDMI receiver Igor Paunovic
@ 2026-07-18 8:57 ` Igor Paunovic
2026-07-18 9:11 ` sashiko-bot
3 siblings, 1 reply; 10+ messages in thread
From: Igor Paunovic @ 2026-07-18 8:57 UTC (permalink / raw)
To: Dmitry Osipenko, Mauro Carvalho Chehab
Cc: Sebastian Reichel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Heiko Stuebner, linux-media, linux-rockchip, linux-arm-kernel,
kernel, devicetree, linux-kernel, Igor Paunovic
Route the HDMI receiver audio to i2s7_8ch, the receive-only I2S
interface dedicated to HDMI RX, through a simple-audio-card with the
receiver as bitclock and frame master. Together with the audio
capture support in the snps_hdmirx driver this exposes a capture-only
ALSA card fed by the HDMI input.
Tested on the Orange Pi 5 Plus with multiple HDMI sources: capture
follows the source sample rate and stays in sync via the FIFO-level
clock tracking in the driver.
Signed-off-by: Igor Paunovic <royalnet026@gmail.com>
---
New in v3.
.../dts/rockchip/rk3588-orangepi-5-plus.dts | 20 +++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts
index 9950d11..d5840e1 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts
@@ -37,6 +37,22 @@
};
};
+ hdmiin-sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "rockchip,hdmiin";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,bitclock-master = <&hdmiin_codec>;
+ simple-audio-card,frame-master = <&hdmiin_codec>;
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s7_8ch>;
+ };
+
+ hdmiin_codec: simple-audio-card,codec {
+ sound-dai = <&hdmi_receiver 0>;
+ };
+ };
+
ir-receiver {
compatible = "gpio-ir-receiver";
gpios = <&gpio4 RK_PB3 GPIO_ACTIVE_LOW>;
@@ -247,6 +263,10 @@
status = "okay";
};
+&i2s7_8ch {
+ status = "okay";
+};
+
&led_blue_gpio {
gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>;
status = "okay";
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v3 2/4] media: synopsys: hdmirx: add HDMI audio capture support
2026-07-18 8:57 ` [PATCH v3 2/4] media: synopsys: hdmirx: add HDMI audio capture support Igor Paunovic
@ 2026-07-18 9:09 ` sashiko-bot
2026-07-18 10:53 ` Igor Paunovic
0 siblings, 1 reply; 10+ messages in thread
From: sashiko-bot @ 2026-07-18 9:09 UTC (permalink / raw)
To: Igor Paunovic; +Cc: conor+dt, robh, devicetree, media-ci
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Incorrect byte-swapping logic completely scrambles the extraction of Audio Clock Regeneration (ACR) CTS and N values, breaking sample rate recovery on little-endian architectures.
- [High] The `audio_work` delayed work is not explicitly cancelled in `hdmirx_remove()`, leading to a Use-After-Free if the driver is unbound while an audio stream is active.
--
--- Patch [2]: [PATCH v3 2/4] media: synopsys: hdmirx: add HDMI audio capture support ---
commit b04bcd22f40b424aac824100715c46f764531875
Author: Igor Paunovic <royalnet026@gmail.com>
media: synopsys: hdmirx: add HDMI audio capture support
The Synopsys DesignWare HDMI RX controller extracts the audio stream
embedded in the incoming HDMI signal and feeds it to an on-SoC I2S
controller. Expose it as an ALSA capture device by registering the
generic hdmi-codec as a child of the controller.
> diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c
> index 25f8ca0d6d946..22f50cbf3fa7a 100644
> --- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c
> +++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c
[ ... ]
> +/* Recover the incoming audio sample rate from the ACR N/CTS + TMDS clock. */
> +static u32 hdmirx_audio_fs(struct snps_hdmirx_dev *hdmirx_dev)
> +{
> + u64 tmds_clk, fs_audio = 0;
> + u32 acr_cts, acr_n, tmdsqpclk_freq;
> + u32 acr_pb3_0, acr_pb7_4;
> +
> + tmdsqpclk_freq = hdmirx_readl(hdmirx_dev, CMU_TMDSQPCLK_FREQ);
> + hdmirx_readl(hdmirx_dev, PKTDEC_ACR_PH2_1);
> + acr_pb3_0 = hdmirx_readl(hdmirx_dev, PKTDEC_ACR_PB3_0);
> + acr_pb7_4 = hdmirx_readl(hdmirx_dev, PKTDEC_ACR_PB7_4);
> + /*
> + * The packet decoder stores the ACR subpacket bytes with packet byte
> + * 0 in register bits [7:0], so byte-swap each word to line the bytes
> + * up: CTS is packet bytes 1-3 (PKTDEC_ACR_PB3_0) and N is packet
> + * bytes 4-6 (PKTDEC_ACR_PB7_4), 20 bits each.
> + */
> + acr_cts = be32_to_cpu((__force __be32)acr_pb3_0) & 0xfffff;
> + acr_n = (be32_to_cpu((__force __be32)acr_pb7_4) & 0x0fffff00) >> 8;
[Severity: High]
Does this byte-swapping logic scramble the extraction of the CTS and N values
on little-endian architectures?
Since the HDMI ACR packet transmits the 20-bit CTS value across PB0, PB1, and
PB2, and because it is little-endian, applying a bitmask like
acr_pb3_0 & 0xfffff natively yields the correct CTS value without any swaps.
By byte-swapping the 32-bit register, the bytes are completely reversed.
The subsequent bitmask extracts the lower 20 bits of the swapped word, which
correspond to the lower nibble of PB1, all of PB2, and all of PB3, discarding
PB0 entirely.
The same applies to acr_pb7_4 to extract N. Will this regression result in
garbage values for both acr_cts and acr_n, forcing the driver to blindly
fall back to the default sample rate?
[ ... ]
> @@ -2784,6 +3052,9 @@ static void hdmirx_remove(struct platform_device *pdev)
> struct device *dev = &pdev->dev;
> struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev);
>
> + if (hdmirx_dev->audio_pdev)
> + platform_device_unregister(hdmirx_dev->audio_pdev);
> +
[Severity: High]
Can this lead to a use-after-free if the driver is unbound while an audio
stream is active?
The v3 changelog notes that the synchronous cancel for the audio_work
delayed work was removed here under the assumption that audio_shutdown()
handles it.
However, ALSA does not synchronously invoke the PCM .shutdown callback
when a device is unregistered if a userspace application holds the file
descriptor open.
Because hdmirx_dev is allocated using devm_kzalloc, it is freed immediately
after hdmirx_remove() returns. Will the un-cancelled audio_work delayed work
subsequently fire and access the freed hdmirx_dev memory?
> v4l2_debugfs_if_free(hdmirx_dev->infoframes);
> debugfs_remove_recursive(hdmirx_dev->debugfs_dir);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260718085728.6797-1-royalnet026@gmail.com?part=2
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 4/4] arm64: dts: rockchip: enable HDMI RX audio capture on Orange Pi 5 Plus
2026-07-18 8:57 ` [PATCH v3 4/4] arm64: dts: rockchip: enable HDMI RX audio capture on Orange Pi 5 Plus Igor Paunovic
@ 2026-07-18 9:11 ` sashiko-bot
2026-07-18 11:04 ` Igor Paunovic
0 siblings, 1 reply; 10+ messages in thread
From: sashiko-bot @ 2026-07-18 9:11 UTC (permalink / raw)
To: Igor Paunovic; +Cc: media-ci, conor+dt, devicetree, robh
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The audio_work delayed work is not cancelled during system suspend, leading to a fatal bus fault.
- [Medium] Incorrect use of be32_to_cpu() for unconditional byte swapping breaks audio capture on big-endian architectures.
--
--- Patch [4]: [PATCH v3 4/4] arm64: dts: rockchip: enable HDMI RX audio capture on Orange Pi 5 Plus ---
commit 030cd8fd5334b79e1751dec57b1de1f5fa4e3df3
Author: Igor Paunovic <royalnet026@gmail.com>
arm64: dts: rockchip: enable HDMI RX audio capture on Orange Pi 5 Plus
This patch routes the HDMI receiver audio to the i2s7_8ch interface. It creates
a simple-audio-card configuration to expose a capture-only ALSA card driven
by the HDMI input. The setup uses the receiver as the bitclock and frame master.
> diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts
> index 145986695720a..2a68610cddbc3 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts
> @@ -37,6 +37,22 @@ hdmi1_con_in: endpoint {
> };
> };
>
> + hdmiin-sound {
> + compatible = "simple-audio-card";
> + simple-audio-card,name = "rockchip,hdmiin";
> + simple-audio-card,format = "i2s";
> + simple-audio-card,bitclock-master = <&hdmiin_codec>;
> + simple-audio-card,frame-master = <&hdmiin_codec>;
> +
> + simple-audio-card,cpu {
> + sound-dai = <&i2s7_8ch>;
> + };
> +
> + hdmiin_codec: simple-audio-card,codec {
> + sound-dai = <&hdmi_receiver 0>;
[Severity: High]
Does exposing this codec to the ALSA subsystem trigger a suspend regression in
the hdmirx driver?
Looking at the underlying codec driver hdmirx_suspend() in snps_hdmirx.c:
drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c:hdmirx_suspend()
{
struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev);
hdmirx_disable_irq(dev);
/* TODO store CEC HW state */
disable_irq(hdmirx_dev->cec->irq);
return hdmirx_disable(dev);
}
The audio_work delayed work is queued on system_unbound_wq, which is not
freezable, but this suspend callback doesn't cancel it.
If system suspend is initiated while audio capture is active, the worker
could fire after clocks are disabled via hdmirx_disable(), resulting in
a bus fault when it performs MMIO reads.
[Severity: Medium]
Will this audio capture work correctly on big-endian architectures?
The underlying hdmirx_audio_fs() driver function uses be32_to_cpu() for an
unconditional byte swap when calculating the ACR subpacket:
drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c:hdmirx_audio_fs()
{
...
acr_cts = be32_to_cpu((__force __be32)acr_pb3_0) & 0xfffff;
acr_n = (be32_to_cpu((__force __be32)acr_pb7_4) & 0x0fffff00) >> 8;
...
}
Since be32_to_cpu() behaves as a no-op on big-endian CPUs, the bytes remain
unswapped, causing the bitwise masking to extract the wrong bytes for the
ACR CTS and N fields.
Should swab32() be used here instead to ensure the byte swap happens
unconditionally on all architectures?
> + };
> + };
> +
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260718085728.6797-1-royalnet026@gmail.com?part=4
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 2/4] media: synopsys: hdmirx: add HDMI audio capture support
2026-07-18 9:09 ` sashiko-bot
@ 2026-07-18 10:53 ` Igor Paunovic
0 siblings, 0 replies; 10+ messages in thread
From: Igor Paunovic @ 2026-07-18 10:53 UTC (permalink / raw)
To: sashiko-reviews, Dmitry Osipenko, Mauro Carvalho Chehab,
Sebastian Reichel, Heiko Stübner, linux-media,
linux-rockchip, linux-arm-kernel, kernel, linux-kernel
Cc: conor+dt, robh, devicetree, media-ci
> Does this byte-swapping logic scramble the extraction of the CTS and N
> values on little-endian architectures?
No. This is the same finding as in the v2 review, where it was already
answered, and the comment this v3 adds above the swap documents exactly
this. Two premises in the report don't match the ACR packet layout:
CTS does not live in PB0..PB2 and is not little-endian. Subpacket
byte 0 is reserved, CTS[19:16] sits in PB1[3:0], CTS[15:8] in PB2 and
CTS[7:0] in PB3 (MSB first), with N likewise in PB4..PB6. The packet
decoder stores PB0 in register bits [7:0], so the byte swap is
precisely what lines the bytes up before the 20-bit masks.
It is also the path validated on hardware: with a 44.1 kHz source the
card reports 44.1 kHz rather than falling back to the 48 kHz default,
and sample-rate switches are followed. Neither would work if the
extraction produced garbage.
> Can this lead to a use-after-free if the driver is unbound while an
> audio stream is active?
No -- the synchronization the report treats as missing is provided by
the ALSA core, and relying on it is why the v2 workaround was dropped
on Dmitry's review in the first place.
The worker is only ever armed between hw_params() and
audio_shutdown(). If a capture stream is still open when the codec
platform device is unregistered, teardown does not complete until the
stream is gone: soc_cleanup_card_resources() calls snd_card_free()
(sound/soc/soc-core.c), which blocks in wait_for_completion() until
the last file handle is closed (sound/core/init.c: "wait, until all
devices are ready for the free operation"). A disconnected card still
routes that final close through the original release path
(snd_disconnect_release() -> disconnected_f_op->release()), so
snd_pcm_release() runs soc_pcm_close() -> hdmi_codec shutdown ->
hdmirx_audio_shutdown(), which clears the streaming flag and
cancel_delayed_work_sync()s the worker.
platform_device_unregister() therefore cannot return with the worker
armed, and the devm-allocated state is freed only after remove()
returns. There is no window for the work to fire on freed memory.
Also exercised on the Orange Pi 5 Plus: unbinding the driver through
sysfs while arecord was actively capturing. The ALSA disconnect kicks
the reader out with ENODEV, the file handle is closed -- which is
where audio_shutdown() runs and cancels the worker -- and only then
does the unbind complete. A subsequent bind re-probes cleanly and the
card comes back. The kernel log stays free of warnings throughout.
Igor
On Sat, Jul 18, 2026 at 11:09 AM <sashiko-bot@kernel.org> wrote:
>
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [High] Incorrect byte-swapping logic completely scrambles the extraction of Audio Clock Regeneration (ACR) CTS and N values, breaking sample rate recovery on little-endian architectures.
> - [High] The `audio_work` delayed work is not explicitly cancelled in `hdmirx_remove()`, leading to a Use-After-Free if the driver is unbound while an audio stream is active.
> --
>
> --- Patch [2]: [PATCH v3 2/4] media: synopsys: hdmirx: add HDMI audio capture support ---
> commit b04bcd22f40b424aac824100715c46f764531875
> Author: Igor Paunovic <royalnet026@gmail.com>
>
> media: synopsys: hdmirx: add HDMI audio capture support
>
> The Synopsys DesignWare HDMI RX controller extracts the audio stream
> embedded in the incoming HDMI signal and feeds it to an on-SoC I2S
> controller. Expose it as an ALSA capture device by registering the
> generic hdmi-codec as a child of the controller.
>
> > diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c
> > index 25f8ca0d6d946..22f50cbf3fa7a 100644
> > --- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c
> > +++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c
>
> [ ... ]
>
> > +/* Recover the incoming audio sample rate from the ACR N/CTS + TMDS clock. */
> > +static u32 hdmirx_audio_fs(struct snps_hdmirx_dev *hdmirx_dev)
> > +{
> > + u64 tmds_clk, fs_audio = 0;
> > + u32 acr_cts, acr_n, tmdsqpclk_freq;
> > + u32 acr_pb3_0, acr_pb7_4;
> > +
> > + tmdsqpclk_freq = hdmirx_readl(hdmirx_dev, CMU_TMDSQPCLK_FREQ);
> > + hdmirx_readl(hdmirx_dev, PKTDEC_ACR_PH2_1);
> > + acr_pb3_0 = hdmirx_readl(hdmirx_dev, PKTDEC_ACR_PB3_0);
> > + acr_pb7_4 = hdmirx_readl(hdmirx_dev, PKTDEC_ACR_PB7_4);
> > + /*
> > + * The packet decoder stores the ACR subpacket bytes with packet byte
> > + * 0 in register bits [7:0], so byte-swap each word to line the bytes
> > + * up: CTS is packet bytes 1-3 (PKTDEC_ACR_PB3_0) and N is packet
> > + * bytes 4-6 (PKTDEC_ACR_PB7_4), 20 bits each.
> > + */
> > + acr_cts = be32_to_cpu((__force __be32)acr_pb3_0) & 0xfffff;
> > + acr_n = (be32_to_cpu((__force __be32)acr_pb7_4) & 0x0fffff00) >> 8;
>
> [Severity: High]
> Does this byte-swapping logic scramble the extraction of the CTS and N values
> on little-endian architectures?
>
> Since the HDMI ACR packet transmits the 20-bit CTS value across PB0, PB1, and
> PB2, and because it is little-endian, applying a bitmask like
> acr_pb3_0 & 0xfffff natively yields the correct CTS value without any swaps.
>
> By byte-swapping the 32-bit register, the bytes are completely reversed.
> The subsequent bitmask extracts the lower 20 bits of the swapped word, which
> correspond to the lower nibble of PB1, all of PB2, and all of PB3, discarding
> PB0 entirely.
>
> The same applies to acr_pb7_4 to extract N. Will this regression result in
> garbage values for both acr_cts and acr_n, forcing the driver to blindly
> fall back to the default sample rate?
>
> [ ... ]
>
> > @@ -2784,6 +3052,9 @@ static void hdmirx_remove(struct platform_device *pdev)
> > struct device *dev = &pdev->dev;
> > struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev);
> >
> > + if (hdmirx_dev->audio_pdev)
> > + platform_device_unregister(hdmirx_dev->audio_pdev);
> > +
>
> [Severity: High]
> Can this lead to a use-after-free if the driver is unbound while an audio
> stream is active?
>
> The v3 changelog notes that the synchronous cancel for the audio_work
> delayed work was removed here under the assumption that audio_shutdown()
> handles it.
>
> However, ALSA does not synchronously invoke the PCM .shutdown callback
> when a device is unregistered if a userspace application holds the file
> descriptor open.
>
> Because hdmirx_dev is allocated using devm_kzalloc, it is freed immediately
> after hdmirx_remove() returns. Will the un-cancelled audio_work delayed work
> subsequently fire and access the freed hdmirx_dev memory?
>
> > v4l2_debugfs_if_free(hdmirx_dev->infoframes);
> > debugfs_remove_recursive(hdmirx_dev->debugfs_dir);
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260718085728.6797-1-royalnet026@gmail.com?part=2
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 4/4] arm64: dts: rockchip: enable HDMI RX audio capture on Orange Pi 5 Plus
2026-07-18 9:11 ` sashiko-bot
@ 2026-07-18 11:04 ` Igor Paunovic
0 siblings, 0 replies; 10+ messages in thread
From: Igor Paunovic @ 2026-07-18 11:04 UTC (permalink / raw)
To: sashiko-reviews, Dmitry Osipenko, Mauro Carvalho Chehab,
Sebastian Reichel, Heiko Stübner, linux-media,
linux-rockchip, linux-arm-kernel, kernel, linux-kernel
Cc: media-ci, conor+dt, devicetree, robh
> Does exposing this codec to the ALSA subsystem trigger a suspend
> regression in the hdmirx driver?
Good catch -- this one is real. The audio worker missed the pattern
the driver already applies to its hotplug and res_change works,
which hdmirx_disable_irq() cancels on the suspend path. Fixed for
v4: suspend cancels audio_work before the controller clocks are
gated, and resume re-arms it when a capture stream is active; the
worker's FIFO error path then resynchronizes the clock and the FIFO
on its first run after resume.
> Should swab32() be used here instead to ensure the byte swap happens
> unconditionally on all architectures?
Yes -- readl() already abstracts the bus endianness, so what this
code wants is an unconditional byte reversal, not an endian
conversion. Switched to swab32() for v4 (no functional change on
arm64, where this controller lives, but the right primitive
regardless).
Both changes are in my tree, compile-tested, and will be part of v4
together with whatever comes out of human review of the series.
Igor
On Sat, Jul 18, 2026 at 11:12 AM <sashiko-bot@kernel.org> wrote:
>
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [High] The audio_work delayed work is not cancelled during system suspend, leading to a fatal bus fault.
> - [Medium] Incorrect use of be32_to_cpu() for unconditional byte swapping breaks audio capture on big-endian architectures.
> --
>
> --- Patch [4]: [PATCH v3 4/4] arm64: dts: rockchip: enable HDMI RX audio capture on Orange Pi 5 Plus ---
> commit 030cd8fd5334b79e1751dec57b1de1f5fa4e3df3
> Author: Igor Paunovic <royalnet026@gmail.com>
>
> arm64: dts: rockchip: enable HDMI RX audio capture on Orange Pi 5 Plus
>
> This patch routes the HDMI receiver audio to the i2s7_8ch interface. It creates
> a simple-audio-card configuration to expose a capture-only ALSA card driven
> by the HDMI input. The setup uses the receiver as the bitclock and frame master.
>
> > diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts
> > index 145986695720a..2a68610cddbc3 100644
> > --- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts
> > +++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts
> > @@ -37,6 +37,22 @@ hdmi1_con_in: endpoint {
> > };
> > };
> >
> > + hdmiin-sound {
> > + compatible = "simple-audio-card";
> > + simple-audio-card,name = "rockchip,hdmiin";
> > + simple-audio-card,format = "i2s";
> > + simple-audio-card,bitclock-master = <&hdmiin_codec>;
> > + simple-audio-card,frame-master = <&hdmiin_codec>;
> > +
> > + simple-audio-card,cpu {
> > + sound-dai = <&i2s7_8ch>;
> > + };
> > +
> > + hdmiin_codec: simple-audio-card,codec {
> > + sound-dai = <&hdmi_receiver 0>;
>
> [Severity: High]
> Does exposing this codec to the ALSA subsystem trigger a suspend regression in
> the hdmirx driver?
>
> Looking at the underlying codec driver hdmirx_suspend() in snps_hdmirx.c:
>
> drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c:hdmirx_suspend()
> {
> struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev);
>
> hdmirx_disable_irq(dev);
>
> /* TODO store CEC HW state */
> disable_irq(hdmirx_dev->cec->irq);
>
> return hdmirx_disable(dev);
> }
>
> The audio_work delayed work is queued on system_unbound_wq, which is not
> freezable, but this suspend callback doesn't cancel it.
>
> If system suspend is initiated while audio capture is active, the worker
> could fire after clocks are disabled via hdmirx_disable(), resulting in
> a bus fault when it performs MMIO reads.
>
> [Severity: Medium]
> Will this audio capture work correctly on big-endian architectures?
>
> The underlying hdmirx_audio_fs() driver function uses be32_to_cpu() for an
> unconditional byte swap when calculating the ACR subpacket:
>
> drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c:hdmirx_audio_fs()
> {
> ...
> acr_cts = be32_to_cpu((__force __be32)acr_pb3_0) & 0xfffff;
> acr_n = (be32_to_cpu((__force __be32)acr_pb7_4) & 0x0fffff00) >> 8;
> ...
> }
>
> Since be32_to_cpu() behaves as a no-op on big-endian CPUs, the bytes remain
> unswapped, causing the bitwise masking to extract the wrong bytes for the
> ACR CTS and N fields.
>
> Should swab32() be used here instead to ensure the byte swap happens
> unconditionally on all architectures?
>
> > + };
> > + };
> > +
>
> [ ... ]
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260718085728.6797-1-royalnet026@gmail.com?part=4
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 3/4] arm64: dts: rockchip: add #sound-dai-cells to the RK3588 HDMI receiver
2026-07-18 8:57 ` [PATCH v3 3/4] arm64: dts: rockchip: add #sound-dai-cells to the RK3588 HDMI receiver Igor Paunovic
@ 2026-07-18 11:12 ` Igor Paunovic
0 siblings, 0 replies; 10+ messages in thread
From: Igor Paunovic @ 2026-07-18 11:12 UTC (permalink / raw)
To: Dmitry Osipenko, Mauro Carvalho Chehab
Cc: Sebastian Reichel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Heiko Stuebner, linux-media, linux-rockchip, linux-arm-kernel,
kernel, devicetree, linux-kernel
A testing note for anyone trying this out, found while exercising
the series today:
after (re)connecting a source, audio capture currently requires the
video capture path to have been started once -- a cold
`arecord -D hw:...` right after plug-in fails with EIO (the I2S
interface gets no bit clock), while the same command succeeds after
one video STREAMON/STREAMOFF cycle, and keeps working from then on
until the source is re-plugged.
Setting DV timings alone is not sufficient; it does take a real
streaming cycle. So for testing audio, either run a video pipeline
first (e.g. v4l2src ! fakesink for a second) or capture both, which
is the normal use case anyway.
I'm investigating which part of the streaming path opens the audio
packet flow, and will either fix it in v4 (if it turns out to be a
missing enable in the audio path) or send it as a follow-up with a
proper analysis.
Igor
On Sat, Jul 18, 2026 at 10:57 AM Igor Paunovic <royalnet026@gmail.com> wrote:
>
> The Synopsys HDMI RX controller exposes two digital audio interfaces,
> one for I2S (0) and one for S/PDIF (1). Add the #sound-dai-cells
> property so audio cards can reference them as a codec, as documented
> by the snps,dw-hdmi-rx binding.
>
> Signed-off-by: Igor Paunovic <royalnet026@gmail.com>
> ---
> New in v3.
>
> arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi
> index a264001..fa100e3 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi
> @@ -338,6 +338,7 @@
> reset-names = "axi", "apb", "ref", "biu";
> rockchip,grf = <&sys_grf>;
> rockchip,vo1-grf = <&vo1_grf>;
> + #sound-dai-cells = <1>;
> status = "disabled";
> };
>
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-07-18 11:12 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-18 8:57 [PATCH v3 0/4] media: synopsys: hdmirx: add HDMI audio capture support Igor Paunovic
2026-07-18 8:57 ` [PATCH v3 1/4] dt-bindings: media: snps,dw-hdmi-rx: add #sound-dai-cells Igor Paunovic
2026-07-18 8:57 ` [PATCH v3 2/4] media: synopsys: hdmirx: add HDMI audio capture support Igor Paunovic
2026-07-18 9:09 ` sashiko-bot
2026-07-18 10:53 ` Igor Paunovic
2026-07-18 8:57 ` [PATCH v3 3/4] arm64: dts: rockchip: add #sound-dai-cells to the RK3588 HDMI receiver Igor Paunovic
2026-07-18 11:12 ` Igor Paunovic
2026-07-18 8:57 ` [PATCH v3 4/4] arm64: dts: rockchip: enable HDMI RX audio capture on Orange Pi 5 Plus Igor Paunovic
2026-07-18 9:11 ` sashiko-bot
2026-07-18 11:04 ` Igor Paunovic
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox