This pull request brings in several fixes for drm-next, mostly for
HDMI. -----BEGIN PGP SIGNATURE----- iQIcBAABCgAGBQJX9qMfAAoJELXWKTbR/J7o8qsP/0A0ZfaDV78fPZSWx7A0xPD/ Y4CPT3PUaGFgk14IhcQX5mxhTqlfAjGE73RP96CyRqAcP1R/NFjaWes/JWPFJKlu q2M3sqNDEF1peuNrp1qh64lhwH9vDO0hEyjkQGCSl/dnfPRFv1xXx//xBIUmzYpd uoUeKvi5D0vNrIbXDGlklMZyXBg6Q7nBJ0NzHqnMzYShBuu+8sURgnNAEGEr5F6t 3JEtowO3ME0THbF9T/yFAg00VcGmuW2hqst0fGFY8zCQMAMChhS73gUUUzifwlFI g5GpoaedPULDx7fCigCQsR5uW1CU1o/cRisONm3J2lxm4Far97UjCLCpGp+4WvRx KX+fWd2ct1eke4AULCPxidxUucGWaE/QG811DkgSBEYEs2xt/EHK/zXnTGVHR4+r fXZGaIh86LEr6vR66RkDaz5KjtdfxhqMimymV60hc+Q3smGh76RnUoAFUCs1h5WF T+SQ9liHzMmEDXHchKFqUdEE7BdOKLOSINCtGYGg3aYetinAMwSk6UantLQrHvD1 ROt5TodOvfnPQz628qx5KbpsP8HMTBHNX54AgzQ0JxGQG0iz9MU7Cd+Ft1bq6zKC c3UdnF5KTTxgEKnRXdbfBLLpPhAioulRNabq9BwI2FItCI5FIcfdwp1i7T0JhtiO cCP3zJUuA8hu06WnKvaE =EELT -----END PGP SIGNATURE----- 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()
This commit is contained in:
commit
a74feb65a4
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 *
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user