Commit 7687a121 authored by Maxime Ripard's avatar Maxime Ripard Committed by Dave Stevenson
Browse files

drm/vc4: hvs: Add support for BCM2712 HVS



The HVS found in the BCM2712, while having a similar role, is very
different from the one found in the previous SoCs. Indeed, the register
layout is fairly different, and the DLIST format is new as well.

Let's introduce the needed functions to support the new HVS.

This commit adds the C-step register layout. The D-step will be
added later.

Signed-off-by: default avatarMaxime Ripard <mripard@kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20241025-drm-vc4-2712-support-v2-10-35efa83c8fc0@raspberrypi.com


Signed-off-by: default avatarDave Stevenson <dave.stevenson@raspberrypi.com>
parent 626ffc5f
Loading
Loading
Loading
Loading
+37 −10
Original line number Diff line number Diff line
@@ -83,13 +83,22 @@ static unsigned int
vc4_crtc_get_cob_allocation(struct vc4_dev *vc4, unsigned int channel)
{
	struct vc4_hvs *hvs = vc4->hvs;
	u32 dispbase = HVS_READ(SCALER_DISPBASEX(channel));
	u32 dispbase, top, base;

	/* Top/base are supposed to be 4-pixel aligned, but the
	 * Raspberry Pi firmware fills the low bits (which are
	 * presumably ignored).
	 */
	u32 top = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_TOP) & ~3;
	u32 base = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_BASE) & ~3;

	if (vc4->gen >= VC4_GEN_6_C) {
		dispbase = HVS_READ(SCALER6_DISPX_COB(channel));
		top = VC4_GET_FIELD(dispbase, SCALER6_DISPX_COB_TOP) & ~3;
		base = VC4_GET_FIELD(dispbase, SCALER6_DISPX_COB_BASE) & ~3;
	} else {
		dispbase = HVS_READ(SCALER_DISPBASEX(channel));
		top = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_TOP) & ~3;
		base = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_BASE) & ~3;
	}

	return top - base + 4;
}
@@ -122,6 +131,9 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc,
	 * Read vertical scanline which is currently composed for our
	 * pixelvalve by the HVS, and also the scaler status.
	 */
	if (vc4->gen >= VC4_GEN_6_C)
		val = HVS_READ(SCALER6_DISPX_STATUS(channel));
	else
		val = HVS_READ(SCALER_DISPSTATX(channel));

	/* Get optional system timestamp after query. */
@@ -131,7 +143,12 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc,
	/* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */

	/* Vertical position of hvs composed scanline. */

	if (vc4->gen >= VC4_GEN_6_C)
		*vpos = VC4_GET_FIELD(val, SCALER6_DISPX_STATUS_YLINE);
	else
		*vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE);

	*hpos = 0;

	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
@@ -459,8 +476,10 @@ static void require_hvs_enabled(struct drm_device *dev)
	struct vc4_dev *vc4 = to_vc4_dev(dev);
	struct vc4_hvs *hvs = vc4->hvs;

	WARN_ON_ONCE((HVS_READ(SCALER_DISPCTRL) & SCALER_DISPCTRL_ENABLE) !=
		     SCALER_DISPCTRL_ENABLE);
	if (vc4->gen >= VC4_GEN_6_C)
		WARN_ON_ONCE(!(HVS_READ(SCALER6_CONTROL) & SCALER6_CONTROL_HVS_EN));
	else
		WARN_ON_ONCE(!(HVS_READ(SCALER_DISPCTRL) & SCALER_DISPCTRL_ENABLE));
}

static int vc4_crtc_disable(struct drm_crtc *crtc,
@@ -789,14 +808,21 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
	struct drm_device *dev = crtc->dev;
	struct vc4_dev *vc4 = to_vc4_dev(dev);
	struct vc4_hvs *hvs = vc4->hvs;
	unsigned int current_dlist;
	u32 chan = vc4_crtc->current_hvs_channel;
	unsigned long flags;

	spin_lock_irqsave(&dev->event_lock, flags);
	spin_lock(&vc4_crtc->irq_lock);

	if (vc4->gen >= VC4_GEN_6_C)
		current_dlist = VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_DL(chan)),
					      SCALER6_DISPX_DL_LACT);
	else
		current_dlist = HVS_READ(SCALER_DISPLACTX(chan));

	if (vc4_crtc->event &&
	    (vc4_crtc->current_dlist == HVS_READ(SCALER_DISPLACTX(chan)) ||
	     vc4_crtc->feeds_txp)) {
	    (vc4_crtc->current_dlist == current_dlist || vc4_crtc->feeds_txp)) {
		drm_crtc_send_vblank_event(crtc, vc4_crtc->event);
		vc4_crtc->event = NULL;
		drm_crtc_vblank_put(crtc);
@@ -807,6 +833,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
		 * the CRTC and encoder already reconfigured, leading to
		 * underruns. This can be seen when reconfiguring the CRTC.
		 */
		if (vc4->gen < VC4_GEN_6_C)
			vc4_hvs_unmask_underrun(hvs, chan);
	}
	spin_unlock(&vc4_crtc->irq_lock);
+6 −0
Original line number Diff line number Diff line
@@ -279,6 +279,7 @@ static void vc4_component_unbind_all(void *ptr)

static const struct of_device_id vc4_dma_range_matches[] = {
	{ .compatible = "brcm,bcm2711-hvs" },
	{ .compatible = "brcm,bcm2712-hvs" },
	{ .compatible = "brcm,bcm2835-hvs" },
	{ .compatible = "brcm,bcm2835-v3d" },
	{ .compatible = "brcm,cygnus-v3d" },
@@ -307,6 +308,11 @@ static int vc4_drm_bind(struct device *dev)
	else
		driver = &vc4_drm_driver;

	if (gen >= VC4_GEN_6_C)
		dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
	else
		dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));

	node = of_find_matching_node_and_match(NULL, vc4_dma_range_matches,
					       NULL);
	if (node) {
+30 −0
Original line number Diff line number Diff line
@@ -317,6 +317,21 @@ struct vc4_v3d {
	struct debugfs_regset32 regset;
};

#define VC4_NUM_UPM_HANDLES 32
struct vc4_upm_refcounts {
	refcount_t refcount;

	/* Allocation size */
	size_t size;
	/* Our allocation in UPM for prefetching. */
	struct drm_mm_node upm;

	/* Pointer back to the HVS structure */
	struct vc4_hvs *hvs;
};

#define HVS_NUM_CHANNELS 3

struct vc4_hvs {
	struct vc4_dev *vc4;
	struct platform_device *pdev;
@@ -325,6 +340,7 @@ struct vc4_hvs {
	unsigned int dlist_mem_size;

	struct clk *core_clk;
	struct clk *disp_clk;

	unsigned long max_core_rate;

@@ -332,8 +348,15 @@ struct vc4_hvs {
	 * list.  Units are dwords.
	 */
	struct drm_mm dlist_mm;

	/* Memory manager for the LBM memory used by HVS scaling. */
	struct drm_mm lbm_mm;

	/* Memory manager for the UPM memory used for prefetching. */
	struct drm_mm upm_mm;
	struct ida upm_handles;
	struct vc4_upm_refcounts upm_refcounts[VC4_NUM_UPM_HANDLES + 1];

	spinlock_t mm_lock;

	struct drm_mm_node mitchell_netravali_filter;
@@ -356,6 +379,7 @@ struct vc4_hvs {
};

#define HVS_NUM_CHANNELS 3
#define HVS_UBM_WORD_SIZE 256

struct vc4_hvs_state {
	struct drm_private_state base;
@@ -425,6 +449,12 @@ struct vc4_plane_state {
	/* Our allocation in LBM for temporary storage during scaling. */
	struct drm_mm_node lbm;

	/* The Unified Pre-Fetcher Handle */
	unsigned int upm_handle[DRM_FORMAT_MAX_PLANES];

	/* Number of lines to pre-fetch */
	unsigned int upm_buffer_lines;

	/* Set when the plane has per-pixel alpha content or does not cover
	 * the entire screen. This is a hint to the CRTC that it might need
	 * to enable background color fill.
+531 −33

File changed.

Preview size limit exceeded, changes collapsed.

+84 −14

File changed.

Preview size limit exceeded, changes collapsed.

Loading