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

Commit f1630338 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm/sde: add back-light notification for AD" into msm-4.9

parents ef791be7 5154c71d
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -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
@@ -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_ */
+110 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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 {
@@ -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;
}
+11 −0
Original line number Diff line number Diff line
@@ -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
@@ -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 */
+118 −2
Original line number Diff line number Diff line
@@ -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;
}
+0 −1
Original line number Diff line number Diff line
@@ -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