aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vc4
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2016-09-02 01:50:19 -0400
committerDave Airlie <airlied@redhat.com>2016-09-02 01:50:19 -0400
commit2c07d5a8b827364af27df4bd6e669705d182be12 (patch)
tree77dbb564a99350bfe2d07939b1ac1e66b0bfa265 /drivers/gpu/drm/vc4
parent2b2fd56d7e92f134ecaae5c89e20f64dd0f95aa2 (diff)
parent67f13690f447841fb3d2f952a6e49b2b28ae379b (diff)
Merge tag 'drm-vc4-next-2016-08-29' of https://github.com/anholt/linux into drm-next
This pull request brings in interlaced vblank timing and a 3D rendering memory/CPU overhead reduction. * tag 'drm-vc4-next-2016-08-29' of https://github.com/anholt/linux: drm/vc4: Don't force new binner overflow allocation per draw. drm/vc4: Enable/Disable vblanks properly in crtc en/disable. drm/vc4: Enable precise vblank timestamping for interlaced modes. drm/vc4: Reject doublescan modes. drm/vc4: Fix handling of interlaced video modes. drm/vc4: Disallow interlaced modes on DPI.
Diffstat (limited to 'drivers/gpu/drm/vc4')
-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
4 files changed, 77 insertions, 19 deletions
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,
163 int vblank_lines; 163 int vblank_lines;
164 int ret = 0; 164 int ret = 0;
165 165
166 /*
167 * XXX Doesn't work well in interlaced mode yet, partially due
168 * to problems in vc4 kms or drm core interlaced mode handling,
169 * so disable for now in interlaced mode.
170 */
171 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
172 return ret;
173
174 /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ 166 /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
175 167
176 /* Get optional system timestamp before query. */ 168 /* Get optional system timestamp before query. */
@@ -191,10 +183,15 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
191 183
192 /* Vertical position of hvs composed scanline. */ 184 /* Vertical position of hvs composed scanline. */
193 *vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE); 185 *vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE);
186 *hpos = 0;
194 187
195 /* No hpos info available. */ 188 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
196 if (hpos) 189 *vpos /= 2;
197 *hpos = 0; 190
191 /* Use hpos to correct for field offset in interlaced mode. */
192 if (VC4_GET_FIELD(val, SCALER_DISPSTATX_FRAME_COUNT) % 2)
193 *hpos += mode->crtc_htotal / 2;
194 }
198 195
199 /* This is the offset we need for translating hvs -> pv scanout pos. */ 196 /* This is the offset we need for translating hvs -> pv scanout pos. */
200 fifo_lines = vc4_crtc->cob_size / mode->crtc_hdisplay; 197 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,
217 * position of the PV. 214 * position of the PV.
218 */ 215 */
219 *vpos -= fifo_lines + 1; 216 *vpos -= fifo_lines + 1;
220 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
221 *vpos /= 2;
222 217
223 ret |= DRM_SCANOUTPOS_ACCURATE; 218 ret |= DRM_SCANOUTPOS_ACCURATE;
224 return ret; 219 return ret;
@@ -480,6 +475,9 @@ static void vc4_crtc_disable(struct drm_crtc *crtc)
480 int ret; 475 int ret;
481 require_hvs_enabled(dev); 476 require_hvs_enabled(dev);
482 477
478 /* Disable vblank irq handling before crtc is disabled. */
479 drm_crtc_vblank_off(crtc);
480
483 CRTC_WRITE(PV_V_CONTROL, 481 CRTC_WRITE(PV_V_CONTROL,
484 CRTC_READ(PV_V_CONTROL) & ~PV_VCONTROL_VIDEN); 482 CRTC_READ(PV_V_CONTROL) & ~PV_VCONTROL_VIDEN);
485 ret = wait_for(!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN), 1); 483 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)
530 /* Turn on the pixel valve, which will emit the vstart signal. */ 528 /* Turn on the pixel valve, which will emit the vstart signal. */
531 CRTC_WRITE(PV_V_CONTROL, 529 CRTC_WRITE(PV_V_CONTROL,
532 CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); 530 CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN);
531
532 /* Enable vblank irq handling after crtc is started. */
533 drm_crtc_vblank_on(crtc);
534}
535
536static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc,
537 const struct drm_display_mode *mode,
538 struct drm_display_mode *adjusted_mode)
539{
540 /* Do not allow doublescan modes from user space */
541 if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) {
542 DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
543 crtc->base.id);
544 return false;
545 }
546
547 /*
548 * Interlaced video modes got CRTC_INTERLACE_HALVE_V applied when
549 * coming from user space. We don't want this, as it screws up
550 * vblank timestamping, so fix it up.
551 */
552 drm_mode_set_crtcinfo(adjusted_mode, 0);
553
554 DRM_DEBUG_KMS("[CRTC:%d] adjusted_mode :\n", crtc->base.id);
555 drm_mode_debug_printmodeline(adjusted_mode);
556
557 return true;
533} 558}
534 559
535static int vc4_crtc_atomic_check(struct drm_crtc *crtc, 560static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
@@ -819,6 +844,7 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
819 .mode_set_nofb = vc4_crtc_mode_set_nofb, 844 .mode_set_nofb = vc4_crtc_mode_set_nofb,
820 .disable = vc4_crtc_disable, 845 .disable = vc4_crtc_disable,
821 .enable = vc4_crtc_enable, 846 .enable = vc4_crtc_enable,
847 .mode_fixup = vc4_crtc_mode_fixup,
822 .atomic_check = vc4_crtc_atomic_check, 848 .atomic_check = vc4_crtc_atomic_check,
823 .atomic_flush = vc4_crtc_atomic_flush, 849 .atomic_flush = vc4_crtc_atomic_flush,
824}; 850};
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)
340 } 340 }
341} 341}
342 342
343static bool vc4_dpi_encoder_mode_fixup(struct drm_encoder *encoder,
344 const struct drm_display_mode *mode,
345 struct drm_display_mode *adjusted_mode)
346{
347 if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
348 return false;
349
350 return true;
351}
352
343static const struct drm_encoder_helper_funcs vc4_dpi_encoder_helper_funcs = { 353static const struct drm_encoder_helper_funcs vc4_dpi_encoder_helper_funcs = {
344 .disable = vc4_dpi_encoder_disable, 354 .disable = vc4_dpi_encoder_disable,
345 .enable = vc4_dpi_encoder_enable, 355 .enable = vc4_dpi_encoder_enable,
356 .mode_fixup = vc4_dpi_encoder_mode_fixup,
346}; 357};
347 358
348static const struct of_device_id vc4_dpi_dt_match[] = { 359static 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:
419 419
420 vc4_flush_caches(dev); 420 vc4_flush_caches(dev);
421 421
422 /* Disable the binner's pre-loaded overflow memory address */
423 V3D_WRITE(V3D_BPOA, 0);
424 V3D_WRITE(V3D_BPOS, 0);
425
426 /* Either put the job in the binner if it uses the binner, or 422 /* Either put the job in the binner if it uses the binner, or
427 * immediately move it to the to-be-rendered queue. 423 * immediately move it to the to-be-rendered queue.
428 */ 424 */
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)
208 return ret; 208 return ret;
209} 209}
210 210
211/*
212 * drm_helper_probe_single_connector_modes() applies drm_mode_set_crtcinfo to
213 * all modes with flag CRTC_INTERLACE_HALVE_V. We don't want this, as it
214 * screws up vblank timestamping for interlaced modes, so fix it up.
215 */
216static int vc4_hdmi_connector_probe_modes(struct drm_connector *connector,
217 uint32_t maxX, uint32_t maxY)
218{
219 struct drm_display_mode *mode;
220 int count;
221
222 count = drm_helper_probe_single_connector_modes(connector, maxX, maxY);
223 if (count == 0)
224 return 0;
225
226 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed adapted modes :\n",
227 connector->base.id, connector->name);
228 list_for_each_entry(mode, &connector->modes, head) {
229 drm_mode_set_crtcinfo(mode, 0);
230 drm_mode_debug_printmodeline(mode);
231 }
232
233 return count;
234}
235
211static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { 236static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
212 .dpms = drm_atomic_helper_connector_dpms, 237 .dpms = drm_atomic_helper_connector_dpms,
213 .detect = vc4_hdmi_connector_detect, 238 .detect = vc4_hdmi_connector_detect,
214 .fill_modes = drm_helper_probe_single_connector_modes, 239 .fill_modes = vc4_hdmi_connector_probe_modes,
215 .destroy = vc4_hdmi_connector_destroy, 240 .destroy = vc4_hdmi_connector_destroy,
216 .reset = drm_atomic_helper_connector_reset, 241 .reset = drm_atomic_helper_connector_reset,
217 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 242 .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,
246 connector->polled = (DRM_CONNECTOR_POLL_CONNECT | 271 connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
247 DRM_CONNECTOR_POLL_DISCONNECT); 272 DRM_CONNECTOR_POLL_DISCONNECT);
248 273
249 connector->interlace_allowed = 0; 274 connector->interlace_allowed = 1;
250 connector->doublescan_allowed = 0; 275 connector->doublescan_allowed = 0;
251 276
252 drm_mode_connector_attach_encoder(connector, encoder); 277 drm_mode_connector_attach_encoder(connector, encoder);