diff options
| -rw-r--r-- | drivers/gpu/drm/vc4/vc4_crtc.c | 64 | ||||
| -rw-r--r-- | drivers/gpu/drm/vc4/vc4_drv.h | 30 | ||||
| -rw-r--r-- | drivers/gpu/drm/vc4/vc4_gem.c | 13 | ||||
| -rw-r--r-- | drivers/gpu/drm/vc4/vc4_hdmi.c | 231 | ||||
| -rw-r--r-- | drivers/gpu/drm/vc4/vc4_regs.h | 19 | ||||
| -rw-r--r-- | drivers/gpu/drm/vc4/vc4_render_cl.c | 21 | ||||
| -rw-r--r-- | drivers/gpu/drm/vc4/vc4_validate.c | 17 |
7 files changed, 306 insertions, 89 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 2682f07d8f1e..7f08d681a74b 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c | |||
| @@ -229,7 +229,7 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, | |||
| 229 | * and need to make things up in a approximative but consistent way. | 229 | * and need to make things up in a approximative but consistent way. |
| 230 | */ | 230 | */ |
| 231 | ret |= DRM_SCANOUTPOS_IN_VBLANK; | 231 | ret |= DRM_SCANOUTPOS_IN_VBLANK; |
| 232 | vblank_lines = mode->crtc_vtotal - mode->crtc_vdisplay; | 232 | vblank_lines = mode->vtotal - mode->vdisplay; |
| 233 | 233 | ||
| 234 | if (flags & DRM_CALLED_FROM_VBLIRQ) { | 234 | if (flags & DRM_CALLED_FROM_VBLIRQ) { |
| 235 | /* | 235 | /* |
| @@ -378,7 +378,7 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) | |||
| 378 | struct drm_crtc_state *state = crtc->state; | 378 | struct drm_crtc_state *state = crtc->state; |
| 379 | struct drm_display_mode *mode = &state->adjusted_mode; | 379 | struct drm_display_mode *mode = &state->adjusted_mode; |
| 380 | bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; | 380 | bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; |
| 381 | u32 vactive = (mode->vdisplay >> (interlace ? 1 : 0)); | 381 | u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1; |
| 382 | u32 format = PV_CONTROL_FORMAT_24; | 382 | u32 format = PV_CONTROL_FORMAT_24; |
| 383 | bool debug_dump_regs = false; | 383 | bool debug_dump_regs = false; |
| 384 | int clock_select = vc4_get_clock_select(crtc); | 384 | int clock_select = vc4_get_clock_select(crtc); |
| @@ -394,47 +394,65 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) | |||
| 394 | CRTC_WRITE(PV_CONTROL, 0); | 394 | CRTC_WRITE(PV_CONTROL, 0); |
| 395 | 395 | ||
| 396 | CRTC_WRITE(PV_HORZA, | 396 | CRTC_WRITE(PV_HORZA, |
| 397 | VC4_SET_FIELD(mode->htotal - mode->hsync_end, | 397 | VC4_SET_FIELD((mode->htotal - |
| 398 | mode->hsync_end) * pixel_rep, | ||
| 398 | PV_HORZA_HBP) | | 399 | PV_HORZA_HBP) | |
| 399 | VC4_SET_FIELD(mode->hsync_end - mode->hsync_start, | 400 | VC4_SET_FIELD((mode->hsync_end - |
| 401 | mode->hsync_start) * pixel_rep, | ||
| 400 | PV_HORZA_HSYNC)); | 402 | PV_HORZA_HSYNC)); |
| 401 | CRTC_WRITE(PV_HORZB, | 403 | CRTC_WRITE(PV_HORZB, |
| 402 | VC4_SET_FIELD(mode->hsync_start - mode->hdisplay, | 404 | VC4_SET_FIELD((mode->hsync_start - |
| 405 | mode->hdisplay) * pixel_rep, | ||
| 403 | PV_HORZB_HFP) | | 406 | PV_HORZB_HFP) | |
| 404 | VC4_SET_FIELD(mode->hdisplay, PV_HORZB_HACTIVE)); | 407 | VC4_SET_FIELD(mode->hdisplay * pixel_rep, PV_HORZB_HACTIVE)); |
| 405 | 408 | ||
| 406 | CRTC_WRITE(PV_VERTA, | 409 | CRTC_WRITE(PV_VERTA, |
| 407 | VC4_SET_FIELD(mode->vtotal - mode->vsync_end, | 410 | VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end, |
| 408 | PV_VERTA_VBP) | | 411 | PV_VERTA_VBP) | |
| 409 | VC4_SET_FIELD(mode->vsync_end - mode->vsync_start, | 412 | VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start, |
| 410 | PV_VERTA_VSYNC)); | 413 | PV_VERTA_VSYNC)); |
| 411 | CRTC_WRITE(PV_VERTB, | 414 | CRTC_WRITE(PV_VERTB, |
| 412 | VC4_SET_FIELD(mode->vsync_start - mode->vdisplay, | 415 | VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay, |
| 413 | PV_VERTB_VFP) | | 416 | PV_VERTB_VFP) | |
| 414 | VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE)); | 417 | VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE)); |
| 415 | 418 | ||
| 416 | if (interlace) { | 419 | if (interlace) { |
| 417 | CRTC_WRITE(PV_VERTA_EVEN, | 420 | CRTC_WRITE(PV_VERTA_EVEN, |
| 418 | VC4_SET_FIELD(mode->vtotal - mode->vsync_end - 1, | 421 | VC4_SET_FIELD(mode->crtc_vtotal - |
| 422 | mode->crtc_vsync_end - 1, | ||
| 419 | PV_VERTA_VBP) | | 423 | PV_VERTA_VBP) | |
| 420 | VC4_SET_FIELD(mode->vsync_end - mode->vsync_start, | 424 | VC4_SET_FIELD(mode->crtc_vsync_end - |
| 425 | mode->crtc_vsync_start, | ||
| 421 | PV_VERTA_VSYNC)); | 426 | PV_VERTA_VSYNC)); |
| 422 | CRTC_WRITE(PV_VERTB_EVEN, | 427 | CRTC_WRITE(PV_VERTB_EVEN, |
| 423 | VC4_SET_FIELD(mode->vsync_start - mode->vdisplay, | 428 | VC4_SET_FIELD(mode->crtc_vsync_start - |
| 429 | mode->crtc_vdisplay, | ||
| 424 | PV_VERTB_VFP) | | 430 | PV_VERTB_VFP) | |
| 425 | VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE)); | 431 | VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE)); |
| 432 | |||
| 433 | /* We set up first field even mode for HDMI. VEC's | ||
| 434 | * NTSC mode would want first field odd instead, once | ||
| 435 | * we support it (to do so, set ODD_FIRST and put the | ||
| 436 | * delay in VSYNCD_EVEN instead). | ||
| 437 | */ | ||
| 438 | CRTC_WRITE(PV_V_CONTROL, | ||
| 439 | PV_VCONTROL_CONTINUOUS | | ||
| 440 | PV_VCONTROL_INTERLACE | | ||
| 441 | VC4_SET_FIELD(mode->htotal * pixel_rep / 2, | ||
| 442 | PV_VCONTROL_ODD_DELAY)); | ||
| 443 | CRTC_WRITE(PV_VSYNCD_EVEN, 0); | ||
| 444 | } else { | ||
| 445 | CRTC_WRITE(PV_V_CONTROL, PV_VCONTROL_CONTINUOUS); | ||
| 426 | } | 446 | } |
| 427 | 447 | ||
| 428 | CRTC_WRITE(PV_HACT_ACT, mode->hdisplay); | 448 | CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); |
| 429 | 449 | ||
| 430 | CRTC_WRITE(PV_V_CONTROL, | ||
| 431 | PV_VCONTROL_CONTINUOUS | | ||
| 432 | (interlace ? PV_VCONTROL_INTERLACE : 0)); | ||
| 433 | 450 | ||
| 434 | CRTC_WRITE(PV_CONTROL, | 451 | CRTC_WRITE(PV_CONTROL, |
| 435 | VC4_SET_FIELD(format, PV_CONTROL_FORMAT) | | 452 | VC4_SET_FIELD(format, PV_CONTROL_FORMAT) | |
| 436 | VC4_SET_FIELD(vc4_get_fifo_full_level(format), | 453 | VC4_SET_FIELD(vc4_get_fifo_full_level(format), |
| 437 | PV_CONTROL_FIFO_LEVEL) | | 454 | PV_CONTROL_FIFO_LEVEL) | |
| 455 | VC4_SET_FIELD(pixel_rep - 1, PV_CONTROL_PIXEL_REP) | | ||
| 438 | PV_CONTROL_CLR_AT_START | | 456 | PV_CONTROL_CLR_AT_START | |
| 439 | PV_CONTROL_TRIGGER_UNDERFLOW | | 457 | PV_CONTROL_TRIGGER_UNDERFLOW | |
| 440 | PV_CONTROL_WAIT_HSTART | | 458 | PV_CONTROL_WAIT_HSTART | |
| @@ -544,16 +562,6 @@ static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc, | |||
| 544 | return false; | 562 | return false; |
| 545 | } | 563 | } |
| 546 | 564 | ||
| 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; | 565 | return true; |
| 558 | } | 566 | } |
| 559 | 567 | ||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 428e24919ef1..7c1e4d97486f 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h | |||
| @@ -122,9 +122,16 @@ to_vc4_dev(struct drm_device *dev) | |||
| 122 | struct vc4_bo { | 122 | struct vc4_bo { |
| 123 | struct drm_gem_cma_object base; | 123 | struct drm_gem_cma_object base; |
| 124 | 124 | ||
| 125 | /* seqno of the last job to render to this BO. */ | 125 | /* seqno of the last job to render using this BO. */ |
| 126 | uint64_t seqno; | 126 | uint64_t seqno; |
| 127 | 127 | ||
| 128 | /* seqno of the last job to use the RCL to write to this BO. | ||
| 129 | * | ||
| 130 | * Note that this doesn't include binner overflow memory | ||
| 131 | * writes. | ||
| 132 | */ | ||
| 133 | uint64_t write_seqno; | ||
| 134 | |||
| 128 | /* List entry for the BO's position in either | 135 | /* List entry for the BO's position in either |
| 129 | * vc4_exec_info->unref_list or vc4_dev->bo_cache.time_list | 136 | * vc4_exec_info->unref_list or vc4_dev->bo_cache.time_list |
| 130 | */ | 137 | */ |
| @@ -216,6 +223,9 @@ struct vc4_exec_info { | |||
| 216 | /* Sequence number for this bin/render job. */ | 223 | /* Sequence number for this bin/render job. */ |
| 217 | uint64_t seqno; | 224 | uint64_t seqno; |
| 218 | 225 | ||
| 226 | /* Latest write_seqno of any BO that binning depends on. */ | ||
| 227 | uint64_t bin_dep_seqno; | ||
| 228 | |||
| 219 | /* Last current addresses the hardware was processing when the | 229 | /* Last current addresses the hardware was processing when the |
| 220 | * hangcheck timer checked on us. | 230 | * hangcheck timer checked on us. |
| 221 | */ | 231 | */ |
| @@ -230,6 +240,13 @@ struct vc4_exec_info { | |||
| 230 | struct drm_gem_cma_object **bo; | 240 | struct drm_gem_cma_object **bo; |
| 231 | uint32_t bo_count; | 241 | uint32_t bo_count; |
| 232 | 242 | ||
| 243 | /* List of BOs that are being written by the RCL. Other than | ||
| 244 | * the binner temporary storage, this is all the BOs written | ||
| 245 | * by the job. | ||
| 246 | */ | ||
| 247 | struct drm_gem_cma_object *rcl_write_bo[4]; | ||
| 248 | uint32_t rcl_write_bo_count; | ||
| 249 | |||
| 233 | /* Pointers for our position in vc4->job_list */ | 250 | /* Pointers for our position in vc4->job_list */ |
| 234 | struct list_head head; | 251 | struct list_head head; |
| 235 | 252 | ||
| @@ -307,18 +324,15 @@ struct vc4_exec_info { | |||
| 307 | static inline struct vc4_exec_info * | 324 | static inline struct vc4_exec_info * |
| 308 | vc4_first_bin_job(struct vc4_dev *vc4) | 325 | vc4_first_bin_job(struct vc4_dev *vc4) |
| 309 | { | 326 | { |
| 310 | if (list_empty(&vc4->bin_job_list)) | 327 | return list_first_entry_or_null(&vc4->bin_job_list, |
| 311 | return NULL; | 328 | struct vc4_exec_info, head); |
| 312 | return list_first_entry(&vc4->bin_job_list, struct vc4_exec_info, head); | ||
| 313 | } | 329 | } |
| 314 | 330 | ||
| 315 | static inline struct vc4_exec_info * | 331 | static inline struct vc4_exec_info * |
| 316 | vc4_first_render_job(struct vc4_dev *vc4) | 332 | vc4_first_render_job(struct vc4_dev *vc4) |
| 317 | { | 333 | { |
| 318 | if (list_empty(&vc4->render_job_list)) | 334 | return list_first_entry_or_null(&vc4->render_job_list, |
| 319 | return NULL; | 335 | struct vc4_exec_info, head); |
| 320 | return list_first_entry(&vc4->render_job_list, | ||
| 321 | struct vc4_exec_info, head); | ||
| 322 | } | 336 | } |
| 323 | 337 | ||
| 324 | static inline struct vc4_exec_info * | 338 | static inline struct vc4_exec_info * |
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index 77daea6cb866..47a095f392f8 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c | |||
| @@ -467,6 +467,11 @@ vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno) | |||
| 467 | list_for_each_entry(bo, &exec->unref_list, unref_head) { | 467 | list_for_each_entry(bo, &exec->unref_list, unref_head) { |
| 468 | bo->seqno = seqno; | 468 | bo->seqno = seqno; |
| 469 | } | 469 | } |
| 470 | |||
| 471 | for (i = 0; i < exec->rcl_write_bo_count; i++) { | ||
| 472 | bo = to_vc4_bo(&exec->rcl_write_bo[i]->base); | ||
| 473 | bo->write_seqno = seqno; | ||
| 474 | } | ||
| 470 | } | 475 | } |
| 471 | 476 | ||
| 472 | /* Queues a struct vc4_exec_info for execution. If no job is | 477 | /* Queues a struct vc4_exec_info for execution. If no job is |
| @@ -669,6 +674,14 @@ vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec) | |||
| 669 | goto fail; | 674 | goto fail; |
| 670 | 675 | ||
| 671 | ret = vc4_validate_shader_recs(dev, exec); | 676 | ret = vc4_validate_shader_recs(dev, exec); |
| 677 | if (ret) | ||
| 678 | goto fail; | ||
| 679 | |||
| 680 | /* Block waiting on any previous rendering into the CS's VBO, | ||
| 681 | * IB, or textures, so that pixels are actually written by the | ||
| 682 | * time we try to read them. | ||
| 683 | */ | ||
| 684 | ret = vc4_wait_for_seqno(dev, exec->bin_dep_seqno, ~0ull, true); | ||
| 672 | 685 | ||
| 673 | fail: | 686 | fail: |
| 674 | drm_free_large(temp); | 687 | drm_free_large(temp); |
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 68ad10634b29..c4cb2e26de32 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c | |||
| @@ -62,6 +62,8 @@ struct vc4_hdmi { | |||
| 62 | struct vc4_hdmi_encoder { | 62 | struct vc4_hdmi_encoder { |
| 63 | struct vc4_encoder base; | 63 | struct vc4_encoder base; |
| 64 | bool hdmi_monitor; | 64 | bool hdmi_monitor; |
| 65 | bool limited_rgb_range; | ||
| 66 | bool rgb_range_selectable; | ||
| 65 | }; | 67 | }; |
| 66 | 68 | ||
| 67 | static inline struct vc4_hdmi_encoder * | 69 | static inline struct vc4_hdmi_encoder * |
| @@ -174,6 +176,9 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) | |||
| 174 | return connector_status_disconnected; | 176 | return connector_status_disconnected; |
| 175 | } | 177 | } |
| 176 | 178 | ||
| 179 | if (drm_probe_ddc(vc4->hdmi->ddc)) | ||
| 180 | return connector_status_connected; | ||
| 181 | |||
| 177 | if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) | 182 | if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) |
| 178 | return connector_status_connected; | 183 | return connector_status_connected; |
| 179 | else | 184 | else |
| @@ -202,41 +207,22 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) | |||
| 202 | return -ENODEV; | 207 | return -ENODEV; |
| 203 | 208 | ||
| 204 | vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); | 209 | vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); |
| 210 | |||
| 211 | if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { | ||
| 212 | vc4_encoder->rgb_range_selectable = | ||
| 213 | drm_rgb_quant_range_selectable(edid); | ||
| 214 | } | ||
| 215 | |||
| 205 | drm_mode_connector_update_edid_property(connector, edid); | 216 | drm_mode_connector_update_edid_property(connector, edid); |
| 206 | ret = drm_add_edid_modes(connector, edid); | 217 | ret = drm_add_edid_modes(connector, edid); |
| 207 | 218 | ||
| 208 | return ret; | 219 | return ret; |
| 209 | } | 220 | } |
| 210 | 221 | ||
| 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 | |||
| 236 | static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { | 222 | static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { |
| 237 | .dpms = drm_atomic_helper_connector_dpms, | 223 | .dpms = drm_atomic_helper_connector_dpms, |
| 238 | .detect = vc4_hdmi_connector_detect, | 224 | .detect = vc4_hdmi_connector_detect, |
| 239 | .fill_modes = vc4_hdmi_connector_probe_modes, | 225 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 240 | .destroy = vc4_hdmi_connector_destroy, | 226 | .destroy = vc4_hdmi_connector_destroy, |
| 241 | .reset = drm_atomic_helper_connector_reset, | 227 | .reset = drm_atomic_helper_connector_reset, |
| 242 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | 228 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
| @@ -294,25 +280,143 @@ static const struct drm_encoder_funcs vc4_hdmi_encoder_funcs = { | |||
| 294 | .destroy = vc4_hdmi_encoder_destroy, | 280 | .destroy = vc4_hdmi_encoder_destroy, |
| 295 | }; | 281 | }; |
| 296 | 282 | ||
| 283 | static int vc4_hdmi_stop_packet(struct drm_encoder *encoder, | ||
| 284 | enum hdmi_infoframe_type type) | ||
| 285 | { | ||
| 286 | struct drm_device *dev = encoder->dev; | ||
| 287 | struct vc4_dev *vc4 = to_vc4_dev(dev); | ||
| 288 | u32 packet_id = type - 0x80; | ||
| 289 | |||
| 290 | HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, | ||
| 291 | HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id)); | ||
| 292 | |||
| 293 | return wait_for(!(HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) & | ||
| 294 | BIT(packet_id)), 100); | ||
| 295 | } | ||
| 296 | |||
| 297 | static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, | ||
| 298 | union hdmi_infoframe *frame) | ||
| 299 | { | ||
| 300 | struct drm_device *dev = encoder->dev; | ||
| 301 | struct vc4_dev *vc4 = to_vc4_dev(dev); | ||
| 302 | u32 packet_id = frame->any.type - 0x80; | ||
| 303 | u32 packet_reg = VC4_HDMI_GCP_0 + VC4_HDMI_PACKET_STRIDE * packet_id; | ||
| 304 | uint8_t buffer[VC4_HDMI_PACKET_STRIDE]; | ||
| 305 | ssize_t len, i; | ||
| 306 | int ret; | ||
| 307 | |||
| 308 | WARN_ONCE(!(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & | ||
| 309 | VC4_HDMI_RAM_PACKET_ENABLE), | ||
| 310 | "Packet RAM has to be on to store the packet."); | ||
| 311 | |||
| 312 | len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer)); | ||
| 313 | if (len < 0) | ||
| 314 | return; | ||
| 315 | |||
| 316 | ret = vc4_hdmi_stop_packet(encoder, frame->any.type); | ||
| 317 | if (ret) { | ||
| 318 | DRM_ERROR("Failed to wait for infoframe to go idle: %d\n", ret); | ||
| 319 | return; | ||
| 320 | } | ||
| 321 | |||
| 322 | for (i = 0; i < len; i += 7) { | ||
| 323 | HDMI_WRITE(packet_reg, | ||
| 324 | buffer[i + 0] << 0 | | ||
| 325 | buffer[i + 1] << 8 | | ||
| 326 | buffer[i + 2] << 16); | ||
| 327 | packet_reg += 4; | ||
| 328 | |||
| 329 | HDMI_WRITE(packet_reg, | ||
| 330 | buffer[i + 3] << 0 | | ||
| 331 | buffer[i + 4] << 8 | | ||
| 332 | buffer[i + 5] << 16 | | ||
| 333 | buffer[i + 6] << 24); | ||
| 334 | packet_reg += 4; | ||
| 335 | } | ||
| 336 | |||
| 337 | HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, | ||
| 338 | HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) | BIT(packet_id)); | ||
| 339 | ret = wait_for((HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) & | ||
| 340 | BIT(packet_id)), 100); | ||
| 341 | if (ret) | ||
| 342 | DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret); | ||
| 343 | } | ||
| 344 | |||
| 345 | static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) | ||
| 346 | { | ||
| 347 | struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); | ||
| 348 | struct drm_crtc *crtc = encoder->crtc; | ||
| 349 | const struct drm_display_mode *mode = &crtc->state->adjusted_mode; | ||
| 350 | union hdmi_infoframe frame; | ||
| 351 | int ret; | ||
| 352 | |||
| 353 | ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode); | ||
| 354 | if (ret < 0) { | ||
| 355 | DRM_ERROR("couldn't fill AVI infoframe\n"); | ||
| 356 | return; | ||
| 357 | } | ||
| 358 | |||
| 359 | if (vc4_encoder->rgb_range_selectable) { | ||
| 360 | if (vc4_encoder->limited_rgb_range) { | ||
| 361 | frame.avi.quantization_range = | ||
| 362 | HDMI_QUANTIZATION_RANGE_LIMITED; | ||
| 363 | } else { | ||
| 364 | frame.avi.quantization_range = | ||
| 365 | HDMI_QUANTIZATION_RANGE_FULL; | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 369 | vc4_hdmi_write_infoframe(encoder, &frame); | ||
| 370 | } | ||
| 371 | |||
| 372 | static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder) | ||
| 373 | { | ||
| 374 | union hdmi_infoframe frame; | ||
| 375 | int ret; | ||
| 376 | |||
| 377 | ret = hdmi_spd_infoframe_init(&frame.spd, "Broadcom", "Videocore"); | ||
| 378 | if (ret < 0) { | ||
| 379 | DRM_ERROR("couldn't fill SPD infoframe\n"); | ||
| 380 | return; | ||
| 381 | } | ||
| 382 | |||
| 383 | frame.spd.sdi = HDMI_SPD_SDI_PC; | ||
| 384 | |||
| 385 | vc4_hdmi_write_infoframe(encoder, &frame); | ||
| 386 | } | ||
| 387 | |||
| 388 | static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) | ||
| 389 | { | ||
| 390 | vc4_hdmi_set_avi_infoframe(encoder); | ||
| 391 | vc4_hdmi_set_spd_infoframe(encoder); | ||
| 392 | } | ||
| 393 | |||
| 297 | static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, | 394 | static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, |
| 298 | struct drm_display_mode *unadjusted_mode, | 395 | struct drm_display_mode *unadjusted_mode, |
| 299 | struct drm_display_mode *mode) | 396 | struct drm_display_mode *mode) |
| 300 | { | 397 | { |
| 398 | struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); | ||
| 301 | struct drm_device *dev = encoder->dev; | 399 | struct drm_device *dev = encoder->dev; |
| 302 | struct vc4_dev *vc4 = to_vc4_dev(dev); | 400 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
| 303 | bool debug_dump_regs = false; | 401 | bool debug_dump_regs = false; |
| 304 | bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; | 402 | bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; |
| 305 | bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; | 403 | bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; |
| 306 | u32 vactive = (mode->vdisplay >> | 404 | bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE; |
| 307 | ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0)); | 405 | u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1; |
| 308 | u32 verta = (VC4_SET_FIELD(mode->vsync_end - mode->vsync_start, | 406 | u32 verta = (VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start, |
| 309 | VC4_HDMI_VERTA_VSP) | | 407 | VC4_HDMI_VERTA_VSP) | |
| 310 | VC4_SET_FIELD(mode->vsync_start - mode->vdisplay, | 408 | VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay, |
| 311 | VC4_HDMI_VERTA_VFP) | | 409 | VC4_HDMI_VERTA_VFP) | |
| 312 | VC4_SET_FIELD(vactive, VC4_HDMI_VERTA_VAL)); | 410 | VC4_SET_FIELD(mode->crtc_vdisplay, VC4_HDMI_VERTA_VAL)); |
| 313 | u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) | | 411 | u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) | |
| 314 | VC4_SET_FIELD(mode->vtotal - mode->vsync_end, | 412 | VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end, |
| 315 | VC4_HDMI_VERTB_VBP)); | 413 | VC4_HDMI_VERTB_VBP)); |
| 414 | u32 vertb_even = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) | | ||
| 415 | VC4_SET_FIELD(mode->crtc_vtotal - | ||
| 416 | mode->crtc_vsync_end - | ||
| 417 | interlaced, | ||
| 418 | VC4_HDMI_VERTB_VBP)); | ||
| 419 | u32 csc_ctl; | ||
| 316 | 420 | ||
| 317 | if (debug_dump_regs) { | 421 | if (debug_dump_regs) { |
| 318 | DRM_INFO("HDMI regs before:\n"); | 422 | DRM_INFO("HDMI regs before:\n"); |
| @@ -321,7 +425,8 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, | |||
| 321 | 425 | ||
| 322 | HD_WRITE(VC4_HD_VID_CTL, 0); | 426 | HD_WRITE(VC4_HD_VID_CTL, 0); |
| 323 | 427 | ||
| 324 | clk_set_rate(vc4->hdmi->pixel_clock, mode->clock * 1000); | 428 | clk_set_rate(vc4->hdmi->pixel_clock, mode->clock * 1000 * |
| 429 | ((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1)); | ||
| 325 | 430 | ||
| 326 | HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, | 431 | HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, |
| 327 | HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | | 432 | HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | |
| @@ -331,29 +436,62 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, | |||
| 331 | HDMI_WRITE(VC4_HDMI_HORZA, | 436 | HDMI_WRITE(VC4_HDMI_HORZA, |
| 332 | (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) | | 437 | (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) | |
| 333 | (hsync_pos ? VC4_HDMI_HORZA_HPOS : 0) | | 438 | (hsync_pos ? VC4_HDMI_HORZA_HPOS : 0) | |
| 334 | VC4_SET_FIELD(mode->hdisplay, VC4_HDMI_HORZA_HAP)); | 439 | VC4_SET_FIELD(mode->hdisplay * pixel_rep, |
| 440 | VC4_HDMI_HORZA_HAP)); | ||
| 335 | 441 | ||
| 336 | HDMI_WRITE(VC4_HDMI_HORZB, | 442 | HDMI_WRITE(VC4_HDMI_HORZB, |
| 337 | VC4_SET_FIELD(mode->htotal - mode->hsync_end, | 443 | VC4_SET_FIELD((mode->htotal - |
| 444 | mode->hsync_end) * pixel_rep, | ||
| 338 | VC4_HDMI_HORZB_HBP) | | 445 | VC4_HDMI_HORZB_HBP) | |
| 339 | VC4_SET_FIELD(mode->hsync_end - mode->hsync_start, | 446 | VC4_SET_FIELD((mode->hsync_end - |
| 447 | mode->hsync_start) * pixel_rep, | ||
| 340 | VC4_HDMI_HORZB_HSP) | | 448 | VC4_HDMI_HORZB_HSP) | |
| 341 | VC4_SET_FIELD(mode->hsync_start - mode->hdisplay, | 449 | VC4_SET_FIELD((mode->hsync_start - |
| 450 | mode->hdisplay) * pixel_rep, | ||
| 342 | VC4_HDMI_HORZB_HFP)); | 451 | VC4_HDMI_HORZB_HFP)); |
| 343 | 452 | ||
| 344 | HDMI_WRITE(VC4_HDMI_VERTA0, verta); | 453 | HDMI_WRITE(VC4_HDMI_VERTA0, verta); |
| 345 | HDMI_WRITE(VC4_HDMI_VERTA1, verta); | 454 | HDMI_WRITE(VC4_HDMI_VERTA1, verta); |
| 346 | 455 | ||
| 347 | HDMI_WRITE(VC4_HDMI_VERTB0, vertb); | 456 | HDMI_WRITE(VC4_HDMI_VERTB0, vertb_even); |
| 348 | HDMI_WRITE(VC4_HDMI_VERTB1, vertb); | 457 | HDMI_WRITE(VC4_HDMI_VERTB1, vertb); |
| 349 | 458 | ||
| 350 | HD_WRITE(VC4_HD_VID_CTL, | 459 | HD_WRITE(VC4_HD_VID_CTL, |
| 351 | (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | | 460 | (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | |
| 352 | (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); | 461 | (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); |
| 353 | 462 | ||
| 463 | csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, | ||
| 464 | VC4_HD_CSC_CTL_ORDER); | ||
| 465 | |||
| 466 | if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) { | ||
| 467 | /* CEA VICs other than #1 requre limited range RGB | ||
| 468 | * output unless overridden by an AVI infoframe. | ||
| 469 | * Apply a colorspace conversion to squash 0-255 down | ||
| 470 | * to 16-235. The matrix here is: | ||
| 471 | * | ||
| 472 | * [ 0 0 0.8594 16] | ||
| 473 | * [ 0 0.8594 0 16] | ||
| 474 | * [ 0.8594 0 0 16] | ||
| 475 | * [ 0 0 0 1] | ||
| 476 | */ | ||
| 477 | csc_ctl |= VC4_HD_CSC_CTL_ENABLE; | ||
| 478 | csc_ctl |= VC4_HD_CSC_CTL_RGB2YCC; | ||
| 479 | csc_ctl |= VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM, | ||
| 480 | VC4_HD_CSC_CTL_MODE); | ||
| 481 | |||
| 482 | HD_WRITE(VC4_HD_CSC_12_11, (0x000 << 16) | 0x000); | ||
| 483 | HD_WRITE(VC4_HD_CSC_14_13, (0x100 << 16) | 0x6e0); | ||
| 484 | HD_WRITE(VC4_HD_CSC_22_21, (0x6e0 << 16) | 0x000); | ||
| 485 | HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000); | ||
| 486 | HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0); | ||
| 487 | HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000); | ||
| 488 | vc4_encoder->limited_rgb_range = true; | ||
| 489 | } else { | ||
| 490 | vc4_encoder->limited_rgb_range = false; | ||
| 491 | } | ||
| 492 | |||
| 354 | /* The RGB order applies even when CSC is disabled. */ | 493 | /* The RGB order applies even when CSC is disabled. */ |
| 355 | HD_WRITE(VC4_HD_CSC_CTL, VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, | 494 | HD_WRITE(VC4_HD_CSC_CTL, csc_ctl); |
| 356 | VC4_HD_CSC_CTL_ORDER)); | ||
| 357 | 495 | ||
| 358 | HDMI_WRITE(VC4_HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); | 496 | HDMI_WRITE(VC4_HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); |
| 359 | 497 | ||
| @@ -368,6 +506,8 @@ static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) | |||
| 368 | struct drm_device *dev = encoder->dev; | 506 | struct drm_device *dev = encoder->dev; |
| 369 | struct vc4_dev *vc4 = to_vc4_dev(dev); | 507 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
| 370 | 508 | ||
| 509 | HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0); | ||
| 510 | |||
| 371 | HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16); | 511 | HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16); |
| 372 | HD_WRITE(VC4_HD_VID_CTL, | 512 | HD_WRITE(VC4_HD_VID_CTL, |
| 373 | HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); | 513 | HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); |
| @@ -394,7 +534,7 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) | |||
| 394 | VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); | 534 | VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); |
| 395 | 535 | ||
| 396 | ret = wait_for(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & | 536 | ret = wait_for(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & |
| 397 | VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1); | 537 | VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1000); |
| 398 | WARN_ONCE(ret, "Timeout waiting for " | 538 | WARN_ONCE(ret, "Timeout waiting for " |
| 399 | "VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n"); | 539 | "VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n"); |
| 400 | } else { | 540 | } else { |
| @@ -406,7 +546,7 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) | |||
| 406 | ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); | 546 | ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); |
| 407 | 547 | ||
| 408 | ret = wait_for(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & | 548 | ret = wait_for(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & |
| 409 | VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1); | 549 | VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1000); |
| 410 | WARN_ONCE(ret, "Timeout waiting for " | 550 | WARN_ONCE(ret, "Timeout waiting for " |
| 411 | "!VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n"); | 551 | "!VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n"); |
| 412 | } | 552 | } |
| @@ -420,9 +560,10 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) | |||
| 420 | HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | | 560 | HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | |
| 421 | VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT); | 561 | VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT); |
| 422 | 562 | ||
| 423 | /* XXX: Set HDMI_RAM_PACKET_CONFIG (1 << 16) and set | 563 | HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, |
| 424 | * up the infoframe. | 564 | VC4_HDMI_RAM_PACKET_ENABLE); |
| 425 | */ | 565 | |
| 566 | vc4_hdmi_set_infoframes(encoder); | ||
| 426 | 567 | ||
| 427 | drift = HDMI_READ(VC4_HDMI_FIFO_CTL); | 568 | drift = HDMI_READ(VC4_HDMI_FIFO_CTL); |
| 428 | drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK; | 569 | drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK; |
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h index 160942a9180e..1aa44c2db556 100644 --- a/drivers/gpu/drm/vc4/vc4_regs.h +++ b/drivers/gpu/drm/vc4/vc4_regs.h | |||
| @@ -175,6 +175,8 @@ | |||
| 175 | # define PV_CONTROL_CLR_AT_START BIT(14) | 175 | # define PV_CONTROL_CLR_AT_START BIT(14) |
| 176 | # define PV_CONTROL_TRIGGER_UNDERFLOW BIT(13) | 176 | # define PV_CONTROL_TRIGGER_UNDERFLOW BIT(13) |
| 177 | # define PV_CONTROL_WAIT_HSTART BIT(12) | 177 | # define PV_CONTROL_WAIT_HSTART BIT(12) |
| 178 | # define PV_CONTROL_PIXEL_REP_MASK VC4_MASK(5, 4) | ||
| 179 | # define PV_CONTROL_PIXEL_REP_SHIFT 4 | ||
| 178 | # define PV_CONTROL_CLK_SELECT_DSI_VEC 0 | 180 | # define PV_CONTROL_CLK_SELECT_DSI_VEC 0 |
| 179 | # define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI 1 | 181 | # define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI 1 |
| 180 | # define PV_CONTROL_CLK_SELECT_MASK VC4_MASK(3, 2) | 182 | # define PV_CONTROL_CLK_SELECT_MASK VC4_MASK(3, 2) |
| @@ -183,6 +185,9 @@ | |||
| 183 | # define PV_CONTROL_EN BIT(0) | 185 | # define PV_CONTROL_EN BIT(0) |
| 184 | 186 | ||
| 185 | #define PV_V_CONTROL 0x04 | 187 | #define PV_V_CONTROL 0x04 |
| 188 | # define PV_VCONTROL_ODD_DELAY_MASK VC4_MASK(22, 6) | ||
| 189 | # define PV_VCONTROL_ODD_DELAY_SHIFT 6 | ||
| 190 | # define PV_VCONTROL_ODD_FIRST BIT(5) | ||
| 186 | # define PV_VCONTROL_INTERLACE BIT(4) | 191 | # define PV_VCONTROL_INTERLACE BIT(4) |
| 187 | # define PV_VCONTROL_CONTINUOUS BIT(1) | 192 | # define PV_VCONTROL_CONTINUOUS BIT(1) |
| 188 | # define PV_VCONTROL_VIDEN BIT(0) | 193 | # define PV_VCONTROL_VIDEN BIT(0) |
| @@ -438,6 +443,8 @@ | |||
| 438 | #define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0 | 443 | #define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0 |
| 439 | # define VC4_HDMI_RAM_PACKET_ENABLE BIT(16) | 444 | # define VC4_HDMI_RAM_PACKET_ENABLE BIT(16) |
| 440 | 445 | ||
| 446 | #define VC4_HDMI_RAM_PACKET_STATUS 0x0a4 | ||
| 447 | |||
| 441 | #define VC4_HDMI_HORZA 0x0c4 | 448 | #define VC4_HDMI_HORZA 0x0c4 |
| 442 | # define VC4_HDMI_HORZA_VPOS BIT(14) | 449 | # define VC4_HDMI_HORZA_VPOS BIT(14) |
| 443 | # define VC4_HDMI_HORZA_HPOS BIT(13) | 450 | # define VC4_HDMI_HORZA_HPOS BIT(13) |
| @@ -499,6 +506,9 @@ | |||
| 499 | 506 | ||
| 500 | #define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0 | 507 | #define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0 |
| 501 | 508 | ||
| 509 | #define VC4_HDMI_GCP_0 0x400 | ||
| 510 | #define VC4_HDMI_PACKET_STRIDE 0x24 | ||
| 511 | |||
| 502 | #define VC4_HD_M_CTL 0x00c | 512 | #define VC4_HD_M_CTL 0x00c |
| 503 | # define VC4_HD_M_REGISTER_FILE_STANDBY (3 << 6) | 513 | # define VC4_HD_M_REGISTER_FILE_STANDBY (3 << 6) |
| 504 | # define VC4_HD_M_RAM_STANDBY (3 << 4) | 514 | # define VC4_HD_M_RAM_STANDBY (3 << 4) |
| @@ -528,10 +538,17 @@ | |||
| 528 | # define VC4_HD_CSC_CTL_MODE_SHIFT 2 | 538 | # define VC4_HD_CSC_CTL_MODE_SHIFT 2 |
| 529 | # define VC4_HD_CSC_CTL_MODE_RGB_TO_SD_YPRPB 0 | 539 | # define VC4_HD_CSC_CTL_MODE_RGB_TO_SD_YPRPB 0 |
| 530 | # define VC4_HD_CSC_CTL_MODE_RGB_TO_HD_YPRPB 1 | 540 | # define VC4_HD_CSC_CTL_MODE_RGB_TO_HD_YPRPB 1 |
| 531 | # define VC4_HD_CSC_CTL_MODE_CUSTOM 2 | 541 | # define VC4_HD_CSC_CTL_MODE_CUSTOM 3 |
| 532 | # define VC4_HD_CSC_CTL_RGB2YCC BIT(1) | 542 | # define VC4_HD_CSC_CTL_RGB2YCC BIT(1) |
| 533 | # define VC4_HD_CSC_CTL_ENABLE BIT(0) | 543 | # define VC4_HD_CSC_CTL_ENABLE BIT(0) |
| 534 | 544 | ||
| 545 | #define VC4_HD_CSC_12_11 0x044 | ||
| 546 | #define VC4_HD_CSC_14_13 0x048 | ||
| 547 | #define VC4_HD_CSC_22_21 0x04c | ||
| 548 | #define VC4_HD_CSC_24_23 0x050 | ||
| 549 | #define VC4_HD_CSC_32_31 0x054 | ||
| 550 | #define VC4_HD_CSC_34_33 0x058 | ||
| 551 | |||
| 535 | #define VC4_HD_FRAME_COUNT 0x068 | 552 | #define VC4_HD_FRAME_COUNT 0x068 |
| 536 | 553 | ||
| 537 | /* HVS display list information. */ | 554 | /* HVS display list information. */ |
diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c index 0f12418725e5..08886a309757 100644 --- a/drivers/gpu/drm/vc4/vc4_render_cl.c +++ b/drivers/gpu/drm/vc4/vc4_render_cl.c | |||
| @@ -45,6 +45,8 @@ struct vc4_rcl_setup { | |||
| 45 | 45 | ||
| 46 | struct drm_gem_cma_object *rcl; | 46 | struct drm_gem_cma_object *rcl; |
| 47 | u32 next_offset; | 47 | u32 next_offset; |
| 48 | |||
| 49 | u32 next_write_bo_index; | ||
| 48 | }; | 50 | }; |
| 49 | 51 | ||
| 50 | static inline void rcl_u8(struct vc4_rcl_setup *setup, u8 val) | 52 | static inline void rcl_u8(struct vc4_rcl_setup *setup, u8 val) |
| @@ -407,6 +409,8 @@ static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec, | |||
| 407 | if (!*obj) | 409 | if (!*obj) |
| 408 | return -EINVAL; | 410 | return -EINVAL; |
| 409 | 411 | ||
| 412 | exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj; | ||
| 413 | |||
| 410 | if (surf->offset & 0xf) { | 414 | if (surf->offset & 0xf) { |
| 411 | DRM_ERROR("MSAA write must be 16b aligned.\n"); | 415 | DRM_ERROR("MSAA write must be 16b aligned.\n"); |
| 412 | return -EINVAL; | 416 | return -EINVAL; |
| @@ -417,7 +421,8 @@ static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec, | |||
| 417 | 421 | ||
| 418 | static int vc4_rcl_surface_setup(struct vc4_exec_info *exec, | 422 | static int vc4_rcl_surface_setup(struct vc4_exec_info *exec, |
| 419 | struct drm_gem_cma_object **obj, | 423 | struct drm_gem_cma_object **obj, |
| 420 | struct drm_vc4_submit_rcl_surface *surf) | 424 | struct drm_vc4_submit_rcl_surface *surf, |
| 425 | bool is_write) | ||
| 421 | { | 426 | { |
| 422 | uint8_t tiling = VC4_GET_FIELD(surf->bits, | 427 | uint8_t tiling = VC4_GET_FIELD(surf->bits, |
| 423 | VC4_LOADSTORE_TILE_BUFFER_TILING); | 428 | VC4_LOADSTORE_TILE_BUFFER_TILING); |
| @@ -440,6 +445,9 @@ static int vc4_rcl_surface_setup(struct vc4_exec_info *exec, | |||
| 440 | if (!*obj) | 445 | if (!*obj) |
| 441 | return -EINVAL; | 446 | return -EINVAL; |
| 442 | 447 | ||
| 448 | if (is_write) | ||
| 449 | exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj; | ||
| 450 | |||
| 443 | if (surf->flags & VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { | 451 | if (surf->flags & VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { |
| 444 | if (surf == &exec->args->zs_write) { | 452 | if (surf == &exec->args->zs_write) { |
| 445 | DRM_ERROR("general zs write may not be a full-res.\n"); | 453 | DRM_ERROR("general zs write may not be a full-res.\n"); |
| @@ -542,6 +550,8 @@ vc4_rcl_render_config_surface_setup(struct vc4_exec_info *exec, | |||
| 542 | if (!*obj) | 550 | if (!*obj) |
| 543 | return -EINVAL; | 551 | return -EINVAL; |
| 544 | 552 | ||
| 553 | exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj; | ||
| 554 | |||
| 545 | if (tiling > VC4_TILING_FORMAT_LT) { | 555 | if (tiling > VC4_TILING_FORMAT_LT) { |
| 546 | DRM_ERROR("Bad tiling format\n"); | 556 | DRM_ERROR("Bad tiling format\n"); |
| 547 | return -EINVAL; | 557 | return -EINVAL; |
| @@ -599,15 +609,18 @@ int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec) | |||
| 599 | if (ret) | 609 | if (ret) |
| 600 | return ret; | 610 | return ret; |
| 601 | 611 | ||
| 602 | ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read); | 612 | ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read, |
| 613 | false); | ||
| 603 | if (ret) | 614 | if (ret) |
| 604 | return ret; | 615 | return ret; |
| 605 | 616 | ||
| 606 | ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read); | 617 | ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read, |
| 618 | false); | ||
| 607 | if (ret) | 619 | if (ret) |
| 608 | return ret; | 620 | return ret; |
| 609 | 621 | ||
| 610 | ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write); | 622 | ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write, |
| 623 | true); | ||
| 611 | if (ret) | 624 | if (ret) |
| 612 | return ret; | 625 | return ret; |
| 613 | 626 | ||
diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c index 9ce1d0adf882..26503e307438 100644 --- a/drivers/gpu/drm/vc4/vc4_validate.c +++ b/drivers/gpu/drm/vc4/vc4_validate.c | |||
| @@ -267,6 +267,9 @@ validate_indexed_prim_list(VALIDATE_ARGS) | |||
| 267 | if (!ib) | 267 | if (!ib) |
| 268 | return -EINVAL; | 268 | return -EINVAL; |
| 269 | 269 | ||
| 270 | exec->bin_dep_seqno = max(exec->bin_dep_seqno, | ||
| 271 | to_vc4_bo(&ib->base)->write_seqno); | ||
| 272 | |||
| 270 | if (offset > ib->base.size || | 273 | if (offset > ib->base.size || |
| 271 | (ib->base.size - offset) / index_size < length) { | 274 | (ib->base.size - offset) / index_size < length) { |
| 272 | DRM_ERROR("IB access overflow (%d + %d*%d > %zd)\n", | 275 | DRM_ERROR("IB access overflow (%d + %d*%d > %zd)\n", |
| @@ -555,8 +558,7 @@ static bool | |||
| 555 | reloc_tex(struct vc4_exec_info *exec, | 558 | reloc_tex(struct vc4_exec_info *exec, |
| 556 | void *uniform_data_u, | 559 | void *uniform_data_u, |
| 557 | struct vc4_texture_sample_info *sample, | 560 | struct vc4_texture_sample_info *sample, |
| 558 | uint32_t texture_handle_index) | 561 | uint32_t texture_handle_index, bool is_cs) |
| 559 | |||
| 560 | { | 562 | { |
| 561 | struct drm_gem_cma_object *tex; | 563 | struct drm_gem_cma_object *tex; |
| 562 | uint32_t p0 = *(uint32_t *)(uniform_data_u + sample->p_offset[0]); | 564 | uint32_t p0 = *(uint32_t *)(uniform_data_u + sample->p_offset[0]); |
| @@ -714,6 +716,11 @@ reloc_tex(struct vc4_exec_info *exec, | |||
| 714 | 716 | ||
| 715 | *validated_p0 = tex->paddr + p0; | 717 | *validated_p0 = tex->paddr + p0; |
| 716 | 718 | ||
| 719 | if (is_cs) { | ||
| 720 | exec->bin_dep_seqno = max(exec->bin_dep_seqno, | ||
| 721 | to_vc4_bo(&tex->base)->write_seqno); | ||
| 722 | } | ||
| 723 | |||
| 717 | return true; | 724 | return true; |
| 718 | fail: | 725 | fail: |
| 719 | DRM_INFO("Texture p0 at %d: 0x%08x\n", sample->p_offset[0], p0); | 726 | DRM_INFO("Texture p0 at %d: 0x%08x\n", sample->p_offset[0], p0); |
| @@ -835,7 +842,8 @@ validate_gl_shader_rec(struct drm_device *dev, | |||
| 835 | if (!reloc_tex(exec, | 842 | if (!reloc_tex(exec, |
| 836 | uniform_data_u, | 843 | uniform_data_u, |
| 837 | &validated_shader->texture_samples[tex], | 844 | &validated_shader->texture_samples[tex], |
| 838 | texture_handles_u[tex])) { | 845 | texture_handles_u[tex], |
| 846 | i == 2)) { | ||
| 839 | return -EINVAL; | 847 | return -EINVAL; |
| 840 | } | 848 | } |
| 841 | } | 849 | } |
| @@ -867,6 +875,9 @@ validate_gl_shader_rec(struct drm_device *dev, | |||
| 867 | uint32_t stride = *(uint8_t *)(pkt_u + o + 5); | 875 | uint32_t stride = *(uint8_t *)(pkt_u + o + 5); |
| 868 | uint32_t max_index; | 876 | uint32_t max_index; |
| 869 | 877 | ||
| 878 | exec->bin_dep_seqno = max(exec->bin_dep_seqno, | ||
| 879 | to_vc4_bo(&vbo->base)->write_seqno); | ||
| 880 | |||
| 870 | if (state->addr & 0x8) | 881 | if (state->addr & 0x8) |
| 871 | stride |= (*(uint32_t *)(pkt_u + 100 + i * 4)) & ~0xff; | 882 | stride |= (*(uint32_t *)(pkt_u + 100 + i * 4)) & ~0xff; |
| 872 | 883 | ||
