Loading drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c +15 −6 Original line number Diff line number Diff line Loading @@ -285,13 +285,17 @@ int dsi_core_clk_stop(struct dsi_core_clks *c_clks) return rc; } static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks) static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks, int index) { int rc = 0; struct dsi_clk_mngr *mngr; mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[0]); if (index >= MAX_DSI_CTRL) { pr_err("Invalid DSI ctrl index\n"); return -EINVAL; } mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[index]); if (mngr->is_cont_splash_enabled) return 0; /* Loading Loading @@ -443,11 +447,16 @@ static void dsi_link_clk_disable(struct dsi_link_clks *l_clks) /** * dsi_link_clk_start() - enable dsi link clocks */ int dsi_link_clk_start(struct dsi_link_clks *clks) static int dsi_link_clk_start(struct dsi_link_clks *clks, int index) { int rc = 0; rc = dsi_link_clk_set_rate(clks); if (index >= MAX_DSI_CTRL) { pr_err("Invalid DSI ctrl index\n"); return -EINVAL; } rc = dsi_link_clk_set_rate(clks, index); if (rc) { pr_err("failed to set clk rates, rc = %d\n", rc); goto error; Loading Loading @@ -561,7 +570,7 @@ static int dsi_display_link_clk_enable(struct dsi_link_clks *clks, m_clks = &clks[master_ndx]; rc = dsi_link_clk_start(m_clks); rc = dsi_link_clk_start(m_clks, master_ndx); if (rc) { pr_err("failed to turn on master clocks, rc=%d\n", rc); goto error; Loading @@ -573,7 +582,7 @@ static int dsi_display_link_clk_enable(struct dsi_link_clks *clks, if (!clk || (clk == m_clks)) continue; rc = dsi_link_clk_start(clk); rc = dsi_link_clk_start(clk, i); if (rc) { pr_err("failed to turn on clocks, rc=%d\n", rc); goto error_disable_master; Loading drivers/gpu/drm/msm/msm_drv.c +1 −55 Original line number Diff line number Diff line Loading @@ -1500,42 +1500,6 @@ static int msm_release(struct inode *inode, struct file *filp) return drm_release(inode, filp); } /** * msm_drv_framebuffer_remove - remove and unreference a framebuffer object * @fb: framebuffer to remove */ void msm_drv_framebuffer_remove(struct drm_framebuffer *fb) { struct drm_device *dev; if (!fb) return; dev = fb->dev; WARN_ON(!list_empty(&fb->filp_head)); drm_framebuffer_unreference(fb); } struct msm_drv_rmfb2_work { struct work_struct work; struct list_head fbs; }; static void msm_drv_rmfb2_work_fn(struct work_struct *w) { struct msm_drv_rmfb2_work *arg = container_of(w, typeof(*arg), work); while (!list_empty(&arg->fbs)) { struct drm_framebuffer *fb = list_first_entry(&arg->fbs, typeof(*fb), filp_head); list_del_init(&fb->filp_head); msm_drv_framebuffer_remove(fb); } } /** * msm_ioctl_rmfb2 - remove an FB from the configuration * @dev: drm device for the ioctl Loading Loading @@ -1579,24 +1543,6 @@ int msm_ioctl_rmfb2(struct drm_device *dev, void *data, list_del_init(&fb->filp_head); mutex_unlock(&file_priv->fbs_lock); /* * we now own the reference that was stored in the fbs list * * drm_framebuffer_remove may fail with -EINTR on pending signals, * so run this in a separate stack as there's no way to correctly * handle this after the fb is already removed from the lookup table. */ if (drm_framebuffer_read_refcount(fb) > 1) { struct msm_drv_rmfb2_work arg; INIT_WORK_ONSTACK(&arg.work, msm_drv_rmfb2_work_fn); INIT_LIST_HEAD(&arg.fbs); list_add_tail(&fb->filp_head, &arg.fbs); schedule_work(&arg.work); flush_work(&arg.work); destroy_work_on_stack(&arg.work); } else drm_framebuffer_unreference(fb); return 0; Loading drivers/gpu/drm/msm/sde/sde_crtc.c +39 −1 Original line number Diff line number Diff line /* * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * Loading Loading @@ -1426,6 +1426,35 @@ static u32 _sde_crtc_calc_inline_prefill(struct drm_crtc *crtc) return sde_kms->catalog->sbuf_prefill + sde_kms->catalog->sbuf_headroom; } uint64_t sde_crtc_get_sbuf_clk(struct drm_crtc_state *state) { struct sde_crtc_state *cstate; u64 tmp; if (!state) { SDE_ERROR("invalid crtc state\n"); return 0; } cstate = to_sde_crtc_state(state); /* * Select the max of the current and previous frame's user mode * clock setting so that reductions in clock voting don't take effect * until the current frame has completed. * * If the sbuf_clk_rate[] FIFO hasn't yet been updated in this commit * cycle (as part of the CRTC's atomic check), compare the current * clock value against sbuf_clk_rate[1] instead of comparing the * sbuf_clk_rate[0]/sbuf_clk_rate[1] values. */ if (cstate->sbuf_clk_shifted) tmp = cstate->sbuf_clk_rate[0]; else tmp = sde_crtc_get_property(cstate, CRTC_PROP_ROT_CLK); return max_t(u64, cstate->sbuf_clk_rate[1], tmp); } static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc, struct drm_crtc_state *old_state, struct sde_crtc *sde_crtc, struct sde_crtc_mixer *mixer) Loading Loading @@ -4030,6 +4059,9 @@ static struct drm_crtc_state *sde_crtc_duplicate_state(struct drm_crtc *crtc) /* clear destination scaler dirty bit */ cstate->ds_dirty = false; /* record whether or not the sbuf_clk_rate fifo has been shifted */ cstate->sbuf_clk_shifted = false; /* duplicate base helper */ __drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base); Loading Loading @@ -4672,6 +4704,12 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, _sde_crtc_setup_is_ppsplit(state); _sde_crtc_setup_lm_bounds(crtc, state); /* record current/previous sbuf clock rate for later */ cstate->sbuf_clk_rate[0] = cstate->sbuf_clk_rate[1]; cstate->sbuf_clk_rate[1] = sde_crtc_get_property( cstate, CRTC_PROP_ROT_CLK); cstate->sbuf_clk_shifted = true; /* 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 +13 −1 Original line number Diff line number Diff line /* * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * Loading Loading @@ -391,6 +391,9 @@ struct sde_crtc_respool { * @new_perf: new performance state being requested * @sbuf_cfg: stream buffer configuration * @sbuf_prefill_line: number of line for inline rotator prefetch * @sbuf_clk_rate : previous and current user specified inline rotator clock * @sbuf_clk_shifted : whether or not sbuf_clk_rate has been shifted as part * of crtc atomic check */ struct sde_crtc_state { struct drm_crtc_state base; Loading Loading @@ -422,6 +425,8 @@ struct sde_crtc_state { struct sde_core_perf_params new_perf; struct sde_ctl_sbuf_cfg sbuf_cfg; u32 sbuf_prefill_line; u64 sbuf_clk_rate[2]; bool sbuf_clk_shifted; struct sde_crtc_respool rp; }; Loading Loading @@ -769,4 +774,11 @@ void sde_crtc_timeline_status(struct drm_crtc *crtc); void sde_crtc_update_cont_splash_mixer_settings( struct drm_crtc *crtc); /** * sde_crtc_get_sbuf_clk - get user specified sbuf clock settings * @state: Pointer to DRM crtc state object * Returns: Filtered sbuf clock setting from user space */ uint64_t sde_crtc_get_sbuf_clk(struct drm_crtc_state *state); #endif /* _SDE_CRTC_H_ */ drivers/gpu/drm/msm/sde/sde_encoder.c +228 −2 Original line number Diff line number Diff line Loading @@ -120,6 +120,13 @@ * Event signals that there were no frame updates for * IDLE_POWERCOLLAPSE_DURATION time. This would disable MDP/DSI core clocks * and request RSC with IDLE state and change the resource state to IDLE. * @SDE_ENC_RC_EVENT_EARLY_WAKEUP: * This event is triggered from the input event thread when touch event is * received from the input device. On receiving this event, * - If the device is in SDE_ENC_RC_STATE_IDLE state, it turns ON the clocks and enable RSC. * - If the device is in SDE_ENC_RC_STATE_ON state, it resets the delayed * off work since a new commit is imminent. */ enum sde_enc_rc_events { SDE_ENC_RC_EVENT_KICKOFF = 1, Loading @@ -128,7 +135,8 @@ enum sde_enc_rc_events { SDE_ENC_RC_EVENT_STOP, SDE_ENC_RC_EVENT_PRE_MODESET, SDE_ENC_RC_EVENT_POST_MODESET, SDE_ENC_RC_EVENT_ENTER_IDLE SDE_ENC_RC_EVENT_ENTER_IDLE, SDE_ENC_RC_EVENT_EARLY_WAKEUP, }; /* Loading Loading @@ -193,6 +201,8 @@ enum sde_enc_rc_states { * @delayed_off_work: delayed worker to schedule disabling of * clks and resources after IDLE_TIMEOUT time. * @vsync_event_work: worker to handle vsync event for autorefresh * @input_event_work: worker to handle input device touch events * @input_handler: handler for input device events * @topology: topology of the display * @vblank_enabled: boolean to track userspace vblank vote * @rsc_config: rsc configuration for display vtotal, fps, etc. Loading Loading @@ -237,6 +247,8 @@ struct sde_encoder_virt { enum sde_enc_rc_states rc_state; struct kthread_delayed_work delayed_off_work; struct kthread_work vsync_event_work; struct kthread_work input_event_work; struct input_handler *input_handler; struct msm_display_topology topology; bool vblank_enabled; Loading Loading @@ -708,6 +720,11 @@ void sde_encoder_destroy(struct drm_encoder *drm_enc) drm_encoder_cleanup(drm_enc); mutex_destroy(&sde_enc->enc_lock); if (sde_enc->input_handler) { input_unregister_handler(sde_enc->input_handler); kfree(sde_enc->input_handler); } kfree(sde_enc); } Loading Loading @@ -1815,6 +1832,45 @@ static int _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc, return 0; } static void sde_encoder_input_event_handler(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct drm_encoder *drm_enc = NULL; struct sde_encoder_virt *sde_enc = NULL; struct msm_drm_thread *disp_thread = NULL; struct msm_drm_private *priv = NULL; if (!handle || !handle->handler || !handle->handler->private) { SDE_ERROR("invalid encoder for the input event\n"); return; } drm_enc = (struct drm_encoder *)handle->handler->private; if (!drm_enc->dev || !drm_enc->dev->dev_private) { SDE_ERROR("invalid parameters\n"); return; } priv = drm_enc->dev->dev_private; sde_enc = to_sde_encoder_virt(drm_enc); if (!sde_enc->crtc || (sde_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread))) { SDE_DEBUG_ENC(sde_enc, "invalid cached CRTC: %d or crtc index: %d\n", sde_enc->crtc == NULL, sde_enc->crtc ? sde_enc->crtc->index : -EINVAL); return; } SDE_EVT32_VERBOSE(DRMID(drm_enc)); disp_thread = &priv->disp_thread[sde_enc->crtc->index]; kthread_queue_work(&disp_thread->worker, &sde_enc->input_event_work); } static int sde_encoder_resource_control(struct drm_encoder *drm_enc, u32 sw_event) { Loading Loading @@ -1966,7 +2022,7 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, idle_pc_duration = IDLE_POWERCOLLAPSE_DURATION; if (!autorefresh_enabled) kthread_queue_delayed_work( kthread_mod_delayed_work( &disp_thread->worker, &sde_enc->delayed_off_work, msecs_to_jiffies(idle_pc_duration)); Loading Loading @@ -2177,7 +2233,57 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, mutex_unlock(&sde_enc->rc_lock); break; case SDE_ENC_RC_EVENT_EARLY_WAKEUP: if (!sde_enc->crtc || sde_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { SDE_DEBUG_ENC(sde_enc, "invalid crtc:%d or crtc index:%d , sw_event:%u\n", sde_enc->crtc == NULL, sde_enc->crtc ? sde_enc->crtc->index : -EINVAL, sw_event); return -EINVAL; } disp_thread = &priv->disp_thread[sde_enc->crtc->index]; mutex_lock(&sde_enc->rc_lock); if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON) { if (sde_enc->cur_master && sde_enc->cur_master->ops.is_autorefresh_enabled) autorefresh_enabled = sde_enc->cur_master->ops.is_autorefresh_enabled( sde_enc->cur_master); if (autorefresh_enabled) { SDE_DEBUG_ENC(sde_enc, "not handling early wakeup since auto refresh is enabled\n"); mutex_lock(&sde_enc->rc_lock); return 0; } if (!sde_crtc_frame_pending(sde_enc->crtc)) kthread_mod_delayed_work(&disp_thread->worker, &sde_enc->delayed_off_work, msecs_to_jiffies( IDLE_POWERCOLLAPSE_DURATION)); } else if (sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) { /* enable all the clks and resources */ _sde_encoder_resource_control_rsc_update(drm_enc, true); _sde_encoder_resource_control_helper(drm_enc, true); kthread_mod_delayed_work(&disp_thread->worker, &sde_enc->delayed_off_work, msecs_to_jiffies( IDLE_POWERCOLLAPSE_DURATION)); sde_enc->rc_state = SDE_ENC_RC_STATE_ON; } SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE8); mutex_unlock(&sde_enc->rc_lock); break; default: SDE_EVT32(DRMID(drm_enc), sw_event, SDE_EVTLOG_ERROR); SDE_ERROR("unexpected sw_event: %d\n", sw_event); Loading Loading @@ -3402,6 +3508,116 @@ static void sde_encoder_vsync_event_handler(unsigned long data) &sde_enc->vsync_event_work); } static void sde_encoder_input_event_work_handler(struct kthread_work *work) { struct sde_encoder_virt *sde_enc = container_of(work, struct sde_encoder_virt, input_event_work); if (!sde_enc) { SDE_ERROR("invalid sde encoder\n"); return; } sde_encoder_resource_control(&sde_enc->base, SDE_ENC_RC_EVENT_EARLY_WAKEUP); } static int _sde_encoder_input_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { struct input_handle *handle; int rc = 0; handle = kzalloc(sizeof(*handle), GFP_KERNEL); if (!handle) return -ENOMEM; handle->dev = dev; handle->handler = handler; handle->name = handler->name; rc = input_register_handle(handle); if (rc) { pr_err("failed to register input handle\n"); goto error; } rc = input_open_device(handle); if (rc) { pr_err("failed to open input device\n"); goto error_unregister; } return 0; error_unregister: input_unregister_handle(handle); error: kfree(handle); return rc; } static void _sde_encoder_input_disconnect(struct input_handle *handle) { input_close_device(handle); input_unregister_handle(handle); kfree(handle); } /** * Structure for specifying event parameters on which to receive callbacks. * This structure will trigger a callback in case of a touch event (specified by * EV_ABS) where there is a change in X and Y coordinates, */ static const struct input_device_id sde_input_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT, .evbit = { BIT_MASK(EV_ABS) }, .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] = BIT_MASK(ABS_MT_POSITION_X) | BIT_MASK(ABS_MT_POSITION_Y) }, }, { }, }; static int _sde_encoder_input_handler( struct sde_encoder_virt *sde_enc) { struct input_handler *input_handler = NULL; int rc = 0; if (sde_enc->input_handler) { SDE_ERROR_ENC(sde_enc, "input_handle is active. unexpected\n"); return -EINVAL; } input_handler = kzalloc(sizeof(*sde_enc->input_handler), GFP_KERNEL); if (!input_handler) return -ENOMEM; input_handler->event = sde_encoder_input_event_handler; input_handler->connect = _sde_encoder_input_connect; input_handler->disconnect = _sde_encoder_input_disconnect; input_handler->name = "sde"; input_handler->id_table = sde_input_ids; input_handler->private = sde_enc; rc = input_register_handler(input_handler); if (rc) { SDE_ERROR_ENC(sde_enc, "input_register_handler failed, rc= %d\n", rc); kfree(input_handler); return rc; } sde_enc->input_handler = input_handler; return rc; } static void sde_encoder_vsync_event_work_handler(struct kthread_work *work) { struct sde_encoder_virt *sde_enc = container_of(work, Loading Loading @@ -4262,6 +4478,13 @@ struct drm_encoder *sde_encoder_init( sde_enc->rsc_client = NULL; } if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) { ret = _sde_encoder_input_handler(sde_enc); if (ret) SDE_ERROR( "input handler registration failed, rc = %d\n", ret); } mutex_init(&sde_enc->rc_lock); kthread_init_delayed_work(&sde_enc->delayed_off_work, sde_encoder_off_work); Loading @@ -4270,6 +4493,9 @@ struct drm_encoder *sde_encoder_init( kthread_init_work(&sde_enc->vsync_event_work, sde_encoder_vsync_event_work_handler); kthread_init_work(&sde_enc->input_event_work, sde_encoder_input_event_work_handler); memcpy(&sde_enc->disp_info, disp_info, sizeof(*disp_info)); SDE_DEBUG_ENC(sde_enc, "created\n"); Loading Loading
drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c +15 −6 Original line number Diff line number Diff line Loading @@ -285,13 +285,17 @@ int dsi_core_clk_stop(struct dsi_core_clks *c_clks) return rc; } static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks) static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks, int index) { int rc = 0; struct dsi_clk_mngr *mngr; mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[0]); if (index >= MAX_DSI_CTRL) { pr_err("Invalid DSI ctrl index\n"); return -EINVAL; } mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[index]); if (mngr->is_cont_splash_enabled) return 0; /* Loading Loading @@ -443,11 +447,16 @@ static void dsi_link_clk_disable(struct dsi_link_clks *l_clks) /** * dsi_link_clk_start() - enable dsi link clocks */ int dsi_link_clk_start(struct dsi_link_clks *clks) static int dsi_link_clk_start(struct dsi_link_clks *clks, int index) { int rc = 0; rc = dsi_link_clk_set_rate(clks); if (index >= MAX_DSI_CTRL) { pr_err("Invalid DSI ctrl index\n"); return -EINVAL; } rc = dsi_link_clk_set_rate(clks, index); if (rc) { pr_err("failed to set clk rates, rc = %d\n", rc); goto error; Loading Loading @@ -561,7 +570,7 @@ static int dsi_display_link_clk_enable(struct dsi_link_clks *clks, m_clks = &clks[master_ndx]; rc = dsi_link_clk_start(m_clks); rc = dsi_link_clk_start(m_clks, master_ndx); if (rc) { pr_err("failed to turn on master clocks, rc=%d\n", rc); goto error; Loading @@ -573,7 +582,7 @@ static int dsi_display_link_clk_enable(struct dsi_link_clks *clks, if (!clk || (clk == m_clks)) continue; rc = dsi_link_clk_start(clk); rc = dsi_link_clk_start(clk, i); if (rc) { pr_err("failed to turn on clocks, rc=%d\n", rc); goto error_disable_master; Loading
drivers/gpu/drm/msm/msm_drv.c +1 −55 Original line number Diff line number Diff line Loading @@ -1500,42 +1500,6 @@ static int msm_release(struct inode *inode, struct file *filp) return drm_release(inode, filp); } /** * msm_drv_framebuffer_remove - remove and unreference a framebuffer object * @fb: framebuffer to remove */ void msm_drv_framebuffer_remove(struct drm_framebuffer *fb) { struct drm_device *dev; if (!fb) return; dev = fb->dev; WARN_ON(!list_empty(&fb->filp_head)); drm_framebuffer_unreference(fb); } struct msm_drv_rmfb2_work { struct work_struct work; struct list_head fbs; }; static void msm_drv_rmfb2_work_fn(struct work_struct *w) { struct msm_drv_rmfb2_work *arg = container_of(w, typeof(*arg), work); while (!list_empty(&arg->fbs)) { struct drm_framebuffer *fb = list_first_entry(&arg->fbs, typeof(*fb), filp_head); list_del_init(&fb->filp_head); msm_drv_framebuffer_remove(fb); } } /** * msm_ioctl_rmfb2 - remove an FB from the configuration * @dev: drm device for the ioctl Loading Loading @@ -1579,24 +1543,6 @@ int msm_ioctl_rmfb2(struct drm_device *dev, void *data, list_del_init(&fb->filp_head); mutex_unlock(&file_priv->fbs_lock); /* * we now own the reference that was stored in the fbs list * * drm_framebuffer_remove may fail with -EINTR on pending signals, * so run this in a separate stack as there's no way to correctly * handle this after the fb is already removed from the lookup table. */ if (drm_framebuffer_read_refcount(fb) > 1) { struct msm_drv_rmfb2_work arg; INIT_WORK_ONSTACK(&arg.work, msm_drv_rmfb2_work_fn); INIT_LIST_HEAD(&arg.fbs); list_add_tail(&fb->filp_head, &arg.fbs); schedule_work(&arg.work); flush_work(&arg.work); destroy_work_on_stack(&arg.work); } else drm_framebuffer_unreference(fb); return 0; Loading
drivers/gpu/drm/msm/sde/sde_crtc.c +39 −1 Original line number Diff line number Diff line /* * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * Loading Loading @@ -1426,6 +1426,35 @@ static u32 _sde_crtc_calc_inline_prefill(struct drm_crtc *crtc) return sde_kms->catalog->sbuf_prefill + sde_kms->catalog->sbuf_headroom; } uint64_t sde_crtc_get_sbuf_clk(struct drm_crtc_state *state) { struct sde_crtc_state *cstate; u64 tmp; if (!state) { SDE_ERROR("invalid crtc state\n"); return 0; } cstate = to_sde_crtc_state(state); /* * Select the max of the current and previous frame's user mode * clock setting so that reductions in clock voting don't take effect * until the current frame has completed. * * If the sbuf_clk_rate[] FIFO hasn't yet been updated in this commit * cycle (as part of the CRTC's atomic check), compare the current * clock value against sbuf_clk_rate[1] instead of comparing the * sbuf_clk_rate[0]/sbuf_clk_rate[1] values. */ if (cstate->sbuf_clk_shifted) tmp = cstate->sbuf_clk_rate[0]; else tmp = sde_crtc_get_property(cstate, CRTC_PROP_ROT_CLK); return max_t(u64, cstate->sbuf_clk_rate[1], tmp); } static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc, struct drm_crtc_state *old_state, struct sde_crtc *sde_crtc, struct sde_crtc_mixer *mixer) Loading Loading @@ -4030,6 +4059,9 @@ static struct drm_crtc_state *sde_crtc_duplicate_state(struct drm_crtc *crtc) /* clear destination scaler dirty bit */ cstate->ds_dirty = false; /* record whether or not the sbuf_clk_rate fifo has been shifted */ cstate->sbuf_clk_shifted = false; /* duplicate base helper */ __drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base); Loading Loading @@ -4672,6 +4704,12 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, _sde_crtc_setup_is_ppsplit(state); _sde_crtc_setup_lm_bounds(crtc, state); /* record current/previous sbuf clock rate for later */ cstate->sbuf_clk_rate[0] = cstate->sbuf_clk_rate[1]; cstate->sbuf_clk_rate[1] = sde_crtc_get_property( cstate, CRTC_PROP_ROT_CLK); cstate->sbuf_clk_shifted = true; /* 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 +13 −1 Original line number Diff line number Diff line /* * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * Loading Loading @@ -391,6 +391,9 @@ struct sde_crtc_respool { * @new_perf: new performance state being requested * @sbuf_cfg: stream buffer configuration * @sbuf_prefill_line: number of line for inline rotator prefetch * @sbuf_clk_rate : previous and current user specified inline rotator clock * @sbuf_clk_shifted : whether or not sbuf_clk_rate has been shifted as part * of crtc atomic check */ struct sde_crtc_state { struct drm_crtc_state base; Loading Loading @@ -422,6 +425,8 @@ struct sde_crtc_state { struct sde_core_perf_params new_perf; struct sde_ctl_sbuf_cfg sbuf_cfg; u32 sbuf_prefill_line; u64 sbuf_clk_rate[2]; bool sbuf_clk_shifted; struct sde_crtc_respool rp; }; Loading Loading @@ -769,4 +774,11 @@ void sde_crtc_timeline_status(struct drm_crtc *crtc); void sde_crtc_update_cont_splash_mixer_settings( struct drm_crtc *crtc); /** * sde_crtc_get_sbuf_clk - get user specified sbuf clock settings * @state: Pointer to DRM crtc state object * Returns: Filtered sbuf clock setting from user space */ uint64_t sde_crtc_get_sbuf_clk(struct drm_crtc_state *state); #endif /* _SDE_CRTC_H_ */
drivers/gpu/drm/msm/sde/sde_encoder.c +228 −2 Original line number Diff line number Diff line Loading @@ -120,6 +120,13 @@ * Event signals that there were no frame updates for * IDLE_POWERCOLLAPSE_DURATION time. This would disable MDP/DSI core clocks * and request RSC with IDLE state and change the resource state to IDLE. * @SDE_ENC_RC_EVENT_EARLY_WAKEUP: * This event is triggered from the input event thread when touch event is * received from the input device. On receiving this event, * - If the device is in SDE_ENC_RC_STATE_IDLE state, it turns ON the clocks and enable RSC. * - If the device is in SDE_ENC_RC_STATE_ON state, it resets the delayed * off work since a new commit is imminent. */ enum sde_enc_rc_events { SDE_ENC_RC_EVENT_KICKOFF = 1, Loading @@ -128,7 +135,8 @@ enum sde_enc_rc_events { SDE_ENC_RC_EVENT_STOP, SDE_ENC_RC_EVENT_PRE_MODESET, SDE_ENC_RC_EVENT_POST_MODESET, SDE_ENC_RC_EVENT_ENTER_IDLE SDE_ENC_RC_EVENT_ENTER_IDLE, SDE_ENC_RC_EVENT_EARLY_WAKEUP, }; /* Loading Loading @@ -193,6 +201,8 @@ enum sde_enc_rc_states { * @delayed_off_work: delayed worker to schedule disabling of * clks and resources after IDLE_TIMEOUT time. * @vsync_event_work: worker to handle vsync event for autorefresh * @input_event_work: worker to handle input device touch events * @input_handler: handler for input device events * @topology: topology of the display * @vblank_enabled: boolean to track userspace vblank vote * @rsc_config: rsc configuration for display vtotal, fps, etc. Loading Loading @@ -237,6 +247,8 @@ struct sde_encoder_virt { enum sde_enc_rc_states rc_state; struct kthread_delayed_work delayed_off_work; struct kthread_work vsync_event_work; struct kthread_work input_event_work; struct input_handler *input_handler; struct msm_display_topology topology; bool vblank_enabled; Loading Loading @@ -708,6 +720,11 @@ void sde_encoder_destroy(struct drm_encoder *drm_enc) drm_encoder_cleanup(drm_enc); mutex_destroy(&sde_enc->enc_lock); if (sde_enc->input_handler) { input_unregister_handler(sde_enc->input_handler); kfree(sde_enc->input_handler); } kfree(sde_enc); } Loading Loading @@ -1815,6 +1832,45 @@ static int _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc, return 0; } static void sde_encoder_input_event_handler(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct drm_encoder *drm_enc = NULL; struct sde_encoder_virt *sde_enc = NULL; struct msm_drm_thread *disp_thread = NULL; struct msm_drm_private *priv = NULL; if (!handle || !handle->handler || !handle->handler->private) { SDE_ERROR("invalid encoder for the input event\n"); return; } drm_enc = (struct drm_encoder *)handle->handler->private; if (!drm_enc->dev || !drm_enc->dev->dev_private) { SDE_ERROR("invalid parameters\n"); return; } priv = drm_enc->dev->dev_private; sde_enc = to_sde_encoder_virt(drm_enc); if (!sde_enc->crtc || (sde_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread))) { SDE_DEBUG_ENC(sde_enc, "invalid cached CRTC: %d or crtc index: %d\n", sde_enc->crtc == NULL, sde_enc->crtc ? sde_enc->crtc->index : -EINVAL); return; } SDE_EVT32_VERBOSE(DRMID(drm_enc)); disp_thread = &priv->disp_thread[sde_enc->crtc->index]; kthread_queue_work(&disp_thread->worker, &sde_enc->input_event_work); } static int sde_encoder_resource_control(struct drm_encoder *drm_enc, u32 sw_event) { Loading Loading @@ -1966,7 +2022,7 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, idle_pc_duration = IDLE_POWERCOLLAPSE_DURATION; if (!autorefresh_enabled) kthread_queue_delayed_work( kthread_mod_delayed_work( &disp_thread->worker, &sde_enc->delayed_off_work, msecs_to_jiffies(idle_pc_duration)); Loading Loading @@ -2177,7 +2233,57 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, mutex_unlock(&sde_enc->rc_lock); break; case SDE_ENC_RC_EVENT_EARLY_WAKEUP: if (!sde_enc->crtc || sde_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { SDE_DEBUG_ENC(sde_enc, "invalid crtc:%d or crtc index:%d , sw_event:%u\n", sde_enc->crtc == NULL, sde_enc->crtc ? sde_enc->crtc->index : -EINVAL, sw_event); return -EINVAL; } disp_thread = &priv->disp_thread[sde_enc->crtc->index]; mutex_lock(&sde_enc->rc_lock); if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON) { if (sde_enc->cur_master && sde_enc->cur_master->ops.is_autorefresh_enabled) autorefresh_enabled = sde_enc->cur_master->ops.is_autorefresh_enabled( sde_enc->cur_master); if (autorefresh_enabled) { SDE_DEBUG_ENC(sde_enc, "not handling early wakeup since auto refresh is enabled\n"); mutex_lock(&sde_enc->rc_lock); return 0; } if (!sde_crtc_frame_pending(sde_enc->crtc)) kthread_mod_delayed_work(&disp_thread->worker, &sde_enc->delayed_off_work, msecs_to_jiffies( IDLE_POWERCOLLAPSE_DURATION)); } else if (sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) { /* enable all the clks and resources */ _sde_encoder_resource_control_rsc_update(drm_enc, true); _sde_encoder_resource_control_helper(drm_enc, true); kthread_mod_delayed_work(&disp_thread->worker, &sde_enc->delayed_off_work, msecs_to_jiffies( IDLE_POWERCOLLAPSE_DURATION)); sde_enc->rc_state = SDE_ENC_RC_STATE_ON; } SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE8); mutex_unlock(&sde_enc->rc_lock); break; default: SDE_EVT32(DRMID(drm_enc), sw_event, SDE_EVTLOG_ERROR); SDE_ERROR("unexpected sw_event: %d\n", sw_event); Loading Loading @@ -3402,6 +3508,116 @@ static void sde_encoder_vsync_event_handler(unsigned long data) &sde_enc->vsync_event_work); } static void sde_encoder_input_event_work_handler(struct kthread_work *work) { struct sde_encoder_virt *sde_enc = container_of(work, struct sde_encoder_virt, input_event_work); if (!sde_enc) { SDE_ERROR("invalid sde encoder\n"); return; } sde_encoder_resource_control(&sde_enc->base, SDE_ENC_RC_EVENT_EARLY_WAKEUP); } static int _sde_encoder_input_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { struct input_handle *handle; int rc = 0; handle = kzalloc(sizeof(*handle), GFP_KERNEL); if (!handle) return -ENOMEM; handle->dev = dev; handle->handler = handler; handle->name = handler->name; rc = input_register_handle(handle); if (rc) { pr_err("failed to register input handle\n"); goto error; } rc = input_open_device(handle); if (rc) { pr_err("failed to open input device\n"); goto error_unregister; } return 0; error_unregister: input_unregister_handle(handle); error: kfree(handle); return rc; } static void _sde_encoder_input_disconnect(struct input_handle *handle) { input_close_device(handle); input_unregister_handle(handle); kfree(handle); } /** * Structure for specifying event parameters on which to receive callbacks. * This structure will trigger a callback in case of a touch event (specified by * EV_ABS) where there is a change in X and Y coordinates, */ static const struct input_device_id sde_input_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT, .evbit = { BIT_MASK(EV_ABS) }, .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] = BIT_MASK(ABS_MT_POSITION_X) | BIT_MASK(ABS_MT_POSITION_Y) }, }, { }, }; static int _sde_encoder_input_handler( struct sde_encoder_virt *sde_enc) { struct input_handler *input_handler = NULL; int rc = 0; if (sde_enc->input_handler) { SDE_ERROR_ENC(sde_enc, "input_handle is active. unexpected\n"); return -EINVAL; } input_handler = kzalloc(sizeof(*sde_enc->input_handler), GFP_KERNEL); if (!input_handler) return -ENOMEM; input_handler->event = sde_encoder_input_event_handler; input_handler->connect = _sde_encoder_input_connect; input_handler->disconnect = _sde_encoder_input_disconnect; input_handler->name = "sde"; input_handler->id_table = sde_input_ids; input_handler->private = sde_enc; rc = input_register_handler(input_handler); if (rc) { SDE_ERROR_ENC(sde_enc, "input_register_handler failed, rc= %d\n", rc); kfree(input_handler); return rc; } sde_enc->input_handler = input_handler; return rc; } static void sde_encoder_vsync_event_work_handler(struct kthread_work *work) { struct sde_encoder_virt *sde_enc = container_of(work, Loading Loading @@ -4262,6 +4478,13 @@ struct drm_encoder *sde_encoder_init( sde_enc->rsc_client = NULL; } if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) { ret = _sde_encoder_input_handler(sde_enc); if (ret) SDE_ERROR( "input handler registration failed, rc = %d\n", ret); } mutex_init(&sde_enc->rc_lock); kthread_init_delayed_work(&sde_enc->delayed_off_work, sde_encoder_off_work); Loading @@ -4270,6 +4493,9 @@ struct drm_encoder *sde_encoder_init( kthread_init_work(&sde_enc->vsync_event_work, sde_encoder_vsync_event_work_handler); kthread_init_work(&sde_enc->input_event_work, sde_encoder_input_event_work_handler); memcpy(&sde_enc->disp_info, disp_info, sizeof(*disp_info)); SDE_DEBUG_ENC(sde_enc, "created\n"); Loading