Commit cb22f12f authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'drm-xilinx-dpsub-20210809' of git://linuxtv.org/pinchartl/media into drm-next



- Miscellaneous fixes in ZynqMP DPSUB driver

Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Link: https://patchwork.freedesktop.org/patch/msgid/YRCSRZZV1HZYPvaG@pendragon.ideasonboard.com
parents 25fed6b3 6ebfd22c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@ config DRM_ZYNQMP_DPSUB
	depends on ARCH_ZYNQMP || COMPILE_TEST
	depends on COMMON_CLK && DRM && OF
	depends on DMADEVICES
	depends on PHY_XILINX_ZYNQMP
	depends on XILINX_ZYNQMP_DPDMA
	select DMA_ENGINE
	select DRM_GEM_CMA_HELPER
	select DRM_KMS_CMA_HELPER
+159 −161
Original line number Diff line number Diff line
@@ -91,7 +91,7 @@ struct zynqmp_disp_format {
};

/**
 * enum zynqmp_disp_id - Layer identifier
 * enum zynqmp_disp_layer_id - Layer identifier
 * @ZYNQMP_DISP_LAYER_VID: Video layer
 * @ZYNQMP_DISP_LAYER_GFX: Graphics layer
 */
@@ -158,43 +158,17 @@ struct zynqmp_disp_layer {
	enum zynqmp_disp_layer_mode mode;
};

/**
 * struct zynqmp_disp_blend - Blender
 * @base: Registers I/O base address
 */
struct zynqmp_disp_blend {
	void __iomem *base;
};

/**
 * struct zynqmp_disp_avbuf - Audio/video buffer manager
 * @base: Registers I/O base address
 */
struct zynqmp_disp_avbuf {
	void __iomem *base;
};

/**
 * struct zynqmp_disp_audio - Audio mixer
 * @base: Registers I/O base address
 * @clk: Audio clock
 * @clk_from_ps: True of the audio clock comes from PS, false from PL
 */
struct zynqmp_disp_audio {
	void __iomem *base;
	struct clk *clk;
	bool clk_from_ps;
};

/**
 * struct zynqmp_disp - Display controller
 * @dev: Device structure
 * @drm: DRM core
 * @dpsub: Display subsystem
 * @crtc: DRM CRTC
 * @blend: Blender (video rendering pipeline)
 * @avbuf: Audio/video buffer manager
 * @audio: Audio mixer
 * @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)
 * @event: Pending vblank event request
 * @pclk: Pixel clock
@@ -207,9 +181,17 @@ struct zynqmp_disp {

	struct drm_crtc crtc;

	struct zynqmp_disp_blend blend;
	struct zynqmp_disp_avbuf avbuf;
	struct zynqmp_disp_audio audio;
	struct {
		void __iomem *base;
	} blend;
	struct {
		void __iomem *base;
	} avbuf;
	struct {
		void __iomem *base;
		struct clk *clk;
		bool clk_from_ps;
	} audio;

	struct zynqmp_disp_layer layers[ZYNQMP_DISP_NUM_LAYERS];

@@ -423,51 +405,60 @@ static const struct zynqmp_disp_format avbuf_gfx_fmts[] = {
	},
};

static u32 zynqmp_disp_avbuf_read(struct zynqmp_disp_avbuf *avbuf, int reg)
static u32 zynqmp_disp_avbuf_read(struct zynqmp_disp *disp, int reg)
{
	return readl(avbuf->base + reg);
	return readl(disp->avbuf.base + reg);
}

static void zynqmp_disp_avbuf_write(struct zynqmp_disp_avbuf *avbuf,
				    int reg, u32 val)
static void zynqmp_disp_avbuf_write(struct zynqmp_disp *disp, int reg, u32 val)
{
	writel(val, avbuf->base + reg);
	writel(val, disp->avbuf.base + reg);
}

static bool zynqmp_disp_layer_is_gfx(const struct zynqmp_disp_layer *layer)
{
	return layer->id == ZYNQMP_DISP_LAYER_GFX;
}

static bool zynqmp_disp_layer_is_video(const struct zynqmp_disp_layer *layer)
{
	return layer->id == ZYNQMP_DISP_LAYER_VID;
}

/**
 * zynqmp_disp_avbuf_set_format - Set the input format for a layer
 * @avbuf: Audio/video buffer manager
 * @layer: The layer ID
 * @disp: Display controller
 * @layer: The layer
 * @fmt: The format information
 *
 * Set the video buffer manager format for @layer to @fmt.
 */
static void zynqmp_disp_avbuf_set_format(struct zynqmp_disp_avbuf *avbuf,
					 enum zynqmp_disp_layer_id layer,
static void zynqmp_disp_avbuf_set_format(struct zynqmp_disp *disp,
					 struct zynqmp_disp_layer *layer,
					 const struct zynqmp_disp_format *fmt)
{
	unsigned int i;
	u32 val;

	val = zynqmp_disp_avbuf_read(avbuf, ZYNQMP_DISP_AV_BUF_FMT);
	val &= layer == ZYNQMP_DISP_LAYER_VID
	val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_FMT);
	val &= zynqmp_disp_layer_is_video(layer)
	    ? ~ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MASK
	    : ~ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_MASK;
	val |= fmt->buf_fmt;
	zynqmp_disp_avbuf_write(avbuf, ZYNQMP_DISP_AV_BUF_FMT, val);
	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_FMT, val);

	for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_SF; i++) {
		unsigned int reg = layer == ZYNQMP_DISP_LAYER_VID
		unsigned int reg = zynqmp_disp_layer_is_video(layer)
				 ? ZYNQMP_DISP_AV_BUF_VID_COMP_SF(i)
				 : ZYNQMP_DISP_AV_BUF_GFX_COMP_SF(i);

		zynqmp_disp_avbuf_write(avbuf, reg, fmt->sf[i]);
		zynqmp_disp_avbuf_write(disp, reg, fmt->sf[i]);
	}
}

/**
 * zynqmp_disp_avbuf_set_clocks_sources - Set the clocks sources
 * @avbuf: Audio/video buffer manager
 * @disp: Display controller
 * @video_from_ps: True if the video clock originates from the PS
 * @audio_from_ps: True if the audio clock originates from the PS
 * @timings_internal: True if video timings are generated internally
@@ -477,7 +468,7 @@ static void zynqmp_disp_avbuf_set_format(struct zynqmp_disp_avbuf *avbuf,
 * generated internally or externally.
 */
static void
zynqmp_disp_avbuf_set_clocks_sources(struct zynqmp_disp_avbuf *avbuf,
zynqmp_disp_avbuf_set_clocks_sources(struct zynqmp_disp *disp,
				     bool video_from_ps, bool audio_from_ps,
				     bool timings_internal)
{
@@ -490,16 +481,16 @@ zynqmp_disp_avbuf_set_clocks_sources(struct zynqmp_disp_avbuf *avbuf,
	if (timings_internal)
		val |= ZYNQMP_DISP_AV_BUF_CLK_SRC_VID_INTERNAL_TIMING;

	zynqmp_disp_avbuf_write(avbuf, ZYNQMP_DISP_AV_BUF_CLK_SRC, val);
	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CLK_SRC, val);
}

/**
 * zynqmp_disp_avbuf_enable_channels - Enable buffer channels
 * @avbuf: Audio/video buffer manager
 * @disp: Display controller
 *
 * Enable all (video and audio) buffer channels.
 */
static void zynqmp_disp_avbuf_enable_channels(struct zynqmp_disp_avbuf *avbuf)
static void zynqmp_disp_avbuf_enable_channels(struct zynqmp_disp *disp)
{
	unsigned int i;
	u32 val;
@@ -509,7 +500,7 @@ static void zynqmp_disp_avbuf_enable_channels(struct zynqmp_disp_avbuf *avbuf)
	       ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_SHIFT);

	for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_VID_GFX_BUFFERS; i++)
		zynqmp_disp_avbuf_write(avbuf, ZYNQMP_DISP_AV_BUF_CHBUF(i),
		zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CHBUF(i),
					val);

	val = ZYNQMP_DISP_AV_BUF_CHBUF_EN |
@@ -517,75 +508,75 @@ static void zynqmp_disp_avbuf_enable_channels(struct zynqmp_disp_avbuf *avbuf)
	       ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_SHIFT);

	for (; i < ZYNQMP_DISP_AV_BUF_NUM_BUFFERS; i++)
		zynqmp_disp_avbuf_write(avbuf, ZYNQMP_DISP_AV_BUF_CHBUF(i),
		zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CHBUF(i),
					val);
}

/**
 * zynqmp_disp_avbuf_disable_channels - Disable buffer channels
 * @avbuf: Audio/video buffer manager
 * @disp: Display controller
 *
 * Disable all (video and audio) buffer channels.
 */
static void zynqmp_disp_avbuf_disable_channels(struct zynqmp_disp_avbuf *avbuf)
static void zynqmp_disp_avbuf_disable_channels(struct zynqmp_disp *disp)
{
	unsigned int i;

	for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_BUFFERS; i++)
		zynqmp_disp_avbuf_write(avbuf, ZYNQMP_DISP_AV_BUF_CHBUF(i),
		zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CHBUF(i),
					ZYNQMP_DISP_AV_BUF_CHBUF_FLUSH);
}

/**
 * zynqmp_disp_avbuf_enable_audio - Enable audio
 * @avbuf: Audio/video buffer manager
 * @disp: Display controller
 *
 * Enable all audio buffers with a non-live (memory) source.
 */
static void zynqmp_disp_avbuf_enable_audio(struct zynqmp_disp_avbuf *avbuf)
static void zynqmp_disp_avbuf_enable_audio(struct zynqmp_disp *disp)
{
	u32 val;

	val = zynqmp_disp_avbuf_read(avbuf, ZYNQMP_DISP_AV_BUF_OUTPUT);
	val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);
	val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MASK;
	val |= ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MEM;
	val |= ZYNQMP_DISP_AV_BUF_OUTPUT_AUD2_EN;
	zynqmp_disp_avbuf_write(avbuf, ZYNQMP_DISP_AV_BUF_OUTPUT, val);
	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);
}

/**
 * zynqmp_disp_avbuf_disable_audio - Disable audio
 * @avbuf: Audio/video buffer manager
 * @disp: Display controller
 *
 * Disable all audio buffers.
 */
static void zynqmp_disp_avbuf_disable_audio(struct zynqmp_disp_avbuf *avbuf)
static void zynqmp_disp_avbuf_disable_audio(struct zynqmp_disp *disp)
{
	u32 val;

	val = zynqmp_disp_avbuf_read(avbuf, ZYNQMP_DISP_AV_BUF_OUTPUT);
	val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);
	val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MASK;
	val |= ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_DISABLE;
	val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_AUD2_EN;
	zynqmp_disp_avbuf_write(avbuf, ZYNQMP_DISP_AV_BUF_OUTPUT, val);
	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);
}

/**
 * zynqmp_disp_avbuf_enable_video - Enable a video layer
 * @avbuf: Audio/video buffer manager
 * @layer: The layer ID
 * @disp: Display controller
 * @layer: The layer
 * @mode: Operating mode of layer
 *
 * Enable the video/graphics buffer for @layer.
 */
static void zynqmp_disp_avbuf_enable_video(struct zynqmp_disp_avbuf *avbuf,
					   enum zynqmp_disp_layer_id layer,
static void zynqmp_disp_avbuf_enable_video(struct zynqmp_disp *disp,
					   struct zynqmp_disp_layer *layer,
					   enum zynqmp_disp_layer_mode mode)
{
	u32 val;

	val = zynqmp_disp_avbuf_read(avbuf, ZYNQMP_DISP_AV_BUF_OUTPUT);
	if (layer == ZYNQMP_DISP_LAYER_VID) {
	val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);
	if (zynqmp_disp_layer_is_video(layer)) {
		val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MASK;
		if (mode == ZYNQMP_DISP_LAYER_NONLIVE)
			val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MEM;
@@ -599,52 +590,52 @@ static void zynqmp_disp_avbuf_enable_video(struct zynqmp_disp_avbuf *avbuf,
		else
			val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_LIVE;
	}
	zynqmp_disp_avbuf_write(avbuf, ZYNQMP_DISP_AV_BUF_OUTPUT, val);
	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);
}

/**
 * zynqmp_disp_avbuf_disable_video - Disable a video layer
 * @avbuf: Audio/video buffer manager
 * @layer: The layer ID
 * @disp: Display controller
 * @layer: The layer
 *
 * Disable the video/graphics buffer for @layer.
 */
static void zynqmp_disp_avbuf_disable_video(struct zynqmp_disp_avbuf *avbuf,
					    enum zynqmp_disp_layer_id layer)
static void zynqmp_disp_avbuf_disable_video(struct zynqmp_disp *disp,
					    struct zynqmp_disp_layer *layer)
{
	u32 val;

	val = zynqmp_disp_avbuf_read(avbuf, ZYNQMP_DISP_AV_BUF_OUTPUT);
	if (layer == ZYNQMP_DISP_LAYER_VID) {
	val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);
	if (zynqmp_disp_layer_is_video(layer)) {
		val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MASK;
		val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_NONE;
	} else {
		val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MASK;
		val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_DISABLE;
	}
	zynqmp_disp_avbuf_write(avbuf, ZYNQMP_DISP_AV_BUF_OUTPUT, val);
	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);
}

/**
 * zynqmp_disp_avbuf_enable - Enable the video pipe
 * @avbuf: Audio/video buffer manager
 * @disp: Display controller
 *
 * De-assert the video pipe reset.
 */
static void zynqmp_disp_avbuf_enable(struct zynqmp_disp_avbuf *avbuf)
static void zynqmp_disp_avbuf_enable(struct zynqmp_disp *disp)
{
	zynqmp_disp_avbuf_write(avbuf, ZYNQMP_DISP_AV_BUF_SRST_REG, 0);
	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_SRST_REG, 0);
}

/**
 * zynqmp_disp_avbuf_disable - Disable the video pipe
 * @avbuf: Audio/video buffer manager
 * @disp: Display controller
 *
 * Assert the video pipe reset.
 */
static void zynqmp_disp_avbuf_disable(struct zynqmp_disp_avbuf *avbuf)
static void zynqmp_disp_avbuf_disable(struct zynqmp_disp *disp)
{
	zynqmp_disp_avbuf_write(avbuf, ZYNQMP_DISP_AV_BUF_SRST_REG,
	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_SRST_REG,
				ZYNQMP_DISP_AV_BUF_SRST_REG_VID_RST);
}

@@ -652,10 +643,9 @@ static void zynqmp_disp_avbuf_disable(struct zynqmp_disp_avbuf *avbuf)
 * Blender (Video Pipeline)
 */

static void zynqmp_disp_blend_write(struct zynqmp_disp_blend *blend,
				    int reg, u32 val)
static void zynqmp_disp_blend_write(struct zynqmp_disp *disp, int reg, u32 val)
{
	writel(val, blend->base + reg);
	writel(val, disp->blend.base + reg);
}

/*
@@ -701,12 +691,12 @@ static const u32 csc_sdtv_to_rgb_offsets[] = {

/**
 * zynqmp_disp_blend_set_output_format - Set the output format of the blender
 * @blend: Blender object
 * @disp: Display controller
 * @format: Output format
 *
 * Set the output format of the blender to @format.
 */
static void zynqmp_disp_blend_set_output_format(struct zynqmp_disp_blend *blend,
static void zynqmp_disp_blend_set_output_format(struct zynqmp_disp *disp,
						enum zynqmp_dpsub_format format)
{
	static const unsigned int blend_output_fmts[] = {
@@ -722,7 +712,7 @@ static void zynqmp_disp_blend_set_output_format(struct zynqmp_disp_blend *blend,
	const u32 *offsets;
	unsigned int i;

	zynqmp_disp_blend_write(blend, ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT, fmt);
	zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT, fmt);
	if (fmt == ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_RGB) {
		coeffs = csc_identity_matrix;
		offsets = csc_zero_offsets;
@@ -732,19 +722,19 @@ static void zynqmp_disp_blend_set_output_format(struct zynqmp_disp_blend *blend,
	}

	for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_COEFF; i++)
		zynqmp_disp_blend_write(blend,
		zynqmp_disp_blend_write(disp,
					ZYNQMP_DISP_V_BLEND_RGB2YCBCR_COEFF(i),
					coeffs[i]);

	for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_OFFSET; i++)
		zynqmp_disp_blend_write(blend,
		zynqmp_disp_blend_write(disp,
					ZYNQMP_DISP_V_BLEND_OUTCSC_OFFSET(i),
					offsets[i]);
}

/**
 * zynqmp_disp_blend_set_bg_color - Set the background color
 * @blend: Blender object
 * @disp: Display controller
 * @rcr: Red/Cr color component
 * @gy: Green/Y color component
 * @bcb: Blue/Cb color component
@@ -753,31 +743,31 @@ static void zynqmp_disp_blend_set_output_format(struct zynqmp_disp_blend *blend,
 * B or Cr, Y and Cb components respectively depending on the selected output
 * format.
 */
static void zynqmp_disp_blend_set_bg_color(struct zynqmp_disp_blend *blend,
static void zynqmp_disp_blend_set_bg_color(struct zynqmp_disp *disp,
					   u32 rcr, u32 gy, u32 bcb)
{
	zynqmp_disp_blend_write(blend, ZYNQMP_DISP_V_BLEND_BG_CLR_0, rcr);
	zynqmp_disp_blend_write(blend, ZYNQMP_DISP_V_BLEND_BG_CLR_1, gy);
	zynqmp_disp_blend_write(blend, ZYNQMP_DISP_V_BLEND_BG_CLR_2, bcb);
	zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_BG_CLR_0, rcr);
	zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_BG_CLR_1, gy);
	zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_BG_CLR_2, bcb);
}

/**
 * zynqmp_disp_blend_set_global_alpha - Configure global alpha blending
 * @blend: Blender object
 * @disp: Display controller
 * @enable: True to enable global alpha blending
 * @alpha: Global alpha value (ignored if @enabled is false)
 */
static void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp_blend *blend,
static void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp *disp,
					       bool enable, u32 alpha)
{
	zynqmp_disp_blend_write(blend, ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA,
	zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA,
				ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_VALUE(alpha) |
				(enable ? ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_EN : 0));
}

/**
 * zynqmp_disp_blend_layer_set_csc - Configure colorspace conversion for layer
 * @blend: Blender object
 * @disp: Display controller
 * @layer: The layer
 * @coeffs: Colorspace conversion matrix
 * @offsets: Colorspace conversion offsets
@@ -786,7 +776,7 @@ static void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp_blend *blend,
 * Columns of the matrix are automatically swapped based on the input format to
 * handle RGB and YCrCb components permutations.
 */
static void zynqmp_disp_blend_layer_set_csc(struct zynqmp_disp_blend *blend,
static void zynqmp_disp_blend_layer_set_csc(struct zynqmp_disp *disp,
					    struct zynqmp_disp_layer *layer,
					    const u16 *coeffs,
					    const u32 *offsets)
@@ -807,32 +797,32 @@ static void zynqmp_disp_blend_layer_set_csc(struct zynqmp_disp_blend *blend,
		}
	}

	if (layer->id == ZYNQMP_DISP_LAYER_VID)
	if (zynqmp_disp_layer_is_video(layer))
		reg = ZYNQMP_DISP_V_BLEND_IN1CSC_COEFF(0);
	else
		reg = ZYNQMP_DISP_V_BLEND_IN2CSC_COEFF(0);

	for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_COEFF; i += 3, reg += 12) {
		zynqmp_disp_blend_write(blend, reg + 0, coeffs[i + swap[0]]);
		zynqmp_disp_blend_write(blend, reg + 4, coeffs[i + swap[1]]);
		zynqmp_disp_blend_write(blend, reg + 8, coeffs[i + swap[2]]);
		zynqmp_disp_blend_write(disp, reg + 0, coeffs[i + swap[0]]);
		zynqmp_disp_blend_write(disp, reg + 4, coeffs[i + swap[1]]);
		zynqmp_disp_blend_write(disp, reg + 8, coeffs[i + swap[2]]);
	}

	if (layer->id == ZYNQMP_DISP_LAYER_VID)
	if (zynqmp_disp_layer_is_video(layer))
		reg = ZYNQMP_DISP_V_BLEND_IN1CSC_OFFSET(0);
	else
		reg = ZYNQMP_DISP_V_BLEND_IN2CSC_OFFSET(0);

	for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_OFFSET; i++)
		zynqmp_disp_blend_write(blend, reg + i * 4, offsets[i]);
		zynqmp_disp_blend_write(disp, reg + i * 4, offsets[i]);
}

/**
 * zynqmp_disp_blend_layer_enable - Enable a layer
 * @blend: Blender object
 * @disp: Display controller
 * @layer: The layer
 */
static void zynqmp_disp_blend_layer_enable(struct zynqmp_disp_blend *blend,
static void zynqmp_disp_blend_layer_enable(struct zynqmp_disp *disp,
					   struct zynqmp_disp_layer *layer)
{
	const u16 *coeffs;
@@ -844,7 +834,7 @@ static void zynqmp_disp_blend_layer_enable(struct zynqmp_disp_blend *blend,
	      (layer->drm_fmt->hsub > 1 ?
	       ZYNQMP_DISP_V_BLEND_LAYER_CONTROL_EN_US : 0);

	zynqmp_disp_blend_write(blend,
	zynqmp_disp_blend_write(disp,
				ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id),
				val);

@@ -856,22 +846,22 @@ static void zynqmp_disp_blend_layer_enable(struct zynqmp_disp_blend *blend,
		offsets = csc_zero_offsets;
	}

	zynqmp_disp_blend_layer_set_csc(blend, layer, coeffs, offsets);
	zynqmp_disp_blend_layer_set_csc(disp, layer, coeffs, offsets);
}

/**
 * zynqmp_disp_blend_layer_disable - Disable a layer
 * @blend: Blender object
 * @disp: Display controller
 * @layer: The layer
 */
static void zynqmp_disp_blend_layer_disable(struct zynqmp_disp_blend *blend,
static void zynqmp_disp_blend_layer_disable(struct zynqmp_disp *disp,
					    struct zynqmp_disp_layer *layer)
{
	zynqmp_disp_blend_write(blend,
	zynqmp_disp_blend_write(disp,
				ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id),
				0);

	zynqmp_disp_blend_layer_set_csc(blend, layer, csc_zero_matrix,
	zynqmp_disp_blend_layer_set_csc(disp, layer, csc_zero_matrix,
					csc_zero_offsets);
}

@@ -879,57 +869,55 @@ static void zynqmp_disp_blend_layer_disable(struct zynqmp_disp_blend *blend,
 * Audio Mixer
 */

static void zynqmp_disp_audio_write(struct zynqmp_disp_audio *audio,
				  int reg, u32 val)
static void zynqmp_disp_audio_write(struct zynqmp_disp *disp, int reg, u32 val)
{
	writel(val, audio->base + reg);
	writel(val, disp->audio.base + reg);
}

/**
 * zynqmp_disp_audio_enable - Enable the audio mixer
 * @audio: Audio mixer
 * @disp: Display controller
 *
 * Enable the audio mixer by de-asserting the soft reset. The audio state is set to
 * default values by the reset, set the default mixer volume explicitly.
 */
static void zynqmp_disp_audio_enable(struct zynqmp_disp_audio *audio)
static void zynqmp_disp_audio_enable(struct zynqmp_disp *disp)
{
	/* Clear the audio soft reset register as it's an non-reset flop. */
	zynqmp_disp_audio_write(audio, ZYNQMP_DISP_AUD_SOFT_RESET, 0);
	zynqmp_disp_audio_write(audio, ZYNQMP_DISP_AUD_MIXER_VOLUME,
	zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_SOFT_RESET, 0);
	zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_MIXER_VOLUME,
				ZYNQMP_DISP_AUD_MIXER_VOLUME_NO_SCALE);
}

/**
 * zynqmp_disp_audio_disable - Disable the audio mixer
 * @audio: Audio mixer
 * @disp: Display controller
 *
 * Disable the audio mixer by asserting its soft reset.
 */
static void zynqmp_disp_audio_disable(struct zynqmp_disp_audio *audio)
static void zynqmp_disp_audio_disable(struct zynqmp_disp *disp)
{
	zynqmp_disp_audio_write(audio, ZYNQMP_DISP_AUD_SOFT_RESET,
	zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_SOFT_RESET,
				ZYNQMP_DISP_AUD_SOFT_RESET_AUD_SRST);
}

static void zynqmp_disp_audio_init(struct device *dev,
				   struct zynqmp_disp_audio *audio)
static void zynqmp_disp_audio_init(struct zynqmp_disp *disp)
{
	/* Try the live PL audio clock. */
	audio->clk = devm_clk_get(dev, "dp_live_audio_aclk");
	if (!IS_ERR(audio->clk)) {
		audio->clk_from_ps = false;
	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. */
	audio->clk = devm_clk_get(dev, "dp_aud_clk");
	if (!IS_ERR(audio->clk)) {
		audio->clk_from_ps = true;
	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(dev, "audio disabled due to missing clock\n");
	dev_err(disp->dev, "audio disabled due to missing clock\n");
}

/* -----------------------------------------------------------------------------
@@ -1025,9 +1013,9 @@ zynqmp_disp_layer_find_format(struct zynqmp_disp_layer *layer,
 */
static void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer)
{
	zynqmp_disp_avbuf_enable_video(&layer->disp->avbuf, layer->id,
	zynqmp_disp_avbuf_enable_video(layer->disp, layer,
				       ZYNQMP_DISP_LAYER_NONLIVE);
	zynqmp_disp_blend_layer_enable(&layer->disp->blend, layer);
	zynqmp_disp_blend_layer_enable(layer->disp, layer);

	layer->mode = ZYNQMP_DISP_LAYER_NONLIVE;
}
@@ -1046,8 +1034,8 @@ static void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer)
	for (i = 0; i < layer->drm_fmt->num_planes; i++)
		dmaengine_terminate_sync(layer->dmas[i].chan);

	zynqmp_disp_avbuf_disable_video(&layer->disp->avbuf, layer->id);
	zynqmp_disp_blend_layer_disable(&layer->disp->blend, layer);
	zynqmp_disp_avbuf_disable_video(layer->disp, layer);
	zynqmp_disp_blend_layer_disable(layer->disp, layer);
}

/**
@@ -1067,8 +1055,7 @@ static void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
	layer->disp_fmt = zynqmp_disp_layer_find_format(layer, info->format);
	layer->drm_fmt = info;

	zynqmp_disp_avbuf_set_format(&layer->disp->avbuf, layer->id,
				     layer->disp_fmt);
	zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);

	/*
	 * Set slave_id for each DMA channel to indicate they're part of a
@@ -1175,6 +1162,10 @@ zynqmp_disp_plane_atomic_disable(struct drm_plane *plane,
		return;

	zynqmp_disp_layer_disable(layer);

	if (zynqmp_disp_layer_is_gfx(layer))
		zynqmp_disp_blend_set_global_alpha(layer->disp, false,
						   plane->state->alpha >> 8);
}

static void
@@ -1204,6 +1195,10 @@ zynqmp_disp_plane_atomic_update(struct drm_plane *plane,

	zynqmp_disp_layer_update(layer, new_state);

	if (zynqmp_disp_layer_is_gfx(layer))
		zynqmp_disp_blend_set_global_alpha(layer->disp, true,
						   plane->state->alpha >> 8);

	/* Enable or re-enable the plane is the format has changed. */
	if (format_changed)
		zynqmp_disp_layer_enable(layer);
@@ -1244,8 +1239,8 @@ static int zynqmp_disp_create_planes(struct zynqmp_disp *disp)
			drm_formats[j] = layer->info->formats[j].drm_fmt;

		/* Graphics layer is primary, and video layer is overlay. */
		type = i == ZYNQMP_DISP_LAYER_GFX
		     ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
		type = zynqmp_disp_layer_is_video(layer)
		     ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY;
		ret = drm_universal_plane_init(disp->drm, &layer->plane, 0,
					       &zynqmp_disp_plane_funcs,
					       drm_formats,
@@ -1256,6 +1251,10 @@ static int zynqmp_disp_create_planes(struct zynqmp_disp *disp)

		drm_plane_helper_add(&layer->plane,
				     &zynqmp_disp_plane_helper_funcs);

		drm_plane_create_zpos_immutable_property(&layer->plane, i);
		if (zynqmp_disp_layer_is_gfx(layer))
			drm_plane_create_alpha_property(&layer->plane);
	}

	return 0;
@@ -1387,14 +1386,14 @@ static int zynqmp_disp_create_layers(struct zynqmp_disp *disp)
 */
static void zynqmp_disp_enable(struct zynqmp_disp *disp)
{
	zynqmp_disp_avbuf_enable(&disp->avbuf);
	zynqmp_disp_avbuf_enable(disp);
	/* Choose clock source based on the DT clock handle. */
	zynqmp_disp_avbuf_set_clocks_sources(&disp->avbuf, disp->pclk_from_ps,
	zynqmp_disp_avbuf_set_clocks_sources(disp, disp->pclk_from_ps,
					     disp->audio.clk_from_ps, true);
	zynqmp_disp_avbuf_enable_channels(&disp->avbuf);
	zynqmp_disp_avbuf_enable_audio(&disp->avbuf);
	zynqmp_disp_avbuf_enable_channels(disp);
	zynqmp_disp_avbuf_enable_audio(disp);

	zynqmp_disp_audio_enable(&disp->audio);
	zynqmp_disp_audio_enable(disp);
}

/**
@@ -1403,11 +1402,11 @@ static void zynqmp_disp_enable(struct zynqmp_disp *disp)
 */
static void zynqmp_disp_disable(struct zynqmp_disp *disp)
{
	zynqmp_disp_audio_disable(&disp->audio);
	zynqmp_disp_audio_disable(disp);

	zynqmp_disp_avbuf_disable_audio(&disp->avbuf);
	zynqmp_disp_avbuf_disable_channels(&disp->avbuf);
	zynqmp_disp_avbuf_disable(&disp->avbuf);
	zynqmp_disp_avbuf_disable_audio(disp);
	zynqmp_disp_avbuf_disable_channels(disp);
	zynqmp_disp_avbuf_disable(disp);
}

static inline struct zynqmp_disp *crtc_to_disp(struct drm_crtc *crtc)
@@ -1452,9 +1451,10 @@ zynqmp_disp_crtc_atomic_enable(struct drm_crtc *crtc,
	struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
	int ret, vrefresh;

	pm_runtime_get_sync(disp->dev);

	zynqmp_disp_crtc_setup_clock(crtc, adjusted_mode);

	pm_runtime_get_sync(disp->dev);
	ret = clk_prepare_enable(disp->pclk);
	if (ret) {
		dev_err(disp->dev, "failed to enable a pixel clock\n");
@@ -1462,10 +1462,8 @@ zynqmp_disp_crtc_atomic_enable(struct drm_crtc *crtc,
		return;
	}

	zynqmp_disp_blend_set_output_format(&disp->blend,
					    ZYNQMP_DPSUB_FORMAT_RGB);
	zynqmp_disp_blend_set_bg_color(&disp->blend, 0, 0, 0);
	zynqmp_disp_blend_set_global_alpha(&disp->blend, false, 0);
	zynqmp_disp_blend_set_output_format(disp, ZYNQMP_DPSUB_FORMAT_RGB);
	zynqmp_disp_blend_set_bg_color(disp, 0, 0, 0);

	zynqmp_disp_enable(disp);

@@ -1674,7 +1672,7 @@ int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
		disp->pclk_from_ps = true;
	}

	zynqmp_disp_audio_init(disp->dev, &disp->audio);
	zynqmp_disp_audio_init(disp);

	ret = zynqmp_disp_create_layers(disp);
	if (ret)
+12 −10
Original line number Diff line number Diff line
@@ -402,10 +402,6 @@ static int zynqmp_dp_phy_init(struct zynqmp_dp *dp)
		}
	}

	ret = zynqmp_dp_reset(dp, false);
	if (ret < 0)
		return ret;

	zynqmp_dp_clr(dp, ZYNQMP_DP_PHY_RESET, ZYNQMP_DP_PHY_RESET_ALL_RESET);

	/*
@@ -441,8 +437,6 @@ static void zynqmp_dp_phy_exit(struct zynqmp_dp *dp)
				ret);
	}

	zynqmp_dp_reset(dp, true);

	for (i = 0; i < dp->num_lanes; i++) {
		ret = phy_exit(dp->phy[i]);
		if (ret)
@@ -1683,9 +1677,13 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
		return PTR_ERR(dp->reset);
	}

	ret = zynqmp_dp_reset(dp, false);
	if (ret < 0)
		return ret;

	ret = zynqmp_dp_phy_probe(dp);
	if (ret)
		return ret;
		goto err_reset;

	/* Initialize the hardware. */
	zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN,
@@ -1697,7 +1695,7 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)

	ret = zynqmp_dp_phy_init(dp);
	if (ret)
		return ret;
		goto err_reset;

	zynqmp_dp_write(dp, ZYNQMP_DP_TRANSMITTER_ENABLE, 1);

@@ -1709,15 +1707,18 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
					zynqmp_dp_irq_handler, IRQF_ONESHOT,
					dev_name(dp->dev), dp);
	if (ret < 0)
		goto error;
		goto err_phy_exit;

	dev_dbg(dp->dev, "ZynqMP DisplayPort Tx probed with %u lanes\n",
		dp->num_lanes);

	return 0;

error:
err_phy_exit:
	zynqmp_dp_phy_exit(dp);
err_reset:
	zynqmp_dp_reset(dp, true);

	return ret;
}

@@ -1735,4 +1736,5 @@ void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub)
	zynqmp_dp_write(dp, ZYNQMP_DP_INT_DS, 0xffffffff);

	zynqmp_dp_phy_exit(dp);
	zynqmp_dp_reset(dp, true);
}