aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt22
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_crtc.c12
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c57
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.h5
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_external.c9
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_external.h2
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_panel.c2
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_plane.c9
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_regs.h14
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_tfp410.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c52
-rw-r--r--drivers/gpu/drm/vc4/vc4_dpi.c11
-rw-r--r--drivers/gpu/drm/vc4/vc4_gem.c4
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c29
14 files changed, 181 insertions, 49 deletions
diff --git a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt
index 6efa4c55d118..a5007aa437f3 100644
--- a/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt
+++ b/Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt
@@ -17,6 +17,18 @@ Optional properties:
the lcd controller.
- max-pixelclock: The maximum pixel clock that can be supported
by the lcd controller in KHz.
+ - blue-and-red-wiring: Recognized values "default", "straight" or
+ "crossed". This property deals with the LCDC revision 2 (found on
+ AM335x) color errata [1].
+ - "straight" indicates normal wiring that supports RGB565,
+ BGR888, and XBGR8888 color formats.
+ - "crossed" indicates wiring that has blue and red wires
+ crossed. This setup supports BGR565, RGB888 and XRGB8888
+ formats.
+ - If the property is not present or its value is not recognized
+ the legacy mode is assumed. This configuration supports RGB565,
+ RGB888 and XRGB8888 formats. However, depending on wiring, the red
+ and blue colors are swapped in either 16 or 24-bit color modes.
Optional nodes:
@@ -28,6 +40,14 @@ Optional nodes:
Documentation/devicetree/bindings/display/tilcdc/tfp410.txt for connecting
tfp410 DVI encoder or lcd panel to lcdc
+[1] There is an errata about AM335x color wiring. For 16-bit color mode
+ the wires work as they should (LCD_DATA[0:4] is for Blue[3:7]),
+ but for 24 bit color modes the wiring of blue and red components is
+ crossed and LCD_DATA[0:4] is for Red[3:7] and LCD_DATA[11:15] is
+ for Blue[3-7]. For more details see section 3.1.1 in AM335x
+ Silicon Errata:
+ http://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=sprz360
+
Example:
fb: fb@4830e000 {
@@ -37,6 +57,8 @@ Example:
interrupts = <36>;
ti,hwmods = "lcdc";
+ blue-and-red-wiring = "crossed";
+
port {
lcdc_0: endpoint@0 {
remote-endpoint = <&hdmi_0>;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 25d6b220ee8a..208768922030 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -69,6 +69,7 @@ static void set_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb)
struct drm_gem_cma_object *gem;
unsigned int depth, bpp;
dma_addr_t start, end;
+ u64 dma_base_and_ceiling;
drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp);
gem = drm_fb_cma_get_gem_obj(fb, 0);
@@ -79,8 +80,13 @@ static void set_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb)
end = start + (crtc->mode.vdisplay * fb->pitches[0]);
- tilcdc_write(dev, LCDC_DMA_FB_BASE_ADDR_0_REG, start);
- tilcdc_write(dev, LCDC_DMA_FB_CEILING_ADDR_0_REG, end);
+ /* Write LCDC_DMA_FB_BASE_ADDR_0_REG and LCDC_DMA_FB_CEILING_ADDR_0_REG
+ * with a single insruction, if available. This should make it more
+ * unlikely that LCDC would fetch the DMA addresses in the middle of
+ * an update.
+ */
+ dma_base_and_ceiling = (u64)(end - 1) << 32 | start;
+ tilcdc_write64(dev, LCDC_DMA_FB_BASE_ADDR_0_REG, dma_base_and_ceiling);
if (tilcdc_crtc->curr_fb)
drm_flip_work_queue(&tilcdc_crtc->unref_work,
@@ -98,6 +104,8 @@ static void tilcdc_crtc_enable_irqs(struct drm_device *dev)
if (priv->rev == 1) {
tilcdc_set(dev, LCDC_RASTER_CTRL_REG,
LCDC_V1_UNDERFLOW_INT_ENA);
+ tilcdc_set(dev, LCDC_DMA_CTRL_REG,
+ LCDC_V1_END_OF_FRAME_INT_ENA);
} else {
tilcdc_write(dev, LCDC_INT_ENABLE_SET_REG,
LCDC_V2_UNDERFLOW_INT_ENA |
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 4405e4bc8056..f8892e9ad169 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -33,6 +33,20 @@
static LIST_HEAD(module_list);
+static const u32 tilcdc_rev1_formats[] = { DRM_FORMAT_RGB565 };
+
+static const u32 tilcdc_straight_formats[] = { DRM_FORMAT_RGB565,
+ DRM_FORMAT_BGR888,
+ DRM_FORMAT_XBGR8888 };
+
+static const u32 tilcdc_crossed_formats[] = { DRM_FORMAT_BGR565,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_XRGB8888 };
+
+static const u32 tilcdc_legacy_formats[] = { DRM_FORMAT_RGB565,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_XRGB8888 };
+
void tilcdc_module_init(struct tilcdc_module *mod, const char *name,
const struct tilcdc_module_ops *funcs)
{
@@ -226,7 +240,6 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
struct platform_device *pdev = dev->platformdev;
struct device_node *node = pdev->dev.of_node;
struct tilcdc_drm_private *priv;
- struct tilcdc_module *mod;
struct resource *res;
u32 bpp = 0;
int ret;
@@ -318,6 +331,37 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
pm_runtime_put_sync(dev->dev);
+ if (priv->rev == 1) {
+ DBG("Revision 1 LCDC supports only RGB565 format");
+ priv->pixelformats = tilcdc_rev1_formats;
+ priv->num_pixelformats = ARRAY_SIZE(tilcdc_rev1_formats);
+ bpp = 16;
+ } else {
+ const char *str = "\0";
+
+ of_property_read_string(node, "blue-and-red-wiring", &str);
+ if (0 == strcmp(str, "crossed")) {
+ DBG("Configured for crossed blue and red wires");
+ priv->pixelformats = tilcdc_crossed_formats;
+ priv->num_pixelformats =
+ ARRAY_SIZE(tilcdc_crossed_formats);
+ bpp = 32; /* Choose bpp with RGB support for fbdef */
+ } else if (0 == strcmp(str, "straight")) {
+ DBG("Configured for straight blue and red wires");
+ priv->pixelformats = tilcdc_straight_formats;
+ priv->num_pixelformats =
+ ARRAY_SIZE(tilcdc_straight_formats);
+ bpp = 16; /* Choose bpp with RGB support for fbdef */
+ } else {
+ DBG("Blue and red wiring '%s' unknown, use legacy mode",
+ str);
+ priv->pixelformats = tilcdc_legacy_formats;
+ priv->num_pixelformats =
+ ARRAY_SIZE(tilcdc_legacy_formats);
+ bpp = 16; /* This is just a guess */
+ }
+ }
+
ret = modeset_init(dev);
if (ret < 0) {
dev_err(dev->dev, "failed to initialize mode setting\n");
@@ -331,7 +375,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
if (ret < 0)
goto fail_mode_config_cleanup;
- ret = tilcdc_add_external_encoders(dev, &bpp);
+ ret = tilcdc_add_external_encoders(dev);
if (ret < 0)
goto fail_component_cleanup;
}
@@ -354,15 +398,6 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
goto fail_vblank_cleanup;
}
- list_for_each_entry(mod, &module_list, list) {
- DBG("%s: preferred_bpp: %d", mod->name, mod->preferred_bpp);
- bpp = mod->preferred_bpp;
- if (bpp > 0)
- break;
- }
-
- drm_helper_disable_unused_functions(dev);
-
drm_mode_config_reset(dev);
priv->fbdev = drm_fbdev_cma_init(dev, bpp,
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index 13001df7dbe8..a6e5e6d4970c 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -65,6 +65,10 @@ struct tilcdc_drm_private {
*/
uint32_t max_width;
+ /* Supported pixel formats */
+ const uint32_t *pixelformats;
+ uint32_t num_pixelformats;
+
/* The context for pm susped/resume cycle is stored here */
struct drm_atomic_state *saved_state;
@@ -112,7 +116,6 @@ struct tilcdc_module {
const char *name;
struct list_head list;
const struct tilcdc_module_ops *funcs;
- unsigned int preferred_bpp;
};
void tilcdc_module_init(struct tilcdc_module *mod, const char *name,
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c
index ad3db4d30b49..68e895021005 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c
@@ -52,7 +52,7 @@ static int tilcdc_external_mode_valid(struct drm_connector *connector,
return MODE_OK;
}
-static int tilcdc_add_external_encoder(struct drm_device *dev, int *bpp,
+static int tilcdc_add_external_encoder(struct drm_device *dev,
struct drm_connector *connector)
{
struct tilcdc_drm_private *priv = dev->dev_private;
@@ -64,7 +64,6 @@ static int tilcdc_add_external_encoder(struct drm_device *dev, int *bpp,
/* Only tda998x is supported at the moment. */
tilcdc_crtc_set_simulate_vesa_sync(priv->crtc, true);
tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_tda998x);
- *bpp = panel_info_tda998x.bpp;
connector_funcs = devm_kzalloc(dev->dev, sizeof(*connector_funcs),
GFP_KERNEL);
@@ -94,7 +93,7 @@ static int tilcdc_add_external_encoder(struct drm_device *dev, int *bpp,
return 0;
}
-int tilcdc_add_external_encoders(struct drm_device *dev, int *bpp)
+int tilcdc_add_external_encoders(struct drm_device *dev)
{
struct tilcdc_drm_private *priv = dev->dev_private;
struct drm_connector *connector;
@@ -108,7 +107,7 @@ int tilcdc_add_external_encoders(struct drm_device *dev, int *bpp)
if (connector == priv->connectors[i])
found = true;
if (!found) {
- ret = tilcdc_add_external_encoder(dev, bpp, connector);
+ ret = tilcdc_add_external_encoder(dev, connector);
if (ret)
return ret;
}
@@ -154,7 +153,7 @@ int tilcdc_get_external_components(struct device *dev,
while ((ep = of_graph_get_next_endpoint(dev->of_node, ep))) {
node = of_graph_get_remote_port_parent(ep);
- if (!node && !of_device_is_available(node)) {
+ if (!node || !of_device_is_available(node)) {
of_node_put(node);
continue;
}
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.h b/drivers/gpu/drm/tilcdc/tilcdc_external.h
index 6aabe2788760..c700e0c1623e 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.h
@@ -18,7 +18,7 @@
#ifndef __TILCDC_EXTERNAL_H__
#define __TILCDC_EXTERNAL_H__
-int tilcdc_add_external_encoders(struct drm_device *dev, int *bpp);
+int tilcdc_add_external_encoders(struct drm_device *dev);
void tilcdc_remove_external_encoders(struct drm_device *dev);
int tilcdc_get_external_components(struct device *dev,
struct component_match **match);
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c
index 4ac1d25eb79b..7b3650901930 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c
@@ -397,8 +397,6 @@ static int panel_probe(struct platform_device *pdev)
goto fail_timings;
}
- mod->preferred_bpp = panel_mod->info->bpp;
-
return 0;
fail_timings:
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_plane.c b/drivers/gpu/drm/tilcdc/tilcdc_plane.c
index 41911e3110e8..74c65fa859b2 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_plane.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_plane.c
@@ -24,10 +24,6 @@
#include "tilcdc_drv.h"
-static const u32 tilcdc_formats[] = { DRM_FORMAT_RGB565,
- DRM_FORMAT_RGB888,
- DRM_FORMAT_XRGB8888 };
-
static struct drm_plane_funcs tilcdc_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
@@ -114,12 +110,13 @@ static const struct drm_plane_helper_funcs plane_helper_funcs = {
int tilcdc_plane_init(struct drm_device *dev,
struct drm_plane *plane)
{
+ struct tilcdc_drm_private *priv = dev->dev_private;
int ret;
ret = drm_plane_init(dev, plane, 1,
&tilcdc_plane_funcs,
- tilcdc_formats,
- ARRAY_SIZE(tilcdc_formats),
+ priv->pixelformats,
+ priv->num_pixelformats,
true);
if (ret) {
dev_err(dev->dev, "Failed to initialize plane: %d\n", ret);
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_regs.h b/drivers/gpu/drm/tilcdc/tilcdc_regs.h
index 1bf5e2553acc..f57c0d62c76a 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_regs.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_regs.h
@@ -119,6 +119,20 @@ static inline void tilcdc_write(struct drm_device *dev, u32 reg, u32 data)
iowrite32(data, priv->mmio + reg);
}
+static inline void tilcdc_write64(struct drm_device *dev, u32 reg, u64 data)
+{
+ struct tilcdc_drm_private *priv = dev->dev_private;
+ volatile void __iomem *addr = priv->mmio + reg;
+
+#ifdef iowrite64
+ iowrite64(data, addr);
+#else
+ __iowmb();
+ /* This compiles to strd (=64-bit write) on ARM7 */
+ *(volatile u64 __force *)addr = __cpu_to_le64(data);
+#endif
+}
+
static inline u32 tilcdc_read(struct drm_device *dev, u32 reg)
{
struct tilcdc_drm_private *priv = dev->dev_private;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
index 741c7b5b8302..c6a70da6473d 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
@@ -327,8 +327,6 @@ static int tfp410_probe(struct platform_device *pdev)
goto fail;
}
- mod->preferred_bpp = dvi_info.bpp;
-
i2c_node = of_find_node_by_phandle(i2c_phandle);
if (!i2c_node) {
dev_err(&pdev->dev, "could not get i2c bus node\n");
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 8fc2b731b59a..2682f07d8f1e 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -163,14 +163,6 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
int vblank_lines;
int ret = 0;
- /*
- * XXX Doesn't work well in interlaced mode yet, partially due
- * to problems in vc4 kms or drm core interlaced mode handling,
- * so disable for now in interlaced mode.
- */
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
- return ret;
-
/* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
/* Get optional system timestamp before query. */
@@ -191,10 +183,15 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
/* Vertical position of hvs composed scanline. */
*vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE);
+ *hpos = 0;
- /* No hpos info available. */
- if (hpos)
- *hpos = 0;
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ *vpos /= 2;
+
+ /* Use hpos to correct for field offset in interlaced mode. */
+ if (VC4_GET_FIELD(val, SCALER_DISPSTATX_FRAME_COUNT) % 2)
+ *hpos += mode->crtc_htotal / 2;
+ }
/* This is the offset we need for translating hvs -> pv scanout pos. */
fifo_lines = vc4_crtc->cob_size / mode->crtc_hdisplay;
@@ -217,8 +214,6 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
* position of the PV.
*/
*vpos -= fifo_lines + 1;
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
- *vpos /= 2;
ret |= DRM_SCANOUTPOS_ACCURATE;
return ret;
@@ -480,6 +475,9 @@ static void vc4_crtc_disable(struct drm_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);
@@ -530,6 +528,33 @@ static void vc4_crtc_enable(struct drm_crtc *crtc)
/* Turn on the pixel valve, which will emit the vstart signal. */
CRTC_WRITE(PV_V_CONTROL,
CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN);
+
+ /* Enable vblank irq handling after crtc is started. */
+ drm_crtc_vblank_on(crtc);
+}
+
+static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ /* Do not allow doublescan modes from user space */
+ if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) {
+ DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
+ crtc->base.id);
+ return false;
+ }
+
+ /*
+ * Interlaced video modes got CRTC_INTERLACE_HALVE_V applied when
+ * coming from user space. We don't want this, as it screws up
+ * vblank timestamping, so fix it up.
+ */
+ drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+ DRM_DEBUG_KMS("[CRTC:%d] adjusted_mode :\n", crtc->base.id);
+ drm_mode_debug_printmodeline(adjusted_mode);
+
+ return true;
}
static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
@@ -819,6 +844,7 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
.mode_set_nofb = vc4_crtc_mode_set_nofb,
.disable = vc4_crtc_disable,
.enable = vc4_crtc_enable,
+ .mode_fixup = vc4_crtc_mode_fixup,
.atomic_check = vc4_crtc_atomic_check,
.atomic_flush = vc4_crtc_atomic_flush,
};
diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c
index 275fedbdbd9e..1e1f6b8184d0 100644
--- a/drivers/gpu/drm/vc4/vc4_dpi.c
+++ b/drivers/gpu/drm/vc4/vc4_dpi.c
@@ -340,9 +340,20 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder)
}
}
+static bool vc4_dpi_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
+ return false;
+
+ return true;
+}
+
static const struct drm_encoder_helper_funcs vc4_dpi_encoder_helper_funcs = {
.disable = vc4_dpi_encoder_disable,
.enable = vc4_dpi_encoder_enable,
+ .mode_fixup = vc4_dpi_encoder_mode_fixup,
};
static const struct of_device_id vc4_dpi_dt_match[] = {
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index 6155e8aca1c6..27c52ec35193 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -419,10 +419,6 @@ again:
vc4_flush_caches(dev);
- /* Disable the binner's pre-loaded overflow memory address */
- V3D_WRITE(V3D_BPOA, 0);
- V3D_WRITE(V3D_BPOS, 0);
-
/* Either put the job in the binner if it uses the binner, or
* immediately move it to the to-be-rendered queue.
*/
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 4452f3631cac..68ad10634b29 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -208,10 +208,35 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
return ret;
}
+/*
+ * drm_helper_probe_single_connector_modes() applies drm_mode_set_crtcinfo to
+ * all modes with flag CRTC_INTERLACE_HALVE_V. We don't want this, as it
+ * screws up vblank timestamping for interlaced modes, so fix it up.
+ */
+static int vc4_hdmi_connector_probe_modes(struct drm_connector *connector,
+ uint32_t maxX, uint32_t maxY)
+{
+ struct drm_display_mode *mode;
+ int count;
+
+ count = drm_helper_probe_single_connector_modes(connector, maxX, maxY);
+ if (count == 0)
+ return 0;
+
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed adapted modes :\n",
+ connector->base.id, connector->name);
+ list_for_each_entry(mode, &connector->modes, head) {
+ drm_mode_set_crtcinfo(mode, 0);
+ drm_mode_debug_printmodeline(mode);
+ }
+
+ return count;
+}
+
static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.detect = vc4_hdmi_connector_detect,
- .fill_modes = drm_helper_probe_single_connector_modes,
+ .fill_modes = vc4_hdmi_connector_probe_modes,
.destroy = vc4_hdmi_connector_destroy,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -246,7 +271,7 @@ static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev,
connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT);
- connector->interlace_allowed = 0;
+ connector->interlace_allowed = 1;
connector->doublescan_allowed = 0;
drm_mode_connector_attach_encoder(connector, encoder);