Loading drivers/gpu/drm/msm/msm_drv.c +24 −0 Original line number Diff line number Diff line Loading @@ -121,13 +121,37 @@ static void msm_fb_output_poll_changed(struct drm_device *dev) msm_drm_helper_hotplug_event(dev); } /** * msm_atomic_helper_check - validate state object * @dev: DRM device * @state: the driver state object * * This is a wrapper for the drm_atomic_helper_check to check the modeset * and state checking for planes. Additionally it checks if any secure * transition(moving CRTC and planes between secure and non-secure states and * vice versa) is allowed or not. When going to secure state, planes * with fb_mode as dir translated only can be staged on the CRTC, and only one * CRTC should be active. * Also mixing of secure and non-secure is not allowed. * * RETURNS * Zero for success or -errorno. */ int msm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { struct msm_drm_private *priv; if (msm_is_suspend_blocked(dev)) { DRM_DEBUG("rejecting commit during suspend\n"); return -EBUSY; } priv = dev->dev_private; if (priv && priv->kms && priv->kms->funcs && priv->kms->funcs->atomic_check) return priv->kms->funcs->atomic_check(priv->kms, state); return drm_atomic_helper_check(dev, state); } Loading drivers/gpu/drm/msm/msm_kms.h +3 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,9 @@ struct msm_kms_funcs { const struct msm_format *msm_fmt, const struct drm_mode_fb_cmd2 *cmd, struct drm_gem_object **bos); /* perform complete atomic check of given atomic state */ int (*atomic_check)(struct msm_kms *kms, struct drm_atomic_state *state); /* misc: */ long (*round_pixclk)(struct msm_kms *kms, unsigned long rate, struct drm_encoder *encoder); Loading drivers/gpu/drm/msm/sde/sde_crtc.c +128 −0 Original line number Diff line number Diff line Loading @@ -2711,6 +2711,130 @@ 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) { struct drm_encoder *encoder; struct sde_crtc_state *cstate; uint32_t secure; uint32_t fb_ns = 0, fb_sec = 0, fb_ns_dir = 0, fb_sec_dir = 0; int encoder_cnt = 0; int rc; if (!crtc || !state) { SDE_ERROR("invalid arguments\n"); return -EINVAL; } cstate = to_sde_crtc_state(state); secure = sde_crtc_get_property(cstate, CRTC_PROP_SECURITY_LEVEL); rc = _sde_crtc_find_plane_fb_modes(state, &fb_ns, &fb_sec, &fb_ns_dir, &fb_sec_dir); if (rc) return rc; /** * validate planes * fb_ns_dir is for secure display use case, * fb_sec_dir is for secure camera preview use case, * fb_sec is for secure video playback, * fb_ns is for normal non secure use cases. */ if (((secure == SDE_DRM_SEC_ONLY) && (fb_ns || fb_sec || fb_sec_dir)) || (fb_sec || fb_sec_dir)) { SDE_ERROR( "crtc%d: invalid planes fb_modes Sec:%d, NS:%d, Sec_Dir:%d, NS_Dir%d\n", crtc->base.id, fb_sec, fb_ns, fb_sec_dir, fb_ns_dir); return -EINVAL; } /** * secure_crtc is not allowed in a shared toppolgy * across different encoders. */ if (fb_ns_dir || fb_sec_dir) { drm_for_each_encoder(encoder, crtc->dev) if (encoder->crtc == crtc) encoder_cnt++; if (encoder_cnt > MAX_ALLOWED_ENCODER_CNT_PER_SECURE_CRTC) { SDE_ERROR( "crtc%d, invalid virtual encoder crtc%d\n", crtc->base.id, encoder_cnt); return -EINVAL; } } SDE_DEBUG("crtc:%d Secure validation successful\n", crtc->base.id); return 0; } static int sde_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { Loading Loading @@ -2757,6 +2881,10 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, _sde_crtc_setup_is_ppsplit(state); _sde_crtc_setup_lm_bounds(crtc, state); rc = _sde_crtc_check_secure_state(crtc, state); if (rc) return rc; /* get plane state for all drm planes associated with crtc state */ drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) { if (IS_ERR_OR_NULL(pstate)) { Loading drivers/gpu/drm/msm/sde/sde_crtc.h +17 −0 Original line number Diff line number Diff line Loading @@ -492,4 +492,21 @@ void sde_crtc_res_put(struct drm_crtc_state *state, u32 type, u64 tag); void sde_crtc_get_crtc_roi(struct drm_crtc_state *state, const struct sde_rect **crtc_roi); /** sde_crt_get_secure_level - retrieve the secure level from the give state * object, this is used to determine the secure state of the crtc * @crtc : Pointer to drm crtc structure * @usr: Pointer to drm crtc state * return: secure_level */ static inline int sde_crtc_get_secure_level(struct drm_crtc *crtc, struct drm_crtc_state *state) { if (!crtc || !state) return -EINVAL; return sde_crtc_get_property(to_sde_crtc_state(state), CRTC_PROP_SECURITY_LEVEL); } #endif /* _SDE_CRTC_H_ */ drivers/gpu/drm/msm/sde/sde_kms.c +98 −0 Original line number Diff line number Diff line Loading @@ -1437,6 +1437,103 @@ static void sde_kms_preclose(struct msm_kms *kms, struct drm_file *file) sde_crtc_cancel_pending_flip(priv->crtcs[i], file); } static int sde_kms_check_secure_transition(struct msm_kms *kms, struct drm_atomic_state *state) { struct sde_kms *sde_kms; struct drm_device *dev; struct drm_crtc *crtc; struct drm_crtc *sec_crtc = NULL, *temp_crtc = NULL; struct drm_crtc_state *crtc_state; int secure_crtc_cnt = 0, active_crtc_cnt = 0; int secure_global_crtc_cnt = 0, active_mode_crtc_cnt = 0; int i; if (!kms || !state) { return -EINVAL; SDE_ERROR("invalid arguments\n"); } /* iterate state object for active and secure crtc */ for_each_crtc_in_state(state, crtc, crtc_state, i) { if (!crtc_state->active) continue; active_crtc_cnt++; if (sde_crtc_get_secure_level(crtc, crtc_state) == SDE_DRM_SEC_ONLY) { sec_crtc = crtc; secure_crtc_cnt++; } } /* bail out from further validation if no secure ctrc */ if (!secure_crtc_cnt) return 0; if ((secure_crtc_cnt > MAX_ALLOWED_SECURE_CLIENT_CNT) || (secure_crtc_cnt && (active_crtc_cnt > MAX_ALLOWED_CRTC_CNT_DURING_SECURE))) { SDE_ERROR("Secure check failed active:%d, secure:%d\n", active_crtc_cnt, secure_crtc_cnt); return -EPERM; } sde_kms = to_sde_kms(kms); dev = sde_kms->dev; /* iterate global list for active and secure crtc */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (!crtc->state->active) continue; active_mode_crtc_cnt++; if (sde_crtc_get_secure_level(crtc, crtc->state) == SDE_DRM_SEC_ONLY) { secure_global_crtc_cnt++; temp_crtc = crtc; } } /** * if more than one crtc is active fail * check if the previous and current commit secure * are same */ if (secure_crtc_cnt && ((active_mode_crtc_cnt > 1) || (secure_global_crtc_cnt && (temp_crtc != sec_crtc)))) SDE_ERROR("Secure check failed active:%d crtc_id:%d\n", active_mode_crtc_cnt, temp_crtc->base.id); return 0; } static int sde_kms_atomic_check(struct msm_kms *kms, struct drm_atomic_state *state) { struct sde_kms *sde_kms; struct drm_device *dev; int ret; if (!kms || !state) return -EINVAL; sde_kms = to_sde_kms(kms); dev = sde_kms->dev; ret = drm_atomic_helper_check(dev, state); if (ret) return ret; /* * Check if any secure transition(moving CRTC between secure and * non-secure state and vice-versa) is allowed or not. when moving * to secure state, planes with fb_mode set to dir_translated only can * be staged on the CRTC, and only one CRTC can be active during * Secure state */ return sde_kms_check_secure_transition(kms, state); } static struct msm_gem_address_space* _sde_kms_get_address_space(struct msm_kms *kms, unsigned int domain) Loading Loading @@ -1479,6 +1576,7 @@ static const struct msm_kms_funcs kms_funcs = { .enable_vblank = sde_kms_enable_vblank, .disable_vblank = sde_kms_disable_vblank, .check_modified_format = sde_format_check_modified_format, .atomic_check = sde_kms_atomic_check, .get_format = sde_get_msm_format, .round_pixclk = sde_kms_round_pixclk, .destroy = sde_kms_destroy, Loading Loading
drivers/gpu/drm/msm/msm_drv.c +24 −0 Original line number Diff line number Diff line Loading @@ -121,13 +121,37 @@ static void msm_fb_output_poll_changed(struct drm_device *dev) msm_drm_helper_hotplug_event(dev); } /** * msm_atomic_helper_check - validate state object * @dev: DRM device * @state: the driver state object * * This is a wrapper for the drm_atomic_helper_check to check the modeset * and state checking for planes. Additionally it checks if any secure * transition(moving CRTC and planes between secure and non-secure states and * vice versa) is allowed or not. When going to secure state, planes * with fb_mode as dir translated only can be staged on the CRTC, and only one * CRTC should be active. * Also mixing of secure and non-secure is not allowed. * * RETURNS * Zero for success or -errorno. */ int msm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { struct msm_drm_private *priv; if (msm_is_suspend_blocked(dev)) { DRM_DEBUG("rejecting commit during suspend\n"); return -EBUSY; } priv = dev->dev_private; if (priv && priv->kms && priv->kms->funcs && priv->kms->funcs->atomic_check) return priv->kms->funcs->atomic_check(priv->kms, state); return drm_atomic_helper_check(dev, state); } Loading
drivers/gpu/drm/msm/msm_kms.h +3 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,9 @@ struct msm_kms_funcs { const struct msm_format *msm_fmt, const struct drm_mode_fb_cmd2 *cmd, struct drm_gem_object **bos); /* perform complete atomic check of given atomic state */ int (*atomic_check)(struct msm_kms *kms, struct drm_atomic_state *state); /* misc: */ long (*round_pixclk)(struct msm_kms *kms, unsigned long rate, struct drm_encoder *encoder); Loading
drivers/gpu/drm/msm/sde/sde_crtc.c +128 −0 Original line number Diff line number Diff line Loading @@ -2711,6 +2711,130 @@ 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) { struct drm_encoder *encoder; struct sde_crtc_state *cstate; uint32_t secure; uint32_t fb_ns = 0, fb_sec = 0, fb_ns_dir = 0, fb_sec_dir = 0; int encoder_cnt = 0; int rc; if (!crtc || !state) { SDE_ERROR("invalid arguments\n"); return -EINVAL; } cstate = to_sde_crtc_state(state); secure = sde_crtc_get_property(cstate, CRTC_PROP_SECURITY_LEVEL); rc = _sde_crtc_find_plane_fb_modes(state, &fb_ns, &fb_sec, &fb_ns_dir, &fb_sec_dir); if (rc) return rc; /** * validate planes * fb_ns_dir is for secure display use case, * fb_sec_dir is for secure camera preview use case, * fb_sec is for secure video playback, * fb_ns is for normal non secure use cases. */ if (((secure == SDE_DRM_SEC_ONLY) && (fb_ns || fb_sec || fb_sec_dir)) || (fb_sec || fb_sec_dir)) { SDE_ERROR( "crtc%d: invalid planes fb_modes Sec:%d, NS:%d, Sec_Dir:%d, NS_Dir%d\n", crtc->base.id, fb_sec, fb_ns, fb_sec_dir, fb_ns_dir); return -EINVAL; } /** * secure_crtc is not allowed in a shared toppolgy * across different encoders. */ if (fb_ns_dir || fb_sec_dir) { drm_for_each_encoder(encoder, crtc->dev) if (encoder->crtc == crtc) encoder_cnt++; if (encoder_cnt > MAX_ALLOWED_ENCODER_CNT_PER_SECURE_CRTC) { SDE_ERROR( "crtc%d, invalid virtual encoder crtc%d\n", crtc->base.id, encoder_cnt); return -EINVAL; } } SDE_DEBUG("crtc:%d Secure validation successful\n", crtc->base.id); return 0; } static int sde_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { Loading Loading @@ -2757,6 +2881,10 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, _sde_crtc_setup_is_ppsplit(state); _sde_crtc_setup_lm_bounds(crtc, state); rc = _sde_crtc_check_secure_state(crtc, state); if (rc) return rc; /* get plane state for all drm planes associated with crtc state */ drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) { if (IS_ERR_OR_NULL(pstate)) { Loading
drivers/gpu/drm/msm/sde/sde_crtc.h +17 −0 Original line number Diff line number Diff line Loading @@ -492,4 +492,21 @@ void sde_crtc_res_put(struct drm_crtc_state *state, u32 type, u64 tag); void sde_crtc_get_crtc_roi(struct drm_crtc_state *state, const struct sde_rect **crtc_roi); /** sde_crt_get_secure_level - retrieve the secure level from the give state * object, this is used to determine the secure state of the crtc * @crtc : Pointer to drm crtc structure * @usr: Pointer to drm crtc state * return: secure_level */ static inline int sde_crtc_get_secure_level(struct drm_crtc *crtc, struct drm_crtc_state *state) { if (!crtc || !state) return -EINVAL; return sde_crtc_get_property(to_sde_crtc_state(state), CRTC_PROP_SECURITY_LEVEL); } #endif /* _SDE_CRTC_H_ */
drivers/gpu/drm/msm/sde/sde_kms.c +98 −0 Original line number Diff line number Diff line Loading @@ -1437,6 +1437,103 @@ static void sde_kms_preclose(struct msm_kms *kms, struct drm_file *file) sde_crtc_cancel_pending_flip(priv->crtcs[i], file); } static int sde_kms_check_secure_transition(struct msm_kms *kms, struct drm_atomic_state *state) { struct sde_kms *sde_kms; struct drm_device *dev; struct drm_crtc *crtc; struct drm_crtc *sec_crtc = NULL, *temp_crtc = NULL; struct drm_crtc_state *crtc_state; int secure_crtc_cnt = 0, active_crtc_cnt = 0; int secure_global_crtc_cnt = 0, active_mode_crtc_cnt = 0; int i; if (!kms || !state) { return -EINVAL; SDE_ERROR("invalid arguments\n"); } /* iterate state object for active and secure crtc */ for_each_crtc_in_state(state, crtc, crtc_state, i) { if (!crtc_state->active) continue; active_crtc_cnt++; if (sde_crtc_get_secure_level(crtc, crtc_state) == SDE_DRM_SEC_ONLY) { sec_crtc = crtc; secure_crtc_cnt++; } } /* bail out from further validation if no secure ctrc */ if (!secure_crtc_cnt) return 0; if ((secure_crtc_cnt > MAX_ALLOWED_SECURE_CLIENT_CNT) || (secure_crtc_cnt && (active_crtc_cnt > MAX_ALLOWED_CRTC_CNT_DURING_SECURE))) { SDE_ERROR("Secure check failed active:%d, secure:%d\n", active_crtc_cnt, secure_crtc_cnt); return -EPERM; } sde_kms = to_sde_kms(kms); dev = sde_kms->dev; /* iterate global list for active and secure crtc */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (!crtc->state->active) continue; active_mode_crtc_cnt++; if (sde_crtc_get_secure_level(crtc, crtc->state) == SDE_DRM_SEC_ONLY) { secure_global_crtc_cnt++; temp_crtc = crtc; } } /** * if more than one crtc is active fail * check if the previous and current commit secure * are same */ if (secure_crtc_cnt && ((active_mode_crtc_cnt > 1) || (secure_global_crtc_cnt && (temp_crtc != sec_crtc)))) SDE_ERROR("Secure check failed active:%d crtc_id:%d\n", active_mode_crtc_cnt, temp_crtc->base.id); return 0; } static int sde_kms_atomic_check(struct msm_kms *kms, struct drm_atomic_state *state) { struct sde_kms *sde_kms; struct drm_device *dev; int ret; if (!kms || !state) return -EINVAL; sde_kms = to_sde_kms(kms); dev = sde_kms->dev; ret = drm_atomic_helper_check(dev, state); if (ret) return ret; /* * Check if any secure transition(moving CRTC between secure and * non-secure state and vice-versa) is allowed or not. when moving * to secure state, planes with fb_mode set to dir_translated only can * be staged on the CRTC, and only one CRTC can be active during * Secure state */ return sde_kms_check_secure_transition(kms, state); } static struct msm_gem_address_space* _sde_kms_get_address_space(struct msm_kms *kms, unsigned int domain) Loading Loading @@ -1479,6 +1576,7 @@ static const struct msm_kms_funcs kms_funcs = { .enable_vblank = sde_kms_enable_vblank, .disable_vblank = sde_kms_disable_vblank, .check_modified_format = sde_format_check_modified_format, .atomic_check = sde_kms_atomic_check, .get_format = sde_get_msm_format, .round_pixclk = sde_kms_round_pixclk, .destroy = sde_kms_destroy, Loading