summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/xlnx/zynqmp_dp.c
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ideasonboard.com>2024-10-23 14:52:43 +0300
committerTomi Valkeinen <tomi.valkeinen@ideasonboard.com>2024-12-19 08:54:00 +0200
commit3ec5c15793051c9fe102ed0674c7925a56205385 (patch)
tree019135375912c52aac5e648d22573e901e05258e /drivers/gpu/drm/xlnx/zynqmp_dp.c
parent0e0ab2462fd3a4c44f03617a9e107ef8c754e05e (diff)
drm: xlnx: zynqmp_dpsub: Add DP audio support
Add basic DisplayPort audio support. Support non-live audio playback from two PCMs (DMA channels), and the volume control in the audio mixer. As older dtb files may not have the audio DMA channels defined, the driver will just mark the audio support as disabled if the audio DMA is missing, and will continue with only display support. Note: Reset doesn't seem to work (ZYNQMP_DISP_AUD_SOFT_RESET). If we do a reset, audio playback won't start again even if, afaics, we do set up all the necessary registers. So, at the moment, resetting the audio block in dp_dai_hw_free() is commented out. Tested-by: Anatoliy Klymenko <anatoliy.klymenko@amd.com> Reviewed-by: Vishal Sagar <vishal.sagar@amd.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> Link: https://patchwork.freedesktop.org/patch/msgid/20241023-xilinx-dp-audio-v4-3-5128881457be@ideasonboard.com
Diffstat (limited to 'drivers/gpu/drm/xlnx/zynqmp_dp.c')
-rw-r--r--drivers/gpu/drm/xlnx/zynqmp_dp.c54
1 files changed, 39 insertions, 15 deletions
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index 56a261a40ea3..0b63fd48ea92 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1342,7 +1342,6 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp,
{
u8 lane_cnt = dp->mode.lane_cnt;
u32 reg, wpl;
- unsigned int rate;
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_HTOTAL, mode->htotal);
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_VTOTAL, mode->vtotal);
@@ -1367,18 +1366,8 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp,
reg = drm_dp_bw_code_to_link_rate(dp->mode.bw_code);
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_N_VID, reg);
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_M_VID, mode->clock);
- rate = zynqmp_dpsub_get_audio_clk_rate(dp->dpsub);
- if (rate) {
- dev_dbg(dp->dev, "Audio rate: %d\n", rate / 512);
- zynqmp_dp_write(dp, ZYNQMP_DP_TX_N_AUD, reg);
- zynqmp_dp_write(dp, ZYNQMP_DP_TX_M_AUD, rate / 1000);
- }
}
- /* Only 2 channel audio is supported now */
- if (zynqmp_dpsub_audio_enabled(dp->dpsub))
- zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CHANNELS, 1);
-
zynqmp_dp_write(dp, ZYNQMP_DP_USER_PIX_WIDTH, 1);
/* Translate to the native 16 bit datapath based on IP core spec */
@@ -1388,6 +1377,44 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp,
}
/* -----------------------------------------------------------------------------
+ * Audio
+ */
+
+void zynqmp_dp_audio_set_channels(struct zynqmp_dp *dp,
+ unsigned int num_channels)
+{
+ zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CHANNELS, num_channels - 1);
+}
+
+void zynqmp_dp_audio_enable(struct zynqmp_dp *dp)
+{
+ zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 1);
+}
+
+void zynqmp_dp_audio_disable(struct zynqmp_dp *dp)
+{
+ zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 0);
+}
+
+void zynqmp_dp_audio_write_n_m(struct zynqmp_dp *dp)
+{
+ unsigned int rate;
+ u32 link_rate;
+
+ if (!(dp->config.misc0 & ZYNQMP_DP_MAIN_STREAM_MISC0_SYNC_LOCK))
+ return;
+
+ link_rate = drm_dp_bw_code_to_link_rate(dp->mode.bw_code);
+
+ rate = clk_get_rate(dp->dpsub->aud_clk);
+
+ dev_dbg(dp->dev, "Audio rate: %d\n", rate / 512);
+
+ zynqmp_dp_write(dp, ZYNQMP_DP_TX_N_AUD, link_rate);
+ zynqmp_dp_write(dp, ZYNQMP_DP_TX_M_AUD, rate / 1000);
+}
+
+/* -----------------------------------------------------------------------------
* DISP Configuration
*/
@@ -1577,8 +1604,7 @@ static void zynqmp_dp_bridge_atomic_enable(struct drm_bridge *bridge,
/* Enable the encoder */
dp->enabled = true;
zynqmp_dp_update_misc(dp);
- if (zynqmp_dpsub_audio_enabled(dp->dpsub))
- zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 1);
+
zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN, 0);
if (dp->status == connector_status_connected) {
for (i = 0; i < 3; i++) {
@@ -1613,8 +1639,6 @@ static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge,
drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN,
ZYNQMP_DP_TX_PHY_POWER_DOWN_ALL);
- if (zynqmp_dpsub_audio_enabled(dp->dpsub))
- zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 0);
zynqmp_dp_disp_disable(dp, old_bridge_state);
mutex_unlock(&dp->lock);