Skip to content

Commit

Permalink
drm/vc4: crtc: Assign output to channel automatically
Browse files Browse the repository at this point in the history
The HVS found in the BCM2711 has 6 outputs and 3 FIFOs, with each output
being connected to a pixelvalve, and some muxing between the FIFOs and
outputs.

Any output cannot feed from any FIFO though, and they all have a bunch of
constraints.

In order to support this, let's store the possible FIFOs each output can be
assigned to in the vc4_crtc_data, and use that information at atomic_check
time to iterate over all the CRTCs enabled and assign them FIFOs.

The channel assigned is then set in the vc4_crtc_state so that the rest of
the driver can use it.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Tested-by: Chanwoo Choi <cw00.choi@samsung.com>
Tested-by: Hoegeun Kwon <hoegeun.kwon@samsung.com>
Tested-by: Stefan Wahren <stefan.wahren@i2se.com>
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Link: https://patchwork.freedesktop.org/patch/msgid/f9aba3814ef37156ff36f310118cdd3954dd3dc5.1599120059.git-series.maxime@cerno.tech
  • Loading branch information
Maxime Ripard committed Sep 7, 2020
1 parent 5963566 commit 87ebcd4
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 26 deletions.
12 changes: 8 additions & 4 deletions drivers/gpu/drm/vc4/vc4_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc,
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state);
unsigned int cob_size;
u32 val;
int fifo_lines;
Expand All @@ -104,7 +105,7 @@ 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(vc4_crtc->channel));
val = HVS_READ(SCALER_DISPSTATX(vc4_crtc_state->assigned_channel));

/* Get optional system timestamp after query. */
if (etime)
Expand All @@ -124,7 +125,7 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc,
*hpos += mode->crtc_htotal / 2;
}

cob_size = vc4_crtc_get_cob_allocation(vc4, vc4_crtc->channel);
cob_size = vc4_crtc_get_cob_allocation(vc4, vc4_crtc_state->assigned_channel);
/* This is the offset we need for translating hvs -> pv scanout pos. */
fifo_lines = cob_size / mode->crtc_hdisplay;

Expand Down Expand Up @@ -520,7 +521,7 @@ 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_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
u32 chan = vc4_crtc->channel;
u32 chan = vc4_state->assigned_channel;
unsigned long flags;

spin_lock_irqsave(&dev->event_lock, flags);
Expand Down Expand Up @@ -719,6 +720,7 @@ struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc)
old_vc4_state = to_vc4_crtc_state(crtc->state);
vc4_state->feed_txp = old_vc4_state->feed_txp;
vc4_state->margins = old_vc4_state->margins;
vc4_state->assigned_channel = old_vc4_state->assigned_channel;

__drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
return &vc4_state->base;
Expand Down Expand Up @@ -779,6 +781,7 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {

static const struct vc4_pv_data bcm2835_pv0_data = {
.base = {
.hvs_available_channels = BIT(0),
.hvs_output = 0,
},
.debugfs_name = "crtc0_regs",
Expand All @@ -791,6 +794,7 @@ static const struct vc4_pv_data bcm2835_pv0_data = {

static const struct vc4_pv_data bcm2835_pv1_data = {
.base = {
.hvs_available_channels = BIT(2),
.hvs_output = 2,
},
.debugfs_name = "crtc1_regs",
Expand All @@ -803,6 +807,7 @@ static const struct vc4_pv_data bcm2835_pv1_data = {

static const struct vc4_pv_data bcm2835_pv2_data = {
.base = {
.hvs_available_channels = BIT(1),
.hvs_output = 1,
},
.debugfs_name = "crtc2_regs",
Expand Down Expand Up @@ -866,7 +871,6 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc,
drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
crtc_funcs, NULL);
drm_crtc_helper_add(crtc, crtc_helper_funcs);
vc4_crtc->channel = vc4_crtc->data->hvs_output;
drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r));
drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size);

Expand Down
7 changes: 4 additions & 3 deletions drivers/gpu/drm/vc4/vc4_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,9 @@ to_vc4_encoder(struct drm_encoder *encoder)
}

struct vc4_crtc_data {
/* Bitmask of channels (FIFOs) of the HVS that the output can source from */
unsigned int hvs_available_channels;

/* Which output of the HVS this pixelvalve sources from. */
int hvs_output;
};
Expand All @@ -471,9 +474,6 @@ struct vc4_crtc {
/* Timestamp at start of vblank irq - unaffected by lock delays. */
ktime_t t_vblank;

/* Which HVS channel we're using for our CRTC. */
int channel;

u8 lut_r[256];
u8 lut_g[256];
u8 lut_b[256];
Expand Down Expand Up @@ -509,6 +509,7 @@ struct vc4_crtc_state {
struct drm_mm_node mm;
bool feed_txp;
bool txp_armed;
unsigned int assigned_channel;

struct {
unsigned int left;
Expand Down
28 changes: 13 additions & 15 deletions drivers/gpu/drm/vc4/vc4_hvs.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ static void vc4_hvs_lut_load(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
u32 i;

/* The LUT memory is laid out with each HVS channel in order,
Expand All @@ -169,7 +170,7 @@ static void vc4_hvs_lut_load(struct drm_crtc *crtc)
*/
HVS_WRITE(SCALER_GAMADDR,
SCALER_GAMADDR_AUTOINC |
(vc4_crtc->channel * 3 * crtc->gamma_size));
(vc4_state->assigned_channel * 3 * crtc->gamma_size));

for (i = 0; i < crtc->gamma_size; i++)
HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_r[i]);
Expand Down Expand Up @@ -249,12 +250,12 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
crtc->state->event = NULL;
}

HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
vc4_state->mm.start);

spin_unlock_irqrestore(&dev->event_lock, flags);
} else {
HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
vc4_state->mm.start);
}
}
Expand All @@ -264,7 +265,6 @@ void vc4_hvs_atomic_enable(struct drm_crtc *crtc,
{
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
struct drm_display_mode *mode = &crtc->state->adjusted_mode;
bool oneshot = vc4_state->feed_txp;
Expand Down Expand Up @@ -292,16 +292,16 @@ void vc4_hvs_atomic_enable(struct drm_crtc *crtc,
SCALER5_DISPCTRLX_HEIGHT) |
(oneshot ? SCALER5_DISPCTRLX_ONESHOT : 0);

HVS_WRITE(SCALER_DISPCTRLX(vc4_crtc->channel), dispctrl);
HVS_WRITE(SCALER_DISPCTRLX(vc4_state->assigned_channel), dispctrl);
}

void vc4_hvs_atomic_disable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
u32 chan = vc4_crtc->channel;
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(old_state);
unsigned int chan = vc4_state->assigned_channel;

if (HVS_READ(SCALER_DISPCTRLX(chan)) &
SCALER_DISPCTRLX_ENABLE) {
Expand Down Expand Up @@ -332,7 +332,6 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
{
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
struct drm_plane *plane;
struct vc4_plane_state *vc4_plane_state;
Expand Down Expand Up @@ -374,8 +373,8 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
/* This sets a black background color fill, as is the case
* with other DRM drivers.
*/
HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel),
HVS_READ(SCALER_DISPBKGNDX(vc4_crtc->channel)) |
HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel),
HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel)) |
SCALER_DISPBKGND_FILL);

/* Only update DISPLIST if the CRTC was already running and is not
Expand All @@ -389,7 +388,7 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
vc4_hvs_update_dlist(crtc);

if (crtc->state->color_mgmt_changed) {
u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_crtc->channel));
u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel));

if (crtc->state->gamma_lut) {
vc4_hvs_update_gamma_lut(crtc);
Expand All @@ -401,7 +400,7 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
*/
dispbkgndx &= ~SCALER_DISPBKGND_GAMMA;
}
HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel), dispbkgndx);
HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel), dispbkgndx);
}

if (debug_dump_regs) {
Expand All @@ -414,12 +413,11 @@ void vc4_hvs_mode_set_nofb(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
struct drm_display_mode *mode = &crtc->state->adjusted_mode;
bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;

if (vc4_crtc->data->hvs_output == 2) {
if (vc4_state->assigned_channel == 2) {
u32 dispctrl;
u32 dsp3_mux;

Expand All @@ -443,7 +441,7 @@ void vc4_hvs_mode_set_nofb(struct drm_crtc *crtc)
HVS_WRITE(SCALER_DISPCTRL, dispctrl | dsp3_mux);
}

HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel),
HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel),
SCALER_DISPBKGND_AUTOHS |
SCALER_DISPBKGND_GAMMA |
(interlace ? SCALER_DISPBKGND_INTERLACE : 0));
Expand Down
Loading

0 comments on commit 87ebcd4

Please sign in to comment.