Merge "msm: mdss: dsi: separate out DBA functionality from DSI"
This commit is contained in:
commit
14a88e8b92
|
@ -36,6 +36,7 @@ obj-$(CONFIG_FB_MSM_MDSS) += mdss_panel.o
|
|||
obj-$(CONFIG_FB_MSM_MDSS) += mdss_hdmi_util.o
|
||||
obj-$(CONFIG_FB_MSM_MDSS) += mdss_hdmi_edid.o
|
||||
obj-$(CONFIG_FB_MSM_MDSS) += mdss_cec_abstract.o
|
||||
obj-$(CONFIG_FB_MSM_MDSS) += mdss_dba_utils.o
|
||||
obj-$(CONFIG_FB_MSM_MDSS_EDP_PANEL) += mdss_edp.o
|
||||
obj-$(CONFIG_FB_MSM_MDSS_EDP_PANEL) += mdss_edp_aux.o
|
||||
|
||||
|
|
|
@ -0,0 +1,465 @@
|
|||
/* Copyright (c) 2015, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
#include <video/msm_dba.h>
|
||||
#include <linux/switch.h>
|
||||
|
||||
#include "mdss_dba_utils.h"
|
||||
#include "mdss_hdmi_edid.h"
|
||||
#include "mdss_fb.h"
|
||||
|
||||
struct mdss_dba_utils_data {
|
||||
struct msm_dba_ops ops;
|
||||
bool hpd_state;
|
||||
bool audio_switch_registered;
|
||||
bool display_switch_registered;
|
||||
struct switch_dev sdev_display;
|
||||
struct switch_dev sdev_audio;
|
||||
struct kobject *kobj;
|
||||
struct mdss_panel_info *pinfo;
|
||||
void *dba_data;
|
||||
void *edid_data;
|
||||
u8 *edid_buf;
|
||||
u32 edid_buf_size;
|
||||
};
|
||||
|
||||
static struct mdss_dba_utils_data *mdss_dba_utils_get_data(
|
||||
struct device *device)
|
||||
{
|
||||
struct msm_fb_data_type *mfd;
|
||||
struct mdss_panel_info *pinfo;
|
||||
struct fb_info *fbi;
|
||||
struct mdss_dba_utils_data *udata = NULL;
|
||||
|
||||
if (!device) {
|
||||
pr_err("Invalid device data\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
fbi = dev_get_drvdata(device);
|
||||
if (!fbi) {
|
||||
pr_err("Invalid fbi data\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
mfd = (struct msm_fb_data_type *)fbi->par;
|
||||
if (!mfd) {
|
||||
pr_err("Invalid mfd data\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
pinfo = mfd->panel_info;
|
||||
if (!pinfo) {
|
||||
pr_err("Invalid pinfo data\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
udata = pinfo->dba_data;
|
||||
end:
|
||||
return udata;
|
||||
}
|
||||
|
||||
static void mdss_dba_utils_send_display_notification(
|
||||
struct mdss_dba_utils_data *udata, int val)
|
||||
{
|
||||
int state = 0;
|
||||
|
||||
if (!udata) {
|
||||
pr_err("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!udata->display_switch_registered) {
|
||||
pr_err("display switch not registered\n");
|
||||
return;
|
||||
}
|
||||
|
||||
state = udata->sdev_display.state;
|
||||
|
||||
switch_set_state(&udata->sdev_display, val);
|
||||
|
||||
pr_debug("cable state %s %d\n",
|
||||
udata->sdev_display.state == state ?
|
||||
"is same" : "switched to",
|
||||
udata->sdev_display.state);
|
||||
}
|
||||
|
||||
static void mdss_dba_utils_send_audio_notification(
|
||||
struct mdss_dba_utils_data *udata, int val)
|
||||
{
|
||||
int state = 0;
|
||||
|
||||
if (!udata) {
|
||||
pr_err("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!udata->audio_switch_registered) {
|
||||
pr_err("audio switch not registered\n");
|
||||
return;
|
||||
}
|
||||
|
||||
state = udata->sdev_audio.state;
|
||||
|
||||
switch_set_state(&udata->sdev_audio, val);
|
||||
|
||||
pr_debug("audio state %s %d\n",
|
||||
udata->sdev_audio.state == state ?
|
||||
"is same" : "switched to",
|
||||
udata->sdev_audio.state);
|
||||
}
|
||||
|
||||
static ssize_t mdss_dba_utils_sysfs_rda_connected(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct mdss_dba_utils_data *udata = NULL;
|
||||
|
||||
if (!dev) {
|
||||
pr_err("invalid device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
udata = mdss_dba_utils_get_data(dev);
|
||||
|
||||
if (!udata) {
|
||||
pr_err("invalid input\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snprintf(buf, PAGE_SIZE, "%d\n", udata->hpd_state);
|
||||
pr_debug("'%d'\n", udata->hpd_state);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(connected, S_IRUGO,
|
||||
mdss_dba_utils_sysfs_rda_connected, NULL);
|
||||
|
||||
static struct attribute *mdss_dba_utils_fs_attrs[] = {
|
||||
&dev_attr_connected.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group mdss_dba_utils_fs_attrs_group = {
|
||||
.attrs = mdss_dba_utils_fs_attrs,
|
||||
};
|
||||
|
||||
static int mdss_dba_utils_sysfs_create(struct kobject *kobj)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!kobj) {
|
||||
pr_err("invalid input\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = sysfs_create_group(kobj, &mdss_dba_utils_fs_attrs_group);
|
||||
if (rc) {
|
||||
pr_err("failed, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mdss_dba_utils_sysfs_remove(struct kobject *kobj)
|
||||
{
|
||||
if (!kobj) {
|
||||
pr_err("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sysfs_remove_group(kobj, &mdss_dba_utils_fs_attrs_group);
|
||||
}
|
||||
|
||||
static void mdss_dba_utils_dba_cb(void *data, enum msm_dba_callback_event event)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct mdss_dba_utils_data *udata = data;
|
||||
bool pluggable = false;
|
||||
|
||||
if (!udata) {
|
||||
pr_err("Invalid data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pr_debug("event: %d\n", event);
|
||||
|
||||
if (udata->pinfo)
|
||||
pluggable = udata->pinfo->is_pluggable;
|
||||
|
||||
switch (event) {
|
||||
case MSM_DBA_CB_HPD_CONNECT:
|
||||
if (udata->ops.get_raw_edid) {
|
||||
ret = udata->ops.get_raw_edid(udata->dba_data,
|
||||
udata->edid_buf_size, udata->edid_buf, 0);
|
||||
|
||||
if (!ret)
|
||||
hdmi_edid_parser(udata->edid_data);
|
||||
else
|
||||
pr_err("failed to get edid%d\n", ret);
|
||||
}
|
||||
|
||||
if (pluggable) {
|
||||
mdss_dba_utils_send_display_notification(udata, 1);
|
||||
mdss_dba_utils_send_audio_notification(udata, 1);
|
||||
} else {
|
||||
mdss_dba_utils_video_on(udata, udata->pinfo);
|
||||
}
|
||||
|
||||
udata->hpd_state = true;
|
||||
break;
|
||||
|
||||
case MSM_DBA_CB_HPD_DISCONNECT:
|
||||
if (pluggable) {
|
||||
mdss_dba_utils_send_audio_notification(udata, 0);
|
||||
mdss_dba_utils_send_display_notification(udata, 0);
|
||||
} else {
|
||||
mdss_dba_utils_video_off(udata);
|
||||
}
|
||||
|
||||
udata->hpd_state = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mdss_dba_utils_video_on() - Allow clients to switch on the video
|
||||
* @data: DBA utils instance which was allocated during registration
|
||||
* @pinfo: detailed panel information like x, y, porch values etc
|
||||
*
|
||||
* This API is used to power on the video on device registered
|
||||
* with DBA.
|
||||
*
|
||||
* Return: returns the result of the video on call on device.
|
||||
*/
|
||||
int mdss_dba_utils_video_on(void *data, struct mdss_panel_info *pinfo)
|
||||
{
|
||||
struct mdss_dba_utils_data *ud = data;
|
||||
struct msm_dba_video_cfg video_cfg;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!ud || !pinfo) {
|
||||
pr_err("invalid input\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
memset(&video_cfg, 0, sizeof(video_cfg));
|
||||
|
||||
video_cfg.h_active = pinfo->xres;
|
||||
video_cfg.v_active = pinfo->yres;
|
||||
video_cfg.h_front_porch = pinfo->lcdc.h_front_porch;
|
||||
video_cfg.v_front_porch = pinfo->lcdc.v_front_porch;
|
||||
video_cfg.h_back_porch = pinfo->lcdc.h_back_porch;
|
||||
video_cfg.v_back_porch = pinfo->lcdc.v_back_porch;
|
||||
video_cfg.h_pulse_width = pinfo->lcdc.h_pulse_width;
|
||||
video_cfg.v_pulse_width = pinfo->lcdc.v_pulse_width;
|
||||
video_cfg.pclk_khz = pinfo->clk_rate / 1000;
|
||||
|
||||
if (ud->ops.video_on)
|
||||
ret = ud->ops.video_on(ud->dba_data, true, &video_cfg, 0);
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* mdss_dba_utils_video_off() - Allow clients to switch off the video
|
||||
* @data: DBA utils instance which was allocated during registration
|
||||
*
|
||||
* This API is used to power off the video on device registered
|
||||
* with DBA.
|
||||
*
|
||||
* Return: returns the result of the video off call on device.
|
||||
*/
|
||||
int mdss_dba_utils_video_off(void *data)
|
||||
{
|
||||
struct mdss_dba_utils_data *ud = data;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!ud) {
|
||||
pr_err("invalid input\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (ud->ops.video_on)
|
||||
ret = ud->ops.video_on(ud->dba_data, false, NULL, 0);
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* mdss_dba_utils_init() - Allow clients to register with DBA utils
|
||||
* @uid: Initialization data for registration.
|
||||
*
|
||||
* This API lets the client to register with DBA Utils module.
|
||||
* This allocate utils' instance and register with DBA (Display
|
||||
* Bridge Abstract). Creates sysfs nodes and switch nodes to interact
|
||||
* with other modules. Also registers with EDID parser to parse
|
||||
* the EDID buffer.
|
||||
*
|
||||
* Return: Instance of DBA utils which needs to be sent as parameter
|
||||
* when calling DBA utils APIs.
|
||||
*/
|
||||
void *mdss_dba_utils_init(struct mdss_dba_utils_init_data *uid)
|
||||
{
|
||||
struct hdmi_edid_init_data edid_init_data;
|
||||
struct mdss_dba_utils_data *udata = NULL;
|
||||
struct msm_dba_reg_info info;
|
||||
int ret = 0;
|
||||
|
||||
if (!uid) {
|
||||
pr_err("invalid input\n");
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
udata = kzalloc(sizeof(*udata), GFP_KERNEL);
|
||||
if (!udata) {
|
||||
pr_err("Not enough Memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
memset(&edid_init_data, 0, sizeof(edid_init_data));
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
/* initialize DBA registration data */
|
||||
strlcpy(info.client_name, uid->client_name, MSM_DBA_CLIENT_NAME_LEN);
|
||||
strlcpy(info.chip_name, uid->chip_name, MSM_DBA_CHIP_NAME_MAX_LEN);
|
||||
info.instance_id = uid->instance_id;
|
||||
info.cb = mdss_dba_utils_dba_cb;
|
||||
info.cb_data = udata;
|
||||
|
||||
/* register client with DBA and get device's ops*/
|
||||
if (IS_ENABLED(CONFIG_MSM_DBA)) {
|
||||
udata->dba_data = msm_dba_register_client(&info, &udata->ops);
|
||||
if (IS_ERR_OR_NULL(udata->dba_data)) {
|
||||
pr_err("ds not configured\n");
|
||||
ret = PTR_ERR(udata->dba_data);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
pr_err("DBA not enabled\n");
|
||||
ret = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* create sysfs nodes for other modules to intract with utils */
|
||||
ret = mdss_dba_utils_sysfs_create(uid->kobj);
|
||||
if (ret) {
|
||||
pr_err("sysfs creation failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* keep init data for future use */
|
||||
udata->kobj = uid->kobj;
|
||||
udata->pinfo = uid->pinfo;
|
||||
|
||||
/* create switch device to update display modules */
|
||||
udata->sdev_display.name = "bridge_display";
|
||||
ret = switch_dev_register(&udata->sdev_display);
|
||||
if (ret) {
|
||||
pr_err("display switch registration failed\n");
|
||||
goto error;
|
||||
}
|
||||
udata->display_switch_registered = true;
|
||||
|
||||
/* create switch device to update audio modules */
|
||||
udata->sdev_audio.name = "hdmi_audio";
|
||||
ret = switch_dev_register(&udata->sdev_audio);
|
||||
if (ret) {
|
||||
pr_err("audio switch registration failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
udata->audio_switch_registered = true;
|
||||
|
||||
/* Initialize EDID feature */
|
||||
edid_init_data.kobj = uid->kobj;
|
||||
|
||||
/* register with edid module for parsing edid buffer */
|
||||
udata->edid_data = hdmi_edid_init(&edid_init_data);
|
||||
if (!udata->edid_data) {
|
||||
pr_err("edid parser init failed\n");
|
||||
ret = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* update edid data to retrieve it back in edid parser */
|
||||
if (uid->pinfo)
|
||||
uid->pinfo->edid_data = udata->edid_data;
|
||||
|
||||
/* get edid buffer from edid parser */
|
||||
udata->edid_buf = edid_init_data.buf;
|
||||
udata->edid_buf_size = edid_init_data.buf_size;
|
||||
|
||||
/* power on downstream device */
|
||||
if (udata->ops.power_on) {
|
||||
ret = udata->ops.power_on(udata->dba_data, true, 0);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
|
||||
return udata;
|
||||
|
||||
error:
|
||||
mdss_dba_utils_deinit(udata);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* mdss_dba_utils_deinit() - Allow clients to de-register with DBA utils
|
||||
* @data: DBA utils data that was allocated during registration.
|
||||
*
|
||||
* This API will release all the resources allocated during registration
|
||||
* and delete the DBA utils instance.
|
||||
*/
|
||||
void mdss_dba_utils_deinit(void *data)
|
||||
{
|
||||
struct mdss_dba_utils_data *udata = data;
|
||||
|
||||
if (!udata) {
|
||||
pr_err("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (udata->edid_data)
|
||||
hdmi_edid_deinit(udata->edid_data);
|
||||
|
||||
if (udata->pinfo)
|
||||
udata->pinfo->edid_data = NULL;
|
||||
|
||||
if (udata->audio_switch_registered)
|
||||
switch_dev_unregister(&udata->sdev_audio);
|
||||
|
||||
if (udata->display_switch_registered)
|
||||
switch_dev_unregister(&udata->sdev_display);
|
||||
|
||||
if (udata->kobj)
|
||||
mdss_dba_utils_sysfs_remove(udata->kobj);
|
||||
|
||||
if (IS_ENABLED(CONFIG_MSM_DBA)) {
|
||||
if (!IS_ERR_OR_NULL(udata->dba_data))
|
||||
msm_dba_deregister_client(udata->dba_data);
|
||||
}
|
||||
|
||||
kfree(udata);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef __MDSS_DBA_UTILS__
|
||||
#define __MDSS_DBA_UTILS__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "mdss_panel.h"
|
||||
|
||||
/**
|
||||
* struct mdss_dba_utils_init_data - Init data for registering with DBA utils.
|
||||
* @kobj: An instance of Kobject for sysfs creation
|
||||
* @instance_id: Instance ID of device registered with DBA
|
||||
* @chip_name: Name of the device registered with DBA
|
||||
* @client_name: Name of the client registering with DBA
|
||||
* @pinfo: Detailed panel information
|
||||
*
|
||||
* This structure's instance is needed to be passed as parameter
|
||||
* to register API to let the DBA utils module configure and
|
||||
* allocate an instance of DBA utils for the client.
|
||||
*/
|
||||
struct mdss_dba_utils_init_data {
|
||||
struct kobject *kobj;
|
||||
u32 instance_id;
|
||||
char *chip_name;
|
||||
char *client_name;
|
||||
struct mdss_panel_info *pinfo;
|
||||
};
|
||||
|
||||
int mdss_dba_utils_video_on(void *data, struct mdss_panel_info *pinfo);
|
||||
int mdss_dba_utils_video_off(void *data);
|
||||
|
||||
void *mdss_dba_utils_init(struct mdss_dba_utils_init_data *init_data);
|
||||
void mdss_dba_utils_deinit(void *data);
|
||||
#endif /* __MDSS_DBA_UTILS__ */
|
|
@ -29,6 +29,7 @@
|
|||
#include "mdss_panel.h"
|
||||
#include "mdss_dsi.h"
|
||||
#include "mdss_debug.h"
|
||||
#include "mdss_dba_utils.h"
|
||||
|
||||
#define XO_CLK_RATE 19200000
|
||||
|
||||
|
@ -38,9 +39,6 @@ static struct mdss_dsi_data *mdss_dsi_res;
|
|||
static int mdss_dsi_pinctrl_set_state(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
|
||||
bool active);
|
||||
|
||||
static void mdss_dsi_send_audio_notification(
|
||||
struct mdss_dsi_ctrl_pdata *ctrl_pdata, int val);
|
||||
|
||||
static struct mdss_dsi_ctrl_pdata *mdss_dsi_get_ctrl(u32 ctrl_id)
|
||||
{
|
||||
if (ctrl_id >= DSI_CTRL_MAX || !mdss_dsi_res)
|
||||
|
@ -1361,10 +1359,6 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata)
|
|||
__func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ctrl_pdata->ds_registered)
|
||||
mdss_dsi_send_audio_notification(
|
||||
ctrl_pdata, 1);
|
||||
}
|
||||
ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
|
||||
}
|
||||
|
@ -1446,10 +1440,6 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata, int power_state)
|
|||
pr_err("%s: Panel OFF failed\n", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ctrl_pdata->ds_registered)
|
||||
mdss_dsi_send_audio_notification(
|
||||
ctrl_pdata, 0);
|
||||
}
|
||||
ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
|
||||
}
|
||||
|
@ -1937,272 +1927,13 @@ static int mdss_dsi_clk_refresh(struct mdss_panel_data *pdata)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static struct mdss_dsi_ctrl_pdata *mdss_dsi_get_drvdata_from_panel_data(
|
||||
struct mdss_panel_data *mpd)
|
||||
{
|
||||
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
|
||||
|
||||
if (!mpd) {
|
||||
pr_err("%s: Invalid panel data\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ctrl_pdata = container_of(mpd, struct mdss_dsi_ctrl_pdata,
|
||||
panel_data);
|
||||
end:
|
||||
return ctrl_pdata;
|
||||
}
|
||||
|
||||
static struct mdss_dsi_ctrl_pdata *mdss_dsi_get_drvdata_from_sysfs_dev(
|
||||
struct device *device)
|
||||
{
|
||||
struct msm_fb_data_type *mfd = NULL;
|
||||
struct mdss_panel_data *panel_data = NULL;
|
||||
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
|
||||
struct fb_info *fbi;
|
||||
|
||||
if (!device) {
|
||||
pr_err("%s: Invalid device data\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
fbi = dev_get_drvdata(device);
|
||||
if (!fbi) {
|
||||
pr_err("%s: Invalid fbi data\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
mfd = (struct msm_fb_data_type *)fbi->par;
|
||||
if (!mfd) {
|
||||
pr_err("%s: Invalid mfd data\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
panel_data = dev_get_platdata(&mfd->pdev->dev);
|
||||
if (!panel_data) {
|
||||
pr_err("%s: Invalid panel data\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ctrl_pdata = mdss_dsi_get_drvdata_from_panel_data(panel_data);
|
||||
|
||||
end:
|
||||
return ctrl_pdata;
|
||||
}
|
||||
|
||||
static ssize_t mdss_dsi_sysfs_rda_connected(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
|
||||
|
||||
if (!dev) {
|
||||
DEV_ERR("%s: invalid device\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctrl_pdata = mdss_dsi_get_drvdata_from_sysfs_dev(dev);
|
||||
|
||||
if (!ctrl_pdata) {
|
||||
DEV_ERR("%s: invalid input\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snprintf(buf, PAGE_SIZE, "%d\n", ctrl_pdata->hpd_state);
|
||||
pr_debug("%s: '%d'\n", __func__, ctrl_pdata->hpd_state);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(connected, S_IRUGO, mdss_dsi_sysfs_rda_connected, NULL);
|
||||
static struct attribute *mdss_dsi_fs_attrs[] = {
|
||||
&dev_attr_connected.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group mdss_dsi_fs_attrs_group = {
|
||||
.attrs = mdss_dsi_fs_attrs,
|
||||
};
|
||||
|
||||
static int mdss_dsi_sysfs_create(struct kobject *kobj)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!kobj) {
|
||||
DEV_ERR("%s: invalid input\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = sysfs_create_group(kobj, &mdss_dsi_fs_attrs_group);
|
||||
if (rc) {
|
||||
pr_err("%s: failed, rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mdss_dsi_send_cable_notification(
|
||||
struct mdss_dsi_ctrl_pdata *ctrl_pdata, int val)
|
||||
{
|
||||
int state = 0;
|
||||
|
||||
if (!ctrl_pdata) {
|
||||
DEV_ERR("%s: invalid input\n", __func__);
|
||||
return;
|
||||
}
|
||||
state = ctrl_pdata->sdev.state;
|
||||
|
||||
switch_set_state(&ctrl_pdata->sdev, val);
|
||||
|
||||
DEV_INFO("%s: cable state %s %d\n", __func__,
|
||||
ctrl_pdata->sdev.state == state ?
|
||||
"is same" : "switched to",
|
||||
ctrl_pdata->sdev.state);
|
||||
}
|
||||
|
||||
static void mdss_dsi_send_audio_notification(
|
||||
struct mdss_dsi_ctrl_pdata *ctrl_pdata, int val)
|
||||
{
|
||||
int state = 0;
|
||||
|
||||
if (!ctrl_pdata) {
|
||||
DEV_ERR("%s: invalid input\n", __func__);
|
||||
return;
|
||||
}
|
||||
state = ctrl_pdata->sdev_audio.state;
|
||||
|
||||
switch_set_state(&ctrl_pdata->sdev_audio, val);
|
||||
|
||||
DEV_INFO("%s: audio state %s %d\n", __func__,
|
||||
ctrl_pdata->sdev_audio.state == state ?
|
||||
"is same" : "switched to",
|
||||
ctrl_pdata->sdev_audio.state);
|
||||
}
|
||||
|
||||
static void mdss_dsi_dba_cb(void *data, enum msm_dba_callback_event event)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct mdss_dsi_ctrl_pdata *ctrl_pdata =
|
||||
(struct mdss_dsi_ctrl_pdata *) data;
|
||||
|
||||
if (!ctrl_pdata) {
|
||||
pr_err("%s: Invalid data\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case MSM_DBA_CB_HPD_CONNECT:
|
||||
ctrl_pdata->hpd_state = true;
|
||||
|
||||
if (ctrl_pdata->dba_ops.get_raw_edid)
|
||||
ret = ctrl_pdata->dba_ops.get_raw_edid(
|
||||
ctrl_pdata->dba_data,
|
||||
ctrl_pdata->edid_buf_size,
|
||||
ctrl_pdata->edid_buf, 0);
|
||||
|
||||
if (!ret)
|
||||
hdmi_edid_parser(ctrl_pdata->edid_data);
|
||||
|
||||
mdss_dsi_send_cable_notification(ctrl_pdata, 1);
|
||||
break;
|
||||
|
||||
case MSM_DBA_CB_HPD_DISCONNECT:
|
||||
mdss_dsi_send_cable_notification(ctrl_pdata, 0);
|
||||
ctrl_pdata->hpd_state = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mdss_dsi_ctrl_init_dba(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
|
||||
{
|
||||
struct hdmi_edid_init_data edid_init_data;
|
||||
struct fb_info *fbi;
|
||||
msm_dba_cb dba_cb = mdss_dsi_dba_cb;
|
||||
|
||||
if (!ctrl_pdata) {
|
||||
pr_err("%s: Invalid ctrl data\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
fbi = ctrl_pdata->fbi;
|
||||
if (!fbi) {
|
||||
pr_err("%s: Invalid fbi data\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
strlcpy(ctrl_pdata->dba_info.client_name, "dsi",
|
||||
MSM_DBA_CLIENT_NAME_LEN);
|
||||
|
||||
strlcpy(ctrl_pdata->dba_info.chip_name, "adv7533",
|
||||
MSM_DBA_CHIP_NAME_MAX_LEN);
|
||||
|
||||
ctrl_pdata->dba_info.instance_id = 0;
|
||||
ctrl_pdata->dba_info.cb = dba_cb;
|
||||
ctrl_pdata->dba_info.cb_data = ctrl_pdata;
|
||||
|
||||
ctrl_pdata->dba_data = msm_dba_register_client(
|
||||
&ctrl_pdata->dba_info,
|
||||
&ctrl_pdata->dba_ops);
|
||||
|
||||
if (IS_ERR_OR_NULL(ctrl_pdata->dba_data)) {
|
||||
pr_err("%s: ds not configured\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (mdss_dsi_sysfs_create(&fbi->dev->kobj)) {
|
||||
pr_err("%s:sysfs creation failed\n",
|
||||
__func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ctrl_pdata->sdev.name = "dsi";
|
||||
if (switch_dev_register(&ctrl_pdata->sdev) < 0) {
|
||||
pr_err("%s: DSI switch registration failed\n",
|
||||
__func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ctrl_pdata->sdev_audio.name = "bridge_audio";
|
||||
if (switch_dev_register(&ctrl_pdata->sdev_audio) < 0) {
|
||||
pr_err("%s: audio switch registration failed\n",
|
||||
__func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Initialize EDID feature */
|
||||
edid_init_data.kobj = &fbi->dev->kobj;
|
||||
edid_init_data.ds_data = NULL;
|
||||
edid_init_data.id = fbi->node;
|
||||
|
||||
ctrl_pdata->edid_data = hdmi_edid_init(&edid_init_data);
|
||||
if (!ctrl_pdata->edid_data) {
|
||||
pr_err("%s: edid parser init failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ctrl_pdata->panel_data.panel_info.edid_data = ctrl_pdata->edid_data;
|
||||
|
||||
/* get edid buffer from edid parser */
|
||||
ctrl_pdata->edid_buf = edid_init_data.buf;
|
||||
ctrl_pdata->edid_buf_size = edid_init_data.buf_size;
|
||||
|
||||
if (ctrl_pdata->dba_ops.power_on)
|
||||
ctrl_pdata->dba_ops.power_on(ctrl_pdata->dba_data,
|
||||
true, 0);
|
||||
|
||||
ctrl_pdata->ds_registered = true;
|
||||
end:
|
||||
return;
|
||||
}
|
||||
|
||||
static void mdss_dsi_dba_work(struct work_struct *work)
|
||||
{
|
||||
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
|
||||
struct delayed_work *dw = to_delayed_work(work);
|
||||
struct mdss_dba_utils_init_data utils_init_data;
|
||||
struct mdss_panel_info *pinfo;
|
||||
|
||||
ctrl_pdata = container_of(dw, struct mdss_dsi_ctrl_pdata, dba_work);
|
||||
if (!ctrl_pdata) {
|
||||
|
@ -2210,7 +1941,24 @@ static void mdss_dsi_dba_work(struct work_struct *work)
|
|||
return;
|
||||
}
|
||||
|
||||
mdss_dsi_ctrl_init_dba(ctrl_pdata);
|
||||
pinfo = &ctrl_pdata->panel_data.panel_info;
|
||||
if (!pinfo) {
|
||||
pr_err("%s: invalid ctrl data\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&utils_init_data, 0, sizeof(utils_init_data));
|
||||
|
||||
utils_init_data.chip_name = "adv7533";
|
||||
utils_init_data.client_name = "dsi";
|
||||
utils_init_data.instance_id = 0;
|
||||
utils_init_data.kobj = ctrl_pdata->kobj;
|
||||
utils_init_data.pinfo = pinfo;
|
||||
|
||||
pinfo->dba_data = mdss_dba_utils_init(&utils_init_data);
|
||||
|
||||
if (!IS_ERR_OR_NULL(pinfo->dba_data))
|
||||
ctrl_pdata->ds_registered = true;
|
||||
}
|
||||
|
||||
static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
|
||||
|
@ -2218,6 +1966,7 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
|
|||
{
|
||||
int rc = 0;
|
||||
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
|
||||
struct fb_info *fbi;
|
||||
int power_state;
|
||||
u32 mode;
|
||||
|
||||
|
@ -2325,10 +2074,15 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
|
|||
case MDSS_EVENT_FB_REGISTERED:
|
||||
mdss_dsi_debugfs_init(ctrl_pdata);
|
||||
|
||||
ctrl_pdata->fbi = (struct fb_info *)arg;
|
||||
fbi = (struct fb_info *)arg;
|
||||
if (!fbi || !fbi->dev)
|
||||
break;
|
||||
|
||||
queue_delayed_work(ctrl_pdata->workq, &ctrl_pdata->dba_work,
|
||||
HZ);
|
||||
ctrl_pdata->kobj = &fbi->dev->kobj;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MSM_DBA))
|
||||
queue_delayed_work(ctrl_pdata->workq,
|
||||
&ctrl_pdata->dba_work, HZ);
|
||||
break;
|
||||
default:
|
||||
pr_debug("%s: unhandled event=%d\n", __func__, event);
|
||||
|
@ -2620,8 +2374,18 @@ static void mdss_dsi_res_deinit(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
for (i = 0; i < DSI_CTRL_MAX; i++) {
|
||||
if (dsi_res->ctrl_pdata[i])
|
||||
if (dsi_res->ctrl_pdata[i]) {
|
||||
if (dsi_res->ctrl_pdata[i]->ds_registered) {
|
||||
struct mdss_panel_info *pinfo =
|
||||
&dsi_res->ctrl_pdata[i]->
|
||||
panel_data.panel_info;
|
||||
|
||||
if (pinfo)
|
||||
mdss_dba_utils_deinit(pinfo->dba_data);
|
||||
}
|
||||
|
||||
devm_kfree(&pdev->dev, dsi_res->ctrl_pdata[i]);
|
||||
}
|
||||
}
|
||||
|
||||
sdata = dsi_res->shared_data;
|
||||
|
|
|
@ -19,12 +19,9 @@
|
|||
#include <linux/irqreturn.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/switch.h>
|
||||
#include <video/msm_dba.h>
|
||||
|
||||
#include "mdss_panel.h"
|
||||
#include "mdss_dsi_cmd.h"
|
||||
#include "mdss_hdmi_edid.h"
|
||||
|
||||
#define MMSS_SERDES_BASE_PHY 0x04f01000 /* mmss (De)Serializer CFG */
|
||||
|
||||
|
@ -461,21 +458,9 @@ struct mdss_dsi_ctrl_pdata {
|
|||
struct mdss_dsi_debugfs_info *debugfs_info;
|
||||
|
||||
bool dfps_status; /* dynamic refresh status */
|
||||
struct switch_dev sdev;
|
||||
bool hpd_state;
|
||||
bool ds_registered;
|
||||
|
||||
struct switch_dev sdev_audio;
|
||||
struct msm_dba_reg_info dba_info;
|
||||
struct msm_dba_ops dba_ops;
|
||||
struct msm_dba_video_cfg dba_video_cfg;
|
||||
void *dba_data;
|
||||
|
||||
void *edid_data;
|
||||
u8 *edid_buf;
|
||||
u32 edid_buf_size;
|
||||
|
||||
struct fb_info *fbi;
|
||||
struct kobject *kobj;
|
||||
|
||||
struct workqueue_struct *workq;
|
||||
struct delayed_work dba_work;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/err.h>
|
||||
|
||||
#include "mdss_dsi.h"
|
||||
#include "mdss_dba_utils.h"
|
||||
|
||||
#define DT_CMD_HDR 6
|
||||
#define MIN_REFRESH_RATE 48
|
||||
|
@ -677,13 +678,8 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
|
|||
if (on_cmds->cmd_cnt)
|
||||
mdss_dsi_panel_cmds_send(ctrl, on_cmds);
|
||||
|
||||
if (ctrl->ds_registered) {
|
||||
if (ctrl->dba_ops.video_on)
|
||||
ret = ctrl->dba_ops.video_on(
|
||||
ctrl->dba_data, true,
|
||||
&ctrl->dba_video_cfg, 0);
|
||||
}
|
||||
|
||||
if (ctrl->ds_registered)
|
||||
mdss_dba_utils_video_on(pinfo->dba_data, pinfo);
|
||||
end:
|
||||
pinfo->blank_state = MDSS_PANEL_BLANK_UNBLANK;
|
||||
pr_debug("%s:-\n", __func__);
|
||||
|
|
|
@ -452,6 +452,7 @@ struct mdss_panel_info {
|
|||
bool is_pluggable;
|
||||
|
||||
void *edid_data;
|
||||
void *dba_data;
|
||||
|
||||
char panel_name[MDSS_MAX_PANEL_LEN];
|
||||
struct mdss_mdp_pp_tear_check te;
|
||||
|
|
|
@ -567,15 +567,8 @@ struct msm_dba_ops {
|
|||
* chip. If Successful, this will return a pointer that should be used as a
|
||||
* handle for all subsequent function calls.
|
||||
*/
|
||||
#ifdef CONFIG_MSM_DBA
|
||||
void *msm_dba_register_client(struct msm_dba_reg_info *info,
|
||||
struct msm_dba_ops *ops);
|
||||
#else
|
||||
static inline void *msm_dba_register_client(struct msm_dba_reg_info *info,
|
||||
struct msm_dba_ops *ops) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* msm_dba_deregister_client() - Allows client to de-register with the driver.
|
||||
|
|
Loading…
Reference in New Issue