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 {
* @blend.base: Register I/O base address for the blender
* @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.clk: Audio clock
* @audio.clk_from_ps: True of the audio clock comes from PS, false from PL
* @layers: Layers (planes)
*/
struct zynqmp_disp {
......@@ -185,8 +183,6 @@ struct zynqmp_disp {
} avbuf;
struct {
void __iomem *base;
struct clk *clk;
bool clk_from_ps;
} audio;
struct zynqmp_disp_layer layers[ZYNQMP_DISP_NUM_LAYERS];
......@@ -892,25 +888,6 @@ static void zynqmp_disp_audio_disable(struct zynqmp_disp *disp)
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
*/
......@@ -929,32 +906,6 @@ void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp)
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
* @disp: Display controller
......@@ -1408,7 +1359,8 @@ static void zynqmp_disp_enable(struct zynqmp_disp *disp)
zynqmp_disp_avbuf_enable(disp);
/* Choose clock source based on the DT clock handle. */
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_audio(disp);
......@@ -1669,8 +1621,6 @@ int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
if (IS_ERR(disp->audio.base))
return PTR_ERR(disp->audio.base);
zynqmp_disp_audio_init(disp);
ret = zynqmp_disp_create_layers(disp);
if (ret)
return ret;
......
......@@ -31,8 +31,6 @@ struct zynqmp_disp;
struct zynqmp_dpsub;
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);
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,
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_disp_get_audio_clk_rate(dp->dpsub->disp);
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);
......@@ -1261,7 +1261,7 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp,
}
/* 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_USER_PIX_WIDTH, 1);
......@@ -1372,7 +1372,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_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_PHY_POWER_DOWN, 0);
if (dp->status == connector_status_connected) {
......@@ -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);
zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN,
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);
pm_runtime_put_sync(dp->dev);
}
......
......@@ -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)
};
/* -----------------------------------------------------------------------------
* 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
*/
......@@ -214,14 +244,16 @@ static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub)
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");
if (!IS_ERR(dpsub->vid_clk))
dpsub->vid_clk_from_ps = false;
else if (PTR_ERR(dpsub->vid_clk) == -EPROBE_DEFER)
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)) {
dpsub->vid_clk = devm_clk_get(dpsub->dev, "dp_vtc_pixel_clk_in");
if (IS_ERR(dpsub->vid_clk)) {
......@@ -231,6 +263,24 @@ static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub)
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;
}
......
......@@ -35,6 +35,8 @@ enum zynqmp_dpsub_format {
* @apb_clk: The APB clock
* @vid_clk: Video clock
* @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
* @bridge: The DP encoder bridge
* @disp: The display controller
......@@ -48,6 +50,8 @@ struct zynqmp_dpsub {
struct clk *apb_clk;
struct clk *vid_clk;
bool vid_clk_from_ps;
struct clk *aud_clk;
bool aud_clk_from_ps;
struct drm_encoder encoder;
struct drm_bridge *bridge;
......@@ -63,4 +67,7 @@ static inline struct zynqmp_dpsub *to_zynqmp_dpsub(struct drm_device *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_ */
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