Loading drivers/gpu/drm/msm/sde/sde_ad4.h +17 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,14 @@ enum ad_property { AD_PROPMAX, }; /** * enum ad_intr_resp_property - ad4 interrupt response enum */ enum ad_intr_resp_property { AD4_BACKLIGHT, AD4_RESPMAX, }; /** * struct sde_ad_hw_cfg - structure for setting the ad properties * @prop: enum of ad property Loading @@ -76,4 +84,13 @@ int sde_validate_dspp_ad4(struct sde_hw_dspp *dspp, u32 *prop); * @cfg: pointer to struct sde_ad_hw_cfg */ void sde_setup_dspp_ad4(struct sde_hw_dspp *dspp, void *cfg); /** * sde_read_intr_resp_ad4 - api to get ad4 interrupt status for event * @dspp: pointer to dspp object * @event: event for which response is needed * @resp: value of event requested */ void sde_read_intr_resp_ad4(struct sde_hw_dspp *dspp, u32 event, u32 *resp); #endif /* _SDE_AD4_H_ */ drivers/gpu/drm/msm/sde/sde_color_processing.c +110 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ #include "sde_hw_dspp.h" #include "sde_hw_lm.h" #include "sde_ad4.h" #include "sde_hw_interrupts.h" #include "sde_core_irq.h" struct sde_cp_node { u32 property_id; Loading @@ -35,6 +37,7 @@ struct sde_cp_node { struct list_head dirty_list; bool is_dspp_feature; u32 prop_blob_sz; struct sde_irq_callback *irq; }; struct sde_cp_prop_attach { Loading Loading @@ -1316,3 +1319,110 @@ static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node, } return ret; } static void sde_cp_ad_interrupt_cb(void *arg, int irq_idx) { struct sde_crtc *crtc = arg; struct drm_event event; uint32_t bl = 0; u32 num_mixers = crtc->num_mixers; struct sde_hw_mixer *hw_lm = NULL; struct sde_hw_dspp *hw_dspp = NULL; int i; event.type = DRM_EVENT_AD_BACKLIGHT; event.length = sizeof(bl); for (i = 0; i < num_mixers; i++) { hw_lm = crtc->mixers[i].hw_lm; hw_dspp = crtc->mixers[i].hw_dspp; if (!hw_lm->cfg.right_mixer) break; } if (!hw_dspp) return; hw_dspp->ops.ad_read_intr_resp(hw_dspp, AD4_BACKLIGHT, &bl); msm_send_crtc_notification(&crtc->base, &event, (u8 *)&bl); } int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *ad_irq) { struct sde_kms *kms = NULL; u32 num_mixers; struct sde_hw_mixer *hw_lm; struct sde_hw_dspp *hw_dspp = NULL; struct sde_crtc *crtc; int i; int irq_idx, ret; struct sde_cp_node prop_node; if (!crtc_drm || !ad_irq) { DRM_ERROR("invalid crtc %pK irq %pK\n", crtc_drm, ad_irq); return -EINVAL; } crtc = to_sde_crtc(crtc_drm); if (!crtc) { DRM_ERROR("invalid sde_crtc %pK\n", crtc); return -EINVAL; } mutex_lock(&crtc->crtc_lock); kms = get_kms(crtc_drm); num_mixers = crtc->num_mixers; memset(&prop_node, 0, sizeof(prop_node)); prop_node.feature = SDE_CP_CRTC_DSPP_AD_BACKLIGHT; ret = sde_cp_ad_validate_prop(&prop_node, crtc); if (ret) { DRM_ERROR("Ad not supported ret %d\n", ret); goto exit; } for (i = 0; i < num_mixers; i++) { hw_lm = crtc->mixers[i].hw_lm; hw_dspp = crtc->mixers[i].hw_dspp; if (!hw_lm->cfg.right_mixer) break; } if (!hw_dspp) { DRM_ERROR("invalid dspp\n"); ret = -EINVAL; goto exit; } irq_idx = sde_core_irq_idx_lookup(kms, SDE_IRQ_TYPE_AD4_BL_DONE, hw_dspp->idx); if (irq_idx < 0) { DRM_ERROR("failed to get the irq idx ret %d\n", irq_idx); ret = irq_idx; goto exit; } if (!en) { sde_core_irq_disable(kms, &irq_idx, 1); sde_core_irq_unregister_callback(kms, irq_idx, ad_irq); ret = 0; goto exit; } INIT_LIST_HEAD(&ad_irq->list); ad_irq->arg = crtc; ad_irq->func = sde_cp_ad_interrupt_cb; ret = sde_core_irq_register_callback(kms, irq_idx, ad_irq); if (ret) { DRM_ERROR("failed to register the callback ret %d\n", ret); goto exit; } ret = sde_core_irq_enable(kms, &irq_idx, 1); if (ret) { DRM_ERROR("failed to enable irq ret %d\n", ret); sde_core_irq_unregister_callback(kms, irq_idx, ad_irq); } exit: mutex_unlock(&crtc->crtc_lock); return ret; } drivers/gpu/drm/msm/sde/sde_color_processing.h +11 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ #define _SDE_COLOR_PROCESSING_H #include <drm/drm_crtc.h> struct sde_irq_callback; /* * PA MEMORY COLOR types * @MEMCOLOR_SKIN Skin memory color type Loading Loading @@ -92,4 +94,13 @@ void sde_cp_crtc_suspend(struct drm_crtc *crtc); * @crtc: Pointer to crtc. */ void sde_cp_crtc_resume(struct drm_crtc *crtc); /** * sde_cp_ad_interrupt: Api to enable/disable ad interrupt * @crtc: Pointer to crtc. * @en: Variable to enable/disable interrupt. * @irq: Pointer to irq callback */ int sde_cp_ad_interrupt(struct drm_crtc *crtc, bool en, struct sde_irq_callback *irq); #endif /*_SDE_COLOR_PROCESSING_H */ drivers/gpu/drm/msm/sde/sde_crtc.c +118 −2 Original line number Diff line number Diff line Loading @@ -2474,8 +2474,124 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) return crtc; } static int _sde_crtc_event_enable(struct sde_kms *kms, struct drm_crtc *crtc_drm, u32 event) { struct sde_crtc *crtc = NULL; struct sde_crtc_irq_info *node; struct msm_drm_private *priv; unsigned long flags; bool found = false; int ret; crtc = to_sde_crtc(crtc_drm); spin_lock_irqsave(&crtc->spin_lock, flags); list_for_each_entry(node, &crtc->user_event_list, list) { if (node->event == event) { found = true; break; } } spin_unlock_irqrestore(&crtc->spin_lock, flags); /* event already enabled */ if (found) return 0; node = kzalloc(sizeof(*node), GFP_KERNEL); if (!node) return -ENOMEM; node->event = event; INIT_LIST_HEAD(&node->list); switch (event) { case DRM_EVENT_AD_BACKLIGHT: node->func = sde_cp_ad_interrupt; break; default: SDE_ERROR("unsupported event %x\n", event); kfree(node); return -EINVAL; } priv = kms->dev->dev_private; ret = 0; if (crtc_drm->enabled) { sde_power_resource_enable(&priv->phandle, kms->core_client, true); ret = node->func(crtc_drm, true, &node->irq); sde_power_resource_enable(&priv->phandle, kms->core_client, false); } if (!ret) { spin_lock_irqsave(&crtc->spin_lock, flags); list_add_tail(&node->list, &crtc->user_event_list); spin_unlock_irqrestore(&crtc->spin_lock, flags); } else { kfree(node); } return ret; } static int _sde_crtc_event_disable(struct sde_kms *kms, struct drm_crtc *crtc_drm, u32 event) { struct sde_crtc *crtc = NULL; struct sde_crtc_irq_info *node = NULL; struct msm_drm_private *priv; unsigned long flags; bool found = false; int ret; crtc = to_sde_crtc(crtc_drm); spin_lock_irqsave(&crtc->spin_lock, flags); list_for_each_entry(node, &crtc->user_event_list, list) { if (node->event == event) { list_del(&node->list); found = true; break; } } spin_unlock_irqrestore(&crtc->spin_lock, flags); /* event already disabled */ if (!found) return 0; /** * crtc is disabled interrupts are cleared remove from the list, * no need to disable/de-register. */ if (!crtc_drm->enabled) { kfree(node); return 0; } priv = kms->dev->dev_private; sde_power_resource_enable(&priv->phandle, kms->core_client, true); ret = node->func(crtc_drm, false, &node->irq); sde_power_resource_enable(&priv->phandle, kms->core_client, false); return ret; } int sde_crtc_register_custom_event(struct sde_kms *kms, struct drm_crtc *crtc_drm, u32 event, bool val) struct drm_crtc *crtc_drm, u32 event, bool en) { struct sde_crtc *crtc = NULL; int ret; crtc = to_sde_crtc(crtc_drm); if (!crtc || !kms || !kms->dev) { DRM_ERROR("invalid sde_crtc %pK kms %pK dev %pK\n", crtc, kms, ((kms) ? (kms->dev) : NULL)); return -EINVAL; } if (en) ret = _sde_crtc_event_enable(kms, crtc_drm, event); else ret = _sde_crtc_event_disable(kms, crtc_drm, event); return ret; } drivers/gpu/drm/msm/sde/sde_encoder.c +0 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ #include "sde_hw_ctl.h" #include "sde_formats.h" #include "sde_encoder_phys.h" #include "sde_color_processing.h" #include "sde_power_handle.h" #include "sde_hw_dsc.h" Loading Loading
drivers/gpu/drm/msm/sde/sde_ad4.h +17 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,14 @@ enum ad_property { AD_PROPMAX, }; /** * enum ad_intr_resp_property - ad4 interrupt response enum */ enum ad_intr_resp_property { AD4_BACKLIGHT, AD4_RESPMAX, }; /** * struct sde_ad_hw_cfg - structure for setting the ad properties * @prop: enum of ad property Loading @@ -76,4 +84,13 @@ int sde_validate_dspp_ad4(struct sde_hw_dspp *dspp, u32 *prop); * @cfg: pointer to struct sde_ad_hw_cfg */ void sde_setup_dspp_ad4(struct sde_hw_dspp *dspp, void *cfg); /** * sde_read_intr_resp_ad4 - api to get ad4 interrupt status for event * @dspp: pointer to dspp object * @event: event for which response is needed * @resp: value of event requested */ void sde_read_intr_resp_ad4(struct sde_hw_dspp *dspp, u32 event, u32 *resp); #endif /* _SDE_AD4_H_ */
drivers/gpu/drm/msm/sde/sde_color_processing.c +110 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ #include "sde_hw_dspp.h" #include "sde_hw_lm.h" #include "sde_ad4.h" #include "sde_hw_interrupts.h" #include "sde_core_irq.h" struct sde_cp_node { u32 property_id; Loading @@ -35,6 +37,7 @@ struct sde_cp_node { struct list_head dirty_list; bool is_dspp_feature; u32 prop_blob_sz; struct sde_irq_callback *irq; }; struct sde_cp_prop_attach { Loading Loading @@ -1316,3 +1319,110 @@ static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node, } return ret; } static void sde_cp_ad_interrupt_cb(void *arg, int irq_idx) { struct sde_crtc *crtc = arg; struct drm_event event; uint32_t bl = 0; u32 num_mixers = crtc->num_mixers; struct sde_hw_mixer *hw_lm = NULL; struct sde_hw_dspp *hw_dspp = NULL; int i; event.type = DRM_EVENT_AD_BACKLIGHT; event.length = sizeof(bl); for (i = 0; i < num_mixers; i++) { hw_lm = crtc->mixers[i].hw_lm; hw_dspp = crtc->mixers[i].hw_dspp; if (!hw_lm->cfg.right_mixer) break; } if (!hw_dspp) return; hw_dspp->ops.ad_read_intr_resp(hw_dspp, AD4_BACKLIGHT, &bl); msm_send_crtc_notification(&crtc->base, &event, (u8 *)&bl); } int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *ad_irq) { struct sde_kms *kms = NULL; u32 num_mixers; struct sde_hw_mixer *hw_lm; struct sde_hw_dspp *hw_dspp = NULL; struct sde_crtc *crtc; int i; int irq_idx, ret; struct sde_cp_node prop_node; if (!crtc_drm || !ad_irq) { DRM_ERROR("invalid crtc %pK irq %pK\n", crtc_drm, ad_irq); return -EINVAL; } crtc = to_sde_crtc(crtc_drm); if (!crtc) { DRM_ERROR("invalid sde_crtc %pK\n", crtc); return -EINVAL; } mutex_lock(&crtc->crtc_lock); kms = get_kms(crtc_drm); num_mixers = crtc->num_mixers; memset(&prop_node, 0, sizeof(prop_node)); prop_node.feature = SDE_CP_CRTC_DSPP_AD_BACKLIGHT; ret = sde_cp_ad_validate_prop(&prop_node, crtc); if (ret) { DRM_ERROR("Ad not supported ret %d\n", ret); goto exit; } for (i = 0; i < num_mixers; i++) { hw_lm = crtc->mixers[i].hw_lm; hw_dspp = crtc->mixers[i].hw_dspp; if (!hw_lm->cfg.right_mixer) break; } if (!hw_dspp) { DRM_ERROR("invalid dspp\n"); ret = -EINVAL; goto exit; } irq_idx = sde_core_irq_idx_lookup(kms, SDE_IRQ_TYPE_AD4_BL_DONE, hw_dspp->idx); if (irq_idx < 0) { DRM_ERROR("failed to get the irq idx ret %d\n", irq_idx); ret = irq_idx; goto exit; } if (!en) { sde_core_irq_disable(kms, &irq_idx, 1); sde_core_irq_unregister_callback(kms, irq_idx, ad_irq); ret = 0; goto exit; } INIT_LIST_HEAD(&ad_irq->list); ad_irq->arg = crtc; ad_irq->func = sde_cp_ad_interrupt_cb; ret = sde_core_irq_register_callback(kms, irq_idx, ad_irq); if (ret) { DRM_ERROR("failed to register the callback ret %d\n", ret); goto exit; } ret = sde_core_irq_enable(kms, &irq_idx, 1); if (ret) { DRM_ERROR("failed to enable irq ret %d\n", ret); sde_core_irq_unregister_callback(kms, irq_idx, ad_irq); } exit: mutex_unlock(&crtc->crtc_lock); return ret; }
drivers/gpu/drm/msm/sde/sde_color_processing.h +11 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ #define _SDE_COLOR_PROCESSING_H #include <drm/drm_crtc.h> struct sde_irq_callback; /* * PA MEMORY COLOR types * @MEMCOLOR_SKIN Skin memory color type Loading Loading @@ -92,4 +94,13 @@ void sde_cp_crtc_suspend(struct drm_crtc *crtc); * @crtc: Pointer to crtc. */ void sde_cp_crtc_resume(struct drm_crtc *crtc); /** * sde_cp_ad_interrupt: Api to enable/disable ad interrupt * @crtc: Pointer to crtc. * @en: Variable to enable/disable interrupt. * @irq: Pointer to irq callback */ int sde_cp_ad_interrupt(struct drm_crtc *crtc, bool en, struct sde_irq_callback *irq); #endif /*_SDE_COLOR_PROCESSING_H */
drivers/gpu/drm/msm/sde/sde_crtc.c +118 −2 Original line number Diff line number Diff line Loading @@ -2474,8 +2474,124 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) return crtc; } static int _sde_crtc_event_enable(struct sde_kms *kms, struct drm_crtc *crtc_drm, u32 event) { struct sde_crtc *crtc = NULL; struct sde_crtc_irq_info *node; struct msm_drm_private *priv; unsigned long flags; bool found = false; int ret; crtc = to_sde_crtc(crtc_drm); spin_lock_irqsave(&crtc->spin_lock, flags); list_for_each_entry(node, &crtc->user_event_list, list) { if (node->event == event) { found = true; break; } } spin_unlock_irqrestore(&crtc->spin_lock, flags); /* event already enabled */ if (found) return 0; node = kzalloc(sizeof(*node), GFP_KERNEL); if (!node) return -ENOMEM; node->event = event; INIT_LIST_HEAD(&node->list); switch (event) { case DRM_EVENT_AD_BACKLIGHT: node->func = sde_cp_ad_interrupt; break; default: SDE_ERROR("unsupported event %x\n", event); kfree(node); return -EINVAL; } priv = kms->dev->dev_private; ret = 0; if (crtc_drm->enabled) { sde_power_resource_enable(&priv->phandle, kms->core_client, true); ret = node->func(crtc_drm, true, &node->irq); sde_power_resource_enable(&priv->phandle, kms->core_client, false); } if (!ret) { spin_lock_irqsave(&crtc->spin_lock, flags); list_add_tail(&node->list, &crtc->user_event_list); spin_unlock_irqrestore(&crtc->spin_lock, flags); } else { kfree(node); } return ret; } static int _sde_crtc_event_disable(struct sde_kms *kms, struct drm_crtc *crtc_drm, u32 event) { struct sde_crtc *crtc = NULL; struct sde_crtc_irq_info *node = NULL; struct msm_drm_private *priv; unsigned long flags; bool found = false; int ret; crtc = to_sde_crtc(crtc_drm); spin_lock_irqsave(&crtc->spin_lock, flags); list_for_each_entry(node, &crtc->user_event_list, list) { if (node->event == event) { list_del(&node->list); found = true; break; } } spin_unlock_irqrestore(&crtc->spin_lock, flags); /* event already disabled */ if (!found) return 0; /** * crtc is disabled interrupts are cleared remove from the list, * no need to disable/de-register. */ if (!crtc_drm->enabled) { kfree(node); return 0; } priv = kms->dev->dev_private; sde_power_resource_enable(&priv->phandle, kms->core_client, true); ret = node->func(crtc_drm, false, &node->irq); sde_power_resource_enable(&priv->phandle, kms->core_client, false); return ret; } int sde_crtc_register_custom_event(struct sde_kms *kms, struct drm_crtc *crtc_drm, u32 event, bool val) struct drm_crtc *crtc_drm, u32 event, bool en) { struct sde_crtc *crtc = NULL; int ret; crtc = to_sde_crtc(crtc_drm); if (!crtc || !kms || !kms->dev) { DRM_ERROR("invalid sde_crtc %pK kms %pK dev %pK\n", crtc, kms, ((kms) ? (kms->dev) : NULL)); return -EINVAL; } if (en) ret = _sde_crtc_event_enable(kms, crtc_drm, event); else ret = _sde_crtc_event_disable(kms, crtc_drm, event); return ret; }
drivers/gpu/drm/msm/sde/sde_encoder.c +0 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ #include "sde_hw_ctl.h" #include "sde_formats.h" #include "sde_encoder_phys.h" #include "sde_color_processing.h" #include "sde_power_handle.h" #include "sde_hw_dsc.h" Loading