Skip to content

Commit

Permalink
drm/vc4: hvs: Add support for BCM2712 HVS
Browse files Browse the repository at this point in the history
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: Maxime Ripard <mripard@kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20241025-drm-vc4-2712-support-v2-10-35efa83c8fc0@raspberrypi.com
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
  • Loading branch information
mripard authored and 6by9 committed Nov 27, 2024
1 parent 626ffc5 commit 7687a12
Show file tree
Hide file tree
Showing 7 changed files with 1,616 additions and 77 deletions.
47 changes: 37 additions & 10 deletions drivers/gpu/drm/vc4/vc4_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -122,7 +131,10 @@ 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.
*/
val = HVS_READ(SCALER_DISPSTATX(channel));
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. */
if (etime)
Expand All @@ -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. */
*vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE);

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) {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -807,7 +833,8 @@ 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.
*/
vc4_hvs_unmask_underrun(hvs, chan);
if (vc4->gen < VC4_GEN_6_C)
vc4_hvs_unmask_underrun(hvs, chan);
}
spin_unlock(&vc4_crtc->irq_lock);
spin_unlock_irqrestore(&dev->event_lock, flags);
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/vc4/vc4_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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" },
Expand Down Expand Up @@ -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) {
Expand Down
30 changes: 30 additions & 0 deletions drivers/gpu/drm/vc4/vc4_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -325,15 +340,23 @@ struct vc4_hvs {
unsigned int dlist_mem_size;

struct clk *core_clk;
struct clk *disp_clk;

unsigned long max_core_rate;

/* Memory manager for CRTCs to allocate space in the display
* 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;
Expand All @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
Loading

0 comments on commit 7687a12

Please sign in to comment.