Merge tag 'LA.UM.8.4.r1-05300-8x98.0' into op8998-ten
"LA.UM.8.4.r1-05300-8x98.0"
This commit is contained in:
commit
653ed5621b
28 changed files with 1131 additions and 273 deletions
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2016-2017,2019 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
|
||||
|
@ -38,6 +38,12 @@
|
|||
qcom,display-type = "primary";
|
||||
};
|
||||
|
||||
&mdss_fb2 {
|
||||
qcom,cont-splash-memory {
|
||||
linux,contiguous-region = <&cont_splash_mem>;
|
||||
};
|
||||
};
|
||||
|
||||
&slim_aud {
|
||||
tasha_codec {
|
||||
wsa_spkr_sd1: msm_cdc_pinctrll {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2013-2020, 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
|
||||
|
@ -841,6 +841,9 @@ static void msm_isp_sync_dual_cam_frame_id(
|
|||
ms_res->src_info[i]->dual_hw_ms_info.index);
|
||||
}
|
||||
}
|
||||
/* the number of frames that are dropped */
|
||||
vfe_dev->isp_page->dual_cam_drop =
|
||||
frame_id - (src_info->frame_id + 1);
|
||||
ms_res->active_src_mask |= (1 << src_info->dual_hw_ms_info.index);
|
||||
src_info->frame_id = frame_id;
|
||||
src_info->dual_hw_ms_info.sync_state = MSM_ISP_DUAL_CAM_SYNC;
|
||||
|
@ -878,6 +881,8 @@ void msm_isp_increment_frame_id(struct vfe_device *vfe_dev,
|
|||
src_info->dual_hw_ms_info.index)) {
|
||||
pr_err_ratelimited("Frame out of sync on vfe %d\n",
|
||||
vfe_dev->pdev->id);
|
||||
/* Notify to do reconfig at SW sync drop*/
|
||||
vfe_dev->isp_page->dual_cam_drop_detected = 1;
|
||||
/*
|
||||
* set this isp as async mode to force
|
||||
*it sync again at the next sof
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2015-2020, 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
|
||||
|
@ -2085,6 +2085,7 @@ static void hdcp_lib_clean(struct hdcp_lib_handle *handle)
|
|||
handle->authenticated = false;
|
||||
|
||||
/* AV mute the sink first to avoid artifacts */
|
||||
if (handle->client_ops->mute_sink)
|
||||
handle->client_ops->mute_sink(handle->client_ctx);
|
||||
|
||||
hdcp_lib_txmtr_deinit(handle);
|
||||
|
@ -2332,19 +2333,20 @@ bool hdcp1_check_if_supported_load_app(void)
|
|||
|
||||
/* start hdcp1 app */
|
||||
if (hdcp1_supported && !hdcp1_handle->qsee_handle) {
|
||||
mutex_init(&hdcp1_ta_cmd_lock);
|
||||
rc = qseecom_start_app(&hdcp1_handle->qsee_handle,
|
||||
HDCP1_APP_NAME,
|
||||
QSEECOM_SBUFF_SIZE);
|
||||
if (rc) {
|
||||
pr_err("hdcp1 qseecom_start_app failed %d\n", rc);
|
||||
hdcp1_supported = false;
|
||||
hdcp1_srm_supported = false;
|
||||
kfree(hdcp1_handle);
|
||||
}
|
||||
}
|
||||
|
||||
/* if hdcp1 app succeeds load SRM TA as well */
|
||||
if (hdcp1_supported && !hdcp1_handle->srm_handle) {
|
||||
mutex_init(&hdcp1_ta_cmd_lock);
|
||||
rc = qseecom_start_app(&hdcp1_handle->srm_handle,
|
||||
SRMAPP_NAME,
|
||||
QSEECOM_SBUFF_SIZE);
|
||||
|
@ -2395,13 +2397,19 @@ int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb)
|
|||
if (aksv_msb == NULL || aksv_lsb == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (!hdcp1_supported || !hdcp1_handle)
|
||||
return -EINVAL;
|
||||
mutex_lock(&hdcp1_ta_cmd_lock);
|
||||
|
||||
if (!hdcp1_supported || !hdcp1_handle) {
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
hdcp1_qsee_handle = hdcp1_handle->qsee_handle;
|
||||
|
||||
if (!hdcp1_qsee_handle)
|
||||
return -EINVAL;
|
||||
if (!hdcp1_qsee_handle) {
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* set keys and request aksv */
|
||||
key_set_req = (struct hdcp1_key_set_req *)hdcp1_qsee_handle->sbuf;
|
||||
|
@ -2417,13 +2425,15 @@ int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb)
|
|||
|
||||
if (rc < 0) {
|
||||
pr_err("qseecom cmd failed err=%d\n", rc);
|
||||
return -ENOKEY;
|
||||
rc = -ENOKEY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
rc = key_set_rsp->ret;
|
||||
if (rc) {
|
||||
pr_err("set key cmd failed, rsp=%d\n", key_set_rsp->ret);
|
||||
return -ENOKEY;
|
||||
rc = -ENOKEY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* copy bytes into msb and lsb */
|
||||
|
@ -2436,7 +2446,9 @@ int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb)
|
|||
*aksv_lsb |= key_set_rsp->ksv[6] << 8;
|
||||
*aksv_lsb |= key_set_rsp->ksv[7];
|
||||
|
||||
return 0;
|
||||
end:
|
||||
mutex_unlock(&hdcp1_ta_cmd_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int hdcp1_validate_receiver_ids(struct hdcp_srm_device_id_t *device_ids,
|
||||
|
@ -2576,8 +2588,10 @@ int hdcp1_set_enc(bool enable)
|
|||
|
||||
hdcp1_qsee_handle = hdcp1_handle->qsee_handle;
|
||||
|
||||
if (!hdcp1_qsee_handle)
|
||||
return -EINVAL;
|
||||
if (!hdcp1_qsee_handle) {
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (hdcp1_enc_enabled == enable) {
|
||||
pr_info("already %s\n", enable ? "enabled" : "disabled");
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2015-2017, 2020, 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
|
||||
|
@ -594,6 +594,41 @@ end:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t cec_wta_clear_logical_addr(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int clear_flag;
|
||||
unsigned long flags;
|
||||
ssize_t ret;
|
||||
struct cec_ctl *ctl = cec_get_ctl(dev);
|
||||
struct cec_ops *ops;
|
||||
|
||||
if (!ctl) {
|
||||
pr_err("Invalid ctl\n");
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ops = ctl->init_data.ops;
|
||||
|
||||
ret = kstrtoint(buf, 10, &clear_flag);
|
||||
if (ret) {
|
||||
pr_err("kstrtoint failed\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = count;
|
||||
|
||||
spin_lock_irqsave(&ctl->lock, flags);
|
||||
if (ctl->enabled) {
|
||||
if (ops && ops->clear_logical_addr)
|
||||
ops->clear_logical_addr(ops->data, !!clear_flag);
|
||||
}
|
||||
spin_unlock_irqrestore(&ctl->lock, flags);
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t cec_rda_msg(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
@ -703,6 +738,8 @@ static DEVICE_ATTR(enable_compliance, S_IRUGO | S_IWUSR,
|
|||
cec_rda_enable_compliance, cec_wta_enable_compliance);
|
||||
static DEVICE_ATTR(logical_addr, S_IRUSR | S_IWUSR,
|
||||
cec_rda_logical_addr, cec_wta_logical_addr);
|
||||
static DEVICE_ATTR(clear_logical_addr, 0200,
|
||||
NULL, cec_wta_clear_logical_addr);
|
||||
static DEVICE_ATTR(rd_msg, S_IRUGO, cec_rda_msg, NULL);
|
||||
static DEVICE_ATTR(wr_msg, S_IWUSR | S_IRUSR, NULL, cec_wta_msg);
|
||||
|
||||
|
@ -710,6 +747,7 @@ static struct attribute *cec_fs_attrs[] = {
|
|||
&dev_attr_enable.attr,
|
||||
&dev_attr_enable_compliance.attr,
|
||||
&dev_attr_logical_addr.attr,
|
||||
&dev_attr_clear_logical_addr.attr,
|
||||
&dev_attr_rd_msg.attr,
|
||||
&dev_attr_wr_msg.attr,
|
||||
NULL,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2015-2016, 2020, 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
|
||||
|
@ -67,6 +67,7 @@ struct cec_ops {
|
|||
int (*send_msg)(void *data,
|
||||
struct cec_msg *msg);
|
||||
void (*wt_logical_addr)(void *data, u8 addr);
|
||||
void (*clear_logical_addr)(void *data, bool flag);
|
||||
void (*wakeup_en)(void *data, bool en);
|
||||
bool (*is_wakeup_en)(void *data);
|
||||
void (*device_suspend)(void *data, bool suspend);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Core MDSS framebuffer driver.
|
||||
*
|
||||
* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2008-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2007 Google Incorporated
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
|
@ -3760,16 +3760,19 @@ static int mdss_fb_pan_display(struct fb_var_screeninfo *var,
|
|||
{
|
||||
struct mdp_display_commit disp_commit;
|
||||
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
|
||||
struct mdss_data_type *mdata = mfd_to_mdata(mfd);
|
||||
|
||||
/*
|
||||
* during mode switch through mode sysfs node, it will trigger a
|
||||
* Abort pan_display operations in following cases:
|
||||
* 1. during mode switch through mode sysfs node, it will trigger a
|
||||
* pan_display after switch. This assumes that fb has been adjusted,
|
||||
* however when using overlays we may not have the right size at this
|
||||
* point, so it needs to go through PREPARE first. Abort pan_display
|
||||
* operations until that happens
|
||||
* point, so it needs to go through PREPARE first.
|
||||
* 2. When the splash handoff is pending.
|
||||
*/
|
||||
if (mfd->switch_state != MDSS_MDP_NO_UPDATE_REQUESTED) {
|
||||
pr_debug("fb%d: pan_display skipped during switch\n",
|
||||
if ((mfd->switch_state != MDSS_MDP_NO_UPDATE_REQUESTED) ||
|
||||
(mdss_fb_is_hdmi_primary(mfd) && mdata->handoff_pending)) {
|
||||
pr_debug("fb%d: pan_display skipped during switch or handoff\n",
|
||||
mfd->index);
|
||||
return 0;
|
||||
}
|
||||
|
@ -4325,17 +4328,23 @@ static int mdss_fb_set_par(struct fb_info *info)
|
|||
mfd->fbi->fix.smem_len = PAGE_ALIGN(mfd->fbi->fix.line_length *
|
||||
mfd->fbi->var.yres) * mfd->fb_page;
|
||||
|
||||
old_format = mdss_grayscale_to_mdp_format(var->grayscale);
|
||||
if (!IS_ERR_VALUE(old_format)) {
|
||||
old_format = mfd->panel_info->out_format;
|
||||
mfd->panel_info->out_format =
|
||||
mdss_grayscale_to_mdp_format(var->grayscale);
|
||||
if (!IS_ERR_VALUE(mfd->panel_info->out_format)) {
|
||||
if (old_format != mfd->panel_info->out_format)
|
||||
mfd->panel_reconfig = true;
|
||||
}
|
||||
|
||||
if (mdss_fb_is_hdmi_primary(mfd) && mfd->panel_reconfig)
|
||||
mfd->force_null_commit = true;
|
||||
|
||||
if (mfd->panel_reconfig || (mfd->fb_imgType != old_imgType)) {
|
||||
mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
|
||||
mdss_fb_var_to_panelinfo(var, mfd->panel_info);
|
||||
mdss_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable);
|
||||
mfd->panel_reconfig = false;
|
||||
mfd->force_null_commit = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2008-2020, 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
|
||||
|
@ -292,6 +292,7 @@ struct msm_fb_data_type {
|
|||
int op_enable;
|
||||
u32 fb_imgType;
|
||||
int panel_reconfig;
|
||||
int force_null_commit;
|
||||
u32 panel_orientation;
|
||||
|
||||
u32 dst_format;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2010-2020, 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
|
||||
|
@ -1348,16 +1348,16 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x *hdcp)
|
|||
}
|
||||
|
||||
do {
|
||||
rc = hdcp_1x_transfer_v_h(hdcp);
|
||||
if (rc)
|
||||
goto error;
|
||||
|
||||
/* do not proceed further if no device connected */
|
||||
if (!hdcp->current_tp.dev_count) {
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = hdcp_1x_transfer_v_h(hdcp);
|
||||
if (rc)
|
||||
goto error;
|
||||
|
||||
rc = hdcp_1x_write_ksv_fifo(hdcp);
|
||||
} while (--v_retry && rc);
|
||||
error:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2010-2017, 2020, 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
|
||||
|
@ -17,6 +17,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/circ_buf.h>
|
||||
|
||||
#include "mdss_hdmi_cec.h"
|
||||
#include "mdss_panel.h"
|
||||
|
@ -33,12 +34,19 @@
|
|||
#define CEC_OP_KEY_PRESS 0x44
|
||||
#define CEC_OP_STANDBY 0x36
|
||||
|
||||
#define CEC_RECV_Q_SIZE 4
|
||||
#define CEC_RECV_Q_MASK 3
|
||||
|
||||
struct hdmi_cec_ctrl {
|
||||
bool cec_enabled;
|
||||
bool cec_wakeup_en;
|
||||
bool cec_device_suspend;
|
||||
|
||||
bool cec_clear_logical_addr;
|
||||
u32 cec_logical_addr;
|
||||
u32 cec_msg_wr_status;
|
||||
struct cec_msg recv_msg[CEC_RECV_Q_SIZE];
|
||||
u32 head;
|
||||
u32 tail;
|
||||
spinlock_t lock;
|
||||
struct work_struct cec_read_work;
|
||||
struct completion cec_msg_wr_done;
|
||||
|
@ -60,6 +68,20 @@ static int hdmi_cec_msg_send(void *data, struct cec_msg *msg)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (msg->sender_id != cec_ctrl->cec_logical_addr &&
|
||||
msg->recvr_id == 0xF) {
|
||||
/*
|
||||
* If the current logical address is not the
|
||||
* same as the sender_id and if the message is
|
||||
* broadcasting, the message is looping back.
|
||||
* Abort the message sending in that case
|
||||
*/
|
||||
DEV_ERR("%s: abort potential MAL msg %d:%d logical %d\n",
|
||||
__func__, msg->sender_id, msg->recvr_id,
|
||||
cec_ctrl->cec_logical_addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
io = cec_ctrl->init_data.io;
|
||||
|
||||
reinit_completion(&cec_ctrl->cec_msg_wr_done);
|
||||
|
@ -164,14 +186,87 @@ static void hdmi_cec_deinit_input_event(struct hdmi_cec_ctrl *cec_ctrl)
|
|||
cec_ctrl->input = NULL;
|
||||
}
|
||||
|
||||
static int hdmi_cec_msg_read(struct hdmi_cec_ctrl *cec_ctrl)
|
||||
{
|
||||
struct dss_io_data *io = NULL;
|
||||
struct cec_msg *msg;
|
||||
u32 data;
|
||||
int i;
|
||||
u32 head;
|
||||
u32 tail;
|
||||
|
||||
if (!cec_ctrl || !cec_ctrl->init_data.io) {
|
||||
DEV_ERR("%s: invalid input\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!cec_ctrl->cec_enabled) {
|
||||
DEV_ERR("%s: cec not enabled\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
head = cec_ctrl->head;
|
||||
tail = READ_ONCE(cec_ctrl->tail);
|
||||
if (CIRC_SPACE(head, tail, CEC_RECV_Q_SIZE) < 1) {
|
||||
DEV_ERR("%s: no more space to hold the buffer\n", __func__);
|
||||
return 0; /* Let's just kick the thread */
|
||||
}
|
||||
|
||||
msg = &cec_ctrl->recv_msg[head];
|
||||
|
||||
io = cec_ctrl->init_data.io;
|
||||
data = DSS_REG_R(io, HDMI_CEC_RD_DATA);
|
||||
|
||||
msg->recvr_id = (data & 0x000F);
|
||||
msg->sender_id = (data & 0x00F0) >> 4;
|
||||
msg->frame_size = (data & 0x1F00) >> 8;
|
||||
if (msg->frame_size < 1 || msg->frame_size > MAX_CEC_FRAME_SIZE) {
|
||||
DEV_ERR("%s: invalid message (frame length = %d)\n",
|
||||
__func__, msg->frame_size);
|
||||
return -EINVAL;
|
||||
} else if (msg->frame_size == 1) {
|
||||
DEV_DBG("%s: polling message (dest[%x] <- init[%x])\n",
|
||||
__func__, msg->recvr_id, msg->sender_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* data block 0 : opcode */
|
||||
data = DSS_REG_R_ND(io, HDMI_CEC_RD_DATA);
|
||||
msg->opcode = data & 0xFF;
|
||||
|
||||
/* data block 1-14 : operand 0-13 */
|
||||
for (i = 0; i < msg->frame_size - 2; i++) {
|
||||
data = DSS_REG_R_ND(io, HDMI_CEC_RD_DATA);
|
||||
msg->operand[i] = data & 0xFF;
|
||||
}
|
||||
|
||||
for (; i < MAX_OPERAND_SIZE; i++)
|
||||
msg->operand[i] = 0;
|
||||
|
||||
/*
|
||||
* Clearing the logical address is used when the system doesn't
|
||||
* need to process CEC command any more.
|
||||
*/
|
||||
if (cec_ctrl->cec_clear_logical_addr)
|
||||
return -EINVAL;
|
||||
|
||||
/* Update head */
|
||||
smp_store_release(&cec_ctrl->head, (head + 1) & CEC_RECV_Q_MASK);
|
||||
|
||||
DEV_DBG("%s: opcode 0x%x, wakup_en %d, device_suspend %d\n", __func__,
|
||||
msg->opcode, cec_ctrl->cec_wakeup_en,
|
||||
cec_ctrl->cec_device_suspend);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hdmi_cec_msg_recv(struct work_struct *work)
|
||||
{
|
||||
int i;
|
||||
u32 data;
|
||||
struct hdmi_cec_ctrl *cec_ctrl = NULL;
|
||||
struct dss_io_data *io = NULL;
|
||||
struct cec_msg msg;
|
||||
struct cec_cbs *cbs;
|
||||
u32 head;
|
||||
u32 tail;
|
||||
|
||||
cec_ctrl = container_of(work, struct hdmi_cec_ctrl, cec_read_work);
|
||||
if (!cec_ctrl || !cec_ctrl->init_data.io) {
|
||||
|
@ -179,49 +274,17 @@ static void hdmi_cec_msg_recv(struct work_struct *work)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!cec_ctrl->cec_enabled) {
|
||||
DEV_ERR("%s: cec not enabled\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
io = cec_ctrl->init_data.io;
|
||||
cbs = cec_ctrl->init_data.cbs;
|
||||
|
||||
data = DSS_REG_R(io, HDMI_CEC_RD_DATA);
|
||||
/* Read head before reading contents */
|
||||
head = smp_load_acquire(&cec_ctrl->head);
|
||||
tail = cec_ctrl->tail;
|
||||
while (CIRC_CNT(head, tail, CEC_RECV_Q_SIZE) >= 1) {
|
||||
memcpy(&msg, &cec_ctrl->recv_msg[tail], sizeof(msg));
|
||||
tail = (tail + 1) & CEC_RECV_Q_MASK;
|
||||
|
||||
msg.recvr_id = (data & 0x000F);
|
||||
msg.sender_id = (data & 0x00F0) >> 4;
|
||||
msg.frame_size = (data & 0x1F00) >> 8;
|
||||
DEV_DBG("%s: Recvd init=[%u] dest=[%u] size=[%u]\n", __func__,
|
||||
msg.sender_id, msg.recvr_id,
|
||||
msg.frame_size);
|
||||
|
||||
if (msg.frame_size < 1 || msg.frame_size > MAX_CEC_FRAME_SIZE) {
|
||||
DEV_ERR("%s: invalid message (frame length = %d)\n",
|
||||
__func__, msg.frame_size);
|
||||
return;
|
||||
} else if (msg.frame_size == 1) {
|
||||
DEV_DBG("%s: polling message (dest[%x] <- init[%x])\n",
|
||||
__func__, msg.recvr_id, msg.sender_id);
|
||||
return;
|
||||
}
|
||||
|
||||
/* data block 0 : opcode */
|
||||
data = DSS_REG_R_ND(io, HDMI_CEC_RD_DATA);
|
||||
msg.opcode = data & 0xFF;
|
||||
|
||||
/* data block 1-14 : operand 0-13 */
|
||||
for (i = 0; i < msg.frame_size - 2; i++) {
|
||||
data = DSS_REG_R_ND(io, HDMI_CEC_RD_DATA);
|
||||
msg.operand[i] = data & 0xFF;
|
||||
}
|
||||
|
||||
for (; i < MAX_OPERAND_SIZE; i++)
|
||||
msg.operand[i] = 0;
|
||||
|
||||
DEV_DBG("%s: opcode 0x%x, wakup_en %d, device_suspend %d\n", __func__,
|
||||
msg.opcode, cec_ctrl->cec_wakeup_en,
|
||||
cec_ctrl->cec_device_suspend);
|
||||
/* Finishing reading before incrementing tail */
|
||||
smp_store_release(&cec_ctrl->tail, tail);
|
||||
|
||||
if ((msg.opcode == CEC_OP_SET_STREAM_PATH ||
|
||||
msg.opcode == CEC_OP_KEY_PRESS) &&
|
||||
|
@ -246,6 +309,7 @@ static void hdmi_cec_msg_recv(struct work_struct *work)
|
|||
|
||||
if (cbs && cbs->msg_recv_notify)
|
||||
cbs->msg_recv_notify(cbs->data, &msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -308,8 +372,12 @@ int hdmi_cec_isr(void *input)
|
|||
if ((cec_intr & BIT(6)) && (cec_intr & BIT(7))) {
|
||||
DEV_DBG("%s: CEC_IRQ_FRAME_RD_DONE\n", __func__);
|
||||
|
||||
rc = hdmi_cec_msg_read(cec_ctrl);
|
||||
if (!rc)
|
||||
queue_work(cec_ctrl->init_data.workq,
|
||||
&cec_ctrl->cec_read_work);
|
||||
|
||||
DSS_REG_W(io, HDMI_CEC_INT, cec_intr | BIT(6));
|
||||
queue_work(cec_ctrl->init_data.workq, &cec_ctrl->cec_read_work);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -360,8 +428,23 @@ static void hdmi_cec_write_logical_addr(void *input, u8 addr)
|
|||
return;
|
||||
}
|
||||
|
||||
if (cec_ctrl->cec_enabled)
|
||||
if (cec_ctrl->cec_enabled) {
|
||||
DSS_REG_W(cec_ctrl->init_data.io, HDMI_CEC_ADDR, addr & 0xF);
|
||||
cec_ctrl->cec_logical_addr = addr & 0xF;
|
||||
}
|
||||
}
|
||||
|
||||
static void hdmi_cec_clear_logical_addr(void *input, bool clear_flag)
|
||||
{
|
||||
struct hdmi_cec_ctrl *cec_ctrl = (struct hdmi_cec_ctrl *)input;
|
||||
|
||||
if (!cec_ctrl || !cec_ctrl->init_data.io) {
|
||||
DEV_ERR("%s: Invalid input\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cec_ctrl->cec_enabled)
|
||||
cec_ctrl->cec_clear_logical_addr = clear_flag;
|
||||
}
|
||||
|
||||
static int hdmi_cec_enable(void *input, bool enable)
|
||||
|
@ -474,6 +557,7 @@ void *hdmi_cec_init(struct hdmi_cec_init_data *init_data)
|
|||
/* populate hardware specific operations to client */
|
||||
ops->send_msg = hdmi_cec_msg_send;
|
||||
ops->wt_logical_addr = hdmi_cec_write_logical_addr;
|
||||
ops->clear_logical_addr = hdmi_cec_clear_logical_addr;
|
||||
ops->enable = hdmi_cec_enable;
|
||||
ops->data = cec_ctrl;
|
||||
ops->wakeup_en = hdmi_cec_wakeup_en;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2010-2020, 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
|
||||
|
@ -51,6 +51,9 @@
|
|||
/* Support for first 5 EDID blocks */
|
||||
#define MAX_EDID_SIZE (EDID_BLOCK_SIZE * MAX_EDID_BLOCKS)
|
||||
|
||||
/* Max refresh rate supported in Hz */
|
||||
#define MAX_REFRESH_RATE_SUPPORTED 60
|
||||
|
||||
#define BUFF_SIZE_3D 128
|
||||
|
||||
#define DTD_MAX 0x04
|
||||
|
@ -89,6 +92,7 @@ enum extended_data_block_types {
|
|||
VIDEO_CAPABILITY_DATA_BLOCK = 0x0,
|
||||
VENDOR_SPECIFIC_VIDEO_DATA_BLOCK = 0x01,
|
||||
HDMI_VIDEO_DATA_BLOCK = 0x04,
|
||||
COLORIMETRY_DATA_BLOCK = 0x05,
|
||||
HDR_STATIC_METADATA_DATA_BLOCK = 0x06,
|
||||
Y420_VIDEO_DATA_BLOCK = 0x0E,
|
||||
VIDEO_FORMAT_PREFERENCE_DATA_BLOCK = 0x0D,
|
||||
|
@ -122,6 +126,16 @@ struct hdmi_edid_sink_caps {
|
|||
bool ind_view_support;
|
||||
};
|
||||
|
||||
struct hdmi_edid_y420_cmdb {
|
||||
u8 *vic_list;
|
||||
u32 len;
|
||||
};
|
||||
|
||||
struct hdmi_edid_colorimetry {
|
||||
u8 standards;
|
||||
u8 metadata_profiles;
|
||||
};
|
||||
|
||||
struct hdmi_edid_ctrl {
|
||||
u8 pt_scan_info;
|
||||
u8 it_scan_info;
|
||||
|
@ -147,12 +161,18 @@ struct hdmi_edid_ctrl {
|
|||
bool keep_resv_timings;
|
||||
bool edid_override;
|
||||
bool hdr_supported;
|
||||
bool override_default_vic;
|
||||
|
||||
bool y420_cmdb_present;
|
||||
bool y420_cmdb_supports_all;
|
||||
struct hdmi_edid_y420_cmdb y420_cmdb;
|
||||
|
||||
struct hdmi_edid_sink_data sink_data;
|
||||
struct hdmi_edid_init_data init_data;
|
||||
struct hdmi_edid_sink_caps sink_caps;
|
||||
struct hdmi_edid_override_data override_data;
|
||||
struct hdmi_edid_hdr_data hdr_data;
|
||||
struct hdmi_edid_colorimetry colorimetry;
|
||||
};
|
||||
|
||||
static bool hdmi_edid_is_mode_supported(struct hdmi_edid_ctrl *edid_ctrl,
|
||||
|
@ -187,6 +207,9 @@ static int hdmi_edid_reset_parser(struct hdmi_edid_ctrl *edid_ctrl)
|
|||
|
||||
edid_ctrl->sink_data.num_of_elements = 0;
|
||||
|
||||
/* reset deep color */
|
||||
edid_ctrl->deep_color = 0;
|
||||
|
||||
/* reset scan info data */
|
||||
edid_ctrl->pt_scan_info = 0;
|
||||
edid_ctrl->it_scan_info = 0;
|
||||
|
@ -200,6 +223,7 @@ static int hdmi_edid_reset_parser(struct hdmi_edid_ctrl *edid_ctrl)
|
|||
|
||||
/* reset resolution related sink data */
|
||||
memset(&edid_ctrl->sink_data, 0, sizeof(edid_ctrl->sink_data));
|
||||
memset(&edid_ctrl->sink_caps, 0, sizeof(edid_ctrl->sink_caps));
|
||||
|
||||
/* reset audio related data */
|
||||
memset(edid_ctrl->audio_data_block, 0,
|
||||
|
@ -224,6 +248,10 @@ static int hdmi_edid_reset_parser(struct hdmi_edid_ctrl *edid_ctrl)
|
|||
edid_ctrl->hdr_data.avg_luminance = 0;
|
||||
edid_ctrl->hdr_data.min_luminance = 0;
|
||||
|
||||
edid_ctrl->y420_cmdb_present = false;
|
||||
edid_ctrl->y420_cmdb_supports_all = false;
|
||||
kfree(edid_ctrl->y420_cmdb.vic_list);
|
||||
memset(&edid_ctrl->y420_cmdb, 0, sizeof(edid_ctrl->y420_cmdb));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -915,28 +943,6 @@ static const u8 *hdmi_edid_find_hfvsdb(const u8 *in_buf)
|
|||
return vsd;
|
||||
}
|
||||
|
||||
static void hdmi_edid_set_y420_support(struct hdmi_edid_ctrl *edid_ctrl,
|
||||
u32 video_format)
|
||||
{
|
||||
u32 i = 0;
|
||||
|
||||
if (!edid_ctrl) {
|
||||
DEV_ERR("%s: Invalid input\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < edid_ctrl->sink_data.num_of_elements; ++i) {
|
||||
if (video_format ==
|
||||
edid_ctrl->sink_data.disp_mode_list[i].video_format) {
|
||||
edid_ctrl->sink_data.disp_mode_list[i].y420_support =
|
||||
true;
|
||||
DEV_DBG("%s: Yuv420 supported for format %d\n",
|
||||
__func__,
|
||||
edid_ctrl->sink_data.disp_mode_list[i].video_format);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void hdmi_edid_add_sink_y420_format(struct hdmi_edid_ctrl *edid_ctrl,
|
||||
u32 video_format)
|
||||
{
|
||||
|
@ -963,6 +969,17 @@ static void hdmi_edid_add_sink_y420_format(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
video_format, msm_hdmi_mode_2string(video_format),
|
||||
supported ? "Supported" : "Not-Supported");
|
||||
|
||||
/* override the default resolution */
|
||||
if (edid_ctrl->override_default_vic) {
|
||||
if (!ret && supported) {
|
||||
sink->disp_mode_list[0].video_format = video_format;
|
||||
sink->disp_mode_list[0].y420_support = true;
|
||||
sink->disp_mode_list[0].rgb_support = false;
|
||||
edid_ctrl->override_default_vic = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret && supported) {
|
||||
sink->disp_mode_list[sink->num_of_elements].video_format
|
||||
= video_format;
|
||||
|
@ -1039,10 +1056,12 @@ static void hdmi_edid_parse_Y420CMDB(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
{
|
||||
u32 offset = 0;
|
||||
u8 svd_len = 0;
|
||||
u32 i = 0, j = 0;
|
||||
u32 i = 0, j = 0, k = 0;
|
||||
u32 video_format = 0;
|
||||
u32 len = 0;
|
||||
const u8 *svd = NULL;
|
||||
struct hdmi_edid_y420_cmdb *y420_cmdb = NULL;
|
||||
|
||||
|
||||
if (!edid_ctrl) {
|
||||
DEV_ERR("%s: invalid input\n", __func__);
|
||||
|
@ -1052,6 +1071,18 @@ static void hdmi_edid_parse_Y420CMDB(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
offset += 2;
|
||||
len = in_buf[0] & 0x1F;
|
||||
|
||||
/*
|
||||
* When the Length field is set to L==1, the Y420CMDB does not include
|
||||
* a YCBCR 4:2:0 Capability Bit Map and all the SVDs in the regular
|
||||
* Video Data Block support YCBCR 4:2:0 sampling mode.
|
||||
*/
|
||||
if (len == 1) {
|
||||
DEV_DBG("%s: All SVDs supports Y420 sampling mode, len = %d\n",
|
||||
__func__, len);
|
||||
edid_ctrl->y420_cmdb_supports_all = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The Y420 Capability map data block should be parsed along with the
|
||||
* video data block. Each bit in Y420CMDB maps to each SVD in data
|
||||
|
@ -1060,16 +1091,33 @@ static void hdmi_edid_parse_Y420CMDB(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
svd = hdmi_edid_find_block(edid_ctrl->edid_buf+0x80, DBC_START_OFFSET,
|
||||
VIDEO_DATA_BLOCK, &svd_len);
|
||||
|
||||
++svd;
|
||||
for (i = 0; i < svd_len; i++, j++) {
|
||||
video_format = *svd & 0x7F;
|
||||
if (in_buf[offset] & (1 << j))
|
||||
hdmi_edid_set_y420_support(edid_ctrl, video_format);
|
||||
if (!svd_len)
|
||||
return;
|
||||
|
||||
if (j & 0x80) {
|
||||
j = j/8;
|
||||
y420_cmdb = &edid_ctrl->y420_cmdb;
|
||||
y420_cmdb->vic_list = kzalloc(svd_len, GFP_KERNEL);
|
||||
if (!y420_cmdb->vic_list) {
|
||||
DEV_ERR("%s: failed to allocated memory for y420 vic_list\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
++svd;
|
||||
|
||||
for (i = 0, k = 0; i < svd_len; i++, svd++) {
|
||||
video_format = *svd & 0x7F;
|
||||
if (in_buf[offset] & (1 << j)) {
|
||||
y420_cmdb->vic_list[k++] = video_format;
|
||||
DEV_DBG("%s: Y420 capability for VIC %d\n",
|
||||
__func__, video_format);
|
||||
y420_cmdb->len++;
|
||||
}
|
||||
|
||||
j++;
|
||||
if (j & 0x8) {
|
||||
j = 0;
|
||||
offset++;
|
||||
if (offset >= len)
|
||||
if (offset >= len + 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1104,6 +1152,26 @@ static void hdmi_edid_parse_hvdb(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
|
||||
}
|
||||
|
||||
static void hdmi_edid_parse_colorimetry(
|
||||
struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf)
|
||||
{
|
||||
u8 len = 0;
|
||||
|
||||
if (!edid_ctrl) {
|
||||
DEV_ERR("%s: invalid input\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
len = in_buf[0] & 0x1F;
|
||||
if ((in_buf[1] != COLORIMETRY_DATA_BLOCK) || (len < 3)) {
|
||||
DEV_ERR("%s: Not a Colorimetry tag code\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
edid_ctrl->colorimetry.standards = in_buf[2];
|
||||
edid_ctrl->colorimetry.metadata_profiles = in_buf[3];
|
||||
}
|
||||
|
||||
static void hdmi_edid_extract_extended_data_blocks(
|
||||
struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf)
|
||||
{
|
||||
|
@ -1130,8 +1198,8 @@ static void hdmi_edid_extract_extended_data_blocks(
|
|||
break;
|
||||
}
|
||||
|
||||
/* The extended data block should at least be 2 bytes long */
|
||||
if (len < 2) {
|
||||
/* The extended data block should at least be 1 bytes long */
|
||||
if (len < 1) {
|
||||
DEV_DBG("%s: invalid block size\n", __func__);
|
||||
continue;
|
||||
}
|
||||
|
@ -1173,6 +1241,7 @@ static void hdmi_edid_extract_extended_data_blocks(
|
|||
case Y420_CAPABILITY_MAP_DATA_BLOCK:
|
||||
DEV_DBG("%s found Y420CMDB byte 3 = 0x%x",
|
||||
__func__, etag[2]);
|
||||
edid_ctrl->y420_cmdb_present = true;
|
||||
hdmi_edid_parse_Y420CMDB(edid_ctrl, etag);
|
||||
break;
|
||||
case Y420_VIDEO_DATA_BLOCK:
|
||||
|
@ -1186,6 +1255,11 @@ static void hdmi_edid_extract_extended_data_blocks(
|
|||
hdmi_edid_parse_hdrdb(edid_ctrl, etag);
|
||||
edid_ctrl->hdr_supported = true;
|
||||
break;
|
||||
case COLORIMETRY_DATA_BLOCK:
|
||||
DEV_DBG("%s found COLORIMETRY block. byte 3 = 0x%x",
|
||||
__func__, etag[2]);
|
||||
hdmi_edid_parse_colorimetry(edid_ctrl, etag);
|
||||
break;
|
||||
default:
|
||||
DEV_DBG("%s: Tag Code %d not supported\n",
|
||||
__func__, etag[1]);
|
||||
|
@ -1216,6 +1290,9 @@ static void hdmi_edid_extract_3d_present(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
}
|
||||
|
||||
offset = HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd);
|
||||
if (offset >= len - 1)
|
||||
return;
|
||||
|
||||
DEV_DBG("%s: EDID: 3D present @ 0x%x = %02x\n", __func__,
|
||||
offset, vsd[offset]);
|
||||
|
||||
|
@ -1331,7 +1408,10 @@ static void hdmi_edid_extract_sink_caps(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
return;
|
||||
|
||||
/* Max TMDS clock is in multiples of 5Mhz. */
|
||||
if (len >= 7 && vsd[7]) {
|
||||
edid_ctrl->sink_caps.max_pclk_in_hz = vsd[7] * 5000000;
|
||||
DEV_DBG("%s: MaxTMDS=%dMHz\n", __func__, (u32)vsd[7] * 5);
|
||||
}
|
||||
|
||||
vsd = hdmi_edid_find_hfvsdb(in_buf);
|
||||
|
||||
|
@ -1344,9 +1424,13 @@ static void hdmi_edid_extract_sink_caps(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
* the sink shall set this filed to 0. The max TMDS support
|
||||
* clock Rate = Max_TMDS_Character_Rates * 5Mhz.
|
||||
*/
|
||||
if (vsd[5] != 0)
|
||||
if (vsd[5] != 0) {
|
||||
edid_ctrl->sink_caps.max_pclk_in_hz =
|
||||
vsd[5] * 5000000;
|
||||
DEV_DBG("%s: HF-VSDB: MaxTMDS=%dMHz\n",
|
||||
__func__, (u32)vsd[5] * 5);
|
||||
}
|
||||
|
||||
edid_ctrl->sink_caps.scdc_present =
|
||||
(vsd[6] & 0x80) ? true : false;
|
||||
edid_ctrl->sink_caps.scramble_support =
|
||||
|
@ -1376,8 +1460,19 @@ static void hdmi_edid_extract_latency_fields(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
|
||||
VENDOR_SPECIFIC_DATA_BLOCK, &len);
|
||||
|
||||
if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE ||
|
||||
!(vsd[8] & BIT(7))) {
|
||||
if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) {
|
||||
DEV_DBG("%s: No/Invalid vendor Specific Data Block\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (len < 8) {
|
||||
DEV_DBG("%s: No extra Vendor Specific information present\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(vsd[8] & BIT(7))) {
|
||||
edid_ctrl->video_latency = (u16)-1;
|
||||
edid_ctrl->audio_latency = (u16)-1;
|
||||
DEV_DBG("%s: EDID: No audio/video latency present\n", __func__);
|
||||
|
@ -1410,8 +1505,8 @@ static u32 hdmi_edid_extract_ieee_reg_id(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
return 0;
|
||||
}
|
||||
|
||||
DEV_DBG("%s: EDID: VSD PhyAddr=%04x, MaxTMDS=%dMHz\n", __func__,
|
||||
((u32)vsd[4] << 8) + (u32)vsd[5], (u32)vsd[7] * 5);
|
||||
DEV_DBG("%s: EDID: VSD PhyAddr=%04x\n", __func__,
|
||||
((u32)vsd[4] << 8) + (u32)vsd[5]);
|
||||
|
||||
edid_ctrl->physical_address = ((u16)vsd[4] << 8) + (u16)vsd[5];
|
||||
|
||||
|
@ -1455,6 +1550,8 @@ static void hdmi_edid_extract_dc(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE)
|
||||
return;
|
||||
|
||||
edid_ctrl->deep_color = 0;
|
||||
if (len >= 6)
|
||||
edid_ctrl->deep_color = (vsd[6] >> 0x3) & 0xF;
|
||||
|
||||
vsd = hdmi_edid_find_hfvsdb(in_buf);
|
||||
|
@ -1650,7 +1747,12 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
timing.pixel_freq = pixel_clk;
|
||||
timing.refresh_rate = refresh_rate;
|
||||
timing.interlaced = interlaced;
|
||||
if (!interlaced)
|
||||
timing.supported = true;
|
||||
|
||||
if (refresh_rate > (MAX_REFRESH_RATE_SUPPORTED * khz_to_hz))
|
||||
timing.supported = false;
|
||||
|
||||
timing.ar = aspect_ratio_4_3 ? HDMI_RES_AR_4_3 :
|
||||
(aspect_ratio_5_4 ? HDMI_RES_AR_5_4 :
|
||||
HDMI_RES_AR_16_9);
|
||||
|
@ -1718,6 +1820,7 @@ static void hdmi_edid_add_sink_video_format(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
struct hdmi_edid_sink_data *sink_data = &edid_ctrl->sink_data;
|
||||
struct disp_mode_info *disp_mode_list = sink_data->disp_mode_list;
|
||||
u32 i = 0;
|
||||
bool y420_supported = false;
|
||||
|
||||
if (video_format >= HDMI_VFRMT_MAX) {
|
||||
DEV_ERR("%s: video format: %s is not supported\n", __func__,
|
||||
|
@ -1729,21 +1832,56 @@ static void hdmi_edid_add_sink_video_format(struct hdmi_edid_ctrl *edid_ctrl,
|
|||
video_format, msm_hdmi_mode_2string(video_format),
|
||||
supported ? "Supported" : "Not-Supported");
|
||||
|
||||
if (edid_ctrl->y420_cmdb_present && video_format < HDMI_VFRMT_END) {
|
||||
if (edid_ctrl->y420_cmdb_supports_all) {
|
||||
y420_supported = true;
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; i < edid_ctrl->y420_cmdb.len; i++) {
|
||||
if (video_format == edid_ctrl->y420_cmdb.vic_list[i]) {
|
||||
y420_supported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
/* override the default resolution */
|
||||
if (edid_ctrl->override_default_vic) {
|
||||
if (!ret && supported) {
|
||||
disp_mode_list[0].video_format = video_format;
|
||||
disp_mode_list[0].rgb_support = true;
|
||||
if (y420_supported)
|
||||
disp_mode_list[0].y420_support = true;
|
||||
edid_ctrl->override_default_vic = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < sink_data->num_of_elements; i++) {
|
||||
u32 vic = disp_mode_list[i].video_format;
|
||||
|
||||
if (vic == video_format) {
|
||||
DEV_DBG("%s: vic %d already added\n", __func__, vic);
|
||||
if (supported)
|
||||
disp_mode_list[i].rgb_support = true;
|
||||
if (y420_supported)
|
||||
disp_mode_list[i].y420_support = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret && supported) {
|
||||
if (!ret && (supported || y420_supported)) {
|
||||
/* todo: MHL */
|
||||
disp_mode_list[sink_data->num_of_elements].video_format =
|
||||
video_format;
|
||||
disp_mode_list[sink_data->num_of_elements].rgb_support =
|
||||
true;
|
||||
if (supported)
|
||||
disp_mode_list[sink_data->num_of_elements].
|
||||
rgb_support = true;
|
||||
if (y420_supported)
|
||||
disp_mode_list[sink_data->num_of_elements].
|
||||
y420_support = true;
|
||||
sink_data->num_of_elements++;
|
||||
}
|
||||
} /* hdmi_edid_add_sink_video_format */
|
||||
|
@ -1914,6 +2052,12 @@ static void hdmi_edid_get_extended_video_formats(
|
|||
return;
|
||||
}
|
||||
|
||||
if (db_len < 8) {
|
||||
DEV_DBG("%s: No extra Vendor Specific information present\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if HDMI_Video_present flag is set or not */
|
||||
if (!(vsd[8] & BIT(5))) {
|
||||
DEV_DBG("%s: extended vfmts are not supported by the sink.\n",
|
||||
|
@ -2289,6 +2433,9 @@ int hdmi_edid_parser(void *input)
|
|||
u16 ieee_reg_id;
|
||||
int status = 0;
|
||||
u32 i = 0;
|
||||
u32 cea_idx = 1;
|
||||
u32 sink_caps_pclk_khz = 0;
|
||||
u32 max_pclk_khz = 0;
|
||||
struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
|
||||
|
||||
if (!edid_ctrl) {
|
||||
|
@ -2315,7 +2462,7 @@ int hdmi_edid_parser(void *input)
|
|||
|
||||
/* EDID_CEA_EXTENSION_FLAG[0x7E] - CEC extension byte */
|
||||
num_of_cea_blocks = edid_buf[EDID_BLOCK_SIZE - 2];
|
||||
DEV_DBG("%s: No. of CEA blocks is [%u]\n", __func__,
|
||||
DEV_DBG("%s: No. of CEA/Extended EDID blocks is [%u]\n", __func__,
|
||||
num_of_cea_blocks);
|
||||
|
||||
/* Find out any CEA extension blocks following block 0 */
|
||||
|
@ -2334,30 +2481,42 @@ int hdmi_edid_parser(void *input)
|
|||
num_of_cea_blocks = MAX_EDID_BLOCKS - 1;
|
||||
}
|
||||
|
||||
if (edid_buf[EDID_BLOCK_SIZE] == 0xF0) {
|
||||
DEV_DBG("%s: Extended EDID Block Map found\n", __func__);
|
||||
edid_buf += EDID_BLOCK_SIZE;
|
||||
cea_idx++;
|
||||
}
|
||||
|
||||
for (i = cea_idx; i <= num_of_cea_blocks; i++) {
|
||||
|
||||
/* check for valid CEA block */
|
||||
if (edid_buf[EDID_BLOCK_SIZE] != 2) {
|
||||
DEV_ERR("%s: Invalid CEA block\n", __func__);
|
||||
num_of_cea_blocks = 0;
|
||||
goto bail;
|
||||
DEV_ERR("%s: Not a CEA block\n", __func__);
|
||||
edid_buf += EDID_BLOCK_SIZE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* goto to CEA extension edid block */
|
||||
edid_buf += EDID_BLOCK_SIZE;
|
||||
|
||||
ieee_reg_id = hdmi_edid_extract_ieee_reg_id(edid_ctrl, edid_buf);
|
||||
DEV_DBG("%s: ieee_reg_id = 0x%08x\n", __func__, ieee_reg_id);
|
||||
ieee_reg_id = hdmi_edid_extract_ieee_reg_id(edid_ctrl,
|
||||
edid_buf);
|
||||
DEV_DBG("%s: ieee_reg_id = 0x%06x\n", __func__, ieee_reg_id);
|
||||
if (ieee_reg_id == EDID_IEEE_REG_ID)
|
||||
edid_ctrl->sink_mode = SINK_MODE_HDMI;
|
||||
else
|
||||
edid_ctrl->sink_mode = SINK_MODE_DVI;
|
||||
|
||||
if (ieee_reg_id == EDID_IEEE_REG_ID) {
|
||||
hdmi_edid_extract_sink_caps(edid_ctrl, edid_buf);
|
||||
hdmi_edid_extract_latency_fields(edid_ctrl, edid_buf);
|
||||
hdmi_edid_extract_dc(edid_ctrl, edid_buf);
|
||||
hdmi_edid_extract_3d_present(edid_ctrl, edid_buf);
|
||||
}
|
||||
hdmi_edid_extract_speaker_allocation_data(edid_ctrl, edid_buf);
|
||||
hdmi_edid_extract_audio_data_blocks(edid_ctrl, edid_buf);
|
||||
hdmi_edid_extract_3d_present(edid_ctrl, edid_buf);
|
||||
hdmi_edid_extract_extended_data_blocks(edid_ctrl, edid_buf);
|
||||
}
|
||||
|
||||
bail:
|
||||
for (i = 1; i <= num_of_cea_blocks; i++) {
|
||||
|
@ -2369,6 +2528,13 @@ bail:
|
|||
|
||||
edid_ctrl->cea_blks = num_of_cea_blocks;
|
||||
|
||||
sink_caps_pclk_khz =
|
||||
hdmi_edid_get_sink_caps_max_tmds_clk(edid_ctrl) / 1000;
|
||||
max_pclk_khz = hdmi_edid_get_max_pclk(edid_ctrl);
|
||||
if (sink_caps_pclk_khz && max_pclk_khz)
|
||||
hdmi_edid_set_max_pclk_rate(edid_ctrl,
|
||||
min(max_pclk_khz, sink_caps_pclk_khz));
|
||||
|
||||
hdmi_edid_get_display_mode(edid_ctrl);
|
||||
|
||||
if (edid_ctrl->keep_resv_timings)
|
||||
|
@ -2561,6 +2727,18 @@ void hdmi_edid_get_hdr_data(void *input,
|
|||
*hdr_data = &edid_ctrl->hdr_data;
|
||||
}
|
||||
|
||||
u8 hdmi_edid_get_colorimetry(void *input)
|
||||
{
|
||||
struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
|
||||
|
||||
if (!edid_ctrl) {
|
||||
DEV_ERR("%s: invalid input\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return edid_ctrl->colorimetry.standards;
|
||||
}
|
||||
|
||||
bool hdmi_edid_is_s3d_mode_supported(void *input, u32 video_mode, u32 s3d_mode)
|
||||
{
|
||||
int i;
|
||||
|
@ -2687,6 +2865,7 @@ void hdmi_edid_set_video_resolution(void *input, u32 resolution, bool reset)
|
|||
edid_ctrl->sink_data.disp_mode_list[0].video_format =
|
||||
resolution;
|
||||
edid_ctrl->sink_data.disp_mode_list[0].rgb_support = true;
|
||||
edid_ctrl->override_default_vic = true;
|
||||
}
|
||||
} /* hdmi_edid_set_video_resolution */
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2010-2020, 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
|
||||
|
@ -20,6 +20,15 @@
|
|||
#define EDID_BLOCK_ADDR 0xA0
|
||||
#define MAX_EDID_BLOCKS 5
|
||||
|
||||
#define EDID_COLORIMETRY_xvYCC_601 (1 << 0)
|
||||
#define EDID_COLORIMETRY_xvYCC_709 (1 << 1)
|
||||
#define EDID_COLORIMETRY_sYCC_601 (1 << 2)
|
||||
#define EDID_COLORIMETRY_ADBYCC_601 (1 << 3)
|
||||
#define EDID_COLORIMETRY_ADB_RGB (1 << 4)
|
||||
#define EDID_COLORIMETRY_BT2020_CYCC (1 << 5)
|
||||
#define EDID_COLORIMETRY_BT2020_YCC (1 << 6)
|
||||
#define EDID_COLORIMETRY_BT2020_RGB (1 << 7)
|
||||
|
||||
struct hdmi_edid_init_data {
|
||||
struct kobject *kobj;
|
||||
struct hdmi_util_ds_data ds_data;
|
||||
|
@ -83,5 +92,6 @@ void hdmi_edid_config_override(void *input, bool enable,
|
|||
void hdmi_edid_set_max_pclk_rate(void *input, u32 max_pclk_khz);
|
||||
bool hdmi_edid_is_audio_supported(void *input);
|
||||
u32 hdmi_edid_get_sink_caps_max_tmds_clk(void *input);
|
||||
u8 hdmi_edid_get_colorimetry(void *input);
|
||||
|
||||
#endif /* __HDMI_EDID_H__ */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2015-2020, 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
|
||||
|
@ -393,31 +393,22 @@ exit:
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t hdmi_hdcp2p2_sysfs_wta_min_level_change(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
static void mdss_hdmi_hdcp2p2_min_level_change(void *client_ctx,
|
||||
int min_enc_level)
|
||||
{
|
||||
struct hdmi_hdcp2p2_ctrl *ctrl =
|
||||
hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_HDCP2P2);
|
||||
(struct hdmi_hdcp2p2_ctrl *)client_ctx;
|
||||
struct hdcp_lib_wakeup_data cdata = {
|
||||
HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE};
|
||||
bool enc_notify = true;
|
||||
enum hdcp_states enc_lvl;
|
||||
int min_enc_lvl;
|
||||
int rc;
|
||||
|
||||
if (!ctrl) {
|
||||
pr_err("invalid input\n");
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
return;
|
||||
}
|
||||
|
||||
rc = kstrtoint(buf, 10, &min_enc_lvl);
|
||||
if (rc) {
|
||||
DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
switch (min_enc_lvl) {
|
||||
switch (min_enc_level) {
|
||||
case 0:
|
||||
enc_lvl = HDCP_STATE_AUTH_ENC_NONE;
|
||||
break;
|
||||
|
@ -431,7 +422,7 @@ static ssize_t hdmi_hdcp2p2_sysfs_wta_min_level_change(struct device *dev,
|
|||
enc_notify = false;
|
||||
}
|
||||
|
||||
pr_debug("enc level changed %d\n", min_enc_lvl);
|
||||
pr_debug("enc level changed %d\n", min_enc_level);
|
||||
|
||||
cdata.context = ctrl->lib_ctx;
|
||||
hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
|
||||
|
@ -441,10 +432,6 @@ static ssize_t hdmi_hdcp2p2_sysfs_wta_min_level_change(struct device *dev,
|
|||
|
||||
if (enc_notify && ctrl->init_data.notify_status)
|
||||
ctrl->init_data.notify_status(ctrl->init_data.cb_data, enc_lvl);
|
||||
|
||||
rc = count;
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void hdmi_hdcp2p2_auth_failed(struct hdmi_hdcp2p2_ctrl *ctrl)
|
||||
|
@ -584,13 +571,10 @@ static int hdmi_hdcp2p2_read_version(struct hdmi_hdcp2p2_ctrl *ctrl,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(min_level_change, S_IWUSR, NULL,
|
||||
hdmi_hdcp2p2_sysfs_wta_min_level_change);
|
||||
static DEVICE_ATTR(tethered, S_IRUGO | S_IWUSR, hdmi_hdcp2p2_sysfs_rda_tethered,
|
||||
hdmi_hdcp2p2_sysfs_wta_tethered);
|
||||
|
||||
static struct attribute *hdmi_hdcp2p2_fs_attrs[] = {
|
||||
&dev_attr_min_level_change.attr,
|
||||
&dev_attr_tethered.attr,
|
||||
NULL,
|
||||
};
|
||||
|
@ -1030,6 +1014,7 @@ void *hdmi_hdcp2p2_init(struct hdcp_init_data *init_data)
|
|||
|
||||
static struct hdcp_client_ops client_ops = {
|
||||
.wakeup = hdmi_hdcp2p2_wakeup,
|
||||
.notify_lvl_change = mdss_hdmi_hdcp2p2_min_level_change,
|
||||
.srm_cb = hdmi_hdcp2p2_srm_cb,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2010-2020, 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
|
||||
|
@ -137,12 +137,36 @@ enum {
|
|||
DATA_BYTE_13,
|
||||
};
|
||||
|
||||
enum hdmi_colorimetry {
|
||||
HDMI_COLORIMETRY_DEFAULT,
|
||||
HDMI_COLORIMETRY_ITU_R_601,
|
||||
HDMI_COLORIMETRY_ITU_R_709,
|
||||
HDMI_COLORIMETRY_EXTENDED
|
||||
};
|
||||
|
||||
enum hdmi_ext_colorimetry {
|
||||
HDMI_COLORIMETRY_XV_YCC_601,
|
||||
HDMI_COLORIMETRY_XV_YCC_709,
|
||||
HDMI_COLORIMETRY_S_YCC_601,
|
||||
HDMI_COLORIMETRY_ADOBE_YCC_601,
|
||||
HDMI_COLORIMETRY_ADOBE_RGB,
|
||||
HDMI_COLORIMETRY_C_YCBCR_BT2020,
|
||||
HDMI_COLORIMETRY_YCBCR_BT2020,
|
||||
HDMI_COLORIMETRY_RESERVED
|
||||
|
||||
};
|
||||
|
||||
enum hdmi_quantization_range {
|
||||
HDMI_QUANTIZATION_DEFAULT,
|
||||
HDMI_QUANTIZATION_LIMITED_RANGE,
|
||||
HDMI_QUANTIZATION_FULL_RANGE
|
||||
};
|
||||
|
||||
enum hdmi_ycc_quantization_range {
|
||||
HDMI_YCC_QUANTIZATION_LIMITED_RANGE,
|
||||
HDMI_YCC_QUANTIZATION_FULL_RANGE
|
||||
};
|
||||
|
||||
enum hdmi_scaling_info {
|
||||
HDMI_SCALING_NONE,
|
||||
HDMI_SCALING_HORZ,
|
||||
|
@ -189,12 +213,29 @@ static int hdmi_panel_config_avi(struct hdmi_panel *panel)
|
|||
avi->bar_info.start_of_right_bar = timing->active_h + 1;
|
||||
|
||||
avi->act_fmt_info_present = true;
|
||||
avi->rgb_quantization_range = HDMI_QUANTIZATION_DEFAULT;
|
||||
avi->yuv_quantization_range = HDMI_QUANTIZATION_DEFAULT;
|
||||
if (pinfo->is_ce_mode) {
|
||||
avi->rgb_quantization_range =
|
||||
HDMI_QUANTIZATION_LIMITED_RANGE;
|
||||
avi->yuv_quantization_range =
|
||||
HDMI_YCC_QUANTIZATION_LIMITED_RANGE;
|
||||
} else {
|
||||
avi->rgb_quantization_range =
|
||||
HDMI_QUANTIZATION_FULL_RANGE;
|
||||
avi->yuv_quantization_range =
|
||||
HDMI_YCC_QUANTIZATION_FULL_RANGE;
|
||||
}
|
||||
|
||||
avi->scaling_info = HDMI_SCALING_NONE;
|
||||
|
||||
avi->colorimetry_info = 0;
|
||||
if (avi->pixel_format == MDP_Y_CBCR_H2V2) {
|
||||
if (pinfo->yres < 720)
|
||||
avi->colorimetry_info = HDMI_COLORIMETRY_ITU_R_601;
|
||||
else
|
||||
avi->colorimetry_info = HDMI_COLORIMETRY_ITU_R_709;
|
||||
} else {
|
||||
avi->colorimetry_info = HDMI_COLORIMETRY_DEFAULT;
|
||||
}
|
||||
|
||||
avi->ext_colorimetry_info = 0;
|
||||
|
||||
avi->pixel_rpt_factor = 0;
|
||||
|
@ -602,13 +643,29 @@ end:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static inline int get_bitdepth(enum hdmi_deep_color_depth bitdepth)
|
||||
{
|
||||
switch (bitdepth) {
|
||||
case HDMI_DEEP_COLOR_DEPTH_24BPP:
|
||||
return 24;
|
||||
case HDMI_DEEP_COLOR_DEPTH_30BPP:
|
||||
return 30;
|
||||
case HDMI_DEEP_COLOR_DEPTH_36BPP:
|
||||
return 36;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int hdmi_panel_setup_dc(struct hdmi_panel *panel)
|
||||
{
|
||||
u32 hdmi_ctrl_reg;
|
||||
u32 vbi_pkt_reg;
|
||||
int rc = 0;
|
||||
|
||||
pr_debug("Deep Color: %s\n", panel->data->dc_enable ? "ON" : "OFF");
|
||||
pr_debug("Deep Color: %s, bitdepth = %d\n",
|
||||
panel->data->dc_enable ? "ON" : "OFF",
|
||||
get_bitdepth(panel->data->bitdepth));
|
||||
|
||||
/* enable deep color if supported */
|
||||
if (panel->data->dc_enable) {
|
||||
|
@ -789,6 +846,53 @@ end:
|
|||
return panel->vic;
|
||||
}
|
||||
|
||||
static int hdmi_panel_avi_update_colorimetry(void *input,
|
||||
bool use_bt2020)
|
||||
{
|
||||
struct hdmi_panel *panel = input;
|
||||
struct mdss_panel_info *pinfo;
|
||||
struct hdmi_video_config *vid_cfg;
|
||||
struct hdmi_avi_infoframe_config *avi;
|
||||
int rc = 0;
|
||||
|
||||
if (!panel) {
|
||||
DEV_ERR("%s: invalid hdmi panel\n", __func__);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Configure AVI infoframe */
|
||||
rc = hdmi_panel_config_avi(panel);
|
||||
if (rc) {
|
||||
DEV_ERR("%s: failed to configure AVI\n", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
pinfo = panel->data->pinfo;
|
||||
vid_cfg = &panel->vid_cfg;
|
||||
avi = &vid_cfg->avi_iframe;
|
||||
|
||||
/* Update Colorimetry */
|
||||
avi->ext_colorimetry_info = 0;
|
||||
|
||||
if (use_bt2020) {
|
||||
avi->colorimetry_info = HDMI_COLORIMETRY_EXTENDED;
|
||||
avi->ext_colorimetry_info = HDMI_COLORIMETRY_YCBCR_BT2020;
|
||||
} else if (avi->pixel_format == MDP_Y_CBCR_H2V2) {
|
||||
if (pinfo->yres < 720)
|
||||
avi->colorimetry_info = HDMI_COLORIMETRY_ITU_R_601;
|
||||
else
|
||||
avi->colorimetry_info = HDMI_COLORIMETRY_ITU_R_709;
|
||||
} else {
|
||||
avi->colorimetry_info = HDMI_COLORIMETRY_DEFAULT;
|
||||
}
|
||||
|
||||
hdmi_panel_set_avi_infoframe(panel);
|
||||
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int hdmi_panel_power_on(void *input)
|
||||
{
|
||||
int rc = 0;
|
||||
|
@ -915,6 +1019,8 @@ void *hdmi_panel_init(struct hdmi_panel_init_data *data)
|
|||
data->ops->off = hdmi_panel_power_off;
|
||||
data->ops->vendor = hdmi_panel_set_vendor_specific_infoframe;
|
||||
data->ops->update_fps = hdmi_panel_update_fps;
|
||||
data->ops->update_colorimetry =
|
||||
hdmi_panel_avi_update_colorimetry;
|
||||
}
|
||||
end:
|
||||
return panel;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2016-2020, 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
|
||||
|
@ -16,6 +16,13 @@
|
|||
#include "mdss_panel.h"
|
||||
#include "mdss_hdmi_util.h"
|
||||
|
||||
enum hdmi_deep_color_depth {
|
||||
HDMI_DEEP_COLOR_DEPTH_24BPP,
|
||||
HDMI_DEEP_COLOR_DEPTH_30BPP,
|
||||
HDMI_DEEP_COLOR_DEPTH_36BPP,
|
||||
HDMI_DEEP_COLOR_DEPTH_RESERVED,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hdmi_panel_data - panel related data information
|
||||
*
|
||||
|
@ -29,6 +36,7 @@
|
|||
* @is_it_content: set to true if content is IT
|
||||
* @scrambler: set to true if scrambler needs to be enabled
|
||||
* @dc_enable: set to true if deep color is enabled
|
||||
* @bitdepth: set the output bitdepth like 24/30 bpp
|
||||
*/
|
||||
struct hdmi_panel_data {
|
||||
struct mdss_panel_info *pinfo;
|
||||
|
@ -41,6 +49,7 @@ struct hdmi_panel_data {
|
|||
bool is_it_content;
|
||||
bool scrambler;
|
||||
bool dc_enable;
|
||||
enum hdmi_deep_color_depth bitdepth;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -56,6 +65,7 @@ struct hdmi_panel_ops {
|
|||
int (*off)(void *input);
|
||||
void (*vendor)(void *input);
|
||||
int (*update_fps)(void *input, u32 fps);
|
||||
int (*update_colorimetry)(void *input, bool use_bt2020);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2010-2017, 2019, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2010-2020, 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
|
||||
|
@ -122,6 +122,11 @@ static int hdmi_tx_get_cable_status(struct platform_device *pdev, u32 vote);
|
|||
static int hdmi_tx_update_ppm(struct hdmi_tx_ctrl *hdmi_ctrl, s32 ppm);
|
||||
static int hdmi_tx_enable_pll_update(struct hdmi_tx_ctrl *hdmi_ctrl,
|
||||
int enable);
|
||||
static void hdmi_tx_hpd_polarity_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
|
||||
bool polarity);
|
||||
static int hdmi_tx_notify_events(struct hdmi_tx_ctrl *hdmi_ctrl, int val);
|
||||
static void hdmi_panel_update_colorimetry(struct hdmi_tx_ctrl *ctrl,
|
||||
bool use_bt2020);
|
||||
|
||||
static struct mdss_hw hdmi_tx_hw = {
|
||||
.hw_ndx = MDSS_HW_HDMI,
|
||||
|
@ -305,7 +310,7 @@ static inline bool hdmi_tx_metadata_type_one(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
return hdr_data->metadata_type_one;
|
||||
}
|
||||
|
||||
static inline bool hdmix_tx_sink_dc_support(struct hdmi_tx_ctrl *hdmi_ctrl)
|
||||
static inline bool hdmi_tx_sink_dc_support(struct hdmi_tx_ctrl *hdmi_ctrl)
|
||||
{
|
||||
void *edid_fd = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID);
|
||||
|
||||
|
@ -325,8 +330,7 @@ static inline bool hdmi_tx_dc_support(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
true);
|
||||
|
||||
return hdmi_ctrl->dc_feature_on &&
|
||||
hdmi_ctrl->dc_support &&
|
||||
hdmix_tx_sink_dc_support(hdmi_ctrl) &&
|
||||
hdmi_tx_sink_dc_support(hdmi_ctrl) &&
|
||||
(tmds_clk_with_dc <= hdmi_edid_get_max_pclk(edid_fd));
|
||||
}
|
||||
|
||||
|
@ -429,9 +433,17 @@ static inline void hdmi_tx_send_audio_notification(
|
|||
}
|
||||
}
|
||||
|
||||
static inline void hdmi_tx_send_video_notification(
|
||||
static inline int hdmi_tx_send_video_notification(
|
||||
struct hdmi_tx_ctrl *hdmi_ctrl, int val, bool async)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!hdmi_ctrl) {
|
||||
pr_err("invalid hdmi_ctrl input\n");
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (hdmi_ctrl && hdmi_ctrl->ext_audio_data.intf_ops.hpd) {
|
||||
u32 flags = 0;
|
||||
|
||||
|
@ -440,9 +452,13 @@ static inline void hdmi_tx_send_video_notification(
|
|||
else
|
||||
flags |= MSM_EXT_DISP_HPD_VIDEO;
|
||||
|
||||
hdmi_ctrl->ext_audio_data.intf_ops.hpd(hdmi_ctrl->ext_pdev,
|
||||
hdmi_ctrl->ext_audio_data.type, val, flags);
|
||||
ret = hdmi_ctrl->ext_audio_data.intf_ops.hpd(
|
||||
hdmi_ctrl->ext_pdev,
|
||||
hdmi_ctrl->ext_audio_data.type,
|
||||
val, flags);
|
||||
}
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void hdmi_tx_ack_state(
|
||||
|
@ -548,8 +564,8 @@ static ssize_t hdmi_tx_sysfs_rda_connected(struct device *dev,
|
|||
}
|
||||
|
||||
mutex_lock(&hdmi_ctrl->tx_lock);
|
||||
ret = snprintf(buf, PAGE_SIZE, "%d\n", hdmi_ctrl->hpd_state);
|
||||
DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_state);
|
||||
ret = snprintf(buf, PAGE_SIZE, "%d\n", hdmi_ctrl->notification_status);
|
||||
DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->notification_status);
|
||||
mutex_unlock(&hdmi_ctrl->tx_lock);
|
||||
|
||||
return ret;
|
||||
|
@ -883,8 +899,7 @@ static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev,
|
|||
* No need to blocking wait for display/audio in this
|
||||
* case since HAL is not up so no ACK can be expected.
|
||||
*/
|
||||
hdmi_tx_send_audio_notification(hdmi_ctrl, 0);
|
||||
hdmi_tx_send_video_notification(hdmi_ctrl, 0, true);
|
||||
hdmi_tx_notify_events(hdmi_ctrl, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -1329,9 +1344,13 @@ static ssize_t hdmi_tx_sysfs_wta_hdr_stream(struct device *dev,
|
|||
hdr_op = hdmi_hdr_get_ops(ctrl->curr_hdr_state,
|
||||
ctrl->hdr_ctrl.hdr_state);
|
||||
|
||||
if (hdr_op == HDR_SEND_INFO)
|
||||
if (hdr_op == HDR_SEND_INFO) {
|
||||
hdmi_panel_set_hdr_infoframe(ctrl);
|
||||
else if (hdr_op == HDR_CLEAR_INFO)
|
||||
if (ctrl->hdr_ctrl.hdr_stream.eotf)
|
||||
hdmi_panel_update_colorimetry(ctrl, true);
|
||||
else
|
||||
hdmi_panel_update_colorimetry(ctrl, false);
|
||||
} else if (hdr_op == HDR_CLEAR_INFO)
|
||||
hdmi_panel_clear_hdr_infoframe(ctrl);
|
||||
|
||||
ctrl->curr_hdr_state = ctrl->hdr_ctrl.hdr_state;
|
||||
|
@ -1848,7 +1867,6 @@ static int hdmi_tx_read_edid(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
}
|
||||
} while ((cea_blks-- > 0) && (block++ < MAX_EDID_BLOCKS));
|
||||
end:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2429,11 +2447,60 @@ static void hdmi_tx_update_hdr_info(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
}
|
||||
}
|
||||
|
||||
static int hdmi_tx_notify_events(struct hdmi_tx_ctrl *hdmi_ctrl, int val)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (val == hdmi_ctrl->notification_status) {
|
||||
pr_debug("%s: No change in notification status %d -> %d\n",
|
||||
__func__, hdmi_ctrl->notification_status, val);
|
||||
goto end;
|
||||
}
|
||||
|
||||
reinit_completion(&hdmi_ctrl->notification_comp);
|
||||
if (atomic_read(&hdmi_ctrl->notification_pending)) {
|
||||
pr_debug("%s: wait for previous event to finish\n", __func__);
|
||||
rc = wait_for_completion_timeout(
|
||||
&hdmi_ctrl->notification_comp, HZ);
|
||||
if (rc <= 0) {
|
||||
pr_debug("%s: wait for pending notification timed out\n",
|
||||
__func__);
|
||||
hdmi_ctrl->pending_event = val;
|
||||
hdmi_ctrl->handle_pe = true;
|
||||
rc = -ETIMEDOUT;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
hdmi_ctrl->notification_status = val;
|
||||
atomic_set(&hdmi_ctrl->notification_pending, 1);
|
||||
|
||||
if (val) {
|
||||
rc = hdmi_tx_send_video_notification(hdmi_ctrl, val, true);
|
||||
} else {
|
||||
hdmi_tx_send_audio_notification(hdmi_ctrl, val);
|
||||
rc = hdmi_tx_send_video_notification(hdmi_ctrl, val, true);
|
||||
}
|
||||
|
||||
if (!rc) {
|
||||
pr_debug("%s: Successfully sent %s notification\n", __func__,
|
||||
val ? "CONNECT" : "DISCONNECT");
|
||||
} else {
|
||||
pr_err("%s: %s notification failed\n", __func__,
|
||||
val ? "CONNECT" : "DISCONNECT");
|
||||
atomic_set(&hdmi_ctrl->notification_pending, 0);
|
||||
}
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void hdmi_tx_hpd_int_work(struct work_struct *work)
|
||||
{
|
||||
struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
|
||||
int rc = -EINVAL;
|
||||
int retry = MAX_EDID_READ_RETRY;
|
||||
unsigned long flags;
|
||||
u32 hpd_state;
|
||||
|
||||
hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, hpd_int_work);
|
||||
if (!hdmi_ctrl) {
|
||||
|
@ -2441,36 +2508,39 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work)
|
|||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&hdmi_ctrl->tx_lock);
|
||||
|
||||
if (!hdmi_ctrl->hpd_initialized) {
|
||||
DEV_DBG("hpd not initialized\n");
|
||||
mutex_unlock(&hdmi_ctrl->tx_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
DEV_DBG("%s: %s\n", __func__,
|
||||
hdmi_ctrl->hpd_state ? "CONNECT" : "DISCONNECT");
|
||||
spin_lock_irqsave(&hdmi_ctrl->hpd_state_lock, flags);
|
||||
hpd_state = hdmi_ctrl->hpd_state;
|
||||
spin_unlock_irqrestore(&hdmi_ctrl->hpd_state_lock, flags);
|
||||
|
||||
DEV_DBG("%s: %s\n", __func__,
|
||||
hpd_state ? "CONNECT" : "DISCONNECT");
|
||||
|
||||
if (hpd_state) {
|
||||
hdmi_tx_hpd_polarity_setup(hdmi_ctrl,
|
||||
HPD_DISCONNECT_POLARITY);
|
||||
|
||||
if (hdmi_ctrl->hpd_state) {
|
||||
while (rc && retry--)
|
||||
rc = hdmi_tx_read_sink_info(hdmi_ctrl);
|
||||
if (!retry && rc)
|
||||
pr_warn_ratelimited("%s: EDID read failed\n", __func__);
|
||||
hdmi_tx_update_deep_color(hdmi_ctrl);
|
||||
hdmi_tx_update_hdr_info(hdmi_ctrl);
|
||||
|
||||
hdmi_tx_notify_events(hdmi_ctrl, hpd_state);
|
||||
|
||||
} else {
|
||||
rc = hdmi_tx_notify_events(hdmi_ctrl, hpd_state);
|
||||
|
||||
if (!rc && !hdmi_ctrl->panel_power_on) {
|
||||
atomic_set(&hdmi_ctrl->notification_pending, 0);
|
||||
hdmi_tx_hpd_polarity_setup(hdmi_ctrl,
|
||||
HPD_CONNECT_POLARITY);
|
||||
}
|
||||
|
||||
mutex_unlock(&hdmi_ctrl->tx_lock);
|
||||
|
||||
if (hdmi_ctrl->hpd_state)
|
||||
hdmi_tx_send_video_notification(hdmi_ctrl,
|
||||
hdmi_ctrl->hpd_state, true);
|
||||
else {
|
||||
hdmi_tx_send_audio_notification(hdmi_ctrl,
|
||||
hdmi_ctrl->hpd_state);
|
||||
hdmi_tx_send_video_notification(hdmi_ctrl,
|
||||
hdmi_ctrl->hpd_state, true);
|
||||
}
|
||||
} /* hdmi_tx_hpd_int_work */
|
||||
|
||||
|
@ -3065,6 +3135,34 @@ static void hdmi_panel_clear_hdr_infoframe(struct hdmi_tx_ctrl *ctrl)
|
|||
DSS_REG_W(io, HDMI_GEN_PKT_CTRL, packet_control);
|
||||
}
|
||||
|
||||
static void hdmi_panel_update_colorimetry(struct hdmi_tx_ctrl *hdmi_ctrl,
|
||||
bool use_bt2020)
|
||||
{
|
||||
void *pdata;
|
||||
|
||||
if (!hdmi_ctrl) {
|
||||
DEV_ERR("%s: invalid hdmi ctrl data\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL);
|
||||
if (!pdata) {
|
||||
DEV_ERR("%s: invalid panel data\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If there is no change in colorimetry, just return */
|
||||
if (use_bt2020 && hdmi_ctrl->use_bt2020)
|
||||
return;
|
||||
else if (!use_bt2020 && !hdmi_ctrl->use_bt2020)
|
||||
return;
|
||||
|
||||
if (hdmi_ctrl->panel_ops.update_colorimetry)
|
||||
hdmi_ctrl->panel_ops.update_colorimetry(pdata, use_bt2020);
|
||||
|
||||
hdmi_ctrl->use_bt2020 = use_bt2020;
|
||||
}
|
||||
|
||||
static int hdmi_tx_audio_info_setup(struct platform_device *pdev,
|
||||
struct msm_ext_disp_audio_setup_params *params)
|
||||
{
|
||||
|
@ -3289,7 +3387,7 @@ static int hdmi_tx_power_off(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
hdmi_tx_core_off(hdmi_ctrl);
|
||||
|
||||
hdmi_ctrl->panel_power_on = false;
|
||||
hdmi_ctrl->dc_support = false;
|
||||
hdmi_ctrl->vic = 0;
|
||||
|
||||
if (hdmi_ctrl->hpd_off_pending || hdmi_ctrl->panel_suspend)
|
||||
hdmi_tx_hpd_off(hdmi_ctrl);
|
||||
|
@ -3337,6 +3435,10 @@ static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
hdmi_ctrl->panel.scrambler = hdmi_edid_get_sink_scrambler_support(
|
||||
edata);
|
||||
hdmi_ctrl->panel.dc_enable = hdmi_tx_dc_support(hdmi_ctrl);
|
||||
if (hdmi_ctrl->panel.dc_enable)
|
||||
hdmi_ctrl->panel.bitdepth = HDMI_DEEP_COLOR_DEPTH_30BPP;
|
||||
else
|
||||
hdmi_ctrl->panel.bitdepth = HDMI_DEEP_COLOR_DEPTH_24BPP;
|
||||
|
||||
if (hdmi_ctrl->panel_ops.on)
|
||||
hdmi_ctrl->panel_ops.on(pdata);
|
||||
|
@ -3362,8 +3464,6 @@ static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
|
||||
hdmi_ctrl->panel_power_on = true;
|
||||
|
||||
hdmi_tx_hpd_polarity_setup(hdmi_ctrl, HPD_DISCONNECT_POLARITY);
|
||||
|
||||
if (hdmi_ctrl->hdmi_tx_hpd_done)
|
||||
hdmi_ctrl->hdmi_tx_hpd_done(hdmi_ctrl->downstream_data);
|
||||
|
||||
|
@ -3415,6 +3515,7 @@ static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
|
||||
hdmi_ctrl->hpd_initialized = false;
|
||||
hdmi_ctrl->hpd_off_pending = false;
|
||||
hdmi_ctrl->dc_support = false;
|
||||
|
||||
DEV_DBG("%s: HPD is now OFF\n", __func__);
|
||||
} /* hdmi_tx_hpd_off */
|
||||
|
@ -3473,6 +3574,7 @@ static int hdmi_tx_hpd_on(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
/* Turn on HPD HW circuit */
|
||||
DSS_REG_W(io, HDMI_HPD_CTRL, reg_val | BIT(28));
|
||||
|
||||
atomic_set(&hdmi_ctrl->notification_pending, 0);
|
||||
hdmi_tx_hpd_polarity_setup(hdmi_ctrl, HPD_CONNECT_POLARITY);
|
||||
DEV_DBG("%s: HPD is now ON\n", __func__);
|
||||
}
|
||||
|
@ -3697,6 +3799,11 @@ static int hdmi_tx_dev_init(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
|
||||
spin_lock_init(&hdmi_ctrl->hpd_state_lock);
|
||||
|
||||
hdmi_ctrl->pending_event = 0;
|
||||
hdmi_ctrl->handle_pe = false;
|
||||
atomic_set(&hdmi_ctrl->notification_pending, 0);
|
||||
init_completion(&hdmi_ctrl->notification_comp);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_create_workq:
|
||||
|
@ -3972,9 +4079,11 @@ sysfs_err:
|
|||
|
||||
static int hdmi_tx_evt_handle_check_param(struct hdmi_tx_ctrl *hdmi_ctrl)
|
||||
{
|
||||
struct mdss_panel_info *pinfo = &hdmi_ctrl->panel_data.panel_info;
|
||||
int new_vic = -1;
|
||||
int rc = 0;
|
||||
|
||||
pinfo->is_ce_mode = false;
|
||||
new_vic = hdmi_panel_get_vic(hdmi_ctrl->evt_arg, &hdmi_ctrl->ds_data);
|
||||
|
||||
if ((new_vic < 0) || (new_vic > HDMI_VFRMT_MAX)) {
|
||||
|
@ -3991,7 +4100,20 @@ static int hdmi_tx_evt_handle_check_param(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
rc = 1;
|
||||
DEV_DBG("%s: res change %d ==> %d\n", __func__,
|
||||
hdmi_ctrl->vic, new_vic);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since bootloader doesn't support DC return 1
|
||||
* for panel reconfig.
|
||||
*/
|
||||
if (hdmi_ctrl->panel_data.panel_info.cont_splash_enabled
|
||||
&& hdmi_tx_dc_support(hdmi_ctrl)) {
|
||||
rc = 1;
|
||||
DEV_DBG("%s: Bitdepth changed\n", __func__);
|
||||
}
|
||||
done:
|
||||
pinfo->is_ce_mode = hdmi_util_is_ce_mode(new_vic);
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
@ -4012,6 +4134,9 @@ static int hdmi_tx_evt_handle_resume(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
goto end;
|
||||
}
|
||||
|
||||
if (hdmi_tx_is_cec_wakeup_en(hdmi_ctrl))
|
||||
hdmi_ctrl->mdss_util->disable_wake_irq(&hdmi_tx_hw);
|
||||
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
@ -4070,6 +4195,9 @@ static int hdmi_tx_evt_handle_suspend(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
if (!hdmi_ctrl->hpd_state && !hdmi_ctrl->panel_power_on)
|
||||
hdmi_tx_hpd_off(hdmi_ctrl);
|
||||
|
||||
if (hdmi_tx_is_cec_wakeup_en(hdmi_ctrl))
|
||||
hdmi_ctrl->mdss_util->enable_wake_irq(&hdmi_tx_hw);
|
||||
|
||||
hdmi_ctrl->panel_suspend = true;
|
||||
hdmi_tx_cec_device_suspend(hdmi_ctrl);
|
||||
end:
|
||||
|
@ -4113,8 +4241,12 @@ end:
|
|||
static int hdmi_tx_evt_handle_close(struct hdmi_tx_ctrl *hdmi_ctrl)
|
||||
{
|
||||
if (hdmi_ctrl->hpd_feature_on && hdmi_ctrl->hpd_initialized &&
|
||||
!hdmi_ctrl->hpd_state)
|
||||
!hdmi_ctrl->notification_status) {
|
||||
atomic_set(&hdmi_ctrl->notification_pending, 0);
|
||||
complete_all(&hdmi_ctrl->notification_comp);
|
||||
|
||||
hdmi_tx_hpd_polarity_setup(hdmi_ctrl, HPD_CONNECT_POLARITY);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -4166,6 +4298,15 @@ static int hdmi_tx_post_evt_handle_unblank(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
{
|
||||
hdmi_tx_ack_state(hdmi_ctrl, true);
|
||||
hdmi_tx_send_audio_notification(hdmi_ctrl, true);
|
||||
|
||||
atomic_set(&hdmi_ctrl->notification_pending, 0);
|
||||
complete_all(&hdmi_ctrl->notification_comp);
|
||||
|
||||
if (hdmi_ctrl->handle_pe) {
|
||||
hdmi_ctrl->handle_pe = false;
|
||||
hdmi_tx_notify_events(hdmi_ctrl, hdmi_ctrl->pending_event);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -4182,8 +4323,7 @@ static int hdmi_tx_post_evt_handle_resume(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
&hdmi_ctrl->hpd_int_done, HZ/10);
|
||||
if (!timeout) {
|
||||
pr_debug("cable removed during suspend\n");
|
||||
hdmi_tx_send_audio_notification(hdmi_ctrl, 0);
|
||||
hdmi_tx_send_video_notification(hdmi_ctrl, 0, true);
|
||||
hdmi_tx_notify_events(hdmi_ctrl, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4194,8 +4334,7 @@ static int hdmi_tx_post_evt_handle_panel_on(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
{
|
||||
if (hdmi_ctrl->panel_suspend) {
|
||||
pr_debug("panel suspend has triggered\n");
|
||||
hdmi_tx_send_audio_notification(hdmi_ctrl, 0);
|
||||
hdmi_tx_send_video_notification(hdmi_ctrl, 0, true);
|
||||
hdmi_tx_notify_events(hdmi_ctrl, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -4259,6 +4398,38 @@ static int hdmi_tx_event_handler(struct mdss_panel_data *panel_data,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static enum mdss_mdp_csc_type mdss_hdmi_get_csc_type(
|
||||
struct mdss_panel_data *panel_data)
|
||||
{
|
||||
struct mdss_panel_info *pinfo;
|
||||
struct mdp_hdr_stream_ctrl *hdr_ctrl;
|
||||
struct mdp_hdr_stream *hdr_data;
|
||||
enum mdss_mdp_csc_type csc_type = MDSS_MDP_CSC_RGB2YUV_709L;
|
||||
|
||||
struct hdmi_tx_ctrl *hdmi_ctrl =
|
||||
hdmi_tx_get_drvdata_from_panel_data(panel_data);
|
||||
|
||||
if (!hdmi_ctrl) {
|
||||
DEV_ERR("%s: invalid hdmi ctrl data\n", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
pinfo = &hdmi_ctrl->panel_data.panel_info;
|
||||
hdr_ctrl = &hdmi_ctrl->hdr_ctrl;
|
||||
hdr_data = &hdr_ctrl->hdr_stream;
|
||||
|
||||
if ((hdr_ctrl->hdr_state == HDR_ENABLE) &&
|
||||
(hdr_data->eotf != 0))
|
||||
csc_type = MDSS_MDP_CSC_RGB2YUV_2020L;
|
||||
else if (pinfo->is_ce_mode)
|
||||
csc_type = MDSS_MDP_CSC_RGB2YUV_709L;
|
||||
else
|
||||
csc_type = MDSS_MDP_CSC_RGB2YUV_709FR;
|
||||
|
||||
error:
|
||||
return csc_type;
|
||||
}
|
||||
|
||||
static int hdmi_tx_register_panel(struct hdmi_tx_ctrl *hdmi_ctrl)
|
||||
{
|
||||
int rc = 0;
|
||||
|
@ -4269,6 +4440,7 @@ static int hdmi_tx_register_panel(struct hdmi_tx_ctrl *hdmi_ctrl)
|
|||
}
|
||||
|
||||
hdmi_ctrl->panel_data.event_handler = hdmi_tx_event_handler;
|
||||
hdmi_ctrl->panel_data.get_csc_type = mdss_hdmi_get_csc_type;
|
||||
|
||||
if (!hdmi_ctrl->pdata.primary)
|
||||
hdmi_ctrl->vic = DEFAULT_VIDEO_RESOLUTION;
|
||||
|
@ -5005,6 +5177,7 @@ static int hdmi_tx_probe(struct platform_device *pdev)
|
|||
hdmi_ctrl->pdata.primary = true;
|
||||
hdmi_ctrl->vic = vic;
|
||||
hdmi_ctrl->panel_data.panel_info.is_prim_panel = true;
|
||||
hdmi_ctrl->panel_data.panel_info.is_ce_mode = true;
|
||||
hdmi_ctrl->panel_data.panel_info.cont_splash_enabled =
|
||||
hdmi_ctrl->mdss_util->panel_intf_status(DISPLAY_1,
|
||||
MDSS_PANEL_INTF_HDMI) ? true : false;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2010-2020, 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
|
||||
|
@ -93,6 +93,12 @@ struct hdmi_tx_ctrl {
|
|||
struct work_struct fps_work;
|
||||
struct mdp_hdr_stream_ctrl hdr_ctrl;
|
||||
|
||||
int pending_event;
|
||||
bool handle_pe;
|
||||
atomic_t notification_pending;
|
||||
struct completion notification_comp;
|
||||
u32 notification_status;
|
||||
|
||||
spinlock_t hpd_state_lock;
|
||||
|
||||
u32 panel_power_on;
|
||||
|
@ -132,6 +138,7 @@ struct hdmi_tx_ctrl {
|
|||
bool power_data_enable[HDMI_TX_MAX_PM];
|
||||
bool dc_support;
|
||||
bool dc_feature_on;
|
||||
bool use_bt2020;
|
||||
|
||||
void (*hdmi_tx_hpd_done)(void *data);
|
||||
void *downstream_data;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2010-2017, 2019, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2010-2020, 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
|
||||
|
@ -566,6 +566,67 @@ int msm_hdmi_get_timing_info(
|
|||
return ret;
|
||||
}
|
||||
|
||||
static u32 cea_mode_alternate_clock(struct msm_hdmi_mode_timing_info *info)
|
||||
{
|
||||
u32 clock = info->pixel_freq;
|
||||
|
||||
if (info->refresh_rate % 6 != 0)
|
||||
return clock;
|
||||
|
||||
clock = DIV_ROUND_CLOSEST(clock * 1000, 1001);
|
||||
|
||||
return clock;
|
||||
}
|
||||
|
||||
bool hdmi_util_is_ce_mode(u32 vic)
|
||||
{
|
||||
struct msm_hdmi_mode_timing_info info1 = {0};
|
||||
struct msm_hdmi_mode_timing_info info2 = {0};
|
||||
u32 mode = 0;
|
||||
u32 clock1, clock2, clock2_alt;
|
||||
bool is_ce_mode = false;
|
||||
|
||||
if (vic <= HDMI_VFRMT_640x480p60_4_3) {
|
||||
is_ce_mode = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (vic >= HDMI_VFRMT_720x480p60_4_3 &&
|
||||
vic <= HDMI_VFRMT_3840x2160p60_64_27) {
|
||||
is_ce_mode = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
msm_hdmi_get_timing_info(&info1, vic);
|
||||
|
||||
for (mode = HDMI_VFRMT_720x480p60_4_3; mode < HDMI_VFRMT_END; mode++) {
|
||||
|
||||
msm_hdmi_get_timing_info(&info2, mode);
|
||||
|
||||
clock1 = info1.pixel_freq;
|
||||
clock2 = info2.pixel_freq;
|
||||
clock2_alt = cea_mode_alternate_clock(&info2);
|
||||
|
||||
if ((clock1 == clock2) || (clock1 == clock2_alt)) {
|
||||
if (info1.active_h == info2.active_h &&
|
||||
info1.front_porch_h == info2.front_porch_h &&
|
||||
info1.pulse_width_h == info2.pulse_width_h &&
|
||||
info1.back_porch_h == info2.back_porch_h &&
|
||||
info1.active_v == info2.active_v &&
|
||||
info1.front_porch_v == info2.front_porch_v &&
|
||||
info1.pulse_width_v == info2.pulse_width_v &&
|
||||
info1.back_porch_v == info2.back_porch_v) {
|
||||
is_ce_mode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
end:
|
||||
pr_debug("%s: vic = %d, is_ce_mode = %d\n", __func__, vic, is_ce_mode);
|
||||
return is_ce_mode;
|
||||
}
|
||||
|
||||
int hdmi_get_supported_mode(struct msm_hdmi_mode_timing_info *info,
|
||||
struct hdmi_util_ds_data *ds_data, u32 mode)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2010-2020, 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
|
||||
|
@ -490,6 +490,7 @@ static inline int hdmi_tx_get_h_total(const struct msm_hdmi_mode_timing_info *t)
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool hdmi_util_is_ce_mode(u32 vic);
|
||||
/* video timing related utility routines */
|
||||
int hdmi_get_video_id_code(struct msm_hdmi_mode_timing_info *timing_in,
|
||||
struct hdmi_util_ds_data *ds_data);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* MDSS MDP Interface (used by framebuffer core)
|
||||
*
|
||||
* Copyright (c) 2007-2018, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2007-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2007 Google Incorporated
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
|
@ -3117,7 +3117,8 @@ static int mdss_mdp_probe(struct platform_device *pdev)
|
|||
MDSS_MDP_REG_SPLIT_DISPLAY_EN);
|
||||
if (intf_sel != 0) {
|
||||
for (i = 0; i < 4; i++)
|
||||
num_of_display_on += ((intf_sel >> i*8) & 0x000000FF);
|
||||
num_of_display_on +=
|
||||
(((intf_sel >> i*8) & 0x000000FF) ? 1 : 0);
|
||||
|
||||
/*
|
||||
* For split display enabled - DSI0, DSI1 interfaces are
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2012-2020, 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
|
||||
|
@ -271,10 +271,12 @@ enum mdss_mdp_csc_type {
|
|||
MDSS_MDP_CSC_RGB2YUV_601L,
|
||||
MDSS_MDP_CSC_RGB2YUV_601FR,
|
||||
MDSS_MDP_CSC_RGB2YUV_709L,
|
||||
MDSS_MDP_CSC_RGB2YUV_709FR,
|
||||
MDSS_MDP_CSC_RGB2YUV_2020L,
|
||||
MDSS_MDP_CSC_RGB2YUV_2020FR,
|
||||
MDSS_MDP_CSC_YUV2YUV,
|
||||
MDSS_MDP_CSC_RGB2RGB,
|
||||
MDSS_MDP_CSC_RGB2RGB_L,
|
||||
MDSS_MDP_MAX_CSC
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2014-2020, 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
|
||||
|
@ -116,6 +116,7 @@ struct mdss_mdp_cdm *mdss_mdp_cdm_init(struct mdss_mdp_ctl *ctl, u32 intf_type)
|
|||
|
||||
cdm->out_intf = intf_type;
|
||||
cdm->is_bypassed = true;
|
||||
cdm->is_only_clamped = false;
|
||||
memset(&cdm->setup, 0x0, sizeof(struct mdp_cdm_cfg));
|
||||
|
||||
return cdm;
|
||||
|
@ -137,11 +138,22 @@ static int mdss_mdp_cdm_csc_setup(struct mdss_mdp_cdm *cdm,
|
|||
|
||||
if ((data->csc_type == MDSS_MDP_CSC_RGB2YUV_601L) ||
|
||||
(data->csc_type == MDSS_MDP_CSC_RGB2YUV_601FR) ||
|
||||
(data->csc_type == MDSS_MDP_CSC_RGB2YUV_709L)) {
|
||||
(data->csc_type == MDSS_MDP_CSC_RGB2YUV_709L) ||
|
||||
(data->csc_type == MDSS_MDP_CSC_RGB2YUV_709FR) ||
|
||||
(data->csc_type == MDSS_MDP_CSC_RGB2YUV_2020L) ||
|
||||
(data->csc_type == MDSS_MDP_CSC_RGB2YUV_2020FR)) {
|
||||
op_mode |= BIT(2); /* DST_DATA_FORMAT = YUV */
|
||||
op_mode &= ~BIT(1); /* SRC_DATA_FORMAT = RGB */
|
||||
op_mode |= BIT(0); /* EN = 1 */
|
||||
cdm->is_bypassed = false;
|
||||
} else if ((cdm->out_intf == MDP_CDM_CDWN_OUTPUT_HDMI) &&
|
||||
((data->csc_type == MDSS_MDP_CSC_RGB2RGB_L) ||
|
||||
(data->csc_type == MDSS_MDP_CSC_RGB2RGB))) {
|
||||
op_mode &= ~BIT(2); /* DST_DATA_FORMAT = RGB */
|
||||
op_mode &= ~BIT(1); /* SRC_DATA_FORMAT = RGB */
|
||||
op_mode |= BIT(0); /* EN = 1 */
|
||||
cdm->is_bypassed = false;
|
||||
cdm->is_only_clamped = true;
|
||||
} else {
|
||||
op_mode = 0;
|
||||
cdm->is_bypassed = true;
|
||||
|
@ -299,8 +311,11 @@ static int mdss_mdp_cdm_out_packer_setup(struct mdss_mdp_cdm *cdm,
|
|||
}
|
||||
opmode &= ~0x6;
|
||||
opmode |= (fmt->chroma_sample << 1);
|
||||
if (!cdm->is_bypassed)
|
||||
if (!cdm->is_bypassed) {
|
||||
cdm_enable |= BIT(19);
|
||||
if (cdm->is_only_clamped)
|
||||
opmode = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Disable HDMI pacler for WB */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014,2016, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2014-2020, 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
|
||||
|
@ -60,6 +60,7 @@ struct mdss_mdp_cdm {
|
|||
bool is_bypassed;
|
||||
struct mdp_cdm_cfg setup;
|
||||
struct completion free_comp;
|
||||
bool is_only_clamped;
|
||||
};
|
||||
|
||||
struct mdss_mdp_cdm *mdss_mdp_cdm_init(struct mdss_mdp_ctl *ctl,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2012-2020, 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
|
||||
|
@ -103,6 +103,9 @@ struct mdss_mdp_video_ctx {
|
|||
u32 intf_irq_mask;
|
||||
spinlock_t mdss_mdp_video_lock;
|
||||
spinlock_t mdss_mdp_intf_intr_lock;
|
||||
|
||||
enum mdss_mdp_csc_type cdm_csc_type;
|
||||
bool yuv_conv;
|
||||
};
|
||||
|
||||
static void mdss_mdp_fetch_start_config(struct mdss_mdp_video_ctx *ctx,
|
||||
|
@ -1023,6 +1026,8 @@ static int mdss_mdp_video_ctx_stop(struct mdss_mdp_ctl *ctl,
|
|||
mdss_mdp_set_intf_intr_callback(ctx, MDSS_MDP_INTF_IRQ_PROG_LINE,
|
||||
NULL, NULL);
|
||||
|
||||
ctx->yuv_conv = false;
|
||||
|
||||
ctx->ref_cnt--;
|
||||
end:
|
||||
mutex_unlock(&ctl->offlock);
|
||||
|
@ -1645,6 +1650,75 @@ end:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int mdss_mdp_update_csc_matrix(struct mdss_mdp_ctl *ctl)
|
||||
{
|
||||
struct mdss_mdp_video_ctx *ctx;
|
||||
struct mdss_data_type *mdata;
|
||||
struct mdss_panel_data *pdata;
|
||||
struct mdss_panel_info *pinfo;
|
||||
struct mdss_mdp_format_params *fmt;
|
||||
enum mdss_mdp_csc_type csc_type;
|
||||
int rc = 0;
|
||||
|
||||
ctx = (struct mdss_mdp_video_ctx *) ctl->intf_ctx[MASTER_CTX];
|
||||
if (!ctx) {
|
||||
pr_err("%s: invalid ctx\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mdata = ctl->mdata;
|
||||
pdata = ctl->panel_data;
|
||||
pinfo = &pdata->panel_info;
|
||||
|
||||
if (!mdss_mdp_is_cdm_supported(mdata, ctl->intf_type, 0)) {
|
||||
pr_debug("%s: CDM is not supported\n", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (IS_ERR_OR_NULL(ctl->cdm)) {
|
||||
pr_debug("%s: CDM is not initialized\n", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!ctx->yuv_conv) {
|
||||
pr_debug("%s: CDM not configured to convert to YUV yet\n",
|
||||
__func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
fmt = mdss_mdp_get_format_params(pinfo->out_format);
|
||||
if (fmt->is_yuv) {
|
||||
csc_type = MDSS_MDP_CSC_RGB2YUV_709L;
|
||||
if (pdata->get_csc_type)
|
||||
csc_type = pdata->get_csc_type(pdata);
|
||||
|
||||
pr_debug("cdm_csc_type = %d csc_type = %d\n",
|
||||
ctx->cdm_csc_type, csc_type);
|
||||
if (ctx->cdm_csc_type != csc_type) {
|
||||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
|
||||
rc = mdss_mdp_csc_setup(MDSS_MDP_BLOCK_CDM,
|
||||
ctl->cdm->num, csc_type);
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
|
||||
|
||||
if (rc) {
|
||||
pr_err("%s: CDM CSC setup failed, rc = %d\n",
|
||||
__func__, rc);
|
||||
goto error;
|
||||
}
|
||||
|
||||
pr_debug("%s: updating csc %d to %d\n", __func__,
|
||||
ctx->cdm_csc_type, csc_type);
|
||||
|
||||
ctx->cdm_csc_type = csc_type;
|
||||
pinfo->csc_type = csc_type;
|
||||
ctl->flush_bits |= BIT(26);
|
||||
}
|
||||
}
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
|
||||
{
|
||||
struct mdss_mdp_video_ctx *ctx;
|
||||
|
@ -1736,6 +1810,8 @@ static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
|
|||
CTL_INTF_EVENT_FLAG_DEFAULT);
|
||||
}
|
||||
|
||||
rc = mdss_mdp_update_csc_matrix(ctl);
|
||||
|
||||
rc = mdss_mdp_video_avr_trigger_setup(ctl);
|
||||
if (rc) {
|
||||
pr_err("avr trigger setup failed\n");
|
||||
|
@ -1955,10 +2031,24 @@ static int mdss_mdp_video_cdm_setup(struct mdss_mdp_cdm *cdm,
|
|||
{
|
||||
struct mdp_cdm_cfg setup;
|
||||
|
||||
if (fmt->is_yuv)
|
||||
if (fmt->is_yuv) {
|
||||
if (pinfo->is_ce_mode) {
|
||||
if (pinfo->yres < 720)
|
||||
setup.csc_type = MDSS_MDP_CSC_RGB2YUV_601L;
|
||||
else
|
||||
setup.csc_type = MDSS_MDP_CSC_RGB2YUV_709L;
|
||||
} else {
|
||||
if (pinfo->yres < 720)
|
||||
setup.csc_type = MDSS_MDP_CSC_RGB2YUV_601FR;
|
||||
else
|
||||
setup.csc_type = MDSS_MDP_CSC_RGB2YUV_709FR;
|
||||
}
|
||||
} else {
|
||||
if (pinfo->is_ce_mode)
|
||||
setup.csc_type = MDSS_MDP_CSC_RGB2RGB_L;
|
||||
else
|
||||
setup.csc_type = MDSS_MDP_CSC_RGB2RGB;
|
||||
}
|
||||
|
||||
switch (fmt->chroma_sample) {
|
||||
case MDSS_MDP_CHROMA_RGB:
|
||||
|
@ -1984,8 +2074,10 @@ static int mdss_mdp_video_cdm_setup(struct mdss_mdp_cdm *cdm,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
pinfo->csc_type = setup.csc_type;
|
||||
|
||||
setup.out_format = pinfo->out_format;
|
||||
setup.mdp_csc_bit_depth = MDP_CDM_CSC_8BIT;
|
||||
setup.mdp_csc_bit_depth = MDP_CDM_CSC_10BIT;
|
||||
setup.output_width = pinfo->xres + pinfo->lcdc.xres_pad;
|
||||
setup.output_height = pinfo->yres + pinfo->lcdc.yres_pad;
|
||||
return mdss_mdp_cdm_setup(cdm, &setup);
|
||||
|
@ -2120,6 +2212,7 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
|
|||
}
|
||||
|
||||
if (mdss_mdp_is_cdm_supported(mdata, ctl->intf_type, 0)) {
|
||||
bool needs_qr_conversion = false;
|
||||
|
||||
fmt = mdss_mdp_get_format_params(pinfo->out_format);
|
||||
if (!fmt) {
|
||||
|
@ -2127,7 +2220,11 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
|
|||
pinfo->out_format);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (fmt->is_yuv) {
|
||||
|
||||
if (ctl->intf_type == MDSS_INTF_HDMI && pinfo->is_ce_mode)
|
||||
needs_qr_conversion = true;
|
||||
|
||||
if (fmt->is_yuv || needs_qr_conversion) {
|
||||
ctl->cdm =
|
||||
mdss_mdp_cdm_init(ctl, MDP_CDM_CDWN_OUTPUT_HDMI);
|
||||
if (!IS_ERR_OR_NULL(ctl->cdm)) {
|
||||
|
@ -2137,6 +2234,10 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
|
|||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (fmt->is_yuv)
|
||||
ctx->yuv_conv = true;
|
||||
|
||||
ctx->cdm_csc_type = pinfo->csc_type;
|
||||
ctl->flush_bits |= BIT(26);
|
||||
} else {
|
||||
pr_err("%s: failed to initialize cdm\n",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2012-2020, 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
|
||||
|
@ -120,6 +120,18 @@ struct mdp_csc_cfg mdp_csc_8bit_convert[MDSS_MDP_MAX_CSC] = {
|
|||
{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
|
||||
{ 0x0010, 0x00eb, 0x0010, 0x00f0, 0x0010, 0x00f0,},
|
||||
},
|
||||
[MDSS_MDP_CSC_RGB2YUV_709FR] = {
|
||||
0,
|
||||
{
|
||||
0x006d, 0x016e, 0x0025,
|
||||
0xffc5, 0xff3b, 0x0100,
|
||||
0x0100, 0xff17, 0xffe9
|
||||
},
|
||||
{ 0x0, 0x0, 0x0,},
|
||||
{ 0x0, 0x0080, 0x0080,},
|
||||
{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
|
||||
{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
|
||||
},
|
||||
[MDSS_MDP_CSC_RGB2YUV_2020L] = {
|
||||
0,
|
||||
{
|
||||
|
@ -168,6 +180,18 @@ struct mdp_csc_cfg mdp_csc_8bit_convert[MDSS_MDP_MAX_CSC] = {
|
|||
{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
|
||||
{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
|
||||
},
|
||||
[MDSS_MDP_CSC_RGB2RGB_L] = {
|
||||
0,
|
||||
{
|
||||
0x01b7, 0x0000, 0x0000,
|
||||
0x0000, 0x01b7, 0x0000,
|
||||
0x0000, 0x0000, 0x01b7,
|
||||
},
|
||||
{ 0x0, 0x0, 0x0,},
|
||||
{ 0x10, 0x10, 0x10,},
|
||||
{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
|
||||
{ 0x10, 0xeb, 0x10, 0xeb, 0x10, 0xeb,},
|
||||
},
|
||||
};
|
||||
|
||||
struct mdp_csc_cfg mdp_csc_10bit_convert[MDSS_MDP_MAX_CSC] = {
|
||||
|
@ -267,6 +291,18 @@ struct mdp_csc_cfg mdp_csc_10bit_convert[MDSS_MDP_MAX_CSC] = {
|
|||
{ 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
|
||||
{ 0x0040, 0x03ac, 0x0040, 0x03c0, 0x0040, 0x03c0,},
|
||||
},
|
||||
[MDSS_MDP_CSC_RGB2YUV_709FR] = {
|
||||
0,
|
||||
{
|
||||
0x006d, 0x016e, 0x0025,
|
||||
0xffc5, 0xff3b, 0x0100,
|
||||
0x0100, 0xff17, 0xffe9
|
||||
},
|
||||
{ 0x0, 0x0, 0x0,},
|
||||
{ 0x0, 0x0200, 0x0200,},
|
||||
{ 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
|
||||
{ 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
|
||||
},
|
||||
[MDSS_MDP_CSC_RGB2YUV_2020L] = {
|
||||
0,
|
||||
{
|
||||
|
@ -315,6 +351,18 @@ struct mdp_csc_cfg mdp_csc_10bit_convert[MDSS_MDP_MAX_CSC] = {
|
|||
{ 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
|
||||
{ 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
|
||||
},
|
||||
[MDSS_MDP_CSC_RGB2RGB_L] = {
|
||||
0,
|
||||
{
|
||||
0x01b7, 0x0000, 0x0000,
|
||||
0x0000, 0x01b7, 0x0000,
|
||||
0x0000, 0x0000, 0x01b7,
|
||||
},
|
||||
{ 0x0, 0x0, 0x0,},
|
||||
{ 0x40, 0x40, 0x40,},
|
||||
{ 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
|
||||
{ 0x40, 0x3ac, 0x40, 0x3ac, 0x40, 0x3ac,},
|
||||
},
|
||||
};
|
||||
|
||||
static struct mdss_mdp_format_params dest_scaler_fmt = {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2013-2015, 2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2013-2020, 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
|
||||
|
@ -286,8 +286,9 @@ int mdss_mdp_splash_cleanup(struct msm_fb_data_type *mfd,
|
|||
/* 1-to-1 mapping */
|
||||
mdss_mdp_splash_iommu_attach(mfd);
|
||||
|
||||
if (use_borderfill && mdp5_data->handoff &&
|
||||
!mfd->splash_info.iommu_dynamic_attached) {
|
||||
if ((use_borderfill && mdp5_data->handoff &&
|
||||
!mfd->splash_info.iommu_dynamic_attached) ||
|
||||
mfd->force_null_commit) {
|
||||
/*
|
||||
* Set up border-fill on the handed off pipes.
|
||||
* This is needed to ensure that there are no memory
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2008-2020, 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
|
||||
|
@ -813,6 +813,8 @@ struct mdss_panel_info {
|
|||
u32 rst_seq_len;
|
||||
u32 vic; /* video identification code */
|
||||
u32 deep_color;
|
||||
bool is_ce_mode; /* CE video format */
|
||||
u8 csc_type;
|
||||
struct mdss_rect roi;
|
||||
struct mdss_dsi_dual_pu_roi dual_roi;
|
||||
int pwm_pmic_gpio;
|
||||
|
@ -1003,6 +1005,7 @@ struct mdss_panel_data {
|
|||
* and teardown.
|
||||
*/
|
||||
int (*event_handler) (struct mdss_panel_data *pdata, int e, void *arg);
|
||||
enum mdss_mdp_csc_type (*get_csc_type)(struct mdss_panel_data *pdata);
|
||||
struct device_node *(*get_fb_node)(struct platform_device *pdev);
|
||||
|
||||
struct list_head timings_list;
|
||||
|
|
|
@ -33,6 +33,8 @@ struct isp_kstate {
|
|||
uint32_t kernel_sofid;
|
||||
uint32_t drop_reconfig;
|
||||
uint32_t vfeid;
|
||||
uint32_t dual_cam_drop_detected;
|
||||
uint32_t dual_cam_drop;
|
||||
};
|
||||
|
||||
enum ISP_START_PIXEL_PATTERN {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2012-2014,2020, 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
|
||||
|
@ -101,7 +101,7 @@ EXPORT_SYMBOL(check_permissions);
|
|||
int msm_ipc_config_sec_rules(void *arg)
|
||||
{
|
||||
struct config_sec_rules_args sec_rules_arg;
|
||||
struct security_rule *rule, *temp_rule;
|
||||
struct security_rule *rule;
|
||||
int key;
|
||||
size_t kgroup_info_sz;
|
||||
int ret;
|
||||
|
@ -117,6 +117,10 @@ int msm_ipc_config_sec_rules(void *arg)
|
|||
if (ret)
|
||||
return -EFAULT;
|
||||
|
||||
/* Default rule change from config util not allowed */
|
||||
if (sec_rules_arg.service_id == ALL_SERVICE)
|
||||
return -EINVAL;
|
||||
|
||||
if (sec_rules_arg.num_group_info <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -174,21 +178,11 @@ int msm_ipc_config_sec_rules(void *arg)
|
|||
|
||||
key = rule->service_id & (SEC_RULES_HASH_SZ - 1);
|
||||
down_write(&security_rules_lock_lha4);
|
||||
if (rule->service_id == ALL_SERVICE) {
|
||||
temp_rule = list_first_entry(&security_rules[key],
|
||||
struct security_rule, list);
|
||||
list_del(&temp_rule->list);
|
||||
kfree(temp_rule->group_id);
|
||||
kfree(temp_rule);
|
||||
}
|
||||
list_add_tail(&rule->list, &security_rules[key]);
|
||||
up_write(&security_rules_lock_lha4);
|
||||
|
||||
if (rule->service_id == ALL_SERVICE)
|
||||
msm_ipc_sync_default_sec_rule((void *)rule);
|
||||
else
|
||||
msm_ipc_sync_sec_rule(rule->service_id, rule->instance_id,
|
||||
(void *)rule);
|
||||
msm_ipc_sync_sec_rule(rule->service_id,
|
||||
rule->instance_id, (void *)rule);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue