msm: mdss: separate out DBA and CEC functionality from DSI
Currently, DBA (Display Bridge Abstract) related functionality is being used in DSI files. Carve out DBA related functionality into a new file which serves as a utility module and can be used by any MDSS driver. Define CEC on/enable functions in DBA (Display Bridge Abstract) so that clients can enable disable CEC based on other dependent CEC modules. Separate out CEC abstract data with CEC driver data and initialize and release corresponding modules properly. Change-Id: I84f53d99547dcd4ce0b8275401b03ed8e96e14d5 Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org> Signed-off-by: Sandeep Panda <spanda@codeaurora.org>
This commit is contained in:
parent
1e58c1ae76
commit
f472340bf7
18 changed files with 2376 additions and 606 deletions
|
@ -15,9 +15,14 @@ Required properties:
|
|||
Optional properties:
|
||||
- adi,enable-audio:
|
||||
- adi,disable-gpios:
|
||||
- adi,irq-gpio: Main IRQ gpio mapping
|
||||
- adi,irq-gpio: Main IRQ gpio mapping
|
||||
- adi,hpd-irq-gpio: HPD IRQ gpio mapping
|
||||
- adi,switch-gpio: DSI switch gpio mapping
|
||||
- qcom,supply-names: Regulator names that supply 5v to bridge chip
|
||||
- qcom,min-voltage-level Minimum voltage level to be supplied to bridge chip
|
||||
- qcom,max-voltage-level Maximum voltage level to be supplied to bridge chip
|
||||
- qcom,enable-load Load current to bridge chip when enabled
|
||||
- qcom,disable-load Load current to bridge chip when disabled
|
||||
|
||||
Example:
|
||||
&soc {
|
||||
|
@ -35,6 +40,12 @@ Example:
|
|||
adi,irq-gpio = <&msm_gpio 31 0x2002>;
|
||||
adi,hpd-irq-gpio = <&msm_gpio 20 0x2003>;
|
||||
adi,switch-gpio = <&msm_gpio 32 0x0>;
|
||||
hpd-5v-en-supply = <&adv_vreg>;
|
||||
qcom,supply-names = "hpd-5v-en";
|
||||
qcom,min-voltage-level = <0>;
|
||||
qcom,max-voltage-level = <0>;
|
||||
qcom,enable-load = <0>;
|
||||
qcom,disable-load = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -446,6 +446,8 @@ Optional properites:
|
|||
- qcom,mdss-dsc-block-prediction-enable: A boolean value to enable/disable the block prediction at decoder.
|
||||
- qcom,mdss-dsc-config-by-manufacture-cmd: A boolean to indicates panel use manufacture command to setup pps
|
||||
instead of standard dcs type 0x0A.
|
||||
- qcom,dba-panel: Indicates whether the current panel is used as a display bridge
|
||||
to a non-DSI interface.
|
||||
- qcom,adjust-timer-wakeup-ms: An integer value to indicate the timer delay(in ms) to accommodate
|
||||
s/w delay while configuring the event timer wakeup logic.
|
||||
|
||||
|
@ -661,6 +663,7 @@ Example:
|
|||
};
|
||||
|
||||
qcom,config-select = <&dsi_sim_vid_config0>;
|
||||
qcom,dba-panel;
|
||||
|
||||
dsi_sim_vid_config0: config0 {
|
||||
qcom,lm-split = <360 360>;
|
||||
|
|
|
@ -44,6 +44,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_core.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
|
||||
|
||||
|
|
768
drivers/video/fbdev/msm/mdss_dba_utils.c
Normal file
768
drivers/video/fbdev/msm/mdss_dba_utils.c
Normal file
|
@ -0,0 +1,768 @@
|
|||
/* 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_cec_core.h"
|
||||
#include "mdss_fb.h"
|
||||
|
||||
/* standard cec buf size + 1 byte specific to driver */
|
||||
#define CEC_BUF_SIZE (MAX_CEC_FRAME_SIZE + 1)
|
||||
#define MAX_SWITCH_NAME_SIZE 5
|
||||
#define MSM_DBA_MAX_PCLK 148500
|
||||
|
||||
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;
|
||||
void *cec_abst_data;
|
||||
u8 *edid_buf;
|
||||
u32 edid_buf_size;
|
||||
u8 cec_buf[CEC_BUF_SIZE];
|
||||
struct cec_ops cops;
|
||||
struct cec_cbs ccbs;
|
||||
char disp_switch_name[MAX_SWITCH_NAME_SIZE];
|
||||
u32 current_vic;
|
||||
};
|
||||
|
||||
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 ssize_t mdss_dba_utils_sysfs_rda_video_mode(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct mdss_dba_utils_data *udata = NULL;
|
||||
|
||||
if (!dev) {
|
||||
pr_debug("invalid device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
udata = mdss_dba_utils_get_data(dev);
|
||||
|
||||
if (!udata) {
|
||||
pr_debug("invalid input\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snprintf(buf, PAGE_SIZE, "%d\n", udata->current_vic);
|
||||
pr_debug("'%d'\n", udata->current_vic);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t mdss_dba_utils_sysfs_wta_hpd(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct mdss_dba_utils_data *udata = NULL;
|
||||
int rc, hpd;
|
||||
|
||||
udata = mdss_dba_utils_get_data(dev);
|
||||
if (!udata) {
|
||||
pr_debug("%s: invalid input\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = kstrtoint(buf, 10, &hpd);
|
||||
if (rc) {
|
||||
pr_debug("%s: kstrtoint failed\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pr_debug("%s: set value: %d hpd state: %d\n", __func__,
|
||||
hpd, udata->hpd_state);
|
||||
if (!hpd) {
|
||||
if (udata->ops.power_on)
|
||||
udata->ops.power_on(udata->dba_data, false, 0);
|
||||
return count;
|
||||
}
|
||||
|
||||
/* power on downstream device */
|
||||
if (udata->ops.power_on)
|
||||
udata->ops.power_on(udata->dba_data, true, 0);
|
||||
|
||||
/* check if cable is connected to bridge chip */
|
||||
if (udata->ops.check_hpd)
|
||||
udata->ops.check_hpd(udata->dba_data, 0);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(connected, S_IRUGO,
|
||||
mdss_dba_utils_sysfs_rda_connected, NULL);
|
||||
|
||||
static DEVICE_ATTR(video_mode, S_IRUGO,
|
||||
mdss_dba_utils_sysfs_rda_video_mode, NULL);
|
||||
|
||||
static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, NULL,
|
||||
mdss_dba_utils_sysfs_wta_hpd);
|
||||
|
||||
static struct attribute *mdss_dba_utils_fs_attrs[] = {
|
||||
&dev_attr_connected.attr,
|
||||
&dev_attr_video_mode.attr,
|
||||
&dev_attr_hpd.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;
|
||||
struct cec_msg msg = {0};
|
||||
bool pluggable = false;
|
||||
bool operands_present = false;
|
||||
u32 no_of_operands, size, i;
|
||||
u32 operands_offset = MAX_CEC_FRAME_SIZE - MAX_OPERAND_SIZE;
|
||||
|
||||
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->hpd_state)
|
||||
break;
|
||||
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 (!udata->hpd_state)
|
||||
break;
|
||||
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;
|
||||
|
||||
case MSM_DBA_CB_CEC_READ_PENDING:
|
||||
if (udata->ops.hdmi_cec_read) {
|
||||
ret = udata->ops.hdmi_cec_read(
|
||||
udata->dba_data,
|
||||
&size,
|
||||
udata->cec_buf, 0);
|
||||
|
||||
if (ret || !size || size > CEC_BUF_SIZE) {
|
||||
pr_err("%s: cec read failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* prepare cec msg */
|
||||
msg.recvr_id = udata->cec_buf[0] & 0x0F;
|
||||
msg.sender_id = (udata->cec_buf[0] & 0xF0) >> 4;
|
||||
msg.opcode = udata->cec_buf[1];
|
||||
msg.frame_size = (udata->cec_buf[MAX_CEC_FRAME_SIZE] & 0x1F);
|
||||
|
||||
operands_present = (msg.frame_size > operands_offset) &&
|
||||
(msg.frame_size <= MAX_CEC_FRAME_SIZE);
|
||||
|
||||
if (operands_present) {
|
||||
no_of_operands = msg.frame_size - operands_offset;
|
||||
|
||||
for (i = 0; i < no_of_operands; i++)
|
||||
msg.operand[i] =
|
||||
udata->cec_buf[operands_offset + i];
|
||||
}
|
||||
|
||||
ret = udata->ccbs.msg_recv_notify(udata->ccbs.data, &msg);
|
||||
if (ret)
|
||||
pr_err("%s: failed to notify cec msg\n", __func__);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int mdss_dba_utils_cec_enable(void *data, bool enable)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct mdss_dba_utils_data *udata = data;
|
||||
|
||||
if (!udata) {
|
||||
pr_err("%s: Invalid data\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (udata->ops.hdmi_cec_on)
|
||||
ret = udata->ops.hdmi_cec_on(udata->dba_data, enable, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mdss_dba_utils_send_cec_msg(void *data, struct cec_msg *msg)
|
||||
{
|
||||
int ret = -EINVAL, i;
|
||||
u32 operands_offset = MAX_CEC_FRAME_SIZE - MAX_OPERAND_SIZE;
|
||||
struct mdss_dba_utils_data *udata = data;
|
||||
|
||||
u8 buf[MAX_CEC_FRAME_SIZE];
|
||||
|
||||
if (!udata || !msg) {
|
||||
pr_err("%s: Invalid data\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buf[0] = (msg->sender_id << 4) | msg->recvr_id;
|
||||
buf[1] = msg->opcode;
|
||||
|
||||
for (i = 0; i < MAX_OPERAND_SIZE &&
|
||||
i < msg->frame_size - operands_offset; i++)
|
||||
buf[operands_offset + i] = msg->operand[i];
|
||||
|
||||
if (udata->ops.hdmi_cec_write)
|
||||
ret = udata->ops.hdmi_cec_write(udata->dba_data,
|
||||
msg->frame_size, (char *)buf, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mdss_dba_utils_init_switch_dev(struct mdss_dba_utils_data *udata,
|
||||
u32 fb_node)
|
||||
{
|
||||
int rc = -EINVAL, ret;
|
||||
|
||||
if (!udata) {
|
||||
pr_err("invalid input\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* create switch device to update display modules */
|
||||
udata->sdev_display.name = "hdmi";
|
||||
rc = switch_dev_register(&udata->sdev_display);
|
||||
if (rc) {
|
||||
pr_err("display switch registration failed\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
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 end;
|
||||
}
|
||||
|
||||
udata->audio_switch_registered = true;
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int mdss_dba_get_vic_panel_info(struct mdss_dba_utils_data *udata,
|
||||
struct mdss_panel_info *pinfo)
|
||||
{
|
||||
struct msm_hdmi_mode_timing_info timing;
|
||||
struct hdmi_util_ds_data ds_data;
|
||||
u32 h_total, v_total, vic = 0;
|
||||
|
||||
if (!udata || !pinfo) {
|
||||
pr_err("%s: invalid input\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
timing.active_h = pinfo->xres;
|
||||
timing.back_porch_h = pinfo->lcdc.h_back_porch;
|
||||
timing.front_porch_h = pinfo->lcdc.h_front_porch;
|
||||
timing.pulse_width_h = pinfo->lcdc.h_pulse_width;
|
||||
h_total = (timing.active_h + timing.back_porch_h +
|
||||
timing.front_porch_h + timing.pulse_width_h);
|
||||
|
||||
timing.active_v = pinfo->yres;
|
||||
timing.back_porch_v = pinfo->lcdc.v_back_porch;
|
||||
timing.front_porch_v = pinfo->lcdc.v_front_porch;
|
||||
timing.pulse_width_v = pinfo->lcdc.v_pulse_width;
|
||||
v_total = (timing.active_v + timing.back_porch_v +
|
||||
timing.front_porch_v + timing.pulse_width_v);
|
||||
|
||||
timing.refresh_rate = pinfo->mipi.frame_rate * 1000;
|
||||
timing.pixel_freq = (h_total * v_total *
|
||||
pinfo->mipi.frame_rate) / 1000;
|
||||
|
||||
ds_data.ds_registered = true;
|
||||
ds_data.ds_max_clk = MSM_DBA_MAX_PCLK;
|
||||
|
||||
vic = hdmi_get_video_id_code(&timing, &ds_data);
|
||||
pr_debug("%s: current vic code is %d\n", __func__, vic);
|
||||
|
||||
return vic;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = (unsigned long)pinfo->clk_rate / 1000;
|
||||
video_cfg.hdmi_mode = hdmi_edid_get_sink_mode(ud->edid_data);
|
||||
|
||||
/* Calculate number of DSI lanes configured */
|
||||
video_cfg.num_of_input_lanes = 0;
|
||||
if (pinfo->mipi.data_lane0)
|
||||
video_cfg.num_of_input_lanes++;
|
||||
if (pinfo->mipi.data_lane1)
|
||||
video_cfg.num_of_input_lanes++;
|
||||
if (pinfo->mipi.data_lane2)
|
||||
video_cfg.num_of_input_lanes++;
|
||||
if (pinfo->mipi.data_lane3)
|
||||
video_cfg.num_of_input_lanes++;
|
||||
|
||||
/* Get scan information from EDID */
|
||||
video_cfg.vic = mdss_dba_get_vic_panel_info(ud, pinfo);
|
||||
ud->current_vic = video_cfg.vic;
|
||||
video_cfg.scaninfo = hdmi_edid_get_sink_scaninfo(ud->edid_data,
|
||||
video_cfg.vic);
|
||||
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_hdcp_enable() - Allow clients to switch on HDCP.
|
||||
* @data: DBA utils instance which was allocated during registration
|
||||
* @enable: flag to enable or disable HDCP authentication
|
||||
*
|
||||
* This API is used to start the HDCP authentication process with the
|
||||
* device registered with DBA.
|
||||
*/
|
||||
void mdss_dba_utils_hdcp_enable(void *data, bool enable)
|
||||
{
|
||||
struct mdss_dba_utils_data *ud = data;
|
||||
|
||||
if (!ud) {
|
||||
pr_err("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ud->ops.hdcp_enable)
|
||||
ud->ops.hdcp_enable(ud->dba_data, enable, enable, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
struct cec_abstract_init_data cec_abst_init_data;
|
||||
void *cec_abst_data;
|
||||
int ret = 0;
|
||||
|
||||
if (!uid) {
|
||||
pr_err("invalid input\n");
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
udata = kzalloc(sizeof(*udata), GFP_KERNEL);
|
||||
if (!udata) {
|
||||
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;
|
||||
|
||||
/* register display and audio switch devices */
|
||||
ret = mdss_dba_utils_init_switch_dev(udata, uid->fb_node);
|
||||
if (ret) {
|
||||
pr_err("switch dev registration failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Initialize EDID feature */
|
||||
edid_init_data.kobj = uid->kobj;
|
||||
edid_init_data.ds_data.ds_registered = true;
|
||||
edid_init_data.ds_data.ds_max_clk = MSM_DBA_MAX_PCLK;
|
||||
edid_init_data.max_pclk_khz = MSM_DBA_MAX_PCLK;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Initialize cec abstract layer and get callbacks */
|
||||
udata->cops.send_msg = mdss_dba_utils_send_cec_msg;
|
||||
udata->cops.enable = mdss_dba_utils_cec_enable;
|
||||
udata->cops.data = udata;
|
||||
|
||||
/* initialize cec abstraction module */
|
||||
cec_abst_init_data.kobj = uid->kobj;
|
||||
cec_abst_init_data.ops = &udata->cops;
|
||||
cec_abst_init_data.cbs = &udata->ccbs;
|
||||
|
||||
udata->cec_abst_data = cec_abstract_init(&cec_abst_init_data);
|
||||
if (IS_ERR_OR_NULL(udata->cec_abst_data)) {
|
||||
pr_err("error initializing cec abstract module\n");
|
||||
ret = PTR_ERR(cec_abst_data);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* update cec data to retrieve it back in cec abstract module */
|
||||
if (uid->pinfo) {
|
||||
uid->pinfo->is_cec_supported = true;
|
||||
uid->pinfo->cec_data = udata->cec_abst_data;
|
||||
|
||||
/*
|
||||
* TODO: Currently there is no support from HAL to send
|
||||
* HPD events to driver for usecase where bridge chip
|
||||
* is used as primary panel. Once support is added remove
|
||||
* this explicit calls to bridge chip driver.
|
||||
*/
|
||||
if (!uid->pinfo->is_pluggable) {
|
||||
if (udata->ops.power_on)
|
||||
udata->ops.power_on(udata->dba_data, true, 0);
|
||||
if (udata->ops.check_hpd)
|
||||
udata->ops.check_hpd(udata->dba_data, 0);
|
||||
}
|
||||
}
|
||||
|
||||
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 (!IS_ERR_OR_NULL(udata->cec_abst_data))
|
||||
cec_abstract_deinit(udata->cec_abst_data);
|
||||
|
||||
if (udata->edid_data)
|
||||
hdmi_edid_deinit(udata->edid_data);
|
||||
|
||||
if (udata->pinfo) {
|
||||
udata->pinfo->edid_data = NULL;
|
||||
udata->pinfo->is_cec_supported = false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
47
drivers/video/fbdev/msm/mdss_dba_utils.h
Normal file
47
drivers/video/fbdev/msm/mdss_dba_utils.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* 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;
|
||||
u32 fb_node;
|
||||
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_hdcp_enable(void *data, bool enable);
|
||||
|
||||
void *mdss_dba_utils_init(struct mdss_dba_utils_init_data *init_data);
|
||||
void mdss_dba_utils_deinit(void *data);
|
||||
#endif /* __MDSS_DBA_UTILS__ */
|
|
@ -32,6 +32,7 @@
|
|||
#include "mdss_dsi.h"
|
||||
#include "mdss_debug.h"
|
||||
#include "mdss_dsi_phy.h"
|
||||
#include "mdss_dba_utils.h"
|
||||
|
||||
#define XO_CLK_RATE 19200000
|
||||
#define CMDLINE_DSI_CTL_NUM_STRING_LEN 2
|
||||
|
@ -1359,13 +1360,16 @@ static int mdss_dsi_pinctrl_set_state(
|
|||
bool active)
|
||||
{
|
||||
struct pinctrl_state *pin_state;
|
||||
struct mdss_panel_info *pinfo = NULL;
|
||||
int rc = -EFAULT;
|
||||
|
||||
if (IS_ERR_OR_NULL(ctrl_pdata->pin_res.pinctrl))
|
||||
return PTR_ERR(ctrl_pdata->pin_res.pinctrl);
|
||||
|
||||
if (mdss_dsi_is_right_ctrl(ctrl_pdata) &&
|
||||
mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) {
|
||||
pinfo = &ctrl_pdata->panel_data.panel_info;
|
||||
if ((mdss_dsi_is_right_ctrl(ctrl_pdata) &&
|
||||
mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) ||
|
||||
pinfo->is_dba_panel) {
|
||||
pr_debug("%s:%d, right ctrl pinctrl config not needed\n",
|
||||
__func__, __LINE__);
|
||||
return 0;
|
||||
|
@ -2216,6 +2220,45 @@ static int mdss_dsi_set_stream_size(struct mdss_panel_data *pdata)
|
|||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
pr_err("%s: invalid ctrl data\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
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.fb_node = ctrl_pdata->fb_node;
|
||||
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;
|
||||
} else {
|
||||
pr_debug("%s: dba device not ready, queue again\n", __func__);
|
||||
queue_delayed_work(ctrl_pdata->workq,
|
||||
&ctrl_pdata->dba_work, HZ);
|
||||
}
|
||||
}
|
||||
|
||||
static int mdss_dsi_reset_write_ptr(struct mdss_panel_data *pdata)
|
||||
{
|
||||
|
||||
|
@ -2311,6 +2354,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;
|
||||
struct mdss_panel_info *pinfo;
|
||||
|
@ -2440,6 +2484,19 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
|
|||
break;
|
||||
case MDSS_EVENT_FB_REGISTERED:
|
||||
mdss_dsi_debugfs_init(ctrl_pdata);
|
||||
|
||||
fbi = (struct fb_info *)arg;
|
||||
if (!fbi || !fbi->dev)
|
||||
break;
|
||||
|
||||
ctrl_pdata->kobj = &fbi->dev->kobj;
|
||||
ctrl_pdata->fb_node = fbi->node;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MSM_DBA) &&
|
||||
pdata->panel_info.is_dba_panel) {
|
||||
queue_delayed_work(ctrl_pdata->workq,
|
||||
&ctrl_pdata->dba_work, HZ);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pr_debug("%s: unhandled event=%d\n", __func__, event);
|
||||
|
@ -2946,6 +3003,16 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev)
|
|||
}
|
||||
disable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio));
|
||||
}
|
||||
|
||||
ctrl_pdata->workq = create_workqueue("mdss_dsi_dba");
|
||||
if (!ctrl_pdata->workq) {
|
||||
pr_err("%s: Error creating workqueue\n", __func__);
|
||||
rc = -EPERM;
|
||||
goto error_pan_node;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&ctrl_pdata->dba_work, mdss_dsi_dba_work);
|
||||
|
||||
pr_debug("%s: Dsi Ctrl->%d initialized\n", __func__, index);
|
||||
|
||||
if (index == 0)
|
||||
|
@ -3036,8 +3103,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;
|
||||
|
@ -3425,6 +3502,10 @@ static int mdss_dsi_ctrl_remove(struct platform_device *pdev)
|
|||
msm_dss_iounmap(&ctrl_pdata->phy_io);
|
||||
msm_dss_iounmap(&ctrl_pdata->ctrl_io);
|
||||
mdss_dsi_debugfs_cleanup(ctrl_pdata);
|
||||
|
||||
if (ctrl_pdata->workq)
|
||||
destroy_workqueue(ctrl_pdata->workq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,13 +19,10 @@
|
|||
#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_dsi_clk.h"
|
||||
#include "mdss_hdmi_edid.h"
|
||||
|
||||
#define MMSS_SERDES_BASE_PHY 0x04f01000 /* mmss (De)Serializer CFG */
|
||||
|
||||
|
@ -516,19 +513,11 @@ struct mdss_dsi_ctrl_pdata {
|
|||
|
||||
struct dsi_err_container err_cont;
|
||||
|
||||
struct switch_dev sdev;
|
||||
bool hpd_state;
|
||||
|
||||
bool ds_registered;
|
||||
|
||||
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[EDID_BLOCK_SIZE * 2];
|
||||
|
||||
struct fb_info *fbi;
|
||||
struct kobject *kobj;
|
||||
int fb_node;
|
||||
|
||||
struct workqueue_struct *workq;
|
||||
struct delayed_work dba_work;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/string.h>
|
||||
|
||||
#include "mdss_dsi.h"
|
||||
#include "mdss_dba_utils.h"
|
||||
|
||||
#define DT_CMD_HDR 6
|
||||
#define MIN_REFRESH_RATE 48
|
||||
|
@ -284,8 +285,10 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
|
|||
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
|
||||
panel_data);
|
||||
|
||||
if (mdss_dsi_is_right_ctrl(ctrl_pdata) &&
|
||||
mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) {
|
||||
pinfo = &(ctrl_pdata->panel_data.panel_info);
|
||||
if ((mdss_dsi_is_right_ctrl(ctrl_pdata) &&
|
||||
mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) ||
|
||||
pinfo->is_dba_panel) {
|
||||
pr_debug("%s:%d, right ctrl gpio configuration not needed\n",
|
||||
__func__, __LINE__);
|
||||
return rc;
|
||||
|
@ -303,7 +306,6 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
|
|||
}
|
||||
|
||||
pr_debug("%s: enable = %d\n", __func__, enable);
|
||||
pinfo = &(ctrl_pdata->panel_data.panel_info);
|
||||
|
||||
if (enable) {
|
||||
rc = mdss_dsi_request_gpios(ctrl_pdata);
|
||||
|
@ -695,17 +697,8 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
|
|||
if (pinfo->compression_mode == COMPRESSION_DSC)
|
||||
mdss_dsi_panel_dsc_pps_send(ctrl, pinfo);
|
||||
|
||||
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 (ret) {
|
||||
pr_err("%s: video on failed for chip %s\n",
|
||||
__func__, ctrl->dba_info.chip_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctrl->ds_registered && pinfo->is_pluggable)
|
||||
mdss_dba_utils_video_on(pinfo->dba_data, pinfo);
|
||||
end:
|
||||
pinfo->blank_state = MDSS_PANEL_BLANK_UNBLANK;
|
||||
pr_debug("%s:-\n", __func__);
|
||||
|
@ -717,6 +710,7 @@ static int mdss_dsi_post_panel_on(struct mdss_panel_data *pdata)
|
|||
struct mdss_dsi_ctrl_pdata *ctrl = NULL;
|
||||
struct mdss_panel_info *pinfo;
|
||||
struct dsi_panel_cmds *cmds;
|
||||
u32 vsync_period = 0;
|
||||
|
||||
if (pdata == NULL) {
|
||||
pr_err("%s: Invalid input data\n", __func__);
|
||||
|
@ -738,6 +732,13 @@ static int mdss_dsi_post_panel_on(struct mdss_panel_data *pdata)
|
|||
mdss_dsi_panel_cmds_send(ctrl, cmds, CMD_REQ_COMMIT);
|
||||
}
|
||||
|
||||
if (pinfo->is_dba_panel && pinfo->is_pluggable) {
|
||||
/* ensure at least 1 frame transfers to down stream device */
|
||||
vsync_period = (MSEC_PER_SEC / pinfo->mipi.frame_rate) + 1;
|
||||
msleep(vsync_period);
|
||||
mdss_dba_utils_hdcp_enable(pinfo->dba_data, true);
|
||||
}
|
||||
|
||||
end:
|
||||
pr_debug("%s:-\n", __func__);
|
||||
return 0;
|
||||
|
@ -767,6 +768,11 @@ static int mdss_dsi_panel_off(struct mdss_panel_data *pdata)
|
|||
if (ctrl->off_cmds.cmd_cnt)
|
||||
mdss_dsi_panel_cmds_send(ctrl, &ctrl->off_cmds, CMD_REQ_COMMIT);
|
||||
|
||||
if (ctrl->ds_registered && pinfo->is_pluggable) {
|
||||
mdss_dba_utils_video_off(pinfo->dba_data);
|
||||
mdss_dba_utils_hdcp_enable(pinfo->dba_data, false);
|
||||
}
|
||||
|
||||
end:
|
||||
pinfo->blank_state = MDSS_PANEL_BLANK_BLANK;
|
||||
pr_debug("%s:-\n", __func__);
|
||||
|
@ -1853,7 +1859,7 @@ static int mdss_dsi_panel_timing_from_dt(struct device_node *np,
|
|||
{
|
||||
u32 tmp;
|
||||
u64 tmp64;
|
||||
int rc, i, len, num_lanes;
|
||||
int rc, i, len;
|
||||
const char *data;
|
||||
struct mdss_dsi_ctrl_pdata *ctrl_pdata;
|
||||
struct mdss_panel_info *pinfo;
|
||||
|
@ -1921,35 +1927,6 @@ static int mdss_dsi_panel_timing_from_dt(struct device_node *np,
|
|||
"qcom,mdss-dsi-panel-clockrate", (u32 *)&tmp64);
|
||||
pt->timing.clk_rate = !rc ? tmp64 : 0;
|
||||
|
||||
/* Update timing parameter to DBA structure*/
|
||||
ctrl_pdata->dba_video_cfg.h_active =
|
||||
pt->timing.xres;
|
||||
ctrl_pdata->dba_video_cfg.h_front_porch =
|
||||
pt->timing.h_front_porch;
|
||||
ctrl_pdata->dba_video_cfg.h_back_porch =
|
||||
pt->timing.h_back_porch;
|
||||
ctrl_pdata->dba_video_cfg.h_pulse_width =
|
||||
pt->timing.h_pulse_width;
|
||||
ctrl_pdata->dba_video_cfg.v_active =
|
||||
pt->timing.yres;
|
||||
ctrl_pdata->dba_video_cfg.v_front_porch =
|
||||
pt->timing.v_front_porch;
|
||||
ctrl_pdata->dba_video_cfg.v_back_porch =
|
||||
pt->timing.v_back_porch;
|
||||
ctrl_pdata->dba_video_cfg.v_pulse_width =
|
||||
pt->timing.v_pulse_width;
|
||||
|
||||
num_lanes = 0;
|
||||
if (pinfo->mipi.data_lane0)
|
||||
num_lanes++;
|
||||
if (pinfo->mipi.data_lane1)
|
||||
num_lanes++;
|
||||
if (pinfo->mipi.data_lane2)
|
||||
num_lanes++;
|
||||
if (pinfo->mipi.data_lane3)
|
||||
num_lanes++;
|
||||
ctrl_pdata->dba_video_cfg.num_of_input_lanes = num_lanes;
|
||||
|
||||
data = of_get_property(np, "qcom,mdss-dsi-panel-timings", &len);
|
||||
if ((!data) || (len != 12)) {
|
||||
pr_debug("%s:%d, Unable to read Phy timing settings",
|
||||
|
@ -2304,124 +2281,15 @@ static int mdss_panel_parse_dt(struct device_node *np,
|
|||
|
||||
mdss_dsi_parse_dfps_config(np, ctrl_pdata);
|
||||
|
||||
pinfo->is_dba_panel = of_property_read_bool(np,
|
||||
"qcom,dba-panel");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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_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,
|
||||
sizeof(ctrl_pdata->edid_buf),
|
||||
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,
|
||||
int ndx)
|
||||
{
|
||||
struct hdmi_edid_init_data edid_init_data;
|
||||
msm_dba_cb dba_cb = mdss_dsi_dba_cb;
|
||||
|
||||
if (!ctrl_pdata) {
|
||||
pr_err("%s: Invalid ctrl data\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
snprintf(ctrl_pdata->dba_info.client_name, MSM_DBA_CLIENT_NAME_LEN,
|
||||
"dsi-%d", ndx);
|
||||
|
||||
strlcpy(ctrl_pdata->dba_info.chip_name, "adv7533",
|
||||
MSM_DBA_CHIP_NAME_MAX_LEN);
|
||||
|
||||
ctrl_pdata->dba_info.instance_id = ndx;
|
||||
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, %p\n", __func__,
|
||||
ctrl_pdata->dba_data);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ctrl_pdata->sdev.name = ctrl_pdata->dba_info.client_name;
|
||||
if (switch_dev_register(&ctrl_pdata->sdev) < 0) {
|
||||
pr_err("%s: DSI switch registration failed\n",
|
||||
__func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
memset(&edid_init_data, 0x00, sizeof(edid_init_data));
|
||||
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;
|
||||
}
|
||||
|
||||
if (ctrl_pdata->dba_ops.power_on)
|
||||
ctrl_pdata->dba_ops.power_on(ctrl_pdata->dba_data,
|
||||
true, 0);
|
||||
|
||||
ctrl_pdata->ds_registered = true;
|
||||
ctrl_pdata->hpd_state = true;
|
||||
mdss_dsi_send_cable_notification(ctrl_pdata, 1);
|
||||
end:
|
||||
return;
|
||||
}
|
||||
|
||||
int mdss_dsi_panel_init(struct device_node *node,
|
||||
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
|
||||
int ndx)
|
||||
|
@ -2464,7 +2332,5 @@ int mdss_dsi_panel_init(struct device_node *node,
|
|||
ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl;
|
||||
ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode;
|
||||
|
||||
mdss_dsi_ctrl_init_dba(ctrl_pdata, ndx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -541,14 +541,16 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev,
|
|||
"pu_en=%d\nxstart=%d\nwalign=%d\nystart=%d\nhalign=%d\n"
|
||||
"min_w=%d\nmin_h=%d\nroi_merge=%d\ndyn_fps_en=%d\n"
|
||||
"min_fps=%d\nmax_fps=%d\npanel_name=%s\n"
|
||||
"primary_panel=%d\nis_pluggable=%d\ndisplay_id=%s\n",
|
||||
"primary_panel=%d\nis_pluggable=%d\ndisplay_id=%s\n"
|
||||
"is_cec_supported=%d\n",
|
||||
pinfo->partial_update_enabled, pinfo->xstart_pix_align,
|
||||
pinfo->width_pix_align, pinfo->ystart_pix_align,
|
||||
pinfo->height_pix_align, pinfo->min_width,
|
||||
pinfo->min_height, pinfo->partial_update_roi_merge,
|
||||
pinfo->dynamic_fps, pinfo->min_fps, pinfo->max_fps,
|
||||
pinfo->panel_name, pinfo->is_prim_panel,
|
||||
pinfo->is_pluggable, pinfo->display_id);
|
||||
pinfo->is_pluggable, pinfo->display_id,
|
||||
pinfo->is_cec_supported);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/device.h>
|
||||
|
||||
#include "mdss_hdmi_cec.h"
|
||||
#include "mdss_panel.h"
|
||||
|
||||
#define CEC_STATUS_WR_ERROR BIT(0)
|
||||
#define CEC_STATUS_WR_DONE BIT(1)
|
||||
|
@ -260,6 +261,7 @@ static int hdmi_cec_enable(void *input, bool enable)
|
|||
u32 hdmi_hw_version, reg_val;
|
||||
struct dss_io_data *io = NULL;
|
||||
struct hdmi_cec_ctrl *cec_ctrl = (struct hdmi_cec_ctrl *)input;
|
||||
struct mdss_panel_info *pinfo;
|
||||
|
||||
if (!cec_ctrl || !cec_ctrl->init_data.io) {
|
||||
DEV_ERR("%s: Invalid input\n", __func__);
|
||||
|
@ -268,6 +270,12 @@ static int hdmi_cec_enable(void *input, bool enable)
|
|||
}
|
||||
|
||||
io = cec_ctrl->init_data.io;
|
||||
pinfo = cec_ctrl->init_data.pinfo;
|
||||
|
||||
if (!pinfo) {
|
||||
DEV_ERR("%s: invalid pinfo\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
/* 19.2Mhz * 0.00005 us = 950 = 0x3B6 */
|
||||
|
|
|
@ -31,11 +31,39 @@
|
|||
struct hdmi_cec_init_data {
|
||||
struct workqueue_struct *workq;
|
||||
struct dss_io_data *io;
|
||||
struct mdss_panel_info *pinfo;
|
||||
struct cec_cbs *cbs;
|
||||
struct cec_ops *ops;
|
||||
};
|
||||
|
||||
/**
|
||||
* hdmi_cec_isr() - interrupt handler for cec hw module
|
||||
* @cec_ctrl: pointer to cec hw module's data
|
||||
*
|
||||
* Return: irq error code
|
||||
*
|
||||
* The API can be called by HDMI Tx driver on receiving hw interrupts
|
||||
* to let the CEC related interrupts handled by this module.
|
||||
*/
|
||||
int hdmi_cec_isr(void *cec_ctrl);
|
||||
|
||||
/**
|
||||
* hdmi_cec_init() - Initialize the CEC hw module
|
||||
* @init_data: data needed to initialize the cec hw module
|
||||
*
|
||||
* Return: pointer to cec hw modules data that needs to be passed when
|
||||
* calling cec hw modules API or error code.
|
||||
*
|
||||
* The API registers CEC HW modules with the client and provides HW
|
||||
* specific operations.
|
||||
*/
|
||||
void *hdmi_cec_init(struct hdmi_cec_init_data *init_data);
|
||||
|
||||
/**
|
||||
* hdmi_cec_deinit() - de-initialize CEC HW module
|
||||
* @data: CEC HW module data
|
||||
*
|
||||
* This API release all resources allocated.
|
||||
*/
|
||||
void hdmi_cec_deinit(void *data);
|
||||
#endif /* __MDSS_HDMI_CEC_H__ */
|
||||
|
|
|
@ -348,7 +348,7 @@ static ssize_t hdmi_edid_sysfs_wta_modes(struct device *dev,
|
|||
}
|
||||
|
||||
rc = hdmi_get_supported_mode(&info,
|
||||
edid_ctrl->init_data.ds_data, vic);
|
||||
&edid_ctrl->init_data.ds_data, vic);
|
||||
if (rc) {
|
||||
DEV_ERR("%s: error getting res details\n", __func__);
|
||||
ret = -EINVAL;
|
||||
|
@ -479,7 +479,7 @@ static ssize_t hdmi_edid_sysfs_rda_res_info(struct device *dev,
|
|||
|
||||
for (; i < no_of_elem && size_to_write < PAGE_SIZE; i++) {
|
||||
ret = hdmi_get_supported_mode(&info,
|
||||
edid_ctrl->init_data.ds_data,
|
||||
&edid_ctrl->init_data.ds_data,
|
||||
minfo->video_format);
|
||||
|
||||
info.pixel_formats =
|
||||
|
@ -800,7 +800,7 @@ static void hdmi_edid_add_sink_y420_format(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
{
|
||||
struct msm_hdmi_mode_timing_info timing = {0};
|
||||
u32 ret = hdmi_get_supported_mode(&timing,
|
||||
edid_ctrl->init_data.ds_data,
|
||||
&edid_ctrl->init_data.ds_data,
|
||||
video_format);
|
||||
u32 supported = hdmi_edid_is_mode_supported(edid_ctrl, &timing);
|
||||
struct hdmi_edid_sink_data *sink = &edid_ctrl->sink_data;
|
||||
|
@ -1471,7 +1471,7 @@ static void hdmi_edid_add_sink_video_format(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
{
|
||||
struct msm_hdmi_mode_timing_info timing = {0};
|
||||
u32 ret = hdmi_get_supported_mode(&timing,
|
||||
edid_ctrl->init_data.ds_data,
|
||||
&edid_ctrl->init_data.ds_data,
|
||||
video_format);
|
||||
u32 supported = hdmi_edid_is_mode_supported(edid_ctrl, &timing);
|
||||
struct hdmi_edid_sink_data *sink_data = &edid_ctrl->sink_data;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
struct hdmi_edid_init_data {
|
||||
struct kobject *kobj;
|
||||
struct hdmi_util_ds_data *ds_data;
|
||||
struct hdmi_util_ds_data ds_data;
|
||||
u32 max_pclk_khz;
|
||||
u8 *buf;
|
||||
u32 buf_size;
|
||||
|
|
|
@ -1662,7 +1662,7 @@ static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl,
|
|||
|
||||
/* Initialize EDID feature */
|
||||
edid_init_data.kobj = hdmi_ctrl->kobj;
|
||||
edid_init_data.ds_data = &hdmi_ctrl->ds_data;
|
||||
edid_init_data.ds_data = hdmi_ctrl->ds_data;
|
||||
edid_init_data.max_pclk_khz = hdmi_ctrl->max_pclk_khz;
|
||||
|
||||
fd = hdmi_edid_init(&edid_init_data);
|
||||
|
@ -1733,6 +1733,7 @@ static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl,
|
|||
/* initialize cec hw feature and get ops */
|
||||
cec_init_data.io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
|
||||
cec_init_data.workq = hdmi_ctrl->workq;
|
||||
cec_init_data.pinfo = &hdmi_ctrl->panel_data.panel_info;
|
||||
cec_init_data.ops = &hdmi_ctrl->hdmi_cec_ops;
|
||||
cec_init_data.cbs = &hdmi_ctrl->hdmi_cec_cbs;
|
||||
|
||||
|
@ -1742,6 +1743,7 @@ static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl,
|
|||
goto err_cec_hw;
|
||||
}
|
||||
|
||||
hdmi_ctrl->panel_data.panel_info.is_cec_supported = true;
|
||||
hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW] = cec_hw_data;
|
||||
|
||||
/* initialize cec abstract layer and get callbacks */
|
||||
|
@ -1763,6 +1765,7 @@ static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl,
|
|||
|
||||
err_cec_abst:
|
||||
hdmi_cec_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW]);
|
||||
hdmi_ctrl->panel_data.panel_info.is_cec_supported = false;
|
||||
err_cec_hw:
|
||||
if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP2P2]) {
|
||||
hdmi_hdcp2p2_deinit(
|
||||
|
@ -4181,6 +4184,7 @@ static void hdmi_tx_dev_deinit(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW]) {
|
||||
hdmi_cec_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW]);
|
||||
hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC_HW] = NULL;
|
||||
hdmi_ctrl->panel_data.panel_info.is_cec_supported = false;
|
||||
}
|
||||
|
||||
if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]) {
|
||||
|
@ -4270,25 +4274,8 @@ static int hdmi_tx_dev_init(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
hdmi_ctrl->audio_data.sample_rate_hz = AUDIO_SAMPLE_RATE_48KHZ;
|
||||
hdmi_ctrl->audio_data.num_of_channels = MSM_HDMI_AUDIO_CHANNEL_2;
|
||||
|
||||
hdmi_ctrl->sdev.name = "hdmi";
|
||||
if (switch_dev_register(&hdmi_ctrl->sdev) < 0) {
|
||||
DEV_ERR("%s: Hdmi switch registration failed\n", __func__);
|
||||
rc = -ENODEV;
|
||||
goto fail_create_workq;
|
||||
}
|
||||
|
||||
hdmi_ctrl->audio_sdev.name = "hdmi_audio";
|
||||
if (switch_dev_register(&hdmi_ctrl->audio_sdev) < 0) {
|
||||
DEV_ERR("%s: hdmi_audio switch registration failed\n",
|
||||
__func__);
|
||||
rc = -ENODEV;
|
||||
goto fail_audio_switch_dev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_audio_switch_dev:
|
||||
switch_dev_unregister(&hdmi_ctrl->sdev);
|
||||
fail_create_workq:
|
||||
if (hdmi_ctrl->workq)
|
||||
destroy_workqueue(hdmi_ctrl->workq);
|
||||
|
@ -4326,6 +4313,31 @@ static int hdmi_tx_start_hdcp(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int hdmi_tx_init_switch_dev(struct hdmi_tx_ctrl *hdmi_ctrl)
|
||||
{
|
||||
int rc = -EINVAL;
|
||||
|
||||
if (!hdmi_ctrl) {
|
||||
DEV_ERR("%s: invalid input\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
hdmi_ctrl->sdev.name = "hdmi";
|
||||
rc = switch_dev_register(&hdmi_ctrl->sdev);
|
||||
if (rc) {
|
||||
DEV_ERR("%s: display switch registration failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
hdmi_ctrl->audio_sdev.name = "hdmi_audio";
|
||||
rc = switch_dev_register(&hdmi_ctrl->audio_sdev);
|
||||
if (rc)
|
||||
DEV_ERR("%s: audio switch registration failed\n", __func__);
|
||||
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data,
|
||||
int event, void *arg)
|
||||
{
|
||||
|
@ -4357,6 +4369,14 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data,
|
|||
return rc;
|
||||
}
|
||||
|
||||
rc = hdmi_tx_init_switch_dev(hdmi_ctrl);
|
||||
if (rc) {
|
||||
DEV_ERR("%s: init switch dev failed.rc=%d\n",
|
||||
__func__, rc);
|
||||
hdmi_tx_sysfs_remove(hdmi_ctrl);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (hdmi_ctrl->pdata.primary || !hdmi_ctrl->pdata.pluggable) {
|
||||
reinit_completion(&hdmi_ctrl->hpd_int_done);
|
||||
rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "mdss_hdmi_util.h"
|
||||
#include "mdss_cec_core.h"
|
||||
|
||||
#define MAX_SWITCH_NAME_SIZE 5
|
||||
|
||||
enum hdmi_tx_io_type {
|
||||
HDMI_TX_CORE_IO,
|
||||
HDMI_TX_QFPROM_IO,
|
||||
|
@ -195,6 +197,8 @@ struct hdmi_tx_ctrl {
|
|||
|
||||
struct cec_ops hdmi_cec_ops;
|
||||
struct cec_cbs hdmi_cec_cbs;
|
||||
|
||||
char disp_switch_name[MAX_SWITCH_NAME_SIZE];
|
||||
};
|
||||
|
||||
#endif /* __MDSS_HDMI_TX_H__ */
|
||||
|
|
|
@ -630,11 +630,13 @@ struct mdss_panel_info {
|
|||
bool is_prim_panel;
|
||||
bool is_pluggable;
|
||||
char display_id[MDSS_DISPLAY_ID_MAX_LEN];
|
||||
bool is_cec_supported;
|
||||
|
||||
/* refer sim_panel_modes enum for different modes */
|
||||
u8 sim_panel_mode;
|
||||
|
||||
void *edid_data;
|
||||
void *dba_data;
|
||||
void *cec_data;
|
||||
|
||||
char panel_name[MDSS_MAX_PANEL_LEN];
|
||||
|
@ -654,6 +656,8 @@ struct mdss_panel_info {
|
|||
struct lvds_panel_info lvds;
|
||||
struct edp_panel_info edp;
|
||||
|
||||
bool is_dba_panel;
|
||||
|
||||
/*
|
||||
* Delay(in ms) to accommodate s/w delay while
|
||||
* configuring the event timer wakeup logic.
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -286,6 +286,7 @@ struct msm_dba_video_cfg {
|
|||
bool hdmi_mode;
|
||||
enum msm_dba_video_aspect_ratio ar;
|
||||
u32 num_of_input_lanes;
|
||||
u8 scaninfo;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -338,6 +339,8 @@ struct msm_dba_video_cfg {
|
|||
* hdcp_get_ksv_list_size first and then allocate 40*size
|
||||
* bytes to hold all the KSVs.
|
||||
* DEFER and ASYNC flags are not supported.
|
||||
* @hdmi_cec_on: enable or disable cec module. Clients need to enable CEC
|
||||
* feature before they do read or write CEC messages.
|
||||
* @hdmi_cec_write: perform a CEC write. For bridges with HDMI as output
|
||||
* interface, this function allows clients to send a CEC
|
||||
* message. Client should pack the data according to the CEC
|
||||
|
@ -381,6 +384,8 @@ struct msm_dba_video_cfg {
|
|||
* have been applied so far after the reset is complete. In case
|
||||
* of multiple clients, driver will issue a reset callback.
|
||||
* @dump_debug_info: dumps debug information to dmesg.
|
||||
* @check_hpd: Check if cable is connected or not. if cable is connected we
|
||||
* send notification to display framework.
|
||||
*
|
||||
* The msm_dba_ops structure represents a set of operations that can be
|
||||
* supported by each bridge chip. Depending on the functionality supported by a
|
||||
|
@ -441,6 +446,10 @@ struct msm_dba_ops {
|
|||
char *buf,
|
||||
u32 flags);
|
||||
|
||||
int (*hdmi_cec_on)(void *client,
|
||||
bool enable,
|
||||
u32 flags);
|
||||
|
||||
int (*hdmi_cec_write)(void *client,
|
||||
u32 size,
|
||||
char *buf,
|
||||
|
@ -474,6 +483,7 @@ struct msm_dba_ops {
|
|||
|
||||
int (*force_reset)(void *client, u32 flags);
|
||||
int (*dump_debug_info)(void *client, u32 flags);
|
||||
int (*check_hpd)(void *client, u32 flags);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -487,15 +497,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…
Add table
Reference in a new issue