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

Commit 0ddf4eae authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm/sde: partial update of display output" into msm-4.9

parents e1032050 8ba47039
Loading
Loading
Loading
Loading
+42 −9
Original line number Diff line number Diff line
@@ -138,6 +138,7 @@ enum msm_mdp_crtc_property {
	CRTC_PROP_MEM_IB,
	CRTC_PROP_ROT_PREFILL_BW,
	CRTC_PROP_ROT_CLK,
	CRTC_PROP_ROI_V1,

	/* total # of properties */
	CRTC_PROP_COUNT
@@ -158,6 +159,7 @@ enum msm_mdp_conn_property {
	CONNECTOR_PROP_DST_Y,
	CONNECTOR_PROP_DST_W,
	CONNECTOR_PROP_DST_H,
	CONNECTOR_PROP_ROI_V1,

	/* enum/bitmask properties */
	CONNECTOR_PROP_TOPOLOGY_NAME,
@@ -199,6 +201,38 @@ enum msm_display_caps {
	MSM_DISPLAY_CAP_EDID		= BIT(3),
};

/**
 * struct msm_roi_alignment - region of interest alignment restrictions
 * @xstart_pix_align: left x offset alignment restriction
 * @width_pix_align: width alignment restriction
 * @ystart_pix_align: top y offset alignment restriction
 * @height_pix_align: height alignment restriction
 * @min_width: minimum width restriction
 * @min_height: minimum height restriction
 */
struct msm_roi_alignment {
	uint32_t xstart_pix_align;
	uint32_t width_pix_align;
	uint32_t ystart_pix_align;
	uint32_t height_pix_align;
	uint32_t min_width;
	uint32_t min_height;
};

/**
 * struct msm_roi_caps - display's region of interest capabilities
 * @enabled: true if some region of interest is supported
 * @merge_rois: merge rois before sending to display
 * @num_roi: maximum number of rois supported
 * @align: roi alignment restrictions
 */
struct msm_roi_caps {
	bool enabled;
	bool merge_rois;
	uint32_t num_roi;
	struct msm_roi_alignment align;
};

/**
 * struct msm_display_dsc_info - defines dsc configuration
 * @version:                 DSC version.
@@ -338,6 +372,7 @@ struct msm_compression_info {
 * @vtotal:		display vertical total
 * @jitter:		display jitter configuration
 * @comp_info:          Compression supported by the display
 * @roi_caps:           Region of interest capability info
 */
struct msm_display_info {
	int intf_type;
@@ -361,21 +396,19 @@ struct msm_display_info {
	uint32_t jitter;

	struct msm_compression_info comp_info;
	struct msm_roi_caps roi_caps;
};

#define MSM_MAX_ROI	4

/**
 * struct msm_roi_mapping - Regions of interest structure for mapping CRTC to
 *	Connector output
 * @num_rects: number of valid rectangles in src and dst arrays
 * @src: source roi rectangle
 * @dst: destination roi rectangle
 * struct msm_roi_list - list of regions of interest for a drm object
 * @num_rects: number of valid rectangles in the roi array
 * @roi: list of roi rectangles
 */
struct msm_roi_mapping {
struct msm_roi_list {
	uint32_t num_rects;
	struct drm_clip_rect src[MSM_MAX_ROI];
	struct drm_clip_rect dst[MSM_MAX_ROI];
	struct drm_clip_rect roi[MSM_MAX_ROI];
};

/**
@@ -383,7 +416,7 @@ struct msm_roi_mapping {
 * @rois: Regions of interest structure for mapping CRTC to Connector output
 */
struct msm_display_kickoff_params {
	struct msm_roi_mapping *rois;
	struct msm_roi_list *rois;
};

/**
+136 −0
Original line number Diff line number Diff line
@@ -21,6 +21,12 @@

#define BL_NODE_NAME_SIZE 32

#define SDE_DEBUG_CONN(c, fmt, ...) SDE_DEBUG("conn%d " fmt,\
		(c) ? (c)->base.base.id : -1, ##__VA_ARGS__)

#define SDE_ERROR_CONN(c, fmt, ...) SDE_ERROR("conn%d " fmt,\
		(c) ? (c)->base.base.id : -1, ##__VA_ARGS__)

static const struct drm_prop_enum_list e_topology_name[] = {
	{SDE_RM_TOPOLOGY_UNKNOWN,	"sde_unknown"},
	{SDE_RM_TOPOLOGY_SINGLEPIPE,	"sde_singlepipe"},
@@ -416,6 +422,122 @@ sde_connector_atomic_duplicate_state(struct drm_connector *connector)
	return &c_state->base;
}

static int _sde_connector_roi_v1_check_roi(
		struct sde_connector *c_conn,
		struct drm_clip_rect *roi_conn,
		const struct msm_roi_caps *caps)
{
	const struct msm_roi_alignment *align = &caps->align;
	int w = roi_conn->x2 - roi_conn->x1;
	int h = roi_conn->y2 - roi_conn->y1;

	if (w <= 0 || h <= 0) {
		SDE_ERROR_CONN(c_conn, "invalid conn roi w %d h %d\n", w, h);
		return -EINVAL;
	}

	if (w < align->min_width || w % align->width_pix_align) {
		SDE_ERROR_CONN(c_conn,
				"invalid conn roi width %d min %d align %d\n",
				w, align->min_width, align->width_pix_align);
		return -EINVAL;
	}

	if (h < align->min_height || h % align->height_pix_align) {
		SDE_ERROR_CONN(c_conn,
				"invalid conn roi height %d min %d align %d\n",
				h, align->min_height, align->height_pix_align);
		return -EINVAL;
	}

	if (roi_conn->x1 % align->xstart_pix_align) {
		SDE_ERROR_CONN(c_conn, "invalid conn roi x1 %d align %d\n",
				roi_conn->x1, align->xstart_pix_align);
		return -EINVAL;
	}

	if (roi_conn->y1 % align->ystart_pix_align) {
		SDE_ERROR_CONN(c_conn, "invalid conn roi y1 %d align %d\n",
				roi_conn->y1, align->ystart_pix_align);
		return -EINVAL;
	}

	return 0;
}

static int _sde_connector_set_roi_v1(
		struct sde_connector *c_conn,
		struct sde_connector_state *c_state,
		void *usr_ptr)
{
	struct sde_drm_roi_v1 roi_v1;
	struct msm_display_info display_info;
	struct msm_roi_caps *caps;
	int i, rc;

	if (!c_conn || !c_state) {
		SDE_ERROR("invalid args\n");
		return -EINVAL;
	}

	rc = sde_connector_get_info(&c_conn->base, &display_info);
	if (rc) {
		SDE_ERROR_CONN(c_conn, "display get info error: %d\n", rc);
		return rc;
	}

	caps = &display_info.roi_caps;
	if (!caps->enabled) {
		SDE_ERROR_CONN(c_conn, "display roi capability is disabled\n");
		return -ENOTSUPP;
	}

	memset(&c_state->rois, 0, sizeof(c_state->rois));

	if (!usr_ptr) {
		SDE_DEBUG_CONN(c_conn, "rois cleared\n");
		return 0;
	}

	if (copy_from_user(&roi_v1, usr_ptr, sizeof(roi_v1))) {
		SDE_ERROR_CONN(c_conn, "failed to copy roi_v1 data\n");
		return -EINVAL;
	}

	SDE_DEBUG_CONN(c_conn, "num_rects %d\n", roi_v1.num_rects);

	if (roi_v1.num_rects == 0) {
		SDE_DEBUG_CONN(c_conn, "rois cleared\n");
		return 0;
	}

	if (roi_v1.num_rects > SDE_MAX_ROI_V1 ||
			roi_v1.num_rects > caps->num_roi) {
		SDE_ERROR_CONN(c_conn, "too many rects specified: %d\n",
				roi_v1.num_rects);
		return -EINVAL;
	}

	c_state->rois.num_rects = roi_v1.num_rects;
	for (i = 0; i < roi_v1.num_rects; ++i) {
		int rc;

		rc = _sde_connector_roi_v1_check_roi(c_conn, &roi_v1.roi[i],
				caps);
		if (rc)
			return rc;

		c_state->rois.roi[i] = roi_v1.roi[i];
		SDE_DEBUG_CONN(c_conn, "roi%d: roi 0x%x 0x%x 0x%x 0x%x\n", i,
				c_state->rois.roi[i].x1,
				c_state->rois.roi[i].y1,
				c_state->rois.roi[i].x2,
				c_state->rois.roi[i].y2);
	}

	return 0;
}

static int sde_connector_atomic_set_property(struct drm_connector *connector,
		struct drm_connector_state *state,
		struct drm_property *property,
@@ -481,6 +603,12 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
			SDE_ERROR("invalid topology_control: 0x%llX\n", val);
	}

	if (idx == CONNECTOR_PROP_ROI_V1) {
		rc = _sde_connector_set_roi_v1(c_conn, c_state, (void *)val);
		if (rc)
			SDE_ERROR_CONN(c_conn, "invalid roi_v1, rc: %d\n", rc);
	}

	/* check for custom property handling */
	if (!rc && c_conn->ops.set_property) {
		rc = c_conn->ops.set_property(connector,
@@ -725,6 +853,7 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
	struct sde_kms_info *info;
	struct sde_connector *c_conn = NULL;
	struct dsi_display *dsi_display;
	struct msm_display_info display_info;
	int rc;

	if (!dev || !dev->dev_private || !encoder) {
@@ -857,6 +986,13 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
		}
	}

	rc = sde_connector_get_info(&c_conn->base, &display_info);
	if (!rc && display_info.roi_caps.enabled) {
		msm_property_install_volatile_range(
				&c_conn->property_info, "sde_drm_roi_v1", 0x0,
				0, ~0, 0, CONNECTOR_PROP_ROI_V1);
	}

	msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
			0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);

+1 −1
Original line number Diff line number Diff line
@@ -281,7 +281,7 @@ struct sde_connector_state {
	int mmu_id;
	uint64_t property_values[CONNECTOR_PROP_COUNT];

	struct msm_roi_mapping rois;
	struct msm_roi_list rois;
};

/**
+359 −16
Original line number Diff line number Diff line
@@ -656,21 +656,344 @@ static void _sde_crtc_setup_dim_layer_cfg(struct drm_crtc *crtc,
	}
}

void sde_crtc_get_crtc_roi(struct drm_crtc_state *state,
		const struct sde_rect **crtc_roi)
{
	struct sde_crtc_state *crtc_state;

	if (!state || !crtc_roi)
		return;

	crtc_state = to_sde_crtc_state(state);
	*crtc_roi = &crtc_state->crtc_roi;
}

static int _sde_crtc_set_roi_v1(struct drm_crtc_state *state,
		void *usr_ptr)
{
	struct drm_crtc *crtc;
	struct sde_crtc_state *cstate;
	struct sde_drm_roi_v1 roi_v1;
	int i;

	if (!state) {
		SDE_ERROR("invalid args\n");
		return -EINVAL;
	}

	cstate = to_sde_crtc_state(state);
	crtc = cstate->base.crtc;

	memset(&cstate->user_roi_list, 0, sizeof(cstate->user_roi_list));

	if (!usr_ptr) {
		SDE_DEBUG("crtc%d: rois cleared\n", DRMID(crtc));
		return 0;
	}

	if (copy_from_user(&roi_v1, usr_ptr, sizeof(roi_v1))) {
		SDE_ERROR("crtc%d: failed to copy roi_v1 data\n", DRMID(crtc));
		return -EINVAL;
	}

	SDE_DEBUG("crtc%d: num_rects %d\n", DRMID(crtc), roi_v1.num_rects);

	if (roi_v1.num_rects == 0) {
		SDE_DEBUG("crtc%d: rois cleared\n", DRMID(crtc));
		return 0;
	}

	if (roi_v1.num_rects > SDE_MAX_ROI_V1) {
		SDE_ERROR("crtc%d: too many rects specified: %d\n", DRMID(crtc),
				roi_v1.num_rects);
		return -EINVAL;
	}

	cstate->user_roi_list.num_rects = roi_v1.num_rects;
	for (i = 0; i < roi_v1.num_rects; ++i) {
		cstate->user_roi_list.roi[i] = roi_v1.roi[i];
		SDE_DEBUG("crtc%d: roi%d: roi (%d,%d) (%d,%d)\n",
				DRMID(crtc), i,
				cstate->user_roi_list.roi[i].x1,
				cstate->user_roi_list.roi[i].y1,
				cstate->user_roi_list.roi[i].x2,
				cstate->user_roi_list.roi[i].y2);
	}

	return 0;
}

static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc,
		struct drm_crtc_state *state)
{
	struct drm_connector *conn;
	struct drm_connector_state *conn_state;
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *crtc_state;
	struct sde_rect *crtc_roi;
	struct drm_clip_rect crtc_clip, *user_rect;
	int i, num_attached_conns = 0;

	if (!crtc || !state)
		return -EINVAL;

	sde_crtc = to_sde_crtc(crtc);
	crtc_state = to_sde_crtc_state(state);
	crtc_roi = &crtc_state->crtc_roi;

	/* init to invalid range maxes */
	crtc_clip.x1 = ~0;
	crtc_clip.y1 = ~0;
	crtc_clip.x2 = 0;
	crtc_clip.y2 = 0;

	for_each_connector_in_state(state->state, conn, conn_state, i) {
		struct sde_connector_state *sde_conn_state;

		if (!conn_state || conn_state->crtc != crtc)
			continue;

		if (num_attached_conns) {
			SDE_ERROR(
				"crtc%d: unsupported: roi on crtc w/ >1 connectors\n",
					DRMID(crtc));
			return -EINVAL;
		}
		++num_attached_conns;

		sde_conn_state = to_sde_connector_state(conn_state);

		if (memcmp(&sde_conn_state->rois, &crtc_state->user_roi_list,
				sizeof(crtc_state->user_roi_list))) {
			SDE_ERROR("%s: crtc -> conn roi scaling unsupported\n",
					sde_crtc->name);
			return -EINVAL;
		}
	}

	/* aggregate all clipping rectangles together for overall crtc roi */
	for (i = 0; i < crtc_state->user_roi_list.num_rects; i++) {
		user_rect = &crtc_state->user_roi_list.roi[i];

		crtc_clip.x1 = min(crtc_clip.x1, user_rect->x1);
		crtc_clip.y1 = min(crtc_clip.y1, user_rect->y1);
		crtc_clip.x2 = max(crtc_clip.x2, user_rect->x2);
		crtc_clip.y2 = max(crtc_clip.y2, user_rect->y2);

		SDE_DEBUG(
			"%s: conn%d roi%d (%d,%d),(%d,%d) -> crtc (%d,%d),(%d,%d)\n",
				sde_crtc->name, DRMID(crtc), i,
				user_rect->x1, user_rect->y1,
				user_rect->x2, user_rect->y2,
				crtc_clip.x1, crtc_clip.y1,
				crtc_clip.x2, crtc_clip.y2);

	}

	if (crtc_clip.x2  && crtc_clip.y2) {
		crtc_roi->x = crtc_clip.x1;
		crtc_roi->y = crtc_clip.y1;
		crtc_roi->w = crtc_clip.x2 - crtc_clip.x1;
		crtc_roi->h = crtc_clip.y2 - crtc_clip.y1;
	} else {
		crtc_roi->x = 0;
		crtc_roi->y = 0;
		crtc_roi->w = 0;
		crtc_roi->h = 0;
	}

	SDE_DEBUG("%s: crtc roi (%d,%d,%d,%d)\n", sde_crtc->name,
			crtc_roi->x, crtc_roi->y, crtc_roi->w, crtc_roi->h);

	return 0;
}

static int _sde_crtc_set_lm_roi(struct drm_crtc *crtc,
		struct drm_crtc_state *state, int lm_idx)
{
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *crtc_state;
	const struct sde_rect *crtc_roi;
	const struct sde_rect *lm_bounds;
	struct sde_rect *lm_roi;

	if (!crtc || !state || lm_idx >= ARRAY_SIZE(crtc_state->lm_bounds))
		return -EINVAL;

	sde_crtc = to_sde_crtc(crtc);
	crtc_state = to_sde_crtc_state(state);
	crtc_roi = &crtc_state->crtc_roi;
	lm_bounds = &crtc_state->lm_bounds[lm_idx];
	lm_roi = &crtc_state->lm_roi[lm_idx];

	if (!sde_kms_rect_is_null(crtc_roi)) {
		sde_kms_rect_intersect(crtc_roi, lm_bounds, lm_roi);
		if (sde_kms_rect_is_null(lm_roi)) {
			SDE_ERROR("unsupported R/L only partial update\n");
			return -EINVAL;
		}
	} else {
		memcpy(lm_roi, lm_bounds, sizeof(*lm_roi));
	}

	SDE_DEBUG("%s: lm%d roi (%d,%d,%d,%d)\n", sde_crtc->name, lm_idx,
			lm_roi->x, lm_roi->y, lm_roi->w, lm_roi->h);

	return 0;
}

static int _sde_crtc_check_rois_centered_and_symmetric(struct drm_crtc *crtc,
		struct drm_crtc_state *state)
{
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *crtc_state;
	const struct sde_rect *roi_prv, *roi_cur;
	int lm_idx;

	if (!crtc || !state)
		return -EINVAL;

	/*
	 * On certain HW, ROIs must be centered on the split between LMs,
	 * and be of equal width.
	 */

	sde_crtc = to_sde_crtc(crtc);
	crtc_state = to_sde_crtc_state(state);

	roi_prv = &crtc_state->lm_roi[0];
	for (lm_idx = 1; lm_idx < sde_crtc->num_mixers; lm_idx++) {
		roi_cur = &crtc_state->lm_roi[lm_idx];

		/* check lm rois are equal width & first roi ends at 2nd roi */
		if (((roi_prv->x + roi_prv->w) != roi_cur->x) ||
				(roi_prv->w != roi_cur->w)) {
			SDE_ERROR("%s: roi lm%d x %d w %d lm%d x %d w %d\n",
					sde_crtc->name,
					lm_idx-1, roi_prv->x, roi_prv->w,
					lm_idx, roi_cur->x, roi_cur->w);
			return -EINVAL;
		}
		roi_prv = roi_cur;
	}

	return 0;
}

static int _sde_crtc_check_planes_within_crtc_roi(struct drm_crtc *crtc,
		struct drm_crtc_state *state)
{
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *crtc_state;
	const struct sde_rect *crtc_roi;
	struct drm_plane_state *pstate;
	struct drm_plane *plane;

	if (!crtc || !state)
		return -EINVAL;

	/*
	 * Reject commit if a Plane CRTC destination coordinates fall outside
	 * the partial CRTC ROI. LM output is determined via connector ROIs,
	 * if they are specified, not Plane CRTC ROIs.
	 */

	sde_crtc = to_sde_crtc(crtc);
	crtc_state = to_sde_crtc_state(state);
	crtc_roi = &crtc_state->crtc_roi;

	if (sde_kms_rect_is_null(crtc_roi))
		return 0;

	drm_atomic_crtc_state_for_each_plane(plane, state) {
		struct sde_rect plane_roi, intersection;

		pstate = drm_atomic_get_plane_state(state->state, plane);
		if (IS_ERR_OR_NULL(pstate)) {
			int rc = PTR_ERR(pstate);

			SDE_ERROR("%s: failed to get plane%d state, %d\n",
					sde_crtc->name, plane->base.id, rc);
			return rc;
		}

		plane_roi.x = pstate->crtc_x;
		plane_roi.y = pstate->crtc_y;
		plane_roi.w = pstate->crtc_w;
		plane_roi.h = pstate->crtc_h;
		sde_kms_rect_intersect(crtc_roi, &plane_roi, &intersection);
		if (!sde_kms_rect_is_equal(&plane_roi, &intersection)) {
			SDE_ERROR(
				"%s: plane%d crtc roi (%d,%d,%d,%d) outside crtc roi (%d,%d,%d,%d)\n",
					sde_crtc->name, plane->base.id,
					plane_roi.x, plane_roi.y,
					plane_roi.w, plane_roi.h,
					crtc_roi->x, crtc_roi->y,
					crtc_roi->w, crtc_roi->h);
			return -E2BIG;
		}
	}

	return 0;
}

static int _sde_crtc_check_rois(struct drm_crtc *crtc,
		struct drm_crtc_state *state)
{
	struct sde_crtc *sde_crtc;
	int lm_idx;
	int rc;

	if (!crtc || !state)
		return -EINVAL;

	sde_crtc = to_sde_crtc(crtc);

	rc = _sde_crtc_set_crtc_roi(crtc, state);
	if (rc)
		return rc;

	for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
		rc = _sde_crtc_set_lm_roi(crtc, state, lm_idx);
		if (rc)
			return rc;
	}

	rc = _sde_crtc_check_rois_centered_and_symmetric(crtc, state);
	if (rc)
		return rc;

	rc = _sde_crtc_check_planes_within_crtc_roi(crtc, state);
	if (rc)
		return rc;

	return 0;
}

static void _sde_crtc_program_lm_output_roi(struct drm_crtc *crtc)
{
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *crtc_state;
	const struct sde_rect *lm_roi;
	struct sde_hw_mixer *hw_lm;
	int lm_idx, lm_horiz_position;

	if (!crtc)
		return;

	sde_crtc = to_sde_crtc(crtc);
	crtc_state = to_sde_crtc_state(crtc->state);

	lm_horiz_position = 0;
	for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
		const struct sde_rect *lm_roi = &crtc_state->lm_bounds[lm_idx];
		struct sde_hw_mixer *hw_lm = sde_crtc->mixers[lm_idx].hw_lm;
		struct sde_hw_mixer_cfg cfg;

		lm_roi = &crtc_state->lm_roi[lm_idx];
		hw_lm = sde_crtc->mixers[lm_idx].hw_lm;

		SDE_EVT32(DRMID(crtc_state->base.crtc), lm_idx,
			lm_roi->x, lm_roi->y, lm_roi->w, lm_roi->h);

		if (sde_kms_rect_is_null(lm_roi))
			continue;

@@ -742,9 +1065,12 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,

		format = to_sde_format(msm_framebuffer_format(pstate->base.fb));

		SDE_EVT32(DRMID(plane), state->src_x, state->src_y,
			state->src_w >> 16, state->src_h >> 16, state->crtc_x,
			state->crtc_y, state->crtc_w, state->crtc_h);
		SDE_EVT32(DRMID(crtc), DRMID(plane),
				state->fb ? state->fb->base.id : -1,
				state->src_x >> 16, state->src_y >> 16,
				state->src_w >> 16, state->src_h >> 16,
				state->crtc_x, state->crtc_y,
				state->crtc_w, state->crtc_h);

		for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
			struct sde_rect intersect;
@@ -877,6 +1203,8 @@ static void _sde_crtc_blend_setup(struct drm_crtc *crtc)
		ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx,
			&sde_crtc->stage_cfg, i);
	}

	_sde_crtc_program_lm_output_roi(crtc);
}

void sde_crtc_prepare_commit(struct drm_crtc *crtc,
@@ -1329,14 +1657,18 @@ static void _sde_crtc_setup_lm_bounds(struct drm_crtc *crtc,
	crtc_split_width = sde_crtc_mixer_width(sde_crtc, adj_mode);

	for (i = 0; i < sde_crtc->num_mixers; i++) {
		struct sde_rect *lm_bound = &cstate->lm_bounds[i];

		lm_bound->x = crtc_split_width * i;
		lm_bound->y = 0;
		lm_bound->w = crtc_split_width;
		lm_bound->h = adj_mode->vdisplay;
		SDE_EVT32(DRMID(crtc), i, lm_bound->x, lm_bound->y,
				lm_bound->w, lm_bound->h);
		cstate->lm_bounds[i].x = crtc_split_width * i;
		cstate->lm_bounds[i].y = 0;
		cstate->lm_bounds[i].w = crtc_split_width;
		cstate->lm_bounds[i].h = adj_mode->vdisplay;
		memcpy(&cstate->lm_roi[i], &cstate->lm_bounds[i],
				sizeof(cstate->lm_roi[i]));
		SDE_EVT32(DRMID(crtc), i,
				cstate->lm_bounds[i].x, cstate->lm_bounds[i].y,
				cstate->lm_bounds[i].w, cstate->lm_bounds[i].h);
		SDE_DEBUG("%s: lm%d bnd&roi (%d,%d,%d,%d)\n", sde_crtc->name, i,
				cstate->lm_roi[i].x, cstate->lm_roi[i].y,
				cstate->lm_roi[i].w, cstate->lm_roi[i].h);
	}

	drm_mode_debug_printmodeline(adj_mode);
@@ -1366,10 +1698,10 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc,
	sde_crtc = to_sde_crtc(crtc);
	dev = crtc->dev;

	if (!sde_crtc->num_mixers)
	if (!sde_crtc->num_mixers) {
		_sde_crtc_setup_mixers(crtc);

		_sde_crtc_setup_lm_bounds(crtc, crtc->state);
	}

	if (sde_crtc->event) {
		WARN_ON(sde_crtc->event);
@@ -2117,6 +2449,11 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
		}
	}

	rc = _sde_crtc_check_rois(crtc, state);
	if (rc) {
		SDE_ERROR("crtc%d failed roi check %d\n", crtc->base.id, rc);
		goto end;
	}

end:
	_sde_crtc_rp_free_unused(&cstate->rp);
@@ -2243,6 +2580,9 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc,
			"dim_layer_v1", 0x0, 0, ~0, 0, CRTC_PROP_DIM_LAYER_V1);
	}

	msm_property_install_volatile_range(&sde_crtc->property_info,
		"sde_drm_roi_v1", 0x0, 0, ~0, 0, CRTC_PROP_ROI_V1);

	sde_kms_info_reset(info);

	sde_kms_info_add_keyint(info, "hw_version", catalog->hwversion);
@@ -2315,6 +2655,9 @@ static int sde_crtc_atomic_set_property(struct drm_crtc *crtc,
			case CRTC_PROP_DIM_LAYER_V1:
				_sde_crtc_set_dim_layer_v1(cstate, (void *)val);
				break;
			case CRTC_PROP_ROI_V1:
				ret = _sde_crtc_set_roi_v1(state, (void *)val);
				break;
			default:
				/* nothing to do */
				break;
+18 −0
Original line number Diff line number Diff line
@@ -250,6 +250,11 @@ struct sde_crtc_respool {
 * @rsc_client    : sde rsc client when mode is valid
 * @lm_bounds     : LM boundaries based on current mode full resolution, no ROI.
 *                  Origin top left of CRTC.
 * @crtc_roi      : Current CRTC ROI. Possibly sub-rectangle of mode.
 *                  Origin top left of CRTC.
 * @lm_roi        : Current LM ROI, possibly sub-rectangle of mode.
 *                  Origin top left of CRTC.
 * @user_roi_list : List of user's requested ROIs as from set property
 * @property_values: Current crtc property values
 * @input_fence_timeout_ns : Cached input fence timeout, in ns
 * @property_blobs: Reference pointers for blob properties
@@ -270,6 +275,9 @@ struct sde_crtc_state {
	bool rsc_update;

	struct sde_rect lm_bounds[CRTC_DUAL_MIXERS];
	struct sde_rect crtc_roi;
	struct sde_rect lm_roi[CRTC_DUAL_MIXERS];
	struct msm_roi_list user_roi_list;

	uint64_t property_values[CRTC_PROP_COUNT];
	uint64_t input_fence_timeout_ns;
@@ -433,4 +441,14 @@ void *sde_crtc_res_get(struct drm_crtc_state *state, u32 type, u64 tag);
 */
void sde_crtc_res_put(struct drm_crtc_state *state, u32 type, u64 tag);

/**
 * sde_crtc_get_crtc_roi - retrieve the crtc_roi from the given state object
 *	used to allow the planes to adjust their final lm out_xy value in the
 *	case of partial update
 * @crtc_state: Pointer to crtc state
 * @crtc_roi: Output pointer to crtc roi in the given state
 */
void sde_crtc_get_crtc_roi(struct drm_crtc_state *state,
		const struct sde_rect **crtc_roi);

#endif /* _SDE_CRTC_H_ */
Loading