Skip to content

Commit

Permalink
drm/vc4: hvs: Support 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.

Signed-off-by: Maxime Ripard <[email protected]>
  • Loading branch information
mripard authored and popcornmix committed Jan 2, 2024
1 parent b05bc9f commit 1ab1fbb
Show file tree
Hide file tree
Showing 7 changed files with 1,540 additions and 82 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) {
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)
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)
*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 @@ -476,8 +493,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)
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 @@ -805,14 +824,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)
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 @@ -823,7 +849,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)
vc4_hvs_unmask_underrun(hvs, chan);
}
spin_unlock(&vc4_crtc->irq_lock);
spin_unlock_irqrestore(&dev->event_lock, flags);
Expand Down
8 changes: 6 additions & 2 deletions drivers/gpu/drm/vc4/vc4_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,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 = "raspberrypi,rpi-firmware-kms" },
{ .compatible = "brcm,bcm2835-v3d" },
Expand Down Expand Up @@ -307,8 +308,6 @@ static int vc4_drm_bind(struct device *dev)
enum vc4_gen gen;
int ret = 0;

dev->coherent_dma_mask = DMA_BIT_MASK(32);

if (of_device_is_compatible(dev->of_node, "brcm,bcm2712-vc6"))
gen = VC4_GEN_6;
else if (of_device_is_compatible(dev->of_node, "brcm,bcm2711-vc5"))
Expand All @@ -321,6 +320,11 @@ static int vc4_drm_bind(struct device *dev)
else
driver = &vc4_drm_driver;

if (gen >= VC4_GEN_6)
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
18 changes: 18 additions & 0 deletions drivers/gpu/drm/vc4/vc4_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,10 @@ struct vc4_hvs {
unsigned int dlist_mem_size;

struct clk *core_clk;
struct clk *disp_clk;

struct {
unsigned int desc;
unsigned int enabled: 1;
} eof_irq[HVS_NUM_CHANNELS];

Expand All @@ -344,6 +346,11 @@ struct vc4_hvs {
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;

spinlock_t mm_lock;

struct list_head stale_dlist_entries;
Expand All @@ -368,6 +375,8 @@ struct vc4_hvs {
bool vc5_hdmi_enable_4096by2160;
};

#define HVS_UBM_WORD_SIZE 256

struct vc4_hvs_state {
struct drm_private_state base;
unsigned long core_clock_rate;
Expand Down Expand Up @@ -436,6 +445,15 @@ struct vc4_plane_state {
/* Our allocation in LBM for temporary storage during scaling. */
struct drm_mm_node lbm;

/* Our allocation in UPM for prefetching. */
struct drm_mm_node upm[DRM_FORMAT_MAX_PLANES];

/* 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 1ab1fbb

Please sign in to comment.