diff options
author | Dave Airlie <airlied@redhat.com> | 2016-10-10 16:32:58 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-10-10 16:32:58 +1000 |
commit | a74feb65a451105bb9aba6ea695b7068b0690046 (patch) | |
tree | 546c4042707df9cbbcc2c4c2dcf446dd03758d4c | |
parent | c2cbc38b9715bd8318062e600668fc30e5a3fbfa (diff) | |
parent | dfccd937deec9283d6ced73e138808e62bec54e8 (diff) | |
download | linux-a74feb65a451105bb9aba6ea695b7068b0690046.tar.gz linux-a74feb65a451105bb9aba6ea695b7068b0690046.tar.bz2 linux-a74feb65a451105bb9aba6ea695b7068b0690046.zip |
Merge tag 'drm-vc4-next-2016-10-06' of https://github.com/anholt/linux into drm-next
This pull request brings in several fixes for drm-next, mostly for
HDMI.
* tag 'drm-vc4-next-2016-10-06' of https://github.com/anholt/linux:
drm/vc4: Add support for double-clocked modes.
drm/vc4: Set up the AVI and SPD infoframes.
drm/vc4: Fix support for interlaced modes on HDMI.
drm/vc4: Increase timeout for HDMI_SCHEDULER_CONTROL changes.
drm/vc4: Fall back to using an EDID probe in the absence of a GPIO.
drm/vc4: Enable limited range RGB output on HDMI with CEA modes.
drm/vc4: Fix races when the CS reads from render targets.
drm/vc4: cleanup with list_first_entry_or_null()
-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, * and need to make things up in a approximative but consistent way. */ ret |= DRM_SCANOUTPOS_IN_VBLANK; - vblank_lines = mode->crtc_vtotal - mode->crtc_vdisplay; + vblank_lines = mode->vtotal - mode->vdisplay; if (flags & DRM_CALLED_FROM_VBLIRQ) { /* @@ -378,7 +378,7 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) struct drm_crtc_state *state = crtc->state; struct drm_display_mode *mode = &state->adjusted_mode; bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; - u32 vactive = (mode->vdisplay >> (interlace ? 1 : 0)); + u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1; u32 format = PV_CONTROL_FORMAT_24; bool debug_dump_regs = false; int clock_select = vc4_get_clock_select(crtc); @@ -394,47 +394,65 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) CRTC_WRITE(PV_CONTROL, 0); CRTC_WRITE(PV_HORZA, - VC4_SET_FIELD(mode->htotal - mode->hsync_end, + VC4_SET_FIELD((mode->htotal - + mode->hsync_end) * pixel_rep, PV_HORZA_HBP) | - VC4_SET_FIELD(mode->hsync_end - mode->hsync_start, + VC4_SET_FIELD((mode->hsync_end - + mode->hsync_start) * pixel_rep, PV_HORZA_HSYNC)); CRTC_WRITE(PV_HORZB, - VC4_SET_FIELD(mode->hsync_start - mode->hdisplay, + VC4_SET_FIELD((mode->hsync_start - + mode->hdisplay) * pixel_rep, PV_HORZB_HFP) | - VC4_SET_FIELD(mode->hdisplay, PV_HORZB_HACTIVE)); + VC4_SET_FIELD(mode->hdisplay * pixel_rep, PV_HORZB_HACTIVE)); CRTC_WRITE(PV_VERTA, - VC4_SET_FIELD(mode->vtotal - mode->vsync_end, + VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end, PV_VERTA_VBP) | - VC4_SET_FIELD(mode->vsync_end - mode->vsync_start, + VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start, PV_VERTA_VSYNC)); CRTC_WRITE(PV_VERTB, - VC4_SET_FIELD(mode->vsync_start - mode->vdisplay, + VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay, PV_VERTB_VFP) | - VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE)); + VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE)); if (interlace) { CRTC_WRITE(PV_VERTA_EVEN, - VC4_SET_FIELD(mode->vtotal - mode->vsync_end - 1, + VC4_SET_FIELD(mode->crtc_vtotal - + mode->crtc_vsync_end - 1, PV_VERTA_VBP) | - VC4_SET_FIELD(mode->vsync_end - mode->vsync_start, + VC4_SET_FIELD(mode->crtc_vsync_end - + mode->crtc_vsync_start, PV_VERTA_VSYNC)); CRTC_WRITE(PV_VERTB_EVEN, - VC4_SET_FIELD(mode->vsync_start - mode->vdisplay, + VC4_SET_FIELD(mode->crtc_vsync_start - + mode->crtc_vdisplay, PV_VERTB_VFP) | - VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE)); + VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE)); + + /* We set up first field even mode for HDMI. VEC's + * NTSC mode would want first field odd instead, once + * we support it (to do so, set ODD_FIRST and put the + * delay in VSYNCD_EVEN instead). + */ + CRTC_WRITE(PV_V_CONTROL, + PV_VCONTROL_CONTINUOUS | + PV_VCONTROL_INTERLACE | + VC4_SET_FIELD(mode->htotal * pixel_rep / 2, + PV_VCONTROL_ODD_DELAY)); + CRTC_WRITE(PV_VSYNCD_EVEN, 0); + } else { + CRTC_WRITE(PV_V_CONTROL, PV_VCONTROL_CONTINUOUS); } - CRTC_WRITE(PV_HACT_ACT, mode->hdisplay); + CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep); - CRTC_WRITE(PV_V_CONTROL, - PV_VCONTROL_CONTINUOUS | - (interlace ? PV_VCONTROL_INTERLACE : 0)); CRTC_WRITE(PV_CONTROL, 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 | @@ -544,16 +562,6 @@ static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc, 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; } 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) struct vc4_bo { struct drm_gem_cma_object base; - /* seqno of the last job to render to this BO. */ + /* seqno of the last job to render using this BO. */ uint64_t seqno; + /* seqno of the last job to use the RCL to write to this BO. + * + * Note that this doesn't include binner overflow memory + * writes. + */ + uint64_t write_seqno; + /* List entry for the BO's position in either * vc4_exec_info->unref_list or vc4_dev->bo_cache.time_list */ @@ -216,6 +223,9 @@ struct vc4_exec_info { /* Sequence number for this bin/render job. */ uint64_t seqno; + /* Latest write_seqno of any BO that binning depends on. */ + uint64_t bin_dep_seqno; + /* Last current addresses the hardware was processing when the * hangcheck timer checked on us. */ @@ -230,6 +240,13 @@ struct vc4_exec_info { struct drm_gem_cma_object **bo; uint32_t bo_count; + /* List of BOs that are being written by the RCL. Other than + * the binner temporary storage, this is all the BOs written + * by the job. + */ + struct drm_gem_cma_object *rcl_write_bo[4]; + uint32_t rcl_write_bo_count; + /* Pointers for our position in vc4->job_list */ struct list_head head; @@ -307,18 +324,15 @@ struct vc4_exec_info { static inline struct vc4_exec_info * vc4_first_bin_job(struct vc4_dev *vc4) { - if (list_empty(&vc4->bin_job_list)) - return NULL; - return list_first_entry(&vc4->bin_job_list, struct vc4_exec_info, head); + return list_first_entry_or_null(&vc4->bin_job_list, + struct vc4_exec_info, head); } static inline struct vc4_exec_info * vc4_first_render_job(struct vc4_dev *vc4) { - if (list_empty(&vc4->render_job_list)) - return NULL; - return list_first_entry(&vc4->render_job_list, - struct vc4_exec_info, head); + return list_first_entry_or_null(&vc4->render_job_list, + struct vc4_exec_info, head); } 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) list_for_each_entry(bo, &exec->unref_list, unref_head) { bo->seqno = seqno; } + + for (i = 0; i < exec->rcl_write_bo_count; i++) { + bo = to_vc4_bo(&exec->rcl_write_bo[i]->base); + bo->write_seqno = seqno; + } } /* 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) goto fail; ret = vc4_validate_shader_recs(dev, exec); + if (ret) + goto fail; + + /* Block waiting on any previous rendering into the CS's VBO, + * IB, or textures, so that pixels are actually written by the + * time we try to read them. + */ + ret = vc4_wait_for_seqno(dev, exec->bin_dep_seqno, ~0ull, true); fail: 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 { struct vc4_hdmi_encoder { struct vc4_encoder base; bool hdmi_monitor; + bool limited_rgb_range; + bool rgb_range_selectable; }; static inline struct vc4_hdmi_encoder * @@ -174,6 +176,9 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) return connector_status_disconnected; } + if (drm_probe_ddc(vc4->hdmi->ddc)) + return connector_status_connected; + if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) return connector_status_connected; else @@ -202,41 +207,22 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) return -ENODEV; vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); + + if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { + vc4_encoder->rgb_range_selectable = + drm_rgb_quant_range_selectable(edid); + } + drm_mode_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); 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 = vc4_hdmi_connector_probe_modes, + .fill_modes = drm_helper_probe_single_connector_modes, .destroy = vc4_hdmi_connector_destroy, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, @@ -294,25 +280,143 @@ static const struct drm_encoder_funcs vc4_hdmi_encoder_funcs = { .destroy = vc4_hdmi_encoder_destroy, }; +static int vc4_hdmi_stop_packet(struct drm_encoder *encoder, + enum hdmi_infoframe_type type) +{ + struct drm_device *dev = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + u32 packet_id = type - 0x80; + + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, + HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id)); + + return wait_for(!(HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) & + BIT(packet_id)), 100); +} + +static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, + union hdmi_infoframe *frame) +{ + struct drm_device *dev = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + u32 packet_id = frame->any.type - 0x80; + u32 packet_reg = VC4_HDMI_GCP_0 + VC4_HDMI_PACKET_STRIDE * packet_id; + uint8_t buffer[VC4_HDMI_PACKET_STRIDE]; + ssize_t len, i; + int ret; + + WARN_ONCE(!(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & + VC4_HDMI_RAM_PACKET_ENABLE), + "Packet RAM has to be on to store the packet."); + + len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer)); + if (len < 0) + return; + + ret = vc4_hdmi_stop_packet(encoder, frame->any.type); + if (ret) { + DRM_ERROR("Failed to wait for infoframe to go idle: %d\n", ret); + return; + } + + for (i = 0; i < len; i += 7) { + HDMI_WRITE(packet_reg, + buffer[i + 0] << 0 | + buffer[i + 1] << 8 | + buffer[i + 2] << 16); + packet_reg += 4; + + HDMI_WRITE(packet_reg, + buffer[i + 3] << 0 | + buffer[i + 4] << 8 | + buffer[i + 5] << 16 | + buffer[i + 6] << 24); + packet_reg += 4; + } + + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, + HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) | BIT(packet_id)); + ret = wait_for((HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) & + BIT(packet_id)), 100); + if (ret) + DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret); +} + +static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) +{ + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); + struct drm_crtc *crtc = encoder->crtc; + const struct drm_display_mode *mode = &crtc->state->adjusted_mode; + union hdmi_infoframe frame; + int ret; + + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode); + if (ret < 0) { + DRM_ERROR("couldn't fill AVI infoframe\n"); + return; + } + + if (vc4_encoder->rgb_range_selectable) { + if (vc4_encoder->limited_rgb_range) { + frame.avi.quantization_range = + HDMI_QUANTIZATION_RANGE_LIMITED; + } else { + frame.avi.quantization_range = + HDMI_QUANTIZATION_RANGE_FULL; + } + } + + vc4_hdmi_write_infoframe(encoder, &frame); +} + +static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder) +{ + union hdmi_infoframe frame; + int ret; + + ret = hdmi_spd_infoframe_init(&frame.spd, "Broadcom", "Videocore"); + if (ret < 0) { + DRM_ERROR("couldn't fill SPD infoframe\n"); + return; + } + + frame.spd.sdi = HDMI_SPD_SDI_PC; + + vc4_hdmi_write_infoframe(encoder, &frame); +} + +static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) +{ + vc4_hdmi_set_avi_infoframe(encoder); + vc4_hdmi_set_spd_infoframe(encoder); +} + static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *unadjusted_mode, struct drm_display_mode *mode) { + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); struct drm_device *dev = encoder->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); bool debug_dump_regs = false; bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; - u32 vactive = (mode->vdisplay >> - ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0)); - u32 verta = (VC4_SET_FIELD(mode->vsync_end - mode->vsync_start, + bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE; + u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1; + u32 verta = (VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start, VC4_HDMI_VERTA_VSP) | - VC4_SET_FIELD(mode->vsync_start - mode->vdisplay, + VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay, VC4_HDMI_VERTA_VFP) | - VC4_SET_FIELD(vactive, VC4_HDMI_VERTA_VAL)); + VC4_SET_FIELD(mode->crtc_vdisplay, VC4_HDMI_VERTA_VAL)); u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) | - VC4_SET_FIELD(mode->vtotal - mode->vsync_end, + VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end, VC4_HDMI_VERTB_VBP)); + u32 vertb_even = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) | + VC4_SET_FIELD(mode->crtc_vtotal - + mode->crtc_vsync_end - + interlaced, + VC4_HDMI_VERTB_VBP)); + u32 csc_ctl; if (debug_dump_regs) { DRM_INFO("HDMI regs before:\n"); @@ -321,7 +425,8 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, HD_WRITE(VC4_HD_VID_CTL, 0); - clk_set_rate(vc4->hdmi->pixel_clock, mode->clock * 1000); + clk_set_rate(vc4->hdmi->pixel_clock, mode->clock * 1000 * + ((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1)); HDMI_WRITE(VC4_HDMI_SCHEDULER_CONTROL, HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | @@ -331,29 +436,62 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, HDMI_WRITE(VC4_HDMI_HORZA, (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) | (hsync_pos ? VC4_HDMI_HORZA_HPOS : 0) | - VC4_SET_FIELD(mode->hdisplay, VC4_HDMI_HORZA_HAP)); + VC4_SET_FIELD(mode->hdisplay * pixel_rep, + VC4_HDMI_HORZA_HAP)); HDMI_WRITE(VC4_HDMI_HORZB, - VC4_SET_FIELD(mode->htotal - mode->hsync_end, + VC4_SET_FIELD((mode->htotal - + mode->hsync_end) * pixel_rep, VC4_HDMI_HORZB_HBP) | - VC4_SET_FIELD(mode->hsync_end - mode->hsync_start, + VC4_SET_FIELD((mode->hsync_end - + mode->hsync_start) * pixel_rep, VC4_HDMI_HORZB_HSP) | - VC4_SET_FIELD(mode->hsync_start - mode->hdisplay, + VC4_SET_FIELD((mode->hsync_start - + mode->hdisplay) * pixel_rep, VC4_HDMI_HORZB_HFP)); HDMI_WRITE(VC4_HDMI_VERTA0, verta); HDMI_WRITE(VC4_HDMI_VERTA1, verta); - HDMI_WRITE(VC4_HDMI_VERTB0, vertb); + HDMI_WRITE(VC4_HDMI_VERTB0, vertb_even); HDMI_WRITE(VC4_HDMI_VERTB1, vertb); HD_WRITE(VC4_HD_VID_CTL, (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); + csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, + VC4_HD_CSC_CTL_ORDER); + + if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) { + /* CEA VICs other than #1 requre limited range RGB + * output unless overridden by an AVI infoframe. + * Apply a colorspace conversion to squash 0-255 down + * to 16-235. The matrix here is: + * + * [ 0 0 0.8594 16] + * [ 0 0.8594 0 16] + * [ 0.8594 0 0 16] + * [ 0 0 0 1] + */ + csc_ctl |= VC4_HD_CSC_CTL_ENABLE; + csc_ctl |= VC4_HD_CSC_CTL_RGB2YCC; + csc_ctl |= VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM, + VC4_HD_CSC_CTL_MODE); + + HD_WRITE(VC4_HD_CSC_12_11, (0x000 << 16) | 0x000); + HD_WRITE(VC4_HD_CSC_14_13, (0x100 << 16) | 0x6e0); + HD_WRITE(VC4_HD_CSC_22_21, (0x6e0 << 16) | 0x000); + HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000); + HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0); + HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000); + vc4_encoder->limited_rgb_range = true; + } else { + vc4_encoder->limited_rgb_range = false; + } + /* The RGB order applies even when CSC is disabled. */ - HD_WRITE(VC4_HD_CSC_CTL, VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, - VC4_HD_CSC_CTL_ORDER)); + HD_WRITE(VC4_HD_CSC_CTL, csc_ctl); HDMI_WRITE(VC4_HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); @@ -368,6 +506,8 @@ static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) struct drm_device *dev = encoder->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0); + HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16); HD_WRITE(VC4_HD_VID_CTL, 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) VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); ret = wait_for(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & - VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1); + VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1000); WARN_ONCE(ret, "Timeout waiting for " "VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n"); } else { @@ -406,7 +546,7 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); ret = wait_for(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) & - VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1); + VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1000); WARN_ONCE(ret, "Timeout waiting for " "!VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n"); } @@ -420,9 +560,10 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT); - /* XXX: Set HDMI_RAM_PACKET_CONFIG (1 << 16) and set - * up the infoframe. - */ + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, + VC4_HDMI_RAM_PACKET_ENABLE); + + vc4_hdmi_set_infoframes(encoder); drift = HDMI_READ(VC4_HDMI_FIFO_CTL); 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 @@ # define PV_CONTROL_CLR_AT_START BIT(14) # define PV_CONTROL_TRIGGER_UNDERFLOW BIT(13) # define PV_CONTROL_WAIT_HSTART BIT(12) +# define PV_CONTROL_PIXEL_REP_MASK VC4_MASK(5, 4) +# define PV_CONTROL_PIXEL_REP_SHIFT 4 # define PV_CONTROL_CLK_SELECT_DSI_VEC 0 # define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI 1 # define PV_CONTROL_CLK_SELECT_MASK VC4_MASK(3, 2) @@ -183,6 +185,9 @@ # define PV_CONTROL_EN BIT(0) #define PV_V_CONTROL 0x04 +# define PV_VCONTROL_ODD_DELAY_MASK VC4_MASK(22, 6) +# define PV_VCONTROL_ODD_DELAY_SHIFT 6 +# define PV_VCONTROL_ODD_FIRST BIT(5) # define PV_VCONTROL_INTERLACE BIT(4) # define PV_VCONTROL_CONTINUOUS BIT(1) # define PV_VCONTROL_VIDEN BIT(0) @@ -438,6 +443,8 @@ #define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0 # define VC4_HDMI_RAM_PACKET_ENABLE BIT(16) +#define VC4_HDMI_RAM_PACKET_STATUS 0x0a4 + #define VC4_HDMI_HORZA 0x0c4 # define VC4_HDMI_HORZA_VPOS BIT(14) # define VC4_HDMI_HORZA_HPOS BIT(13) @@ -499,6 +506,9 @@ #define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0 +#define VC4_HDMI_GCP_0 0x400 +#define VC4_HDMI_PACKET_STRIDE 0x24 + #define VC4_HD_M_CTL 0x00c # define VC4_HD_M_REGISTER_FILE_STANDBY (3 << 6) # define VC4_HD_M_RAM_STANDBY (3 << 4) @@ -528,10 +538,17 @@ # define VC4_HD_CSC_CTL_MODE_SHIFT 2 # define VC4_HD_CSC_CTL_MODE_RGB_TO_SD_YPRPB 0 # define VC4_HD_CSC_CTL_MODE_RGB_TO_HD_YPRPB 1 -# define VC4_HD_CSC_CTL_MODE_CUSTOM 2 +# define VC4_HD_CSC_CTL_MODE_CUSTOM 3 # define VC4_HD_CSC_CTL_RGB2YCC BIT(1) # define VC4_HD_CSC_CTL_ENABLE BIT(0) +#define VC4_HD_CSC_12_11 0x044 +#define VC4_HD_CSC_14_13 0x048 +#define VC4_HD_CSC_22_21 0x04c +#define VC4_HD_CSC_24_23 0x050 +#define VC4_HD_CSC_32_31 0x054 +#define VC4_HD_CSC_34_33 0x058 + #define VC4_HD_FRAME_COUNT 0x068 /* 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 { struct drm_gem_cma_object *rcl; u32 next_offset; + + u32 next_write_bo_index; }; 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, if (!*obj) return -EINVAL; + exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj; + if (surf->offset & 0xf) { DRM_ERROR("MSAA write must be 16b aligned.\n"); return -EINVAL; @@ -417,7 +421,8 @@ static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec, static int vc4_rcl_surface_setup(struct vc4_exec_info *exec, struct drm_gem_cma_object **obj, - struct drm_vc4_submit_rcl_surface *surf) + struct drm_vc4_submit_rcl_surface *surf, + bool is_write) { uint8_t tiling = VC4_GET_FIELD(surf->bits, VC4_LOADSTORE_TILE_BUFFER_TILING); @@ -440,6 +445,9 @@ static int vc4_rcl_surface_setup(struct vc4_exec_info *exec, if (!*obj) return -EINVAL; + if (is_write) + exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj; + if (surf->flags & VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) { if (surf == &exec->args->zs_write) { 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, if (!*obj) return -EINVAL; + exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj; + if (tiling > VC4_TILING_FORMAT_LT) { DRM_ERROR("Bad tiling format\n"); return -EINVAL; @@ -599,15 +609,18 @@ int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec) if (ret) return ret; - ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read); + ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read, + false); if (ret) return ret; - ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read); + ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read, + false); if (ret) return ret; - ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write); + ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write, + true); if (ret) return ret; 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) if (!ib) return -EINVAL; + exec->bin_dep_seqno = max(exec->bin_dep_seqno, + to_vc4_bo(&ib->base)->write_seqno); + if (offset > ib->base.size || (ib->base.size - offset) / index_size < length) { DRM_ERROR("IB access overflow (%d + %d*%d > %zd)\n", @@ -555,8 +558,7 @@ static bool reloc_tex(struct vc4_exec_info *exec, void *uniform_data_u, struct vc4_texture_sample_info *sample, - uint32_t texture_handle_index) - + uint32_t texture_handle_index, bool is_cs) { struct drm_gem_cma_object *tex; uint32_t p0 = *(uint32_t *)(uniform_data_u + sample->p_offset[0]); @@ -714,6 +716,11 @@ reloc_tex(struct vc4_exec_info *exec, *validated_p0 = tex->paddr + p0; + if (is_cs) { + exec->bin_dep_seqno = max(exec->bin_dep_seqno, + to_vc4_bo(&tex->base)->write_seqno); + } + return true; fail: 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, if (!reloc_tex(exec, uniform_data_u, &validated_shader->texture_samples[tex], - texture_handles_u[tex])) { + texture_handles_u[tex], + i == 2)) { return -EINVAL; } } @@ -867,6 +875,9 @@ validate_gl_shader_rec(struct drm_device *dev, uint32_t stride = *(uint8_t *)(pkt_u + o + 5); uint32_t max_index; + exec->bin_dep_seqno = max(exec->bin_dep_seqno, + to_vc4_bo(&vbo->base)->write_seqno); + if (state->addr & 0x8) stride |= (*(uint32_t *)(pkt_u + 100 + i * 4)) & ~0xff; |