summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/vc4/vc4_crtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/vc4/vc4_crtc.c')
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c368
1 files changed, 287 insertions, 81 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 6d8fa6118fc1..482219fb4db2 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -65,6 +65,20 @@ static const struct debugfs_reg32 crtc_regs[] = {
VC4_REG32(PV_HACT_ACT),
};
+static unsigned int
+vc4_crtc_get_cob_allocation(struct vc4_dev *vc4, unsigned int channel)
+{
+ u32 dispbase = HVS_READ(SCALER_DISPBASEX(channel));
+ /* 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;
+
+ return top - base + 4;
+}
+
static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc,
bool in_vblank_irq,
int *vpos, int *hpos,
@@ -74,6 +88,8 @@ 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;
int vblank_lines;
@@ -89,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)
@@ -109,8 +125,9 @@ 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_state->assigned_channel);
/* This is the offset we need for translating hvs -> pv scanout pos. */
- fifo_lines = vc4_crtc->cob_size / mode->crtc_hdisplay;
+ fifo_lines = cob_size / mode->crtc_hdisplay;
if (fifo_lines > 0)
ret = true;
@@ -189,10 +206,22 @@ void vc4_crtc_destroy(struct drm_crtc *crtc)
drm_crtc_cleanup(crtc);
}
-static u32 vc4_get_fifo_full_level(u32 format)
+static u32 vc4_get_fifo_full_level(struct vc4_crtc *vc4_crtc, u32 format)
{
- static const u32 fifo_len_bytes = 64;
+ const struct vc4_crtc_data *crtc_data = vc4_crtc_to_vc4_crtc_data(vc4_crtc);
+ const struct vc4_pv_data *pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc);
+ u32 fifo_len_bytes = pv_data->fifo_depth;
+ /*
+ * Pixels are pulled from the HVS if the number of bytes is
+ * lower than the FIFO full level.
+ *
+ * The latency of the pixel fetch mechanism is 6 pixels, so we
+ * need to convert those 6 pixels in bytes, depending on the
+ * format, and then subtract that from the length of the FIFO
+ * to make sure we never end up in a situation where the FIFO
+ * is full.
+ */
switch (format) {
case PV_CONTROL_FORMAT_DSIV_16:
case PV_CONTROL_FORMAT_DSIC_16:
@@ -202,10 +231,30 @@ static u32 vc4_get_fifo_full_level(u32 format)
case PV_CONTROL_FORMAT_24:
case PV_CONTROL_FORMAT_DSIV_24:
default:
+ /*
+ * For some reason, the pixelvalve4 doesn't work with
+ * the usual formula and will only work with 32.
+ */
+ if (crtc_data->hvs_output == 5)
+ return 32;
+
return fifo_len_bytes - 3 * HVS_FIFO_LATENCY_PIX;
}
}
+static u32 vc4_crtc_get_fifo_full_level_bits(struct vc4_crtc *vc4_crtc,
+ u32 format)
+{
+ u32 level = vc4_get_fifo_full_level(vc4_crtc, format);
+ u32 ret = 0;
+
+ ret |= VC4_SET_FIELD((level >> 6),
+ PV5_CONTROL_FIFO_LEVEL_HIGH);
+
+ return ret | VC4_SET_FIELD(level & 0x3f,
+ PV_CONTROL_FIFO_LEVEL);
+}
+
/*
* Returns the encoder attached to the CRTC.
*
@@ -230,11 +279,23 @@ static struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc)
return NULL;
}
+static void vc4_crtc_pixelvalve_reset(struct drm_crtc *crtc)
+{
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+
+ /* The PV needs to be disabled before it can be flushed */
+ CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) & ~PV_CONTROL_EN);
+ CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | PV_CONTROL_FIFO_CLR);
+}
+
static void vc4_crtc_config_pv(struct drm_crtc *crtc)
{
+ struct drm_device *dev = crtc->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc);
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+ const struct vc4_pv_data *pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc);
struct drm_crtc_state *state = crtc->state;
struct drm_display_mode *mode = &state->adjusted_mode;
bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;
@@ -242,24 +303,29 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc)
bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 ||
vc4_encoder->type == VC4_ENCODER_TYPE_DSI1);
u32 format = is_dsi ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
+ u8 ppc = pv_data->pixels_per_clock;
+ bool debug_dump_regs = false;
- /* Reset the PV fifo. */
- CRTC_WRITE(PV_CONTROL, 0);
- CRTC_WRITE(PV_CONTROL, PV_CONTROL_FIFO_CLR | PV_CONTROL_EN);
- CRTC_WRITE(PV_CONTROL, 0);
+ if (debug_dump_regs) {
+ struct drm_printer p = drm_info_printer(&vc4_crtc->pdev->dev);
+ dev_info(&vc4_crtc->pdev->dev, "CRTC %d regs before:\n",
+ drm_crtc_index(crtc));
+ drm_print_regset32(&p, &vc4_crtc->regset);
+ }
+
+ vc4_crtc_pixelvalve_reset(crtc);
CRTC_WRITE(PV_HORZA,
- VC4_SET_FIELD((mode->htotal -
- mode->hsync_end) * pixel_rep,
+ VC4_SET_FIELD((mode->htotal - mode->hsync_end) * pixel_rep / ppc,
PV_HORZA_HBP) |
- VC4_SET_FIELD((mode->hsync_end -
- mode->hsync_start) * pixel_rep,
+ VC4_SET_FIELD((mode->hsync_end - mode->hsync_start) * pixel_rep / ppc,
PV_HORZA_HSYNC));
+
CRTC_WRITE(PV_HORZB,
- VC4_SET_FIELD((mode->hsync_start -
- mode->hdisplay) * pixel_rep,
+ VC4_SET_FIELD((mode->hsync_start - mode->hdisplay) * pixel_rep / ppc,
PV_HORZB_HFP) |
- VC4_SET_FIELD(mode->hdisplay * pixel_rep, PV_HORZB_HACTIVE));
+ VC4_SET_FIELD(mode->hdisplay * pixel_rep / ppc,
+ PV_HORZB_HACTIVE));
CRTC_WRITE(PV_VERTA,
VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
@@ -306,35 +372,20 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc)
if (is_dsi)
CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep);
- CRTC_WRITE(PV_CONTROL,
+ if (vc4->hvs->hvs5)
+ CRTC_WRITE(PV_MUX_CFG,
+ VC4_SET_FIELD(PV_MUX_CFG_RGB_PIXEL_MUX_MODE_NO_SWAP,
+ PV_MUX_CFG_RGB_PIXEL_MUX_MODE));
+
+ CRTC_WRITE(PV_CONTROL, PV_CONTROL_FIFO_CLR |
+ vc4_crtc_get_fifo_full_level_bits(vc4_crtc, format) |
VC4_SET_FIELD(format, PV_CONTROL_FORMAT) |
- VC4_SET_FIELD(vc4_get_fifo_full_level(format),
- PV_CONTROL_FIFO_LEVEL) |
VC4_SET_FIELD(pixel_rep - 1, PV_CONTROL_PIXEL_REP) |
PV_CONTROL_CLR_AT_START |
PV_CONTROL_TRIGGER_UNDERFLOW |
PV_CONTROL_WAIT_HSTART |
VC4_SET_FIELD(vc4_encoder->clock_select,
- PV_CONTROL_CLK_SELECT) |
- PV_CONTROL_FIFO_CLR |
- PV_CONTROL_EN);
-}
-
-static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
-{
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
- bool debug_dump_regs = false;
-
- if (debug_dump_regs) {
- struct drm_printer p = drm_info_printer(&vc4_crtc->pdev->dev);
- dev_info(&vc4_crtc->pdev->dev, "CRTC %d regs before:\n",
- drm_crtc_index(crtc));
- drm_print_regset32(&p, &vc4_crtc->regset);
- }
-
- vc4_crtc_config_pv(crtc);
-
- vc4_hvs_mode_set_nofb(crtc);
+ PV_CONTROL_CLK_SELECT));
if (debug_dump_regs) {
struct drm_printer p = drm_info_printer(&vc4_crtc->pdev->dev);
@@ -352,24 +403,86 @@ static void require_hvs_enabled(struct drm_device *dev)
SCALER_DISPCTRL_ENABLE);
}
+static int vc4_crtc_disable(struct drm_crtc *crtc, unsigned int channel)
+{
+ struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc);
+ struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ int ret;
+
+ CRTC_WRITE(PV_V_CONTROL,
+ CRTC_READ(PV_V_CONTROL) & ~PV_VCONTROL_VIDEN);
+ ret = wait_for(!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN), 1);
+ WARN_ONCE(ret, "Timeout waiting for !PV_VCONTROL_VIDEN\n");
+
+ /*
+ * This delay is needed to avoid to get a pixel stuck in an
+ * unflushable FIFO between the pixelvalve and the HDMI
+ * controllers on the BCM2711.
+ *
+ * Timing is fairly sensitive here, so mdelay is the safest
+ * approach.
+ *
+ * If it was to be reworked, the stuck pixel happens on a
+ * BCM2711 when changing mode with a good probability, so a
+ * script that changes mode on a regular basis should trigger
+ * the bug after less than 10 attempts. It manifests itself with
+ * every pixels being shifted by one to the right, and thus the
+ * last pixel of a line actually being displayed as the first
+ * pixel on the next line.
+ */
+ mdelay(20);
+
+ if (vc4_encoder && vc4_encoder->post_crtc_disable)
+ vc4_encoder->post_crtc_disable(encoder);
+
+ vc4_crtc_pixelvalve_reset(crtc);
+ vc4_hvs_stop_channel(dev, channel);
+
+ if (vc4_encoder && vc4_encoder->post_crtc_powerdown)
+ vc4_encoder->post_crtc_powerdown(encoder);
+
+ return 0;
+}
+
+int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
+{
+ struct drm_device *drm = crtc->dev;
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+ int channel;
+
+ if (!(of_device_is_compatible(vc4_crtc->pdev->dev.of_node,
+ "brcm,bcm2711-pixelvalve2") ||
+ of_device_is_compatible(vc4_crtc->pdev->dev.of_node,
+ "brcm,bcm2711-pixelvalve4")))
+ return 0;
+
+ if (!(CRTC_READ(PV_CONTROL) & PV_CONTROL_EN))
+ return 0;
+
+ if (!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN))
+ return 0;
+
+ channel = vc4_hvs_get_fifo_from_output(drm, vc4_crtc->data->hvs_output);
+ if (channel < 0)
+ return 0;
+
+ return vc4_crtc_disable(crtc, channel);
+}
+
static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
+ struct vc4_crtc_state *old_vc4_state = to_vc4_crtc_state(old_state);
struct drm_device *dev = crtc->dev;
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
- int ret;
require_hvs_enabled(dev);
/* Disable vblank irq handling before crtc is disabled. */
drm_crtc_vblank_off(crtc);
- CRTC_WRITE(PV_V_CONTROL,
- CRTC_READ(PV_V_CONTROL) & ~PV_VCONTROL_VIDEN);
- ret = wait_for(!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN), 1);
- WARN_ONCE(ret, "Timeout waiting for !PV_VCONTROL_VIDEN\n");
-
- vc4_hvs_atomic_disable(crtc, old_state);
+ vc4_crtc_disable(crtc, old_vc4_state->assigned_channel);
/*
* Make sure we issue a vblank event after disabling the CRTC if
@@ -390,6 +503,8 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
{
struct drm_device *dev = crtc->dev;
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+ struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc);
+ struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
require_hvs_enabled(dev);
@@ -400,11 +515,24 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
vc4_hvs_atomic_enable(crtc, old_state);
+ if (vc4_encoder->pre_crtc_configure)
+ vc4_encoder->pre_crtc_configure(encoder);
+
+ vc4_crtc_config_pv(crtc);
+
+ CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | PV_CONTROL_EN);
+
+ if (vc4_encoder->pre_crtc_enable)
+ vc4_encoder->pre_crtc_enable(encoder);
+
/* When feeding the transposer block the pixelvalve is unneeded and
* should not be enabled.
*/
CRTC_WRITE(PV_V_CONTROL,
CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN);
+
+ if (vc4_encoder->post_crtc_enable)
+ vc4_encoder->post_crtc_enable(encoder);
}
static enum drm_mode_status vc4_crtc_mode_valid(struct drm_crtc *crtc,
@@ -499,7 +627,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);
@@ -516,7 +644,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.
*/
- vc4_hvs_unmask_underrun(dev, vc4_crtc->channel);
+ vc4_hvs_unmask_underrun(dev, chan);
}
spin_unlock_irqrestore(&dev->event_lock, flags);
}
@@ -698,6 +826,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;
@@ -723,11 +852,19 @@ void vc4_crtc_destroy_state(struct drm_crtc *crtc,
void vc4_crtc_reset(struct drm_crtc *crtc)
{
+ struct vc4_crtc_state *vc4_crtc_state;
+
if (crtc->state)
vc4_crtc_destroy_state(crtc, crtc->state);
- crtc->state = kzalloc(sizeof(struct vc4_crtc_state), GFP_KERNEL);
- if (crtc->state)
- __drm_atomic_helper_crtc_reset(crtc, crtc->state);
+
+ vc4_crtc_state = kzalloc(sizeof(*vc4_crtc_state), GFP_KERNEL);
+ if (!vc4_crtc_state) {
+ crtc->state = NULL;
+ return;
+ }
+
+ vc4_crtc_state->assigned_channel = VC4_HVS_CHANNEL_DISABLED;
+ __drm_atomic_helper_crtc_reset(crtc, &vc4_crtc_state->base);
}
static const struct drm_crtc_funcs vc4_crtc_funcs = {
@@ -747,7 +884,6 @@ static const struct drm_crtc_funcs vc4_crtc_funcs = {
};
static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
- .mode_set_nofb = vc4_crtc_mode_set_nofb,
.mode_valid = vc4_crtc_mode_valid,
.atomic_check = vc4_crtc_atomic_check,
.atomic_flush = vc4_hvs_atomic_flush,
@@ -758,9 +894,12 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
static const struct vc4_pv_data bcm2835_pv0_data = {
.base = {
- .hvs_channel = 0,
+ .hvs_available_channels = BIT(0),
+ .hvs_output = 0,
},
.debugfs_name = "crtc0_regs",
+ .fifo_depth = 64,
+ .pixels_per_clock = 1,
.encoder_types = {
[PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0,
[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_DPI,
@@ -769,9 +908,12 @@ static const struct vc4_pv_data bcm2835_pv0_data = {
static const struct vc4_pv_data bcm2835_pv1_data = {
.base = {
- .hvs_channel = 2,
+ .hvs_available_channels = BIT(2),
+ .hvs_output = 2,
},
.debugfs_name = "crtc1_regs",
+ .fifo_depth = 64,
+ .pixels_per_clock = 1,
.encoder_types = {
[PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1,
[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_SMI,
@@ -780,19 +922,94 @@ static const struct vc4_pv_data bcm2835_pv1_data = {
static const struct vc4_pv_data bcm2835_pv2_data = {
.base = {
- .hvs_channel = 1,
+ .hvs_available_channels = BIT(1),
+ .hvs_output = 1,
},
.debugfs_name = "crtc2_regs",
+ .fifo_depth = 64,
+ .pixels_per_clock = 1,
.encoder_types = {
- [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI,
+ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI0,
[PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC,
},
};
+static const struct vc4_pv_data bcm2711_pv0_data = {
+ .base = {
+ .hvs_available_channels = BIT(0),
+ .hvs_output = 0,
+ },
+ .debugfs_name = "crtc0_regs",
+ .fifo_depth = 64,
+ .pixels_per_clock = 1,
+ .encoder_types = {
+ [0] = VC4_ENCODER_TYPE_DSI0,
+ [1] = VC4_ENCODER_TYPE_DPI,
+ },
+};
+
+static const struct vc4_pv_data bcm2711_pv1_data = {
+ .base = {
+ .hvs_available_channels = BIT(0) | BIT(1) | BIT(2),
+ .hvs_output = 3,
+ },
+ .debugfs_name = "crtc1_regs",
+ .fifo_depth = 64,
+ .pixels_per_clock = 1,
+ .encoder_types = {
+ [0] = VC4_ENCODER_TYPE_DSI1,
+ [1] = VC4_ENCODER_TYPE_SMI,
+ },
+};
+
+static const struct vc4_pv_data bcm2711_pv2_data = {
+ .base = {
+ .hvs_available_channels = BIT(0) | BIT(1) | BIT(2),
+ .hvs_output = 4,
+ },
+ .debugfs_name = "crtc2_regs",
+ .fifo_depth = 256,
+ .pixels_per_clock = 2,
+ .encoder_types = {
+ [0] = VC4_ENCODER_TYPE_HDMI0,
+ },
+};
+
+static const struct vc4_pv_data bcm2711_pv3_data = {
+ .base = {
+ .hvs_available_channels = BIT(1),
+ .hvs_output = 1,
+ },
+ .debugfs_name = "crtc3_regs",
+ .fifo_depth = 64,
+ .pixels_per_clock = 1,
+ .encoder_types = {
+ [0] = VC4_ENCODER_TYPE_VEC,
+ },
+};
+
+static const struct vc4_pv_data bcm2711_pv4_data = {
+ .base = {
+ .hvs_available_channels = BIT(0) | BIT(1) | BIT(2),
+ .hvs_output = 5,
+ },
+ .debugfs_name = "crtc4_regs",
+ .fifo_depth = 64,
+ .pixels_per_clock = 2,
+ .encoder_types = {
+ [0] = VC4_ENCODER_TYPE_HDMI1,
+ },
+};
+
static const struct of_device_id vc4_crtc_dt_match[] = {
{ .compatible = "brcm,bcm2835-pixelvalve0", .data = &bcm2835_pv0_data },
{ .compatible = "brcm,bcm2835-pixelvalve1", .data = &bcm2835_pv1_data },
{ .compatible = "brcm,bcm2835-pixelvalve2", .data = &bcm2835_pv2_data },
+ { .compatible = "brcm,bcm2711-pixelvalve0", .data = &bcm2711_pv0_data },
+ { .compatible = "brcm,bcm2711-pixelvalve1", .data = &bcm2711_pv1_data },
+ { .compatible = "brcm,bcm2711-pixelvalve2", .data = &bcm2711_pv2_data },
+ { .compatible = "brcm,bcm2711-pixelvalve3", .data = &bcm2711_pv3_data },
+ { .compatible = "brcm,bcm2711-pixelvalve4", .data = &bcm2711_pv4_data },
{}
};
@@ -819,26 +1036,11 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm,
}
}
-static void
-vc4_crtc_get_cob_allocation(struct vc4_crtc *vc4_crtc)
-{
- struct drm_device *drm = vc4_crtc->base.dev;
- struct vc4_dev *vc4 = to_vc4_dev(drm);
- u32 dispbase = HVS_READ(SCALER_DISPBASEX(vc4_crtc->channel));
- /* 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;
-
- vc4_crtc->cob_size = top - base + 4;
-}
-
int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc,
const struct drm_crtc_funcs *crtc_funcs,
const struct drm_crtc_helper_funcs *crtc_helper_funcs)
{
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
struct drm_crtc *crtc = &vc4_crtc->base;
struct drm_plane *primary_plane;
unsigned int i;
@@ -858,15 +1060,17 @@ 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_channel;
- drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r));
- drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size);
- /* We support CTM, but only for one CRTC at a time. It's therefore
- * implemented as private driver state in vc4_kms, not here.
- */
- drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size);
- vc4_crtc_get_cob_allocation(vc4_crtc);
+ if (!vc4->hvs->hvs5) {
+ drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r));
+
+ drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size);
+
+ /* We support CTM, but only for one CRTC at a time. It's therefore
+ * implemented as private driver state in vc4_kms, not here.
+ */
+ drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size);
+ }
for (i = 0; i < crtc->gamma_size; i++) {
vc4_crtc->lut_r[i] = i;
@@ -915,7 +1119,9 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
CRTC_WRITE(PV_INTEN, 0);
CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START);
ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
- vc4_crtc_irq_handler, 0, "vc4 crtc", vc4_crtc);
+ vc4_crtc_irq_handler,
+ IRQF_SHARED,
+ "vc4 crtc", vc4_crtc);
if (ret)
goto err_destroy_planes;