Loading drivers/gpu/drm/msm/msm_drv.h +1 −0 Original line number Diff line number Diff line Loading @@ -155,6 +155,7 @@ enum msm_mdp_crtc_property { CRTC_PROP_SECURITY_LEVEL, CRTC_PROP_IDLE_TIMEOUT, CRTC_PROP_DEST_SCALER, CRTC_PROP_CAPTURE_OUTPUT, CRTC_PROP_ENABLE_SUI_ENHANCEMENT, Loading drivers/gpu/drm/msm/sde/sde_connector.c +5 −3 Original line number Diff line number Diff line Loading @@ -1236,7 +1236,7 @@ void sde_connector_prepare_fence(struct drm_connector *connector) } void sde_connector_complete_commit(struct drm_connector *connector, ktime_t ts) ktime_t ts, enum sde_fence_event fence_event) { if (!connector) { SDE_ERROR("invalid connector\n"); Loading @@ -1244,7 +1244,8 @@ void sde_connector_complete_commit(struct drm_connector *connector, } /* signal connector's retire fence */ sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, false); sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, fence_event); } void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts) Loading @@ -1255,7 +1256,8 @@ void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts) } /* signal connector's retire fence */ sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, true); sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, SDE_FENCE_RESET_TIMELINE); } static void sde_connector_update_hdr_props(struct drm_connector *connector) Loading drivers/gpu/drm/msm/sde/sde_connector.h +3 −1 Original line number Diff line number Diff line Loading @@ -585,8 +585,10 @@ void sde_connector_prepare_fence(struct drm_connector *connector); * sde_connector_complete_commit - signal completion of current commit * @connector: Pointer to drm connector object * @ts: timestamp to be updated in the fence signalling * @fence_event: enum value to indicate nature of fence event */ void sde_connector_complete_commit(struct drm_connector *connector, ktime_t ts); void sde_connector_complete_commit(struct drm_connector *connector, ktime_t ts, enum sde_fence_event fence_event); /** * sde_connector_commit_reset - reset the completion signal Loading drivers/gpu/drm/msm/sde/sde_crtc.c +135 −144 Original line number Diff line number Diff line Loading @@ -936,7 +936,9 @@ static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc, struct sde_crtc *sde_crtc; struct sde_crtc_state *crtc_state; struct sde_rect *crtc_roi; int i, num_attached_conns = 0; struct msm_mode_info mode_info; int i = 0; int rc; bool is_crtc_roi_dirty; bool is_any_conn_roi_dirty; Loading @@ -958,13 +960,14 @@ static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc, 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)); rc = sde_connector_get_mode_info(conn_state, &mode_info); if (rc) { SDE_ERROR("failed to get mode info\n"); return -EINVAL; } ++num_attached_conns; if (!mode_info.roi_caps.enabled) continue; sde_conn = to_sde_connector(conn_state->connector); sde_conn_state = to_sde_connector_state(conn_state); Loading Loading @@ -1285,13 +1288,6 @@ static int _sde_crtc_check_rois(struct drm_crtc *crtc, sde_crtc = to_sde_crtc(crtc); sde_crtc_state = to_sde_crtc_state(state); if (hweight_long(state->connector_mask) != 1) { SDE_ERROR("invalid connector count(%d) for crtc: %d\n", (int)hweight_long(state->connector_mask), crtc->base.id); return -EINVAL; } /* * check connector array cached at modeset time since incoming atomic * state may not include any connectors if they aren't modified Loading @@ -1307,15 +1303,13 @@ static int _sde_crtc_check_rois(struct drm_crtc *crtc, SDE_ERROR("failed to get mode info\n"); return -EINVAL; } break; } if (!mode_info.roi_caps.enabled) return 0; continue; if (sde_crtc_state->user_roi_list.num_rects > mode_info.roi_caps.num_roi) { SDE_ERROR("roi count is more than supported limit, %d > %d\n", SDE_ERROR("roi count is exceeding limit, %d > %d\n", sde_crtc_state->user_roi_list.num_rects, mode_info.roi_caps.num_roi); return -E2BIG; Loading @@ -1342,6 +1336,7 @@ static int _sde_crtc_check_rois(struct drm_crtc *crtc, rc = _sde_crtc_check_planes_within_crtc_roi(crtc, state); if (rc) return rc; } return 0; } Loading Loading @@ -2116,15 +2111,62 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc) } } static void sde_crtc_frame_event_cb(void *data, u32 event) { struct drm_crtc *crtc = (struct drm_crtc *)data; struct sde_crtc *sde_crtc; struct msm_drm_private *priv; struct sde_crtc_frame_event *fevent; struct sde_crtc_frame_event_cb_data *cb_data; unsigned long flags; u32 crtc_id; cb_data = (struct sde_crtc_frame_event_cb_data *)data; if (!data) { SDE_ERROR("invalid parameters\n"); return; } crtc = cb_data->crtc; if (!crtc || !crtc->dev || !crtc->dev->dev_private) { SDE_ERROR("invalid parameters\n"); return; } sde_crtc = to_sde_crtc(crtc); priv = crtc->dev->dev_private; crtc_id = drm_crtc_index(crtc); SDE_DEBUG("crtc%d\n", crtc->base.id); SDE_EVT32_VERBOSE(DRMID(crtc), event); spin_lock_irqsave(&sde_crtc->spin_lock, flags); fevent = list_first_entry_or_null(&sde_crtc->frame_event_list, struct sde_crtc_frame_event, list); if (fevent) list_del_init(&fevent->list); spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); if (!fevent) { SDE_ERROR("crtc%d event %d overflow\n", crtc->base.id, event); SDE_EVT32(DRMID(crtc), event); return; } fevent->event = event; fevent->crtc = crtc; fevent->connector = cb_data->connector; fevent->ts = ktime_get(); kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work); } void sde_crtc_prepare_commit(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { struct sde_crtc *sde_crtc; struct sde_crtc_state *cstate; struct drm_connector *conn; struct sde_crtc_retire_event *retire_event = NULL; unsigned long flags; int i; struct drm_encoder *encoder; if (!crtc || !crtc->state) { SDE_ERROR("invalid crtc\n"); Loading @@ -2141,31 +2183,17 @@ void sde_crtc_prepare_commit(struct drm_crtc *crtc, drm_for_each_connector(conn, crtc->dev) if (conn->state && conn->state->crtc == crtc && cstate->num_connectors < MAX_CONNECTORS) { encoder = conn->state->best_encoder; if (encoder) sde_encoder_register_frame_event_callback( encoder, sde_crtc_frame_event_cb, crtc); cstate->connectors[cstate->num_connectors++] = conn; sde_connector_prepare_fence(conn); } for (i = 0; i < SDE_CRTC_FRAME_EVENT_SIZE; i++) { retire_event = &sde_crtc->retire_events[i]; if (list_empty(&retire_event->list)) break; retire_event = NULL; } if (retire_event) { retire_event->num_connectors = cstate->num_connectors; for (i = 0; i < cstate->num_connectors; i++) retire_event->connectors[i] = cstate->connectors[i]; spin_lock_irqsave(&sde_crtc->spin_lock, flags); list_add_tail(&retire_event->list, &sde_crtc->retire_event_list); spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); } else { SDE_ERROR("crtc%d retire event overflow\n", crtc->base.id); SDE_EVT32(DRMID(crtc), SDE_EVTLOG_ERROR); } /* prepare main output fence */ sde_fence_prepare(&sde_crtc->output_fence); } Loading Loading @@ -2216,9 +2244,16 @@ enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc) return INTF_MODE_NONE; } drm_for_each_encoder(encoder, crtc->dev) if (encoder->crtc == crtc) drm_for_each_encoder(encoder, crtc->dev) { if (encoder->crtc != crtc) continue; /* continue if copy encoder is encountered */ if (sde_encoder_in_clone_mode(encoder)) continue; return sde_encoder_get_intf_mode(encoder); } return INTF_MODE_NONE; } Loading @@ -2243,38 +2278,16 @@ static void sde_crtc_vblank_cb(void *data) SDE_EVT32_VERBOSE(DRMID(crtc)); } static void _sde_crtc_retire_event(struct drm_crtc *crtc, ktime_t ts) static void _sde_crtc_retire_event(struct drm_connector *connector, ktime_t ts, bool is_error) { struct sde_crtc_retire_event *retire_event; struct sde_crtc *sde_crtc; unsigned long flags; int i; if (!crtc) { if (!connector) { SDE_ERROR("invalid param\n"); return; } sde_crtc = to_sde_crtc(crtc); spin_lock_irqsave(&sde_crtc->spin_lock, flags); retire_event = list_first_entry_or_null(&sde_crtc->retire_event_list, struct sde_crtc_retire_event, list); if (retire_event) list_del_init(&retire_event->list); spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); if (!retire_event) { SDE_ERROR("crtc%d retire event without kickoff\n", crtc->base.id); SDE_EVT32(DRMID(crtc), SDE_EVTLOG_ERROR); return; } SDE_ATRACE_BEGIN("signal_retire_fence"); for (i = 0; (i < retire_event->num_connectors) && retire_event->connectors[i]; ++i) sde_connector_complete_commit( retire_event->connectors[i], ts); sde_connector_complete_commit(connector, ts, is_error); SDE_ATRACE_END("signal_retire_fence"); } Loading @@ -2287,6 +2300,7 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) struct sde_kms *sde_kms; unsigned long flags; bool frame_done = false; bool in_clone_mode = false; if (!work) { SDE_ERROR("invalid work handle\n"); Loading Loading @@ -2315,10 +2329,11 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) SDE_EVT32_VERBOSE(DRMID(crtc), fevent->event, SDE_EVTLOG_FUNC_ENTRY); if (fevent->event & (SDE_ENCODER_FRAME_EVENT_DONE | SDE_ENCODER_FRAME_EVENT_ERROR | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) { in_clone_mode = sde_encoder_in_clone_mode(fevent->connector->encoder); if (!in_clone_mode && (fevent->event & (SDE_ENCODER_FRAME_EVENT_ERROR | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD | SDE_ENCODER_FRAME_EVENT_DONE))) { if (atomic_read(&sde_crtc->frame_pending) < 1) { /* this should not happen */ SDE_ERROR("crtc%d ts:%lld invalid frame_pending:%d\n", Loading Loading @@ -2347,13 +2362,17 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE) { SDE_ATRACE_BEGIN("signal_release_fence"); sde_fence_signal(&sde_crtc->output_fence, fevent->ts, false); sde_fence_signal(&sde_crtc->output_fence, fevent->ts, (fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR) ? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL); SDE_ATRACE_END("signal_release_fence"); } if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE) /* this api should be called without spin_lock */ _sde_crtc_retire_event(crtc, fevent->ts); _sde_crtc_retire_event(fevent->connector, fevent->ts, (fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR) ? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL); if (fevent->event & SDE_ENCODER_FRAME_EVENT_PANEL_DEAD) SDE_ERROR("crtc%d ts:%lld received panel dead event\n", Loading @@ -2368,46 +2387,6 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) SDE_ATRACE_END("crtc_frame_event"); } static void sde_crtc_frame_event_cb(void *data, u32 event) { struct drm_crtc *crtc = (struct drm_crtc *)data; struct sde_crtc *sde_crtc; struct msm_drm_private *priv; struct sde_crtc_frame_event *fevent; unsigned long flags; u32 crtc_id; if (!crtc || !crtc->dev || !crtc->dev->dev_private) { SDE_ERROR("invalid parameters\n"); return; } sde_crtc = to_sde_crtc(crtc); priv = crtc->dev->dev_private; crtc_id = drm_crtc_index(crtc); SDE_DEBUG("crtc%d\n", crtc->base.id); SDE_EVT32_VERBOSE(DRMID(crtc), event); spin_lock_irqsave(&sde_crtc->spin_lock, flags); fevent = list_first_entry_or_null(&sde_crtc->frame_event_list, struct sde_crtc_frame_event, list); if (fevent) list_del_init(&fevent->list); spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); if (!fevent) { SDE_ERROR("crtc%d event %d overflow\n", crtc->base.id, event); SDE_EVT32(DRMID(crtc), event); return; } fevent->event = event; fevent->crtc = crtc; fevent->ts = ktime_get(); 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) { Loading Loading @@ -2977,6 +2956,10 @@ static void _sde_crtc_setup_mixers(struct drm_crtc *crtc) if (enc->crtc != crtc) continue; /* avoid overwriting mixers info from a copy encoder */ if (sde_encoder_in_clone_mode(enc)) continue; _sde_crtc_setup_mixer_for_encoder(crtc, enc); } Loading Loading @@ -4211,7 +4194,8 @@ static void sde_crtc_disable(struct drm_crtc *crtc) * reset the fence timeline if crtc will not be enabled for this commit */ if (!crtc->state->active || !crtc->state->enable) { sde_fence_signal(&sde_crtc->output_fence, ktime_get(), true); sde_fence_signal(&sde_crtc->output_fence, ktime_get(), SDE_FENCE_RESET_TIMELINE); for (i = 0; i < cstate->num_connectors; ++i) sde_connector_commit_reset(cstate->connectors[i], ktime_get()); Loading Loading @@ -4276,7 +4260,7 @@ static void sde_crtc_enable(struct drm_crtc *crtc) if (encoder->crtc != crtc) continue; sde_encoder_register_frame_event_callback(encoder, sde_crtc_frame_event_cb, (void *)crtc); sde_crtc_frame_event_cb, crtc); } if (!sde_crtc->enabled && !sde_crtc->suspend && Loading Loading @@ -4935,6 +4919,11 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, {SDE_DRM_SEC_ONLY, "sec_only"}, }; static const struct drm_prop_enum_list e_cwb_data_points[] = { {CAPTURE_MIXER_OUT, "capture_mixer_out"}, {CAPTURE_DSPP_OUT, "capture_pp_out"}, }; SDE_DEBUG("\n"); if (!crtc || !catalog) { Loading Loading @@ -5014,6 +5003,12 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, "enable_sui_enhancement", 0, 0, U64_MAX, 0, CRTC_PROP_ENABLE_SUI_ENHANCEMENT); if (catalog->has_cwb_support) msm_property_install_enum(&sde_crtc->property_info, "capture_mode", 0, 0, e_cwb_data_points, ARRAY_SIZE(e_cwb_data_points), CRTC_PROP_CAPTURE_OUTPUT); msm_property_install_blob(&sde_crtc->property_info, "capabilities", DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO); Loading Loading @@ -5887,10 +5882,6 @@ static int _sde_crtc_init_events(struct sde_crtc *sde_crtc) list_add_tail(&sde_crtc->event_cache[i].list, &sde_crtc->event_free_list); INIT_LIST_HEAD(&sde_crtc->retire_event_list); for (i = 0; i < ARRAY_SIZE(sde_crtc->retire_events); i++) INIT_LIST_HEAD(&sde_crtc->retire_events[i].list); return rc; } Loading drivers/gpu/drm/msm/sde/sde_crtc.h +24 −5 Original line number Diff line number Diff line Loading @@ -31,7 +31,8 @@ #define SDE_CRTC_NAME_SIZE 12 /* define the maximum number of in-flight frame events */ #define SDE_CRTC_FRAME_EVENT_SIZE 4 /* Expand it to 2x for handling atleast 2 connectors safely */ #define SDE_CRTC_FRAME_EVENT_SIZE (4 * 2) /** * enum sde_crtc_client_type: crtc client type Loading @@ -47,6 +48,16 @@ enum sde_crtc_client_type { RT_RSC_CLIENT, }; /** * enum sde_crtc_output_capture_point * @MIXER_OUT : capture mixer output * @DSPP_OUT : capture output of dspp */ enum sde_crtc_output_capture_point { CAPTURE_MIXER_OUT, CAPTURE_DSPP_OUT }; /** * @connectors : Currently associated drm connectors for retire event * @num_connectors: Number of associated drm connectors for retire event Loading Loading @@ -80,10 +91,21 @@ struct sde_crtc_mixer { u32 pipe_mask; }; /** * struct sde_crtc_frame_event_cb_data : info of drm objects of a frame event * @crtc: pointer to drm crtc object registered for frame event * @connector: pointer to drm connector which is source of frame event */ struct sde_crtc_frame_event_cb_data { struct drm_crtc *crtc; struct drm_connector *connector; }; /** * struct sde_crtc_frame_event: stores crtc frame event for crtc processing * @work: base work structure * @crtc: Pointer to crtc handling this event * @connector: pointer to drm connector which is source of frame event * @list: event list * @ts: timestamp at queue entry * @event: event identifier Loading @@ -91,6 +113,7 @@ struct sde_crtc_mixer { struct sde_crtc_frame_event { struct kthread_work work; struct drm_crtc *crtc; struct drm_connector *connector; struct list_head list; ktime_t ts; u32 event; Loading Loading @@ -161,8 +184,6 @@ struct sde_crtc_event { * @frame_events : static allocation of in-flight frame events * @frame_event_list : available frame event list * @spin_lock : spin lock for frame event, transaction status, etc... * @retire_events : static allocation of retire fence connector * @retire_event_list : available retire fence connector list * @frame_done_comp : for frame_event_done synchronization * @event_thread : Pointer to event handler thread * @event_worker : Event worker queue Loading Loading @@ -234,8 +255,6 @@ struct sde_crtc { struct sde_crtc_frame_event frame_events[SDE_CRTC_FRAME_EVENT_SIZE]; struct list_head frame_event_list; spinlock_t spin_lock; struct sde_crtc_retire_event retire_events[SDE_CRTC_FRAME_EVENT_SIZE]; struct list_head retire_event_list; struct completion frame_done_comp; /* for handling internal event thread */ Loading Loading
drivers/gpu/drm/msm/msm_drv.h +1 −0 Original line number Diff line number Diff line Loading @@ -155,6 +155,7 @@ enum msm_mdp_crtc_property { CRTC_PROP_SECURITY_LEVEL, CRTC_PROP_IDLE_TIMEOUT, CRTC_PROP_DEST_SCALER, CRTC_PROP_CAPTURE_OUTPUT, CRTC_PROP_ENABLE_SUI_ENHANCEMENT, Loading
drivers/gpu/drm/msm/sde/sde_connector.c +5 −3 Original line number Diff line number Diff line Loading @@ -1236,7 +1236,7 @@ void sde_connector_prepare_fence(struct drm_connector *connector) } void sde_connector_complete_commit(struct drm_connector *connector, ktime_t ts) ktime_t ts, enum sde_fence_event fence_event) { if (!connector) { SDE_ERROR("invalid connector\n"); Loading @@ -1244,7 +1244,8 @@ void sde_connector_complete_commit(struct drm_connector *connector, } /* signal connector's retire fence */ sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, false); sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, fence_event); } void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts) Loading @@ -1255,7 +1256,8 @@ void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts) } /* signal connector's retire fence */ sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, true); sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, SDE_FENCE_RESET_TIMELINE); } static void sde_connector_update_hdr_props(struct drm_connector *connector) Loading
drivers/gpu/drm/msm/sde/sde_connector.h +3 −1 Original line number Diff line number Diff line Loading @@ -585,8 +585,10 @@ void sde_connector_prepare_fence(struct drm_connector *connector); * sde_connector_complete_commit - signal completion of current commit * @connector: Pointer to drm connector object * @ts: timestamp to be updated in the fence signalling * @fence_event: enum value to indicate nature of fence event */ void sde_connector_complete_commit(struct drm_connector *connector, ktime_t ts); void sde_connector_complete_commit(struct drm_connector *connector, ktime_t ts, enum sde_fence_event fence_event); /** * sde_connector_commit_reset - reset the completion signal Loading
drivers/gpu/drm/msm/sde/sde_crtc.c +135 −144 Original line number Diff line number Diff line Loading @@ -936,7 +936,9 @@ static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc, struct sde_crtc *sde_crtc; struct sde_crtc_state *crtc_state; struct sde_rect *crtc_roi; int i, num_attached_conns = 0; struct msm_mode_info mode_info; int i = 0; int rc; bool is_crtc_roi_dirty; bool is_any_conn_roi_dirty; Loading @@ -958,13 +960,14 @@ static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc, 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)); rc = sde_connector_get_mode_info(conn_state, &mode_info); if (rc) { SDE_ERROR("failed to get mode info\n"); return -EINVAL; } ++num_attached_conns; if (!mode_info.roi_caps.enabled) continue; sde_conn = to_sde_connector(conn_state->connector); sde_conn_state = to_sde_connector_state(conn_state); Loading Loading @@ -1285,13 +1288,6 @@ static int _sde_crtc_check_rois(struct drm_crtc *crtc, sde_crtc = to_sde_crtc(crtc); sde_crtc_state = to_sde_crtc_state(state); if (hweight_long(state->connector_mask) != 1) { SDE_ERROR("invalid connector count(%d) for crtc: %d\n", (int)hweight_long(state->connector_mask), crtc->base.id); return -EINVAL; } /* * check connector array cached at modeset time since incoming atomic * state may not include any connectors if they aren't modified Loading @@ -1307,15 +1303,13 @@ static int _sde_crtc_check_rois(struct drm_crtc *crtc, SDE_ERROR("failed to get mode info\n"); return -EINVAL; } break; } if (!mode_info.roi_caps.enabled) return 0; continue; if (sde_crtc_state->user_roi_list.num_rects > mode_info.roi_caps.num_roi) { SDE_ERROR("roi count is more than supported limit, %d > %d\n", SDE_ERROR("roi count is exceeding limit, %d > %d\n", sde_crtc_state->user_roi_list.num_rects, mode_info.roi_caps.num_roi); return -E2BIG; Loading @@ -1342,6 +1336,7 @@ static int _sde_crtc_check_rois(struct drm_crtc *crtc, rc = _sde_crtc_check_planes_within_crtc_roi(crtc, state); if (rc) return rc; } return 0; } Loading Loading @@ -2116,15 +2111,62 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc) } } static void sde_crtc_frame_event_cb(void *data, u32 event) { struct drm_crtc *crtc = (struct drm_crtc *)data; struct sde_crtc *sde_crtc; struct msm_drm_private *priv; struct sde_crtc_frame_event *fevent; struct sde_crtc_frame_event_cb_data *cb_data; unsigned long flags; u32 crtc_id; cb_data = (struct sde_crtc_frame_event_cb_data *)data; if (!data) { SDE_ERROR("invalid parameters\n"); return; } crtc = cb_data->crtc; if (!crtc || !crtc->dev || !crtc->dev->dev_private) { SDE_ERROR("invalid parameters\n"); return; } sde_crtc = to_sde_crtc(crtc); priv = crtc->dev->dev_private; crtc_id = drm_crtc_index(crtc); SDE_DEBUG("crtc%d\n", crtc->base.id); SDE_EVT32_VERBOSE(DRMID(crtc), event); spin_lock_irqsave(&sde_crtc->spin_lock, flags); fevent = list_first_entry_or_null(&sde_crtc->frame_event_list, struct sde_crtc_frame_event, list); if (fevent) list_del_init(&fevent->list); spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); if (!fevent) { SDE_ERROR("crtc%d event %d overflow\n", crtc->base.id, event); SDE_EVT32(DRMID(crtc), event); return; } fevent->event = event; fevent->crtc = crtc; fevent->connector = cb_data->connector; fevent->ts = ktime_get(); kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work); } void sde_crtc_prepare_commit(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { struct sde_crtc *sde_crtc; struct sde_crtc_state *cstate; struct drm_connector *conn; struct sde_crtc_retire_event *retire_event = NULL; unsigned long flags; int i; struct drm_encoder *encoder; if (!crtc || !crtc->state) { SDE_ERROR("invalid crtc\n"); Loading @@ -2141,31 +2183,17 @@ void sde_crtc_prepare_commit(struct drm_crtc *crtc, drm_for_each_connector(conn, crtc->dev) if (conn->state && conn->state->crtc == crtc && cstate->num_connectors < MAX_CONNECTORS) { encoder = conn->state->best_encoder; if (encoder) sde_encoder_register_frame_event_callback( encoder, sde_crtc_frame_event_cb, crtc); cstate->connectors[cstate->num_connectors++] = conn; sde_connector_prepare_fence(conn); } for (i = 0; i < SDE_CRTC_FRAME_EVENT_SIZE; i++) { retire_event = &sde_crtc->retire_events[i]; if (list_empty(&retire_event->list)) break; retire_event = NULL; } if (retire_event) { retire_event->num_connectors = cstate->num_connectors; for (i = 0; i < cstate->num_connectors; i++) retire_event->connectors[i] = cstate->connectors[i]; spin_lock_irqsave(&sde_crtc->spin_lock, flags); list_add_tail(&retire_event->list, &sde_crtc->retire_event_list); spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); } else { SDE_ERROR("crtc%d retire event overflow\n", crtc->base.id); SDE_EVT32(DRMID(crtc), SDE_EVTLOG_ERROR); } /* prepare main output fence */ sde_fence_prepare(&sde_crtc->output_fence); } Loading Loading @@ -2216,9 +2244,16 @@ enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc) return INTF_MODE_NONE; } drm_for_each_encoder(encoder, crtc->dev) if (encoder->crtc == crtc) drm_for_each_encoder(encoder, crtc->dev) { if (encoder->crtc != crtc) continue; /* continue if copy encoder is encountered */ if (sde_encoder_in_clone_mode(encoder)) continue; return sde_encoder_get_intf_mode(encoder); } return INTF_MODE_NONE; } Loading @@ -2243,38 +2278,16 @@ static void sde_crtc_vblank_cb(void *data) SDE_EVT32_VERBOSE(DRMID(crtc)); } static void _sde_crtc_retire_event(struct drm_crtc *crtc, ktime_t ts) static void _sde_crtc_retire_event(struct drm_connector *connector, ktime_t ts, bool is_error) { struct sde_crtc_retire_event *retire_event; struct sde_crtc *sde_crtc; unsigned long flags; int i; if (!crtc) { if (!connector) { SDE_ERROR("invalid param\n"); return; } sde_crtc = to_sde_crtc(crtc); spin_lock_irqsave(&sde_crtc->spin_lock, flags); retire_event = list_first_entry_or_null(&sde_crtc->retire_event_list, struct sde_crtc_retire_event, list); if (retire_event) list_del_init(&retire_event->list); spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); if (!retire_event) { SDE_ERROR("crtc%d retire event without kickoff\n", crtc->base.id); SDE_EVT32(DRMID(crtc), SDE_EVTLOG_ERROR); return; } SDE_ATRACE_BEGIN("signal_retire_fence"); for (i = 0; (i < retire_event->num_connectors) && retire_event->connectors[i]; ++i) sde_connector_complete_commit( retire_event->connectors[i], ts); sde_connector_complete_commit(connector, ts, is_error); SDE_ATRACE_END("signal_retire_fence"); } Loading @@ -2287,6 +2300,7 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) struct sde_kms *sde_kms; unsigned long flags; bool frame_done = false; bool in_clone_mode = false; if (!work) { SDE_ERROR("invalid work handle\n"); Loading Loading @@ -2315,10 +2329,11 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) SDE_EVT32_VERBOSE(DRMID(crtc), fevent->event, SDE_EVTLOG_FUNC_ENTRY); if (fevent->event & (SDE_ENCODER_FRAME_EVENT_DONE | SDE_ENCODER_FRAME_EVENT_ERROR | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) { in_clone_mode = sde_encoder_in_clone_mode(fevent->connector->encoder); if (!in_clone_mode && (fevent->event & (SDE_ENCODER_FRAME_EVENT_ERROR | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD | SDE_ENCODER_FRAME_EVENT_DONE))) { if (atomic_read(&sde_crtc->frame_pending) < 1) { /* this should not happen */ SDE_ERROR("crtc%d ts:%lld invalid frame_pending:%d\n", Loading Loading @@ -2347,13 +2362,17 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE) { SDE_ATRACE_BEGIN("signal_release_fence"); sde_fence_signal(&sde_crtc->output_fence, fevent->ts, false); sde_fence_signal(&sde_crtc->output_fence, fevent->ts, (fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR) ? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL); SDE_ATRACE_END("signal_release_fence"); } if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE) /* this api should be called without spin_lock */ _sde_crtc_retire_event(crtc, fevent->ts); _sde_crtc_retire_event(fevent->connector, fevent->ts, (fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR) ? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL); if (fevent->event & SDE_ENCODER_FRAME_EVENT_PANEL_DEAD) SDE_ERROR("crtc%d ts:%lld received panel dead event\n", Loading @@ -2368,46 +2387,6 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) SDE_ATRACE_END("crtc_frame_event"); } static void sde_crtc_frame_event_cb(void *data, u32 event) { struct drm_crtc *crtc = (struct drm_crtc *)data; struct sde_crtc *sde_crtc; struct msm_drm_private *priv; struct sde_crtc_frame_event *fevent; unsigned long flags; u32 crtc_id; if (!crtc || !crtc->dev || !crtc->dev->dev_private) { SDE_ERROR("invalid parameters\n"); return; } sde_crtc = to_sde_crtc(crtc); priv = crtc->dev->dev_private; crtc_id = drm_crtc_index(crtc); SDE_DEBUG("crtc%d\n", crtc->base.id); SDE_EVT32_VERBOSE(DRMID(crtc), event); spin_lock_irqsave(&sde_crtc->spin_lock, flags); fevent = list_first_entry_or_null(&sde_crtc->frame_event_list, struct sde_crtc_frame_event, list); if (fevent) list_del_init(&fevent->list); spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); if (!fevent) { SDE_ERROR("crtc%d event %d overflow\n", crtc->base.id, event); SDE_EVT32(DRMID(crtc), event); return; } fevent->event = event; fevent->crtc = crtc; fevent->ts = ktime_get(); 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) { Loading Loading @@ -2977,6 +2956,10 @@ static void _sde_crtc_setup_mixers(struct drm_crtc *crtc) if (enc->crtc != crtc) continue; /* avoid overwriting mixers info from a copy encoder */ if (sde_encoder_in_clone_mode(enc)) continue; _sde_crtc_setup_mixer_for_encoder(crtc, enc); } Loading Loading @@ -4211,7 +4194,8 @@ static void sde_crtc_disable(struct drm_crtc *crtc) * reset the fence timeline if crtc will not be enabled for this commit */ if (!crtc->state->active || !crtc->state->enable) { sde_fence_signal(&sde_crtc->output_fence, ktime_get(), true); sde_fence_signal(&sde_crtc->output_fence, ktime_get(), SDE_FENCE_RESET_TIMELINE); for (i = 0; i < cstate->num_connectors; ++i) sde_connector_commit_reset(cstate->connectors[i], ktime_get()); Loading Loading @@ -4276,7 +4260,7 @@ static void sde_crtc_enable(struct drm_crtc *crtc) if (encoder->crtc != crtc) continue; sde_encoder_register_frame_event_callback(encoder, sde_crtc_frame_event_cb, (void *)crtc); sde_crtc_frame_event_cb, crtc); } if (!sde_crtc->enabled && !sde_crtc->suspend && Loading Loading @@ -4935,6 +4919,11 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, {SDE_DRM_SEC_ONLY, "sec_only"}, }; static const struct drm_prop_enum_list e_cwb_data_points[] = { {CAPTURE_MIXER_OUT, "capture_mixer_out"}, {CAPTURE_DSPP_OUT, "capture_pp_out"}, }; SDE_DEBUG("\n"); if (!crtc || !catalog) { Loading Loading @@ -5014,6 +5003,12 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, "enable_sui_enhancement", 0, 0, U64_MAX, 0, CRTC_PROP_ENABLE_SUI_ENHANCEMENT); if (catalog->has_cwb_support) msm_property_install_enum(&sde_crtc->property_info, "capture_mode", 0, 0, e_cwb_data_points, ARRAY_SIZE(e_cwb_data_points), CRTC_PROP_CAPTURE_OUTPUT); msm_property_install_blob(&sde_crtc->property_info, "capabilities", DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO); Loading Loading @@ -5887,10 +5882,6 @@ static int _sde_crtc_init_events(struct sde_crtc *sde_crtc) list_add_tail(&sde_crtc->event_cache[i].list, &sde_crtc->event_free_list); INIT_LIST_HEAD(&sde_crtc->retire_event_list); for (i = 0; i < ARRAY_SIZE(sde_crtc->retire_events); i++) INIT_LIST_HEAD(&sde_crtc->retire_events[i].list); return rc; } Loading
drivers/gpu/drm/msm/sde/sde_crtc.h +24 −5 Original line number Diff line number Diff line Loading @@ -31,7 +31,8 @@ #define SDE_CRTC_NAME_SIZE 12 /* define the maximum number of in-flight frame events */ #define SDE_CRTC_FRAME_EVENT_SIZE 4 /* Expand it to 2x for handling atleast 2 connectors safely */ #define SDE_CRTC_FRAME_EVENT_SIZE (4 * 2) /** * enum sde_crtc_client_type: crtc client type Loading @@ -47,6 +48,16 @@ enum sde_crtc_client_type { RT_RSC_CLIENT, }; /** * enum sde_crtc_output_capture_point * @MIXER_OUT : capture mixer output * @DSPP_OUT : capture output of dspp */ enum sde_crtc_output_capture_point { CAPTURE_MIXER_OUT, CAPTURE_DSPP_OUT }; /** * @connectors : Currently associated drm connectors for retire event * @num_connectors: Number of associated drm connectors for retire event Loading Loading @@ -80,10 +91,21 @@ struct sde_crtc_mixer { u32 pipe_mask; }; /** * struct sde_crtc_frame_event_cb_data : info of drm objects of a frame event * @crtc: pointer to drm crtc object registered for frame event * @connector: pointer to drm connector which is source of frame event */ struct sde_crtc_frame_event_cb_data { struct drm_crtc *crtc; struct drm_connector *connector; }; /** * struct sde_crtc_frame_event: stores crtc frame event for crtc processing * @work: base work structure * @crtc: Pointer to crtc handling this event * @connector: pointer to drm connector which is source of frame event * @list: event list * @ts: timestamp at queue entry * @event: event identifier Loading @@ -91,6 +113,7 @@ struct sde_crtc_mixer { struct sde_crtc_frame_event { struct kthread_work work; struct drm_crtc *crtc; struct drm_connector *connector; struct list_head list; ktime_t ts; u32 event; Loading Loading @@ -161,8 +184,6 @@ struct sde_crtc_event { * @frame_events : static allocation of in-flight frame events * @frame_event_list : available frame event list * @spin_lock : spin lock for frame event, transaction status, etc... * @retire_events : static allocation of retire fence connector * @retire_event_list : available retire fence connector list * @frame_done_comp : for frame_event_done synchronization * @event_thread : Pointer to event handler thread * @event_worker : Event worker queue Loading Loading @@ -234,8 +255,6 @@ struct sde_crtc { struct sde_crtc_frame_event frame_events[SDE_CRTC_FRAME_EVENT_SIZE]; struct list_head frame_event_list; spinlock_t spin_lock; struct sde_crtc_retire_event retire_events[SDE_CRTC_FRAME_EVENT_SIZE]; struct list_head retire_event_list; struct completion frame_done_comp; /* for handling internal event thread */ Loading