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

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

Merge "msm: mdss: esd recovery support for 8x10 targets"

parents 390cc7a8 f4976c00
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -42,4 +42,8 @@ obj-$(CONFIG_FB_MSM_QPIC_ILI_QVGA_PANEL) += qpic_panel_ili_qvga.o

obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o

ifeq ($(CONFIG_FB_MSM_MDSS_MDP3),y)
obj-$(CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS) += dsi_status_v2.o
else
obj-$(CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS) += mdss_dsi_status.o
endif
+34 −0
Original line number Diff line number Diff line
@@ -223,6 +223,9 @@ irqreturn_t msm_dsi_isr_handler(int irq, void *ptr)

	spin_unlock(&ctrl->mdp_lock);

	if (isr & DSI_INTR_BTA_DONE)
		complete(&ctrl->bta_comp);

	return IRQ_HANDLED;
}

@@ -1171,6 +1174,35 @@ static int msm_dsi_cont_on(struct mdss_panel_data *pdata)
	return 0;
}

static int msm_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
	int ret = 0;

	if (ctrl_pdata == NULL) {
		pr_err("%s: Invalid input data\n", __func__);
		return 0;
	}

	mutex_lock(&ctrl_pdata->cmd_mutex);
	msm_dsi_set_irq(ctrl_pdata, DSI_INTR_BTA_DONE_MASK);
	INIT_COMPLETION(ctrl_pdata->bta_comp);

	/* BTA trigger */
	MIPI_OUTP(dsi_host_private->dsi_base + DSI_CMD_MODE_BTA_SW_TRIGGER,
									0x01);
	wmb();
	ret = wait_for_completion_killable_timeout(&ctrl_pdata->bta_comp,
									HZ/10);
	msm_dsi_clear_irq(ctrl_pdata, DSI_INTR_BTA_DONE_MASK);
	mutex_unlock(&ctrl_pdata->cmd_mutex);

	if (ret <= 0)
		pr_err("%s: DSI BTA error: %i\n", __func__, __LINE__);

	pr_debug("%s: BTA done with ret: %d\n", __func__, ret);
	return ret;
}

static void msm_dsi_debug_enable_clock(int on)
{
	if (dsi_host_private->debug_enable_clk)
@@ -1334,6 +1366,7 @@ void msm_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl)
{
	init_completion(&ctrl->dma_comp);
	init_completion(&ctrl->mdp_comp);
	init_completion(&ctrl->bta_comp);
	init_completion(&ctrl->video_comp);
	spin_lock_init(&ctrl->irq_lock);
	spin_lock_init(&ctrl->mdp_lock);
@@ -1344,6 +1377,7 @@ void msm_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl)
	dsi_buf_alloc(&ctrl->rx_buf, SZ_4K);
	ctrl->cmdlist_commit = msm_dsi_cmdlist_commit;
	ctrl->panel_mode = ctrl->panel_data.panel_info.mipi.mode;
	ctrl->check_status = msm_dsi_bta_status_check;
}

static int msm_dsi_probe(struct platform_device *pdev)
+4 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@

#define DSI_INTR_ERROR_MASK			BIT(25)
#define DSI_INTR_ERROR				BIT(24)
#define DSI_INTR_BTA_DONE_MASK			BIT(21)
#define DSI_INTR_BTA_DONE			BIT(20)
#define DSI_INTR_VIDEO_DONE_MASK		BIT(17)
#define DSI_INTR_VIDEO_DONE			BIT(16)
#define DSI_INTR_CMD_MDP_DONE_MASK		BIT(9)
@@ -24,6 +26,8 @@
#define DSI_INTR_CMD_DMA_DONE_MASK		BIT(1)
#define DSI_INTR_CMD_DMA_DONE			BIT(0)

#define DSI_BTA_TERM				BIT(1)

#define DSI_CTRL				0x0000
#define DSI_STATUS				0x0004
#define DSI_FIFO_STATUS			0x0008
+188 −0
Original line number Diff line number Diff line
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fb.h>
#include <linux/notifier.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/iopoll.h>
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/sysfs.h>

#include "mdss_fb.h"
#include "mdss_dsi.h"
#include "mdss_panel.h"
#include "mdp3_ctrl.h"

#define STATUS_CHECK_INTERVAL 5000

/**
 * dsi_status_data - Stores all the data necessary for this module
 * @fb_notif: Used to egister for the fb events
 * @live_status: Delayed worker structure, used to associate the
 * delayed worker function
 * @mfd: Used to store the msm_fb_data_type received when the notifier
 * call back happens
 * @root: Stores the dir created by debuugfs
 * @debugfs_reset_panel: The debugfs variable used to inject errors
 */

struct dsi_status_data {
	struct notifier_block fb_notifier;
	struct delayed_work check_status;
	struct msm_fb_data_type *mfd;
	uint32_t check_interval;
};
static struct dsi_status_data *pstatus_data;
static uint32_t interval = STATUS_CHECK_INTERVAL;

static void check_dsi_ctrl_status(struct work_struct *work)
{
	struct dsi_status_data *pdsi_status = NULL;
	struct mdss_panel_data *pdata = NULL;
	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
	struct mdp3_session_data *mdp3_session = NULL;
	int ret = 0;

	pdsi_status = container_of(to_delayed_work(work),
		struct dsi_status_data, check_status);
	if (!pdsi_status) {
		pr_err("%s: DSI status data not available\n", __func__);
		return;
	}

	pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev);
	if (!pdata) {
		pr_err("%s: Panel data not available\n", __func__);
		return;
	}
	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
							panel_data);
	if (!ctrl_pdata || !ctrl_pdata->check_status) {
		pr_err("%s: DSI ctrl or status_check callback not avilable\n",
								__func__);
		return;
	}
	mdp3_session = pdsi_status->mfd->mdp.private1;
	mutex_lock(&mdp3_session->lock);

	ret = ctrl_pdata->check_status(ctrl_pdata);

	mutex_unlock(&mdp3_session->lock);

	if ((pdsi_status->mfd->panel_power_on)) {
		if (ret > 0) {
			schedule_delayed_work(&pdsi_status->check_status,
				msecs_to_jiffies(pdsi_status->check_interval));
		} else {
			char *envp[2] = {"PANEL_ALIVE=0", NULL};
			pdata->panel_info.panel_dead = true;
			ret = kobject_uevent_env(
				&pdsi_status->mfd->fbi->dev->kobj,
							KOBJ_CHANGE, envp);
			pr_err("%s: Panel has gone bad, sending uevent - %s\n",
							__func__, envp[0]);
		}
	}
}

/**
 * fb_notifier_callback() - Call back function for the fb_register_client()
 * notifying events
 * @self  : notifier block
 * @event : The event that was triggered
 * @data  : Of type struct fb_event
 *
 * - This function listens for FB_BLANK_UNBLANK and FB_BLANK_POWERDOWN events
 * - Based on the event the delayed work is either scheduled again after
 * PANEL_STATUS_CHECK_INTERVAL or cancelled
 */
static int fb_event_callback(struct notifier_block *self,
				unsigned long event, void *data)
{
	struct fb_event *evdata = (struct fb_event *)data;
	struct dsi_status_data *pdata = container_of(self,
				struct dsi_status_data, fb_notifier);
	pdata->mfd = (struct msm_fb_data_type *)evdata->info->par;

	if (event == FB_EVENT_BLANK && evdata) {
		int *blank = evdata->data;
		switch (*blank) {
		case FB_BLANK_UNBLANK:
			schedule_delayed_work(&pdata->check_status,
			msecs_to_jiffies(STATUS_CHECK_INTERVAL));
			break;
		case FB_BLANK_POWERDOWN:
			cancel_delayed_work(&pdata->check_status);
			break;
		}
	}
	return 0;
}

int __init mdss_dsi_status_init(void)
{
	int rc;

	pstatus_data = kzalloc(sizeof(struct dsi_status_data), GFP_KERNEL);
	if (!pstatus_data) {
		pr_err("%s: can't alloc mem\n", __func__);
		rc = -ENOMEM;
		return rc;
	}

	memset(pstatus_data, 0, sizeof(struct dsi_status_data));

	pstatus_data->fb_notifier.notifier_call = fb_event_callback;

	rc = fb_register_client(&pstatus_data->fb_notifier);
	if (rc < 0) {
		pr_err("%s: fb_register_client failed, returned with rc=%d\n",
								__func__, rc);
		kfree(pstatus_data);
		return -EPERM;
	}

	pstatus_data->check_interval = interval;
	pr_info("%s: DSI status check interval:%d\n", __func__, interval);

	INIT_DELAYED_WORK(&pstatus_data->check_status, check_dsi_ctrl_status);

	pr_debug("%s: DSI ctrl status thread initialized\n", __func__);

	return rc;
}

void __exit mdss_dsi_status_exit(void)
{
	fb_unregister_client(&pstatus_data->fb_notifier);
	cancel_delayed_work_sync(&pstatus_data->check_status);
	kfree(pstatus_data);
	pr_debug("%s: DSI ctrl status thread removed\n", __func__);
}

module_param(interval, uint, 0);
MODULE_PARM_DESC(interval,
	"Duration in milliseconds to send BTA command for checking"
	"DSI status periodically");

module_init(mdss_dsi_status_init);
module_exit(mdss_dsi_status_exit);

MODULE_LICENSE("GPL v2");