Skip to content

Commit 3ec5c15

Browse files
committed
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 <[email protected]> Reviewed-by: Vishal Sagar <[email protected]> Signed-off-by: Tomi Valkeinen <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 0e0ab24 commit 3ec5c15

File tree

9 files changed

+526
-101
lines changed

9 files changed

+526
-101
lines changed

drivers/gpu/drm/xlnx/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,12 @@ config DRM_ZYNQMP_DPSUB
1717
This is a DRM/KMS driver for ZynqMP DisplayPort controller. Choose
1818
this option if you have a Xilinx ZynqMP SoC with DisplayPort
1919
subsystem.
20+
21+
config DRM_ZYNQMP_DPSUB_AUDIO
22+
bool "ZynqMP DisplayPort Audio Support"
23+
depends on DRM_ZYNQMP_DPSUB
24+
depends on SND && SND_SOC
25+
select SND_SOC_GENERIC_DMAENGINE_PCM
26+
help
27+
Choose this option to enable DisplayPort audio support in the ZynqMP
28+
DisplayPort driver.

drivers/gpu/drm/xlnx/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
zynqmp-dpsub-y := zynqmp_disp.o zynqmp_dpsub.o zynqmp_dp.o zynqmp_kms.o
2+
zynqmp-dpsub-$(CONFIG_DRM_ZYNQMP_DPSUB_AUDIO) += zynqmp_dp_audio.o
23
obj-$(CONFIG_DRM_ZYNQMP_DPSUB) += zynqmp-dpsub.o

drivers/gpu/drm/xlnx/zynqmp_disp.c

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,6 @@ struct zynqmp_disp_layer {
143143
* @dpsub: Display subsystem
144144
* @blend: Register I/O base address for the blender
145145
* @avbuf: Register I/O base address for the audio/video buffer manager
146-
* @audio: Registers I/O base address for the audio mixer
147146
* @layers: Layers (planes)
148147
*/
149148
struct zynqmp_disp {
@@ -152,7 +151,6 @@ struct zynqmp_disp {
152151

153152
void __iomem *blend;
154153
void __iomem *avbuf;
155-
void __iomem *audio;
156154

157155
struct zynqmp_disp_layer layers[ZYNQMP_DPSUB_NUM_LAYERS];
158156
};
@@ -865,42 +863,6 @@ static void zynqmp_disp_blend_layer_disable(struct zynqmp_disp *disp,
865863
csc_zero_offsets);
866864
}
867865

868-
/* -----------------------------------------------------------------------------
869-
* Audio Mixer
870-
*/
871-
872-
static void zynqmp_disp_audio_write(struct zynqmp_disp *disp, int reg, u32 val)
873-
{
874-
writel(val, disp->audio + reg);
875-
}
876-
877-
/**
878-
* zynqmp_disp_audio_enable - Enable the audio mixer
879-
* @disp: Display controller
880-
*
881-
* Enable the audio mixer by de-asserting the soft reset. The audio state is set to
882-
* default values by the reset, set the default mixer volume explicitly.
883-
*/
884-
static void zynqmp_disp_audio_enable(struct zynqmp_disp *disp)
885-
{
886-
/* Clear the audio soft reset register as it's an non-reset flop. */
887-
zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_SOFT_RESET, 0);
888-
zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_MIXER_VOLUME,
889-
ZYNQMP_DISP_AUD_MIXER_VOLUME_NO_SCALE);
890-
}
891-
892-
/**
893-
* zynqmp_disp_audio_disable - Disable the audio mixer
894-
* @disp: Display controller
895-
*
896-
* Disable the audio mixer by asserting its soft reset.
897-
*/
898-
static void zynqmp_disp_audio_disable(struct zynqmp_disp *disp)
899-
{
900-
zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_SOFT_RESET,
901-
ZYNQMP_DISP_AUD_SOFT_RESET_AUD_SRST);
902-
}
903-
904866
/* -----------------------------------------------------------------------------
905867
* ZynqMP Display Layer & DRM Plane
906868
*/
@@ -1341,8 +1303,6 @@ void zynqmp_disp_enable(struct zynqmp_disp *disp)
13411303
disp->dpsub->vid_clk_from_ps);
13421304
zynqmp_disp_avbuf_enable_channels(disp);
13431305
zynqmp_disp_avbuf_enable_audio(disp);
1344-
1345-
zynqmp_disp_audio_enable(disp);
13461306
}
13471307

13481308
/**
@@ -1351,8 +1311,6 @@ void zynqmp_disp_enable(struct zynqmp_disp *disp)
13511311
*/
13521312
void zynqmp_disp_disable(struct zynqmp_disp *disp)
13531313
{
1354-
zynqmp_disp_audio_disable(disp);
1355-
13561314
zynqmp_disp_avbuf_disable_audio(disp);
13571315
zynqmp_disp_avbuf_disable_channels(disp);
13581316
zynqmp_disp_avbuf_disable(disp);
@@ -1421,12 +1379,6 @@ int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub)
14211379
goto error;
14221380
}
14231381

1424-
disp->audio = devm_platform_ioremap_resource_byname(pdev, "aud");
1425-
if (IS_ERR(disp->audio)) {
1426-
ret = PTR_ERR(disp->audio);
1427-
goto error;
1428-
}
1429-
14301382
ret = zynqmp_disp_create_layers(disp);
14311383
if (ret)
14321384
goto error;

drivers/gpu/drm/xlnx/zynqmp_disp_regs.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,12 +177,7 @@
177177
#define ZYNQMP_DISP_AUD_MIXER_VOLUME 0x0
178178
#define ZYNQMP_DISP_AUD_MIXER_VOLUME_NO_SCALE 0x20002000
179179
#define ZYNQMP_DISP_AUD_MIXER_META_DATA 0x4
180-
#define ZYNQMP_DISP_AUD_CH_STATUS0 0x8
181-
#define ZYNQMP_DISP_AUD_CH_STATUS1 0xc
182-
#define ZYNQMP_DISP_AUD_CH_STATUS2 0x10
183-
#define ZYNQMP_DISP_AUD_CH_STATUS3 0x14
184-
#define ZYNQMP_DISP_AUD_CH_STATUS4 0x18
185-
#define ZYNQMP_DISP_AUD_CH_STATUS5 0x1c
180+
#define ZYNQMP_DISP_AUD_CH_STATUS(x) (0x8 + ((x) * 4))
186181
#define ZYNQMP_DISP_AUD_CH_A_DATA0 0x20
187182
#define ZYNQMP_DISP_AUD_CH_A_DATA1 0x24
188183
#define ZYNQMP_DISP_AUD_CH_A_DATA2 0x28

drivers/gpu/drm/xlnx/zynqmp_dp.c

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,7 +1342,6 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp,
13421342
{
13431343
u8 lane_cnt = dp->mode.lane_cnt;
13441344
u32 reg, wpl;
1345-
unsigned int rate;
13461345

13471346
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_HTOTAL, mode->htotal);
13481347
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,
13671366
reg = drm_dp_bw_code_to_link_rate(dp->mode.bw_code);
13681367
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_N_VID, reg);
13691368
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_M_VID, mode->clock);
1370-
rate = zynqmp_dpsub_get_audio_clk_rate(dp->dpsub);
1371-
if (rate) {
1372-
dev_dbg(dp->dev, "Audio rate: %d\n", rate / 512);
1373-
zynqmp_dp_write(dp, ZYNQMP_DP_TX_N_AUD, reg);
1374-
zynqmp_dp_write(dp, ZYNQMP_DP_TX_M_AUD, rate / 1000);
1375-
}
13761369
}
13771370

1378-
/* Only 2 channel audio is supported now */
1379-
if (zynqmp_dpsub_audio_enabled(dp->dpsub))
1380-
zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CHANNELS, 1);
1381-
13821371
zynqmp_dp_write(dp, ZYNQMP_DP_USER_PIX_WIDTH, 1);
13831372

13841373
/* Translate to the native 16 bit datapath based on IP core spec */
@@ -1387,6 +1376,44 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp,
13871376
zynqmp_dp_write(dp, ZYNQMP_DP_USER_DATA_COUNT_PER_LANE, reg);
13881377
}
13891378

1379+
/* -----------------------------------------------------------------------------
1380+
* Audio
1381+
*/
1382+
1383+
void zynqmp_dp_audio_set_channels(struct zynqmp_dp *dp,
1384+
unsigned int num_channels)
1385+
{
1386+
zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CHANNELS, num_channels - 1);
1387+
}
1388+
1389+
void zynqmp_dp_audio_enable(struct zynqmp_dp *dp)
1390+
{
1391+
zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 1);
1392+
}
1393+
1394+
void zynqmp_dp_audio_disable(struct zynqmp_dp *dp)
1395+
{
1396+
zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 0);
1397+
}
1398+
1399+
void zynqmp_dp_audio_write_n_m(struct zynqmp_dp *dp)
1400+
{
1401+
unsigned int rate;
1402+
u32 link_rate;
1403+
1404+
if (!(dp->config.misc0 & ZYNQMP_DP_MAIN_STREAM_MISC0_SYNC_LOCK))
1405+
return;
1406+
1407+
link_rate = drm_dp_bw_code_to_link_rate(dp->mode.bw_code);
1408+
1409+
rate = clk_get_rate(dp->dpsub->aud_clk);
1410+
1411+
dev_dbg(dp->dev, "Audio rate: %d\n", rate / 512);
1412+
1413+
zynqmp_dp_write(dp, ZYNQMP_DP_TX_N_AUD, link_rate);
1414+
zynqmp_dp_write(dp, ZYNQMP_DP_TX_M_AUD, rate / 1000);
1415+
}
1416+
13901417
/* -----------------------------------------------------------------------------
13911418
* DISP Configuration
13921419
*/
@@ -1577,8 +1604,7 @@ static void zynqmp_dp_bridge_atomic_enable(struct drm_bridge *bridge,
15771604
/* Enable the encoder */
15781605
dp->enabled = true;
15791606
zynqmp_dp_update_misc(dp);
1580-
if (zynqmp_dpsub_audio_enabled(dp->dpsub))
1581-
zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 1);
1607+
15821608
zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN, 0);
15831609
if (dp->status == connector_status_connected) {
15841610
for (i = 0; i < 3; i++) {
@@ -1613,8 +1639,6 @@ static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge,
16131639
drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
16141640
zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN,
16151641
ZYNQMP_DP_TX_PHY_POWER_DOWN_ALL);
1616-
if (zynqmp_dpsub_audio_enabled(dp->dpsub))
1617-
zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 0);
16181642

16191643
zynqmp_dp_disp_disable(dp, old_bridge_state);
16201644
mutex_unlock(&dp->lock);

drivers/gpu/drm/xlnx/zynqmp_dp.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,11 @@ void zynqmp_dp_disable_vblank(struct zynqmp_dp *dp);
2222
int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub);
2323
void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub);
2424

25+
void zynqmp_dp_audio_set_channels(struct zynqmp_dp *dp,
26+
unsigned int num_channels);
27+
void zynqmp_dp_audio_enable(struct zynqmp_dp *dp);
28+
void zynqmp_dp_audio_disable(struct zynqmp_dp *dp);
29+
30+
void zynqmp_dp_audio_write_n_m(struct zynqmp_dp *dp);
31+
2532
#endif /* _ZYNQMP_DP_H_ */

0 commit comments

Comments
 (0)