Commit c979296e authored by Laurent Pinchart's avatar Laurent Pinchart
Browse files

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
Loading
Loading
Loading
Loading
+2 −52
Original line number Diff line number Diff line
@@ -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;
+0 −2
Original line number Diff line number Diff line
@@ -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);
+4 −4
Original line number Diff line number Diff line
@@ -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);
}
+52 −2
Original line number Diff line number Diff line
@@ -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;
}

+7 −0
Original line number Diff line number Diff line
@@ -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_ */