Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a74feb65 authored by Dave Airlie's avatar Dave Airlie
Browse files

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()
parents c2cbc38b dfccd937
Loading
Loading
Loading
Loading
+36 −28
Original line number Diff line number Diff line
@@ -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));
	}

	CRTC_WRITE(PV_HACT_ACT, mode->hdisplay);
			   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 |
		   (interlace ? PV_VCONTROL_INTERLACE : 0));
			   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 * pixel_rep);


	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;
}

+22 −8
Original line number Diff line number Diff line
@@ -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,17 +324,14 @@ 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,
	return list_first_entry_or_null(&vc4->render_job_list,
					struct vc4_exec_info, head);
}

+13 −0
Original line number Diff line number Diff line
@@ -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);
+186 −45
Original line number Diff line number Diff line
@@ -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);
	drm_mode_connector_update_edid_property(connector, edid);
	ret = drm_add_edid_modes(connector, edid);

	return ret;
	if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
		vc4_encoder->rgb_range_selectable =
			drm_rgb_quant_range_selectable(edid);
	}

/*
 * 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);
	}
	drm_mode_connector_update_edid_property(connector, edid);
	ret = drm_add_edid_modes(connector, edid);

	return count;
	return ret;
}

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;
+18 −1
Original line number Diff line number Diff line
@@ -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. */
Loading