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

Commit f41f04e3 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: manage secure and non-secure transition in sde"

parents 566de96b 1b3340c4
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -735,6 +735,7 @@ struct page **msm_gem_get_pages(struct drm_gem_object *obj);
void msm_gem_put_pages(struct drm_gem_object *obj);
void msm_gem_put_iova(struct drm_gem_object *obj,
		struct msm_gem_address_space *aspace);
dma_addr_t msm_gem_get_dma_addr(struct drm_gem_object *obj);
int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
		struct drm_mode_create_dumb *args);
int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
@@ -777,6 +778,7 @@ void msm_framebuffer_cleanup(struct drm_framebuffer *fb,
		struct msm_gem_address_space *aspace);
uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb,
		struct msm_gem_address_space *aspace, int plane);
uint32_t msm_framebuffer_phys(struct drm_framebuffer *fb, int plane);
struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane);
const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb);
struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
+16 −0
Original line number Diff line number Diff line
@@ -190,6 +190,22 @@ uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb,
	return msm_gem_iova(msm_fb->planes[plane], aspace) + fb->offsets[plane];
}

uint32_t msm_framebuffer_phys(struct drm_framebuffer *fb,
		int plane)
{
	struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
	dma_addr_t phys_addr;

	if (!msm_fb->planes[plane])
		return 0;

	phys_addr = msm_gem_get_dma_addr(msm_fb->planes[plane]);
	if (!phys_addr)
		return 0;

	return phys_addr + fb->offsets[plane];
}

struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane)
{
	struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
+13 −0
Original line number Diff line number Diff line
@@ -290,6 +290,19 @@ uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj)
	return offset;
}

dma_addr_t msm_gem_get_dma_addr(struct drm_gem_object *obj)
{
	struct msm_gem_object *msm_obj = to_msm_bo(obj);
	struct drm_device *dev = obj->dev;

	if (IS_ERR_OR_NULL(msm_obj->sgt)) {
		dev_err(dev->dev, "invalid scatter/gather table\n");
		return 0;
	}

	return sg_dma_address(msm_obj->sgt->sgl);
}

static void obj_remove_domain(struct msm_gem_vma *domain)
{
	if (domain) {
+375 −56
Original line number Diff line number Diff line
@@ -38,6 +38,15 @@
#include "sde_power_handle.h"
#include "sde_core_perf.h"
#include "sde_trace.h"
#include <soc/qcom/scm.h>
#include "soc/qcom/secure_buffer.h"

/* defines for secure channel call */
#define SEC_SID_CNT               2
#define SEC_SID_MASK_0            0x80881
#define SEC_SID_MASK_1            0x80C81
#define MEM_PROTECT_SD_CTRL_SWITCH 0x18
#define MDP_DEVICE_ID            0x1A

struct sde_crtc_irq_info {
	struct sde_irq_callback irq;
@@ -1516,6 +1525,348 @@ static void _sde_crtc_blend_setup(struct drm_crtc *crtc)
	_sde_crtc_program_lm_output_roi(crtc);
}

static int _sde_crtc_find_plane_fb_modes(struct drm_crtc_state *state,
		uint32_t *fb_ns,
		uint32_t *fb_sec,
		uint32_t *fb_ns_dir,
		uint32_t *fb_sec_dir)
{
	struct drm_plane *plane;
	const struct drm_plane_state *pstate;
	struct sde_plane_state *sde_pstate;
	uint32_t mode = 0;
	int rc;

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

	*fb_ns = 0;
	*fb_sec = 0;
	*fb_ns_dir = 0;
	*fb_sec_dir = 0;
	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
		if (IS_ERR_OR_NULL(pstate)) {
			rc = PTR_ERR(pstate);
			SDE_ERROR("crtc%d failed to get plane%d state%d\n",
					state->crtc->base.id,
					plane->base.id, rc);
			return rc;
		}
		sde_pstate = to_sde_plane_state(pstate);
		mode = sde_plane_get_property(sde_pstate,
				PLANE_PROP_FB_TRANSLATION_MODE);
		switch (mode) {
		case SDE_DRM_FB_NON_SEC:
			(*fb_ns)++;
			break;
		case SDE_DRM_FB_SEC:
			(*fb_sec)++;
			break;
		case SDE_DRM_FB_NON_SEC_DIR_TRANS:
			(*fb_ns_dir)++;
			break;
		case SDE_DRM_FB_SEC_DIR_TRANS:
			(*fb_sec_dir)++;
			break;
		default:
			SDE_ERROR("Error: Plane[%d], fb_trans_mode:%d",
					plane->base.id,
					mode);
			return -EINVAL;
		}
	}
	return 0;
}

/**
 * sde_crtc_get_secure_transition_ops - determines the operations that
 * need to be performed before transitioning to secure state
 * This function should be called after swapping the new state
 * @crtc: Pointer to drm crtc structure
 * Returns the bitmask of operations need to be performed, -Error in
 * case of error cases
 */
int sde_crtc_get_secure_transition_ops(struct drm_crtc *crtc,
		struct drm_crtc_state *old_crtc_state,
		bool old_valid_fb)
{
	struct drm_plane *plane;
	struct drm_encoder *encoder;
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *cstate;
	struct sde_crtc_smmu_state_data *smmu_state;
	uint32_t translation_mode = 0;
	int ops  = 0;
	bool post_commit = false;

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

	sde_crtc = to_sde_crtc(crtc);
	cstate = to_sde_crtc_state(crtc->state);
	smmu_state = &sde_crtc->smmu_state;

	SDE_DEBUG("crtc%d, secure_level%d\n",
			crtc->base.id,
			sde_crtc_get_secure_level(crtc, crtc->state));

	/**
	 * SMMU operations need to be delayed in case of
	 * video mode panels when switching back to non_secure
	 * mode
	 */
	drm_for_each_encoder(encoder, crtc->dev) {
		if (encoder->crtc != crtc)
			continue;

		post_commit &= !sde_encoder_is_cmd_mode(encoder);
	}

	drm_atomic_crtc_for_each_plane(plane, crtc) {
		if (!plane->state)
			continue;

		translation_mode = sde_plane_get_property(
				to_sde_plane_state(plane->state),
				PLANE_PROP_FB_TRANSLATION_MODE);
		if (translation_mode > SDE_DRM_FB_SEC_DIR_TRANS) {
			SDE_ERROR("crtc%d, invalid translation_mode%d\n",
					crtc->base.id,
					translation_mode);
			return -EINVAL;
		}

		/**
		 * we can break if we find sec_fir or non_sec_dir
		 * plane
		 */
		if ((translation_mode == SDE_DRM_FB_NON_SEC_DIR_TRANS) ||
			(translation_mode == SDE_DRM_FB_SEC_DIR_TRANS))
			break;
	}

	switch (translation_mode) {
	case SDE_DRM_FB_NON_SEC_DIR_TRANS:
		if (smmu_state->state == ATTACHED) {
			smmu_state->state = DETACH_ALL_REQ;
			smmu_state->transition_type = PRE_COMMIT;
			ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
			if (old_valid_fb) {
				ops |= (SDE_KMS_OPS_WAIT_FOR_TX_DONE  |
					SDE_KMS_OPS_CLEANUP_PLANE_FB);
			}
		}
		break;
	case SDE_DRM_FB_SEC_DIR_TRANS:
		if (smmu_state->state == ATTACHED) {
			smmu_state->state = DETACH_SEC_REQ;
			smmu_state->transition_type = PRE_COMMIT;
			ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
		}
		break;
	case SDE_DRM_FB_SEC:
	case SDE_DRM_FB_NON_SEC:
		if (smmu_state->state == DETACHED_SEC) {
			smmu_state->state = ATTACH_SEC_REQ;
			smmu_state->transition_type = post_commit ?
				POST_COMMIT : PRE_COMMIT;
			ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
			if (translation_mode == SDE_DRM_FB_SEC)
				ops |= SDE_KMS_OPS_PREPARE_PLANE_FB;
		} else if (smmu_state->state == DETACHED) {
			smmu_state->state = ATTACH_ALL_REQ;
			smmu_state->transition_type = post_commit ?
				POST_COMMIT : PRE_COMMIT;
			ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE |
				SDE_KMS_OPS_PREPARE_PLANE_FB;
			if (old_valid_fb)
				ops |= (SDE_KMS_OPS_WAIT_FOR_TX_DONE |
				 SDE_KMS_OPS_CLEANUP_PLANE_FB);
		}
		break;
	default:
		SDE_ERROR("invalid plane fb_mode:%d\n",
				translation_mode);
		ops = 0;
		return -EINVAL;
	}

	SDE_DEBUG("SMMU State:%d, type:%d ops:%x\n", smmu_state->state,
			smmu_state->transition_type,
			ops);
	return ops;
}

/**
 * _sde_crtc_scm_call - makes secure channel call to switch the VMIDs
 * @vimd: switch the stage 2 translation to this VMID.
 */
static int _sde_crtc_scm_call(int vmid)
{
	struct scm_desc desc = {0};
	uint32_t num_sids;
	uint32_t *sec_sid;
	uint32_t mem_protect_sd_ctrl_id = MEM_PROTECT_SD_CTRL_SWITCH;
	int ret = 0;

	/* This info should be queried from catalog */
	num_sids = SEC_SID_CNT;
	sec_sid = kcalloc(num_sids, sizeof(uint32_t), GFP_KERNEL);
	if (!sec_sid)
		return -ENOMEM;

	/**
	 * derive this info from device tree/catalog, this is combination of
	 * smr mask and SID for secure
	 */
	sec_sid[0] = SEC_SID_MASK_0;
	sec_sid[1] = SEC_SID_MASK_1;
	dmac_flush_range(&sec_sid, &sec_sid + num_sids);

	SDE_DEBUG("calling scm_call for vmid %d", vmid);

	desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL);
	desc.args[0] = MDP_DEVICE_ID;
	desc.args[1] = SCM_BUFFER_PHYS(&sec_sid);
	desc.args[2] = sizeof(uint32_t) * num_sids;
	desc.args[3] =  vmid;

	ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
				mem_protect_sd_ctrl_id), &desc);
	if (ret) {
		SDE_ERROR("Error:scm_call2, vmid (%lld): ret%d\n",
				desc.args[3],
				ret);
	}

	kfree(sec_sid);
	return ret;
}

/**
 * sde_crtc_secure_ctrl - Initiates the operations to swtich  between secure
 *                       and non-secure mode
 * @crtc: Pointer to crtc
 * @post_commit: if this operation is triggered after commit
 */
int sde_crtc_secure_ctrl(struct drm_crtc *crtc, bool post_commit)
{
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *cstate;
	struct sde_kms *sde_kms;
	struct sde_crtc_smmu_state_data *smmu_state;
	int ret = 0;
	int old_smmu_state;

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

	sde_kms = _sde_crtc_get_kms(crtc);
	if (!sde_kms) {
		SDE_ERROR("invalid kms\n");
		return -EINVAL;
	}

	sde_crtc = to_sde_crtc(crtc);
	cstate = to_sde_crtc_state(crtc->state);
	smmu_state = &sde_crtc->smmu_state;
	old_smmu_state = smmu_state->state;

	if ((!smmu_state->transition_type) ||
	    ((smmu_state->transition_type == POST_COMMIT) && !post_commit))
		/* Bail out */
		return 0;


	/* Secure UI use case enable */
	switch (smmu_state->state) {
	case DETACH_ALL_REQ:
		/* detach_all_contexts */
		ret = sde_kms_mmu_detach(sde_kms, false);
		if (ret) {
			SDE_ERROR("crtc: %d, failed to detach %d\n",
					crtc->base.id, ret);
			goto error;
		}

		ret = _sde_crtc_scm_call(VMID_CP_SEC_DISPLAY);
		if (ret)
			goto error;

		smmu_state->state = DETACHED;
		break;
	/* Secure UI use case disable */
	case ATTACH_ALL_REQ:
		ret = _sde_crtc_scm_call(VMID_CP_PIXEL);
		if (ret)
			goto error;

		/* attach_all_contexts */
		ret = sde_kms_mmu_attach(sde_kms, false);
		if (ret) {
			SDE_ERROR("crtc: %d, failed to attach %d\n",
					crtc->base.id,
					ret);
			goto error;
		}

		smmu_state->state = ATTACHED;

		break;
	/* Secure preview enable */
	case DETACH_SEC_REQ:
		/* detach secure_context */
		ret = sde_kms_mmu_detach(sde_kms, true);
		if (ret) {
			SDE_ERROR("crtc: %d, failed to detach %d\n",
					crtc->base.id,
					ret);
			goto error;
		}

		smmu_state->state = DETACHED_SEC;
		ret = _sde_crtc_scm_call(VMID_CP_CAMERA_PREVIEW);
		if (ret)
			goto error;

		break;

	/* Secure preview disable */
	case ATTACH_SEC_REQ:
		ret = _sde_crtc_scm_call(VMID_CP_PIXEL);
		if (ret)
			goto error;

		ret = sde_kms_mmu_attach(sde_kms, true);
		if (ret) {
			SDE_ERROR("crtc: %d, failed to attach %d\n",
					crtc->base.id,
					ret);
			goto error;
		}
		smmu_state->state = ATTACHED;
		break;
	default:
		break;
	}

	SDE_DEBUG("crtc: %d, old_state %d new_state %d\n", crtc->base.id,
			old_smmu_state,
			smmu_state->state);
	smmu_state->transition_error = false;
	smmu_state->transition_type = NONE;

error:
	smmu_state->transition_error = true;
	return ret;
}

void sde_crtc_prepare_commit(struct drm_crtc *crtc,
		struct drm_crtc_state *old_state)
{
@@ -1755,6 +2106,26 @@ static void sde_crtc_frame_event_cb(void *data, u32 event)
	kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work);
}

void sde_crtc_complete_commit(struct drm_crtc *crtc,
		struct drm_crtc_state *old_state)
{
	struct sde_crtc *sde_crtc;
	struct sde_crtc_smmu_state_data *smmu_state;

	if (!crtc || !crtc->state) {
		SDE_ERROR("invalid crtc\n");
		return;
	}

	sde_crtc = to_sde_crtc(crtc);
	SDE_EVT32_VERBOSE(DRMID(crtc));
	smmu_state = &sde_crtc->smmu_state;

	/* complete secure transitions if any */
	if (smmu_state->transition_type == POST_COMMIT)
		sde_crtc_secure_ctrl(crtc, true);
}

/**
 * _sde_crtc_set_input_fence_timeout - update ns version of in fence timeout
 * @cstate: Pointer to sde crtc state
@@ -2155,8 +2526,11 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc,
	 *                      required writes/flushing before crtc's "flush
	 *                      everything" call below.
	 */
	drm_atomic_crtc_for_each_plane(plane, crtc)
	drm_atomic_crtc_for_each_plane(plane, crtc) {
		if (sde_crtc->smmu_state.transition_error)
			sde_plane_set_error(plane, true);
		sde_plane_flush(plane);
	}

	/* Kickoff will be scheduled by outer layer */
}
@@ -2860,61 +3234,6 @@ static int _sde_crtc_excl_dim_layer_check(struct drm_crtc_state *state,
	return rc;
}

static int _sde_crtc_find_plane_fb_modes(struct drm_crtc_state *state,
		uint32_t *fb_ns,
		uint32_t *fb_sec,
		uint32_t *fb_ns_dir,
		uint32_t *fb_sec_dir)
{
	struct drm_plane *plane;
	const struct drm_plane_state *pstate;
	struct sde_plane_state *sde_pstate;
	uint32_t mode = 0;
	int rc;

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

	*fb_ns = 0;
	*fb_sec = 0;
	*fb_ns_dir = 0;
	*fb_sec_dir = 0;
	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
		if (IS_ERR_OR_NULL(pstate)) {
			rc = PTR_ERR(pstate);
			SDE_ERROR("crtc%d failed to get plane%d state%d\n",
					state->crtc->base.id,
					plane->base.id, rc);
			return rc;
		}
		sde_pstate = to_sde_plane_state(pstate);
		mode = sde_plane_get_property(sde_pstate,
				PLANE_PROP_FB_TRANSLATION_MODE);
		switch (mode) {
		case SDE_DRM_FB_NON_SEC:
			(*fb_ns)++;
			break;
		case SDE_DRM_FB_SEC:
			(*fb_sec)++;
			break;
		case SDE_DRM_FB_NON_SEC_DIR_TRANS:
			(*fb_ns_dir)++;
			break;
		case SDE_DRM_FB_SEC_DIR_TRANS:
			(*fb_sec_dir)++;
			break;
		default:
			SDE_ERROR("Error: Plane[%d], fb_trans_mode:%d",
					plane->base.id,
					mode);
			return -EINVAL;
		}
	}
	return 0;
}

static int _sde_crtc_check_secure_state(struct drm_crtc *crtc,
		struct drm_crtc_state *state)
{
+74 −0
Original line number Diff line number Diff line
@@ -46,6 +46,50 @@ enum sde_crtc_client_type {
	RT_RSC_CLIENT,
};

/**
 * enum sde_crtc_smmu_state:	smmu state
 * @ATTACHED:	 all the context banks are attached.
 * @DETACHED:	 all the context banks are detached.
 * @DETACHED_SEC:	 secure context bank is detached.
 * @ATTACH_ALL_REQ:	 transient state of attaching context banks.
 * @DETACH_ALL_REQ:	 transient state of detaching context banks.
 * @DETACH_SEC_REQ:	 tranisent state of secure context bank is detached
 * @ATTACH_SEC_REQ:	 transient state of attaching secure context bank.
 */
enum sde_crtc_smmu_state {
	ATTACHED = 0,
	DETACHED,
	DETACHED_SEC,
	ATTACH_ALL_REQ,
	DETACH_ALL_REQ,
	DETACH_SEC_REQ,
	ATTACH_SEC_REQ,
};

/**
 * enum sde_crtc_smmu_state_transition_type: state transition type
 * @NONE: no pending state transitions
 * @PRE_COMMIT: state transitions should be done before processing the commit
 * @POST_COMMIT: state transitions to be done after processing the commit.
 */
enum sde_crtc_smmu_state_transition_type {
	NONE,
	PRE_COMMIT,
	POST_COMMIT
};

/**
 * struct sde_crtc_smmu_state_data: stores the smmu state and transition type
 * @state: current state of smmu context banks
 * @transition_type: transition request type
 * @transition_error: whether there is error while transitioning the state
 */
struct sde_crtc_smmu_state_data {
	uint32_t state;
	uint32_t transition_type;
	uint32_t transition_error;
};

/**
 * struct sde_crtc_mixer: stores the map for each virtual pipeline in the CRTC
 * @hw_lm:	LM HW Driver context
@@ -211,6 +255,8 @@ struct sde_crtc {

	struct mutex rp_lock;
	struct list_head rp_head;

	struct sde_crtc_smmu_state_data smmu_state;
};

#define to_sde_crtc(x) container_of(x, struct sde_crtc, base)
@@ -387,6 +433,14 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc);
void sde_crtc_prepare_commit(struct drm_crtc *crtc,
		struct drm_crtc_state *old_state);

/**
 * sde_crtc_complete_commit - callback signalling completion of current commit
 * @crtc: Pointer to drm crtc object
 * @old_state: Pointer to drm crtc old state object
 */
void sde_crtc_complete_commit(struct drm_crtc *crtc,
		struct drm_crtc_state *old_state);

/**
 * sde_crtc_init - create a new crtc object
 * @dev: sde device
@@ -527,5 +581,25 @@ static inline int sde_crtc_get_secure_level(struct drm_crtc *crtc,
			CRTC_PROP_SECURITY_LEVEL);
}

/**
 * sde_crtc_get_secure_transition - determines the operations to be
 * performed before transitioning to secure state
 * This function should be called after swapping the new state
 * @crtc: Pointer to drm crtc structure
 * @old_crtc_state: Poniter to previous CRTC state
 * Returns the bitmask of operations need to be performed, -Error in
 * case of error cases
 */
int sde_crtc_get_secure_transition_ops(struct drm_crtc *crtc,
		struct drm_crtc_state *old_crtc_state,
		bool old_valid_fb);

/**
 * sde_crtc_secure_ctrl - Initiates the transition between secure and
 *                          non-secure world
 * @crtc: Pointer to crtc
 * @post_commit: if this operation is triggered after commit
 */
int sde_crtc_secure_ctrl(struct drm_crtc *crtc, bool post_commit);

#endif /* _SDE_CRTC_H_ */
Loading