diff options
| author | Dave Airlie <airlied@redhat.com> | 2016-09-02 01:50:19 -0400 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2016-09-02 01:50:19 -0400 |
| commit | 2c07d5a8b827364af27df4bd6e669705d182be12 (patch) | |
| tree | 77dbb564a99350bfe2d07939b1ac1e66b0bfa265 /drivers/gpu/drm/vc4 | |
| parent | 2b2fd56d7e92f134ecaae5c89e20f64dd0f95aa2 (diff) | |
| parent | 67f13690f447841fb3d2f952a6e49b2b28ae379b (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.c | 52 | ||||
| -rw-r--r-- | drivers/gpu/drm/vc4/vc4_dpi.c | 11 | ||||
| -rw-r--r-- | drivers/gpu/drm/vc4/vc4_gem.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/vc4/vc4_hdmi.c | 29 |
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 | |||
| 536 | static 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 | ||
| 535 | static int vc4_crtc_atomic_check(struct drm_crtc *crtc, | 560 | 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 = { | |||
| 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 | ||
| 343 | static 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 | |||
| 343 | static const struct drm_encoder_helper_funcs vc4_dpi_encoder_helper_funcs = { | 353 | static 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 | ||
| 348 | static const struct of_device_id vc4_dpi_dt_match[] = { | 359 | 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: | |||
| 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 | */ | ||
| 216 | static 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 | |||
| 211 | static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { | 236 | static 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); |
