Commit c979296e authored by Laurent Pinchart's avatar Laurent Pinchart

drm: xlnx: zynqmp_dpsub: Move audio clk from zynqmp_disp to zynqmp_dpsub

The audio clock is an external resource from the DPSUB point of view,
not a resource internal to the display controller. Move it to the
zynqmp_dpsub structure, to allow accessing it from outside the disp
code.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
parent 1682ade6
...@@ -166,8 +166,6 @@ struct zynqmp_disp_layer { ...@@ -166,8 +166,6 @@ struct zynqmp_disp_layer {
* @blend.base: Register I/O base address for the blender * @blend.base: Register I/O base address for the blender
* @avbuf.base: Register I/O base address for the audio/video buffer manager * @avbuf.base: Register I/O base address for the audio/video buffer manager
* @audio.base: Registers I/O base address for the audio mixer * @audio.base: Registers I/O base address for the audio mixer
* @audio.clk: Audio clock
* @audio.clk_from_ps: True of the audio clock comes from PS, false from PL
* @layers: Layers (planes) * @layers: Layers (planes)
*/ */
struct zynqmp_disp { struct zynqmp_disp {
...@@ -185,8 +183,6 @@ struct zynqmp_disp { ...@@ -185,8 +183,6 @@ struct zynqmp_disp {
} avbuf; } avbuf;
struct { struct {
void __iomem *base; void __iomem *base;
struct clk *clk;
bool clk_from_ps;
} audio; } audio;
struct zynqmp_disp_layer layers[ZYNQMP_DISP_NUM_LAYERS]; struct zynqmp_disp_layer layers[ZYNQMP_DISP_NUM_LAYERS];
...@@ -892,25 +888,6 @@ static void zynqmp_disp_audio_disable(struct zynqmp_disp *disp) ...@@ -892,25 +888,6 @@ static void zynqmp_disp_audio_disable(struct zynqmp_disp *disp)
ZYNQMP_DISP_AUD_SOFT_RESET_AUD_SRST); ZYNQMP_DISP_AUD_SOFT_RESET_AUD_SRST);
} }
static void zynqmp_disp_audio_init(struct zynqmp_disp *disp)
{
/* Try the live PL audio clock. */
disp->audio.clk = devm_clk_get(disp->dev, "dp_live_audio_aclk");
if (!IS_ERR(disp->audio.clk)) {
disp->audio.clk_from_ps = false;
return;
}
/* If the live PL audio clock is not valid, fall back to PS clock. */
disp->audio.clk = devm_clk_get(disp->dev, "dp_aud_clk");
if (!IS_ERR(disp->audio.clk)) {
disp->audio.clk_from_ps = true;
return;
}
dev_err(disp->dev, "audio disabled due to missing clock\n");
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* ZynqMP Display external functions for zynqmp_dp * ZynqMP Display external functions for zynqmp_dp
*/ */
...@@ -929,32 +906,6 @@ void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp) ...@@ -929,32 +906,6 @@ void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp)
drm_crtc_handle_vblank(crtc); drm_crtc_handle_vblank(crtc);
} }
/**
* zynqmp_disp_audio_enabled - If the audio is enabled
* @disp: Display controller
*
* Return if the audio is enabled depending on the audio clock.
*
* Return: true if audio is enabled, or false.
*/
bool zynqmp_disp_audio_enabled(struct zynqmp_disp *disp)
{
return !!disp->audio.clk;
}
/**
* zynqmp_disp_get_audio_clk_rate - Get the current audio clock rate
* @disp: Display controller
*
* Return: the current audio clock rate.
*/
unsigned int zynqmp_disp_get_audio_clk_rate(struct zynqmp_disp *disp)
{
if (zynqmp_disp_audio_enabled(disp))
return 0;
return clk_get_rate(disp->audio.clk);
}
/** /**
* zynqmp_disp_get_crtc_mask - Return the CRTC bit mask * zynqmp_disp_get_crtc_mask - Return the CRTC bit mask
* @disp: Display controller * @disp: Display controller
...@@ -1408,7 +1359,8 @@ static void zynqmp_disp_enable(struct zynqmp_disp *disp) ...@@ -1408,7 +1359,8 @@ static void zynqmp_disp_enable(struct zynqmp_disp *disp)
zynqmp_disp_avbuf_enable(disp); zynqmp_disp_avbuf_enable(disp);
/* Choose clock source based on the DT clock handle. */ /* Choose clock source based on the DT clock handle. */
zynqmp_disp_avbuf_set_clocks_sources(disp, disp->dpsub->vid_clk_from_ps, zynqmp_disp_avbuf_set_clocks_sources(disp, disp->dpsub->vid_clk_from_ps,
disp->audio.clk_from_ps, true); disp->dpsub->aud_clk_from_ps,
true);
zynqmp_disp_avbuf_enable_channels(disp); zynqmp_disp_avbuf_enable_channels(disp);
zynqmp_disp_avbuf_enable_audio(disp); zynqmp_disp_avbuf_enable_audio(disp);
...@@ -1669,8 +1621,6 @@ int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) ...@@ -1669,8 +1621,6 @@ int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
if (IS_ERR(disp->audio.base)) if (IS_ERR(disp->audio.base))
return PTR_ERR(disp->audio.base); return PTR_ERR(disp->audio.base);
zynqmp_disp_audio_init(disp);
ret = zynqmp_disp_create_layers(disp); ret = zynqmp_disp_create_layers(disp);
if (ret) if (ret)
return ret; return ret;
......
...@@ -31,8 +31,6 @@ struct zynqmp_disp; ...@@ -31,8 +31,6 @@ struct zynqmp_disp;
struct zynqmp_dpsub; struct zynqmp_dpsub;
void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp); void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp);
bool zynqmp_disp_audio_enabled(struct zynqmp_disp *disp);
unsigned int zynqmp_disp_get_audio_clk_rate(struct zynqmp_disp *disp);
uint32_t zynqmp_disp_get_crtc_mask(struct zynqmp_disp *disp); uint32_t zynqmp_disp_get_crtc_mask(struct zynqmp_disp *disp);
int zynqmp_disp_drm_init(struct zynqmp_dpsub *dpsub); int zynqmp_disp_drm_init(struct zynqmp_dpsub *dpsub);
......
...@@ -1252,7 +1252,7 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp, ...@@ -1252,7 +1252,7 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp,
reg = drm_dp_bw_code_to_link_rate(dp->mode.bw_code); 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_N_VID, reg);
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_M_VID, mode->clock); zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_M_VID, mode->clock);
rate = zynqmp_disp_get_audio_clk_rate(dp->dpsub->disp); rate = zynqmp_dpsub_get_audio_clk_rate(dp->dpsub);
if (rate) { if (rate) {
dev_dbg(dp->dev, "Audio rate: %d\n", rate / 512); 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_N_AUD, reg);
...@@ -1261,7 +1261,7 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp, ...@@ -1261,7 +1261,7 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp,
} }
/* Only 2 channel audio is supported now */ /* Only 2 channel audio is supported now */
if (zynqmp_disp_audio_enabled(dp->dpsub->disp)) if (zynqmp_dpsub_audio_enabled(dp->dpsub))
zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CHANNELS, 1); zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CHANNELS, 1);
zynqmp_dp_write(dp, ZYNQMP_DP_USER_PIX_WIDTH, 1); zynqmp_dp_write(dp, ZYNQMP_DP_USER_PIX_WIDTH, 1);
...@@ -1372,7 +1372,7 @@ static void zynqmp_dp_bridge_atomic_enable(struct drm_bridge *bridge, ...@@ -1372,7 +1372,7 @@ static void zynqmp_dp_bridge_atomic_enable(struct drm_bridge *bridge,
/* Enable the encoder */ /* Enable the encoder */
dp->enabled = true; dp->enabled = true;
zynqmp_dp_update_misc(dp); zynqmp_dp_update_misc(dp);
if (zynqmp_disp_audio_enabled(dp->dpsub->disp)) if (zynqmp_dpsub_audio_enabled(dp->dpsub))
zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 1); zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 1);
zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN, 0); zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN, 0);
if (dp->status == connector_status_connected) { if (dp->status == connector_status_connected) {
...@@ -1406,7 +1406,7 @@ static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge, ...@@ -1406,7 +1406,7 @@ static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge,
drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D3); 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_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN,
ZYNQMP_DP_TX_PHY_POWER_DOWN_ALL); ZYNQMP_DP_TX_PHY_POWER_DOWN_ALL);
if (zynqmp_disp_audio_enabled(dp->dpsub->disp)) if (zynqmp_dpsub_audio_enabled(dp->dpsub))
zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 0); zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 0);
pm_runtime_put_sync(dp->dev); pm_runtime_put_sync(dp->dev);
} }
......
...@@ -196,6 +196,36 @@ static const struct dev_pm_ops zynqmp_dpsub_pm_ops = { ...@@ -196,6 +196,36 @@ static const struct dev_pm_ops zynqmp_dpsub_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(zynqmp_dpsub_suspend, zynqmp_dpsub_resume) SET_SYSTEM_SLEEP_PM_OPS(zynqmp_dpsub_suspend, zynqmp_dpsub_resume)
}; };
/* -----------------------------------------------------------------------------
* DPSUB Configuration
*/
/**
* zynqmp_dpsub_audio_enabled - If the audio is enabled
* @dpsub: DisplayPort subsystem
*
* Return if the audio is enabled depending on the audio clock.
*
* Return: true if audio is enabled, or false.
*/
bool zynqmp_dpsub_audio_enabled(struct zynqmp_dpsub *dpsub)
{
return !!dpsub->aud_clk;
}
/**
* zynqmp_dpsub_get_audio_clk_rate - Get the current audio clock rate
* @dpsub: DisplayPort subsystem
*
* Return: the current audio clock rate.
*/
unsigned int zynqmp_dpsub_get_audio_clk_rate(struct zynqmp_dpsub *dpsub)
{
if (zynqmp_dpsub_audio_enabled(dpsub))
return 0;
return clk_get_rate(dpsub->aud_clk);
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* Probe & Remove * Probe & Remove
*/ */
...@@ -214,14 +244,16 @@ static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub) ...@@ -214,14 +244,16 @@ static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub)
return ret; return ret;
} }
/* Try the live PL video clock */ /*
* Try the live PL video clock, and fall back to the PS clock if the
* live PL video clock isn't valid.
*/
dpsub->vid_clk = devm_clk_get(dpsub->dev, "dp_live_video_in_clk"); dpsub->vid_clk = devm_clk_get(dpsub->dev, "dp_live_video_in_clk");
if (!IS_ERR(dpsub->vid_clk)) if (!IS_ERR(dpsub->vid_clk))
dpsub->vid_clk_from_ps = false; dpsub->vid_clk_from_ps = false;
else if (PTR_ERR(dpsub->vid_clk) == -EPROBE_DEFER) else if (PTR_ERR(dpsub->vid_clk) == -EPROBE_DEFER)
return PTR_ERR(dpsub->vid_clk); return PTR_ERR(dpsub->vid_clk);
/* If the live PL video clock is not valid, fall back to PS clock */
if (IS_ERR_OR_NULL(dpsub->vid_clk)) { if (IS_ERR_OR_NULL(dpsub->vid_clk)) {
dpsub->vid_clk = devm_clk_get(dpsub->dev, "dp_vtc_pixel_clk_in"); dpsub->vid_clk = devm_clk_get(dpsub->dev, "dp_vtc_pixel_clk_in");
if (IS_ERR(dpsub->vid_clk)) { if (IS_ERR(dpsub->vid_clk)) {
...@@ -231,6 +263,24 @@ static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub) ...@@ -231,6 +263,24 @@ static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub)
dpsub->vid_clk_from_ps = true; dpsub->vid_clk_from_ps = true;
} }
/*
* Try the live PL audio clock, and fall back to the PS clock if the
* live PL audio clock isn't valid. Missing audio clock disables audio
* but isn't an error.
*/
dpsub->aud_clk = devm_clk_get(dpsub->dev, "dp_live_audio_aclk");
if (!IS_ERR(dpsub->aud_clk)) {
dpsub->aud_clk_from_ps = false;
return 0;
}
dpsub->aud_clk = devm_clk_get(dpsub->dev, "dp_aud_clk");
if (!IS_ERR(dpsub->aud_clk)) {
dpsub->aud_clk_from_ps = true;
return 0;
}
dev_info(dpsub->dev, "audio disabled due to missing clock\n");
return 0; return 0;
} }
......
...@@ -35,6 +35,8 @@ enum zynqmp_dpsub_format { ...@@ -35,6 +35,8 @@ enum zynqmp_dpsub_format {
* @apb_clk: The APB clock * @apb_clk: The APB clock
* @vid_clk: Video clock * @vid_clk: Video clock
* @vid_clk_from_ps: True of the video clock comes from PS, false from PL * @vid_clk_from_ps: True of the video clock comes from PS, false from PL
* @aud_clk: Audio clock
* @aud_clk_from_ps: True of the audio clock comes from PS, false from PL
* @encoder: The dummy DRM encoder * @encoder: The dummy DRM encoder
* @bridge: The DP encoder bridge * @bridge: The DP encoder bridge
* @disp: The display controller * @disp: The display controller
...@@ -48,6 +50,8 @@ struct zynqmp_dpsub { ...@@ -48,6 +50,8 @@ struct zynqmp_dpsub {
struct clk *apb_clk; struct clk *apb_clk;
struct clk *vid_clk; struct clk *vid_clk;
bool vid_clk_from_ps; bool vid_clk_from_ps;
struct clk *aud_clk;
bool aud_clk_from_ps;
struct drm_encoder encoder; struct drm_encoder encoder;
struct drm_bridge *bridge; struct drm_bridge *bridge;
...@@ -63,4 +67,7 @@ static inline struct zynqmp_dpsub *to_zynqmp_dpsub(struct drm_device *drm) ...@@ -63,4 +67,7 @@ static inline struct zynqmp_dpsub *to_zynqmp_dpsub(struct drm_device *drm)
return container_of(drm, struct zynqmp_dpsub, drm); return container_of(drm, struct zynqmp_dpsub, drm);
} }
bool zynqmp_dpsub_audio_enabled(struct zynqmp_dpsub *dpsub);
unsigned int zynqmp_dpsub_get_audio_clk_rate(struct zynqmp_dpsub *dpsub);
#endif /* _ZYNQMP_DPSUB_H_ */ #endif /* _ZYNQMP_DPSUB_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment