Merge "disp: msm: dp: add colorspace property for MSM DP"

This commit is contained in:
qctecmdr 2019-07-28 01:12:00 -07:00 committed by Gerrit - the friendly Code Review server
commit 60d59191c8
13 changed files with 640 additions and 165 deletions

View File

@ -6,7 +6,6 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <drm/drm_dp_helper.h>
#include "dp_catalog.h" #include "dp_catalog.h"
#include "dp_reg.h" #include "dp_reg.h"
@ -478,6 +477,29 @@ static u32 dp_catalog_ctrl_read_hdcp_status(struct dp_catalog_ctrl *ctrl)
return dp_read(catalog->exe_mode, io_data, DP_HDCP_STATUS); return dp_read(catalog->exe_mode, io_data, DP_HDCP_STATUS);
} }
static void dp_catalog_panel_sdp_update(struct dp_catalog_panel *panel)
{
struct dp_catalog_private *catalog;
struct dp_io_data *io_data;
u32 sdp_cfg3_off = 0;
if (panel->stream_id >= DP_STREAM_MAX) {
pr_err("invalid stream_id:%d\n", panel->stream_id);
return;
}
if (panel->stream_id == DP_STREAM_1)
sdp_cfg3_off = MMSS_DP1_SDP_CFG3 - MMSS_DP_SDP_CFG3;
catalog = dp_catalog_get_priv(panel);
io_data = catalog->io.dp_link;
dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG3 + sdp_cfg3_off,
0x01);
dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG3 + sdp_cfg3_off,
0x00);
}
static void dp_catalog_panel_setup_vsif_infoframe_sdp( static void dp_catalog_panel_setup_vsif_infoframe_sdp(
struct dp_catalog_panel *panel) struct dp_catalog_panel *panel)
{ {
@ -496,11 +518,11 @@ static void dp_catalog_panel_setup_vsif_infoframe_sdp(
mst_offset = MMSS_DP1_VSCEXT_0 - MMSS_DP_VSCEXT_0; mst_offset = MMSS_DP1_VSCEXT_0 - MMSS_DP_VSCEXT_0;
catalog = dp_catalog_get_priv(panel); catalog = dp_catalog_get_priv(panel);
hdr = &panel->hdr_data.hdr_meta; hdr = &panel->hdr_meta;
io_data = catalog->io.dp_link; io_data = catalog->io.dp_link;
/* HEADER BYTE 1 */ /* HEADER BYTE 1 */
header = panel->hdr_data.vscext_header_byte1; header = panel->dhdr_vsif_sdp.HB1;
parity = dp_header_get_parity(header); parity = dp_header_get_parity(header);
data = ((header << HEADER_BYTE_1_BIT) data = ((header << HEADER_BYTE_1_BIT)
| (parity << PARITY_BYTE_1_BIT)); | (parity << PARITY_BYTE_1_BIT));
@ -510,7 +532,7 @@ static void dp_catalog_panel_setup_vsif_infoframe_sdp(
off += sizeof(data); off += sizeof(data);
/* HEADER BYTE 2 */ /* HEADER BYTE 2 */
header = panel->hdr_data.vscext_header_byte2; header = panel->dhdr_vsif_sdp.HB2;
parity = dp_header_get_parity(header); parity = dp_header_get_parity(header);
data = ((header << HEADER_BYTE_2_BIT) data = ((header << HEADER_BYTE_2_BIT)
| (parity << PARITY_BYTE_2_BIT)); | (parity << PARITY_BYTE_2_BIT));
@ -518,7 +540,7 @@ static void dp_catalog_panel_setup_vsif_infoframe_sdp(
data); data);
/* HEADER BYTE 3 */ /* HEADER BYTE 3 */
header = panel->hdr_data.vscext_header_byte3; header = panel->dhdr_vsif_sdp.HB3;
parity = dp_header_get_parity(header); parity = dp_header_get_parity(header);
data = ((header << HEADER_BYTE_3_BIT) data = ((header << HEADER_BYTE_3_BIT)
| (parity << PARITY_BYTE_3_BIT)); | (parity << PARITY_BYTE_3_BIT));
@ -541,6 +563,8 @@ static void dp_catalog_panel_setup_hdr_infoframe_sdp(
struct dp_io_data *io_data; struct dp_io_data *io_data;
u32 header, parity, data, mst_offset = 0; u32 header, parity, data, mst_offset = 0;
u8 buf[SZ_64], off = 0; u8 buf[SZ_64], off = 0;
u32 const version = 0x01;
u32 const length = 0x1a;
if (panel->stream_id >= DP_STREAM_MAX) { if (panel->stream_id >= DP_STREAM_MAX) {
DP_ERR("invalid stream_id:%d\n", panel->stream_id); DP_ERR("invalid stream_id:%d\n", panel->stream_id);
@ -551,11 +575,11 @@ static void dp_catalog_panel_setup_hdr_infoframe_sdp(
mst_offset = MMSS_DP1_GENERIC2_0 - MMSS_DP_GENERIC2_0; mst_offset = MMSS_DP1_GENERIC2_0 - MMSS_DP_GENERIC2_0;
catalog = dp_catalog_get_priv(panel); catalog = dp_catalog_get_priv(panel);
hdr = &panel->hdr_data.hdr_meta; hdr = &panel->hdr_meta;
io_data = catalog->io.dp_link; io_data = catalog->io.dp_link;
/* HEADER BYTE 1 */ /* HEADER BYTE 1 */
header = panel->hdr_data.shdr_header_byte1; header = panel->shdr_if_sdp.HB1;
parity = dp_header_get_parity(header); parity = dp_header_get_parity(header);
data = ((header << HEADER_BYTE_1_BIT) data = ((header << HEADER_BYTE_1_BIT)
| (parity << PARITY_BYTE_1_BIT)); | (parity << PARITY_BYTE_1_BIT));
@ -565,7 +589,7 @@ static void dp_catalog_panel_setup_hdr_infoframe_sdp(
off += sizeof(data); off += sizeof(data);
/* HEADER BYTE 2 */ /* HEADER BYTE 2 */
header = panel->hdr_data.shdr_header_byte2; header = panel->shdr_if_sdp.HB2;
parity = dp_header_get_parity(header); parity = dp_header_get_parity(header);
data = ((header << HEADER_BYTE_2_BIT) data = ((header << HEADER_BYTE_2_BIT)
| (parity << PARITY_BYTE_2_BIT)); | (parity << PARITY_BYTE_2_BIT));
@ -573,7 +597,7 @@ static void dp_catalog_panel_setup_hdr_infoframe_sdp(
data); data);
/* HEADER BYTE 3 */ /* HEADER BYTE 3 */
header = panel->hdr_data.shdr_header_byte3; header = panel->shdr_if_sdp.HB3;
parity = dp_header_get_parity(header); parity = dp_header_get_parity(header);
data = ((header << HEADER_BYTE_3_BIT) data = ((header << HEADER_BYTE_3_BIT)
| (parity << PARITY_BYTE_3_BIT)); | (parity << PARITY_BYTE_3_BIT));
@ -584,8 +608,8 @@ static void dp_catalog_panel_setup_hdr_infoframe_sdp(
memcpy(buf + off, &data, sizeof(data)); memcpy(buf + off, &data, sizeof(data));
off += sizeof(data); off += sizeof(data);
data = panel->hdr_data.version; data = version;
data |= panel->hdr_data.length << 8; data |= length << 8;
data |= hdr->eotf << 16; data |= hdr->eotf << 16;
dp_write(catalog->exe_mode, io_data, MMSS_DP_GENERIC2_2 + mst_offset, dp_write(catalog->exe_mode, io_data, MMSS_DP_GENERIC2_2 + mst_offset,
data); data);
@ -661,7 +685,7 @@ static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel)
struct dp_catalog_private *catalog; struct dp_catalog_private *catalog;
struct dp_io_data *io_data; struct dp_io_data *io_data;
u32 header, parity, data, mst_offset = 0; u32 header, parity, data, mst_offset = 0;
u8 bpc, off = 0; u8 off = 0;
u8 buf[SZ_128]; u8 buf[SZ_128];
if (!panel) { if (!panel) {
@ -681,7 +705,7 @@ static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel)
io_data = catalog->io.dp_link; io_data = catalog->io.dp_link;
/* HEADER BYTE 1 */ /* HEADER BYTE 1 */
header = panel->hdr_data.vsc_header_byte1; header = panel->vsc_colorimetry.header.HB1;
parity = dp_header_get_parity(header); parity = dp_header_get_parity(header);
data = ((header << HEADER_BYTE_1_BIT) data = ((header << HEADER_BYTE_1_BIT)
| (parity << PARITY_BYTE_1_BIT)); | (parity << PARITY_BYTE_1_BIT));
@ -691,7 +715,7 @@ static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel)
off += sizeof(data); off += sizeof(data);
/* HEADER BYTE 2 */ /* HEADER BYTE 2 */
header = panel->hdr_data.vsc_header_byte2; header = panel->vsc_colorimetry.header.HB2;
parity = dp_header_get_parity(header); parity = dp_header_get_parity(header);
data = ((header << HEADER_BYTE_2_BIT) data = ((header << HEADER_BYTE_2_BIT)
| (parity << PARITY_BYTE_2_BIT)); | (parity << PARITY_BYTE_2_BIT));
@ -699,7 +723,7 @@ static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel)
data); data);
/* HEADER BYTE 3 */ /* HEADER BYTE 3 */
header = panel->hdr_data.vsc_header_byte3; header = panel->vsc_colorimetry.header.HB3;
parity = dp_header_get_parity(header); parity = dp_header_get_parity(header);
data = ((header << HEADER_BYTE_3_BIT) data = ((header << HEADER_BYTE_3_BIT)
| (parity << PARITY_BYTE_3_BIT)); | (parity << PARITY_BYTE_3_BIT));
@ -731,24 +755,9 @@ static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel)
memcpy(buf + off, &data, sizeof(data)); memcpy(buf + off, &data, sizeof(data));
off += sizeof(data); off += sizeof(data);
switch (panel->hdr_data.bpc) { data = (panel->vsc_colorimetry.data[16] & 0xFF) |
default: ((panel->vsc_colorimetry.data[17] & 0xFF) << 8) |
case 10: ((panel->vsc_colorimetry.data[18] & 0x7) << 16);
bpc = BIT(1);
break;
case 8:
bpc = BIT(0);
break;
case 6:
bpc = 0;
break;
}
data = (panel->hdr_data.colorimetry & 0xF) |
((panel->hdr_data.pixel_encoding & 0xF) << 4) |
(bpc << 8) |
((panel->hdr_data.dynamic_range & 0x1) << 15) |
((panel->hdr_data.content_type & 0x7) << 16);
dp_write(catalog->exe_mode, io_data, MMSS_DP_GENERIC0_6 + mst_offset, dp_write(catalog->exe_mode, io_data, MMSS_DP_GENERIC0_6 + mst_offset,
data); data);
@ -775,15 +784,125 @@ static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel)
DUMP_PREFIX_NONE, 16, 4, buf, off, false); DUMP_PREFIX_NONE, 16, 4, buf, off, false);
} }
static void dp_catalog_panel_config_sdp(struct dp_catalog_panel *panel,
bool en)
{
struct dp_catalog_private *catalog;
struct dp_io_data *io_data;
u32 cfg, cfg2;
u32 sdp_cfg_off = 0;
u32 sdp_cfg2_off = 0;
if (panel->stream_id >= DP_STREAM_MAX) {
DP_ERR("invalid stream_id:%d\n", panel->stream_id);
return;
}
catalog = dp_catalog_get_priv(panel);
io_data = catalog->io.dp_link;
if (panel->stream_id == DP_STREAM_1) {
sdp_cfg_off = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG;
sdp_cfg2_off = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2;
}
cfg = dp_read(catalog->exe_mode, io_data,
MMSS_DP_SDP_CFG + sdp_cfg_off);
cfg2 = dp_read(catalog->exe_mode, io_data,
MMSS_DP_SDP_CFG2 + sdp_cfg2_off);
if (en) {
/* GEN0_SDP_EN */
cfg |= BIT(17);
dp_write(catalog->exe_mode, io_data,
MMSS_DP_SDP_CFG + sdp_cfg_off, cfg);
/* GENERIC0_SDPSIZE */
cfg2 |= BIT(16);
dp_write(catalog->exe_mode, io_data,
MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2);
/* setup the GENERIC0 in case of en = true */
dp_catalog_panel_setup_vsc_sdp(panel);
} else {
/* GEN0_SDP_EN */
cfg &= ~BIT(17);
dp_write(catalog->exe_mode, io_data,
MMSS_DP_SDP_CFG + sdp_cfg_off, cfg);
/* GENERIC0_SDPSIZE */
cfg2 &= ~BIT(16);
dp_write(catalog->exe_mode, io_data,
MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2);
}
dp_catalog_panel_sdp_update(panel);
}
static void dp_catalog_panel_config_misc(struct dp_catalog_panel *panel)
{
struct dp_catalog_private *catalog;
struct dp_io_data *io_data;
u32 reg_offset = 0;
if (!panel) {
pr_err("invalid input\n");
return;
}
if (panel->stream_id >= DP_STREAM_MAX) {
pr_err("invalid stream_id:%d\n", panel->stream_id);
return;
}
catalog = dp_catalog_get_priv(panel);
io_data = catalog->io.dp_link;
if (panel->stream_id == DP_STREAM_1)
reg_offset = DP1_MISC1_MISC0 - DP_MISC1_MISC0;
DP_DEBUG("misc settings = 0x%x\n", panel->misc_val);
dp_write(catalog->exe_mode, io_data, DP_MISC1_MISC0 + reg_offset,
panel->misc_val);
}
static int dp_catalog_panel_set_colorspace(struct dp_catalog_panel *panel,
bool vsc_supported)
{
struct dp_catalog_private *catalog;
struct dp_io_data *io_data;
if (!panel) {
pr_err("invalid input\n");
return -EINVAL;
}
if (panel->stream_id >= DP_STREAM_MAX) {
pr_err("invalid stream_id:%d\n", panel->stream_id);
return -EINVAL;
}
catalog = dp_catalog_get_priv(panel);
io_data = catalog->io.dp_link;
if (vsc_supported) {
dp_catalog_panel_setup_vsc_sdp(panel);
dp_catalog_panel_sdp_update(panel);
} else
dp_catalog_panel_config_misc(panel);
return 0;
}
static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en, static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en,
u32 dhdr_max_pkts) u32 dhdr_max_pkts, bool flush)
{ {
struct dp_catalog_private *catalog; struct dp_catalog_private *catalog;
struct dp_io_data *io_data; struct dp_io_data *io_data;
u32 cfg, cfg2, cfg4, misc; u32 cfg, cfg2, cfg4, misc;
u32 sdp_cfg_off = 0; u32 sdp_cfg_off = 0;
u32 sdp_cfg2_off = 0; u32 sdp_cfg2_off = 0;
u32 sdp_cfg3_off = 0;
u32 sdp_cfg4_off = 0; u32 sdp_cfg4_off = 0;
u32 misc1_misc0_off = 0; u32 misc1_misc0_off = 0;
@ -803,7 +922,6 @@ static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en,
if (panel->stream_id == DP_STREAM_1) { if (panel->stream_id == DP_STREAM_1) {
sdp_cfg_off = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG; sdp_cfg_off = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG;
sdp_cfg2_off = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2; sdp_cfg2_off = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2;
sdp_cfg3_off = MMSS_DP1_SDP_CFG3 - MMSS_DP_SDP_CFG3;
sdp_cfg4_off = MMSS_DP1_SDP_CFG4 - MMSS_DP_SDP_CFG4; sdp_cfg4_off = MMSS_DP1_SDP_CFG4 - MMSS_DP_SDP_CFG4;
misc1_misc0_off = DP1_MISC1_MISC0 - DP_MISC1_MISC0; misc1_misc0_off = DP1_MISC1_MISC0 - DP_MISC1_MISC0;
} }
@ -826,34 +944,30 @@ static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en,
dp_catalog_panel_setup_vsif_infoframe_sdp(panel); dp_catalog_panel_setup_vsif_infoframe_sdp(panel);
} }
/* GEN0_SDP_EN, GEN2_SDP_EN */ /* GEN2_SDP_EN */
cfg |= BIT(17) | BIT(19); cfg |= BIT(19);
dp_write(catalog->exe_mode, io_data, dp_write(catalog->exe_mode, io_data,
MMSS_DP_SDP_CFG + sdp_cfg_off, cfg); MMSS_DP_SDP_CFG + sdp_cfg_off, cfg);
/* GENERIC0_SDPSIZE GENERIC2_SDPSIZE */ /* GENERIC2_SDPSIZE */
cfg2 |= BIT(16) | BIT(20); cfg2 |= BIT(20);
dp_write(catalog->exe_mode, io_data, dp_write(catalog->exe_mode, io_data,
MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2); MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2);
dp_catalog_panel_setup_vsc_sdp(panel);
dp_catalog_panel_setup_hdr_infoframe_sdp(panel); dp_catalog_panel_setup_hdr_infoframe_sdp(panel);
/* indicates presence of VSC (BIT(6) of MISC1) */ if (panel->hdr_meta.eotf)
misc |= BIT(14);
if (panel->hdr_data.hdr_meta.eotf)
DP_DEBUG("Enabled\n"); DP_DEBUG("Enabled\n");
else else
DP_DEBUG("Reset\n"); DP_DEBUG("Reset\n");
} else { } else {
/* VSCEXT_SDP_EN, GEN0_SDP_EN */ /* VSCEXT_SDP_ENG */
cfg &= ~BIT(16) & ~BIT(17) & ~BIT(19); cfg &= ~BIT(16) & ~BIT(19);
dp_write(catalog->exe_mode, io_data, dp_write(catalog->exe_mode, io_data,
MMSS_DP_SDP_CFG + sdp_cfg_off, cfg); MMSS_DP_SDP_CFG + sdp_cfg_off, cfg);
/* GENERIC0_SDPSIZE GENERIC2_SDPSIZE */ /* GENERIC0_SDPSIZE GENERIC2_SDPSIZE */
cfg2 &= ~BIT(16) & ~BIT(20); cfg2 &= ~BIT(20);
dp_write(catalog->exe_mode, io_data, dp_write(catalog->exe_mode, io_data,
MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2); MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2);
@ -862,19 +976,13 @@ static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en,
dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG4 dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG4
+ sdp_cfg4_off, cfg4); + sdp_cfg4_off, cfg4);
/* switch back to MSA */
misc &= ~BIT(14);
DP_DEBUG("Disabled\n"); DP_DEBUG("Disabled\n");
} }
dp_write(catalog->exe_mode, io_data, DP_MISC1_MISC0 + misc1_misc0_off, if (flush) {
misc); DP_DEBUG("flushing HDR metadata\n");
dp_catalog_panel_sdp_update(panel);
dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG3 + sdp_cfg3_off, }
0x01);
dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG3 + sdp_cfg3_off,
0x00);
} }
static void dp_catalog_panel_update_transfer_unit( static void dp_catalog_panel_update_transfer_unit(
@ -1109,33 +1217,6 @@ static void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog_ctrl *ctrl,
} }
} }
static void dp_catalog_panel_config_misc(struct dp_catalog_panel *panel)
{
struct dp_catalog_private *catalog;
struct dp_io_data *io_data;
u32 reg_offset = 0;
if (!panel) {
DP_ERR("invalid input\n");
return;
}
if (panel->stream_id >= DP_STREAM_MAX) {
DP_ERR("invalid stream_id:%d\n", panel->stream_id);
return;
}
catalog = dp_catalog_get_priv(panel);
io_data = catalog->io.dp_link;
if (panel->stream_id == DP_STREAM_1)
reg_offset = DP1_MISC1_MISC0 - DP_MISC1_MISC0;
DP_DEBUG("misc settings = 0x%x\n", panel->misc_val);
dp_write(catalog->exe_mode, io_data, DP_MISC1_MISC0 + reg_offset,
panel->misc_val);
}
static void dp_catalog_panel_config_msa(struct dp_catalog_panel *panel, static void dp_catalog_panel_config_msa(struct dp_catalog_panel *panel,
u32 rate, u32 stream_rate_khz) u32 rate, u32 stream_rate_khz)
{ {
@ -2494,7 +2575,6 @@ static void dp_catalog_panel_config_spd(struct dp_catalog_panel *panel)
u32 offset = 0; u32 offset = 0;
u32 sdp_cfg_off = 0; u32 sdp_cfg_off = 0;
u32 sdp_cfg2_off = 0; u32 sdp_cfg2_off = 0;
u32 sdp_cfg3_off = 0;
/* /*
* Source Device Information * Source Device Information
@ -2567,7 +2647,6 @@ static void dp_catalog_panel_config_spd(struct dp_catalog_panel *panel)
if (panel->stream_id == DP_STREAM_1) { if (panel->stream_id == DP_STREAM_1) {
sdp_cfg_off = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG; sdp_cfg_off = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG;
sdp_cfg2_off = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2; sdp_cfg2_off = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2;
sdp_cfg3_off = MMSS_DP1_SDP_CFG3 - MMSS_DP_SDP_CFG3;
} }
spd_cfg = dp_read(catalog->exe_mode, io_data, spd_cfg = dp_read(catalog->exe_mode, io_data,
@ -2584,10 +2663,7 @@ static void dp_catalog_panel_config_spd(struct dp_catalog_panel *panel)
dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG2 + sdp_cfg2_off, dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG2 + sdp_cfg2_off,
spd_cfg2); spd_cfg2);
dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG3 + sdp_cfg3_off, dp_catalog_panel_sdp_update(panel);
0x1);
dp_write(catalog->exe_mode, io_data, MMSS_DP_SDP_CFG3 + sdp_cfg3_off,
0x0);
} }
static void dp_catalog_get_io_buf(struct dp_catalog_private *catalog) static void dp_catalog_get_io_buf(struct dp_catalog_private *catalog)
@ -2745,9 +2821,11 @@ struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_parser *parser)
struct dp_catalog_panel panel = { struct dp_catalog_panel panel = {
.timing_cfg = dp_catalog_panel_timing_cfg, .timing_cfg = dp_catalog_panel_timing_cfg,
.config_hdr = dp_catalog_panel_config_hdr, .config_hdr = dp_catalog_panel_config_hdr,
.config_sdp = dp_catalog_panel_config_sdp,
.tpg_config = dp_catalog_panel_tpg_cfg, .tpg_config = dp_catalog_panel_tpg_cfg,
.config_spd = dp_catalog_panel_config_spd, .config_spd = dp_catalog_panel_config_spd,
.config_misc = dp_catalog_panel_config_misc, .config_misc = dp_catalog_panel_config_misc,
.set_colorspace = dp_catalog_panel_set_colorspace,
.config_msa = dp_catalog_panel_config_msa, .config_msa = dp_catalog_panel_config_msa,
.update_transfer_unit = dp_catalog_panel_update_transfer_unit, .update_transfer_unit = dp_catalog_panel_update_transfer_unit,
.config_ctrl = dp_catalog_panel_config_ctrl, .config_ctrl = dp_catalog_panel_config_ctrl,

View File

@ -6,6 +6,7 @@
#ifndef _DP_CATALOG_H_ #ifndef _DP_CATALOG_H_
#define _DP_CATALOG_H_ #define _DP_CATALOG_H_
#include <drm/drm_dp_helper.h>
#include <drm/msm_drm.h> #include <drm/msm_drm.h>
#include "dp_parser.h" #include "dp_parser.h"
@ -39,32 +40,9 @@ enum dp_stream_id {
DP_STREAM_MAX, DP_STREAM_MAX,
}; };
struct dp_catalog_hdr_data { struct dp_catalog_vsc_sdp_colorimetry {
u32 vsc_header_byte0; struct dp_sdp_header header;
u32 vsc_header_byte1; u8 data[32];
u32 vsc_header_byte2;
u32 vsc_header_byte3;
u32 vscext_header_byte0;
u32 vscext_header_byte1;
u32 vscext_header_byte2;
u32 vscext_header_byte3;
u32 shdr_header_byte0;
u32 shdr_header_byte1;
u32 shdr_header_byte2;
u32 shdr_header_byte3;
u32 bpc;
u32 version;
u32 length;
u32 pixel_encoding;
u32 colorimetry;
u32 dynamic_range;
u32 content_type;
struct drm_msm_ext_hdr_metadata hdr_meta;
}; };
struct dp_catalog_aux { struct dp_catalog_aux {
@ -197,7 +175,10 @@ struct dp_catalog_panel {
u8 *spd_vendor_name; u8 *spd_vendor_name;
u8 *spd_product_description; u8 *spd_product_description;
struct dp_catalog_hdr_data hdr_data; struct dp_catalog_vsc_sdp_colorimetry vsc_colorimetry;
struct dp_sdp_header dhdr_vsif_sdp;
struct dp_sdp_header shdr_if_sdp;
struct drm_msm_ext_hdr_metadata hdr_meta;
/* TPG */ /* TPG */
u32 hsync_period; u32 hsync_period;
@ -222,7 +203,10 @@ struct dp_catalog_panel {
int (*timing_cfg)(struct dp_catalog_panel *panel); int (*timing_cfg)(struct dp_catalog_panel *panel);
void (*config_hdr)(struct dp_catalog_panel *panel, bool en, void (*config_hdr)(struct dp_catalog_panel *panel, bool en,
u32 dhdr_max_pkts); u32 dhdr_max_pkts, bool flush);
void (*config_sdp)(struct dp_catalog_panel *panel, bool en);
int (*set_colorspace)(struct dp_catalog_panel *panel,
bool vsc_supported);
void (*tpg_config)(struct dp_catalog_panel *panel, bool enable); void (*tpg_config)(struct dp_catalog_panel *panel, bool enable);
void (*config_spd)(struct dp_catalog_panel *panel); void (*config_spd)(struct dp_catalog_panel *panel);
void (*config_misc)(struct dp_catalog_panel *panel); void (*config_misc)(struct dp_catalog_panel *panel);

View File

@ -1627,7 +1627,7 @@ static void dp_display_stream_post_enable(struct dp_display_private *dp,
struct dp_panel *dp_panel) struct dp_panel *dp_panel)
{ {
dp_panel->spd_config(dp_panel); dp_panel->spd_config(dp_panel);
dp_panel->setup_hdr(dp_panel, NULL, false, 0); dp_panel->setup_hdr(dp_panel, NULL, false, 0, true);
} }
static int dp_display_post_enable(struct dp_display *dp_display, void *panel) static int dp_display_post_enable(struct dp_display *dp_display, void *panel)
@ -1676,6 +1676,14 @@ end:
return 0; return 0;
} }
static void dp_display_clear_colorspaces(struct dp_display *dp_display)
{
struct drm_connector *connector;
connector = dp_display->base_connector;
connector->color_enc_fmt = 0;
}
static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) static int dp_display_pre_disable(struct dp_display *dp_display, void *panel)
{ {
struct dp_display_private *dp; struct dp_display_private *dp;
@ -1732,6 +1740,8 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel)
} }
} }
dp_display_clear_colorspaces(dp_display);
clean: clean:
if (dp_panel->audio_supported) if (dp_panel->audio_supported)
dp_panel->audio->off(dp_panel->audio); dp_panel->audio->off(dp_panel->audio);
@ -2082,8 +2092,10 @@ static int dp_display_config_hdr(struct dp_display *dp_display, void *panel,
struct drm_msm_ext_hdr_metadata *hdr, bool dhdr_update) struct drm_msm_ext_hdr_metadata *hdr, bool dhdr_update)
{ {
struct dp_panel *dp_panel; struct dp_panel *dp_panel;
struct sde_connector *sde_conn;
struct dp_display_private *dp; struct dp_display_private *dp;
u64 core_clk_rate; u64 core_clk_rate;
bool flush_hdr;
if (!dp_display || !panel) { if (!dp_display || !panel) {
DP_ERR("invalid input\n"); DP_ERR("invalid input\n");
@ -2092,6 +2104,7 @@ static int dp_display_config_hdr(struct dp_display *dp_display, void *panel,
dp_panel = panel; dp_panel = panel;
dp = container_of(dp_display, struct dp_display_private, dp_display); dp = container_of(dp_display, struct dp_display_private, dp_display);
sde_conn = to_sde_connector(dp_panel->connector);
core_clk_rate = dp->power->clk_get_rate(dp->power, "core_clk"); core_clk_rate = dp->power->clk_get_rate(dp->power, "core_clk");
if (!core_clk_rate) { if (!core_clk_rate) {
@ -2099,7 +2112,36 @@ static int dp_display_config_hdr(struct dp_display *dp_display, void *panel,
return -EINVAL; return -EINVAL;
} }
return dp_panel->setup_hdr(dp_panel, hdr, dhdr_update, core_clk_rate); /*
* In rare cases where HDR metadata is updated independently
* flush the HDR metadata immediately instead of relying on
* the colorspace
*/
flush_hdr = !sde_conn->colorspace_updated;
if (flush_hdr)
DP_DEBUG("flushing the HDR metadata\n");
else
DP_DEBUG("piggy-backing with colorspace\n");
return dp_panel->setup_hdr(dp_panel, hdr, dhdr_update,
core_clk_rate, flush_hdr);
}
static int dp_display_setup_colospace(struct dp_display *dp_display,
void *panel,
u32 colorspace)
{
struct dp_panel *dp_panel;
if (!dp_display || !panel) {
pr_err("invalid input\n");
return -EINVAL;
}
dp_panel = panel;
return dp_panel->set_colorspace(dp_panel, colorspace);
} }
static int dp_display_create_workqueue(struct dp_display_private *dp) static int dp_display_create_workqueue(struct dp_display_private *dp)
@ -2623,6 +2665,7 @@ static int dp_display_probe(struct platform_device *pdev)
dp_display_mst_get_fixed_topology_port; dp_display_mst_get_fixed_topology_port;
g_dp_display->wakeup_phy_layer = g_dp_display->wakeup_phy_layer =
dp_display_wakeup_phy_layer; dp_display_wakeup_phy_layer;
g_dp_display->set_colorspace = dp_display_setup_colospace;
rc = component_add(&pdev->dev, &dp_display_comp_ops); rc = component_add(&pdev->dev, &dp_display_comp_ops);
if (rc) { if (rc) {

View File

@ -93,6 +93,8 @@ struct dp_display {
int (*config_hdr)(struct dp_display *dp_display, void *panel, int (*config_hdr)(struct dp_display *dp_display, void *panel,
struct drm_msm_ext_hdr_metadata *hdr_meta, struct drm_msm_ext_hdr_metadata *hdr_meta,
bool dhdr_update); bool dhdr_update);
int (*set_colorspace)(struct dp_display *dp_display, void *panel,
u32 colorspace);
int (*post_init)(struct dp_display *dp_display); int (*post_init)(struct dp_display *dp_display);
int (*mst_install)(struct dp_display *dp_display, int (*mst_install)(struct dp_display *dp_display,
struct dp_mst_drm_install_info *mst_install_info); struct dp_mst_drm_install_info *mst_install_info);

View File

@ -326,6 +326,25 @@ int dp_connector_config_hdr(struct drm_connector *connector, void *display,
c_state->dyn_hdr_meta.dynamic_hdr_update); c_state->dyn_hdr_meta.dynamic_hdr_update);
} }
int dp_connector_set_colorspace(struct drm_connector *connector,
void *display)
{
struct dp_display *dp_display = display;
struct sde_connector *sde_conn;
if (!dp_display || !connector)
return -EINVAL;
sde_conn = to_sde_connector(connector);
if (!sde_conn->drv_panel) {
pr_err("invalid dp panel\n");
return -EINVAL;
}
return dp_display->set_colorspace(dp_display,
sde_conn->drv_panel, connector->state->colorspace);
}
int dp_connector_post_init(struct drm_connector *connector, void *display) int dp_connector_post_init(struct drm_connector *connector, void *display)
{ {
int rc; int rc;
@ -469,6 +488,32 @@ void dp_connector_post_open(struct drm_connector *connector, void *display)
dp->post_open(dp); dp->post_open(dp);
} }
int dp_connector_atomic_check(struct drm_connector *connector,
void *display,
struct drm_connector_state *c_state)
{
struct sde_connector *sde_conn;
struct drm_connector_state *old_state =
drm_atomic_get_old_connector_state(c_state->state, connector);
if (!connector || !display)
return -EINVAL;
sde_conn = to_sde_connector(connector);
/*
* Marking the colorspace has been changed
* the flag shall be checked in the pre_kickoff
* to configure the new colorspace in HW
*/
if (c_state->colorspace != old_state->colorspace) {
DP_DEBUG("colorspace has been updated\n");
sde_conn->colorspace_updated = true;
}
return 0;
}
int dp_connector_get_modes(struct drm_connector *connector, int dp_connector_get_modes(struct drm_connector *connector,
void *display, const struct msm_resource_caps_info *avail_res) void *display, const struct msm_resource_caps_info *avail_res)
{ {

View File

@ -37,6 +37,27 @@ int dp_connector_config_hdr(struct drm_connector *connector,
void *display, void *display,
struct sde_connector_state *c_state); struct sde_connector_state *c_state);
/**
* dp_connector_atomic_check - callback to perform atomic
* check for DP
* @connector: Pointer to drm connector structure
* @display: Pointer to private display handle
* @c_state: connect state data
* Returns: Zero on success
*/
int dp_connector_atomic_check(struct drm_connector *connector,
void *display,
struct drm_connector_state *c_state);
/**
* dp_connector_set_colorspace - callback to set new colorspace
* @connector: Pointer to drm connector structure
* @display: Pointer to private display handle
* Returns: Zero on success
*/
int dp_connector_set_colorspace(struct drm_connector *connector,
void *display);
/** /**
* dp_connector_post_init - callback to perform additional initialization steps * dp_connector_post_init - callback to perform additional initialization steps
* @connector: Pointer to drm connector structure * @connector: Pointer to drm connector structure

View File

@ -1352,7 +1352,7 @@ static int dp_link_get_colorimetry_config(struct dp_link *dp_link)
/* Only RGB_VESA nd RGB_CEA supported for now */ /* Only RGB_VESA nd RGB_CEA supported for now */
switch (dr) { switch (dr) {
case DP_DYNAMIC_RANGE_RGB_CEA: case DP_DYNAMIC_RANGE_RGB_CEA:
cc = BIT(3); cc = BIT(2);
break; break;
case DP_DYNAMIC_RANGE_RGB_VESA: case DP_DYNAMIC_RANGE_RGB_VESA:
default: default:

View File

@ -189,6 +189,98 @@ struct tu_algo_data {
s64 ratio; s64 ratio;
}; };
/**
* Mapper function which outputs colorimetry and dynamic range
* to be used for a given colorspace value when the vsc sdp
* packets are used to change the colorimetry.
*/
static void get_sdp_colorimetry_range(struct dp_panel_private *panel,
u32 colorspace, u32 *colorimetry, u32 *dynamic_range)
{
u32 cc;
/*
* Some rules being used for assignment of dynamic
* range for colorimetry using SDP:
*
* 1) If compliance test is ongoing return sRGB with
* CEA primaries
* 2) For BT2020 cases, dynamic range shall be CEA
* 3) For DCI-P3 cases, as per HW team dynamic range
* shall be VESA for RGB and CEA for YUV content
* Hence defaulting to RGB and picking VESA
* 4) Default shall be sRGB with VESA
*/
cc = panel->link->get_colorimetry_config(panel->link);
if (cc) {
*colorimetry = sRGB;
*dynamic_range = CEA;
return;
}
switch (colorspace) {
case DRM_MODE_COLORIMETRY_BT2020_RGB:
*colorimetry = ITU_R_BT_2020_RGB;
*dynamic_range = CEA;
break;
case DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65:
case DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER:
*colorimetry = DCI_P3;
*dynamic_range = VESA;
break;
default:
*colorimetry = sRGB;
*dynamic_range = VESA;
}
}
/**
* Mapper function which outputs colorimetry to be used for a
* given colorspace value when misc field of MSA is used to
* change the colorimetry. Currently only RGB formats have been
* added. This API will be extended to YUV once its supported on DP.
*/
static u8 get_misc_colorimetry_val(struct dp_panel_private *panel,
u32 colorspace)
{
u8 colorimetry;
u32 cc;
cc = panel->link->get_colorimetry_config(panel->link);
/*
* If there is a non-zero value then compliance test-case
* is going on, otherwise we can honor the colorspace setting
*/
if (cc)
return cc;
switch (colorspace) {
case DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65:
case DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER:
colorimetry = 0x7;
break;
case DRM_MODE_DP_COLORIMETRY_SRGB:
colorimetry = 0x4;
break;
case DRM_MODE_DP_COLORIMETRY_RGB_WIDE_GAMUT:
colorimetry = 0x3;
break;
case DRM_MODE_DP_COLORIMETRY_SCRGB:
colorimetry = 0xb;
break;
case DRM_MODE_COLORIMETRY_OPRGB:
colorimetry = 0xc;
break;
default:
colorimetry = 0;
}
return colorimetry;
}
static int _tu_param_compare(s64 a, s64 b) static int _tu_param_compare(s64 a, s64 b)
{ {
u32 a_int, a_frac, a_sign; u32 a_int, a_frac, a_sign;
@ -2485,7 +2577,11 @@ static int dp_panel_deinit_panel_info(struct dp_panel *dp_panel, u32 flags)
{ {
int rc = 0; int rc = 0;
struct dp_panel_private *panel; struct dp_panel_private *panel;
struct dp_catalog_hdr_data *hdr; struct drm_msm_ext_hdr_metadata *hdr_meta;
struct dp_sdp_header *dhdr_vsif_sdp;
struct sde_connector *sde_conn;
struct dp_sdp_header *shdr_if_sdp;
struct dp_catalog_vsc_sdp_colorimetry *vsc_colorimetry;
struct drm_connector *connector; struct drm_connector *connector;
struct sde_connector_state *c_state; struct sde_connector_state *c_state;
@ -2500,17 +2596,26 @@ static int dp_panel_deinit_panel_info(struct dp_panel *dp_panel, u32 flags)
} }
panel = container_of(dp_panel, struct dp_panel_private, dp_panel); panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
hdr = &panel->catalog->hdr_data; hdr_meta = &panel->catalog->hdr_meta;
dhdr_vsif_sdp = &panel->catalog->dhdr_vsif_sdp;
shdr_if_sdp = &panel->catalog->shdr_if_sdp;
vsc_colorimetry = &panel->catalog->vsc_colorimetry;
if (!panel->custom_edid && dp_panel->edid_ctrl->edid) if (!panel->custom_edid && dp_panel->edid_ctrl->edid)
sde_free_edid((void **)&dp_panel->edid_ctrl); sde_free_edid((void **)&dp_panel->edid_ctrl);
dp_panel_set_stream_info(dp_panel, DP_STREAM_MAX, 0, 0, 0, 0); dp_panel_set_stream_info(dp_panel, DP_STREAM_MAX, 0, 0, 0, 0);
memset(&dp_panel->pinfo, 0, sizeof(dp_panel->pinfo)); memset(&dp_panel->pinfo, 0, sizeof(dp_panel->pinfo));
memset(&hdr->hdr_meta, 0, sizeof(hdr->hdr_meta)); memset(hdr_meta, 0, sizeof(struct drm_msm_ext_hdr_metadata));
memset(dhdr_vsif_sdp, 0, sizeof(struct dp_sdp_header));
memset(shdr_if_sdp, 0, sizeof(struct dp_sdp_header));
memset(vsc_colorimetry, 0,
sizeof(struct dp_catalog_vsc_sdp_colorimetry));
panel->panel_on = false; panel->panel_on = false;
connector = dp_panel->connector; connector = dp_panel->connector;
sde_conn = to_sde_connector(connector);
c_state = to_sde_connector_state(connector->state); c_state = to_sde_connector_state(connector->state);
connector->hdr_eotf = 0; connector->hdr_eotf = 0;
@ -2521,6 +2626,8 @@ static int dp_panel_deinit_panel_info(struct dp_panel *dp_panel, u32 flags)
connector->hdr_supported = false; connector->hdr_supported = false;
connector->hdr_plus_app_ver = 0; connector->hdr_plus_app_ver = 0;
sde_conn->colorspace_updated = false;
memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta)); memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta));
memset(&c_state->dyn_hdr_meta, 0, sizeof(c_state->dyn_hdr_meta)); memset(&c_state->dyn_hdr_meta, 0, sizeof(c_state->dyn_hdr_meta));
@ -2651,14 +2758,133 @@ static u32 dp_panel_calc_dhdr_pkt_limit(struct dp_panel *dp_panel,
return calc_pkt_limit; return calc_pkt_limit;
} }
static void dp_panel_setup_colorimetry_sdp(struct dp_panel *dp_panel,
u32 cspace)
{
struct dp_panel_private *panel;
struct dp_catalog_vsc_sdp_colorimetry *hdr_colorimetry;
u8 bpc;
u32 colorimetry = 0;
u32 dynamic_range = 0;
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
hdr_colorimetry = &panel->catalog->vsc_colorimetry;
hdr_colorimetry->header.HB0 = 0x00;
hdr_colorimetry->header.HB1 = 0x07;
hdr_colorimetry->header.HB2 = 0x05;
hdr_colorimetry->header.HB3 = 0x13;
get_sdp_colorimetry_range(panel, cspace, &colorimetry,
&dynamic_range);
/* VSC SDP Payload for DB16 */
hdr_colorimetry->data[16] = (RGB << 4) | colorimetry;
/* VSC SDP Payload for DB17 */
hdr_colorimetry->data[17] = (dynamic_range << 7);
bpc = (dp_panel->pinfo.bpp / 3);
switch (bpc) {
default:
case 10:
hdr_colorimetry->data[17] |= BIT(1);
break;
case 8:
hdr_colorimetry->data[17] |= BIT(0);
break;
case 6:
hdr_colorimetry->data[17] |= 0;
break;
}
/* VSC SDP Payload for DB18 */
hdr_colorimetry->data[18] = GRAPHICS;
}
static void dp_panel_setup_hdr_if(struct dp_panel_private *panel)
{
struct dp_sdp_header *shdr_if;
shdr_if = &panel->catalog->shdr_if_sdp;
shdr_if->HB0 = 0x00;
shdr_if->HB1 = 0x87;
shdr_if->HB2 = 0x1D;
shdr_if->HB3 = 0x13 << 2;
}
static void dp_panel_setup_dhdr_vsif(struct dp_panel_private *panel)
{
struct dp_sdp_header *dhdr_vsif;
dhdr_vsif = &panel->catalog->dhdr_vsif_sdp;
dhdr_vsif->HB0 = 0x00;
dhdr_vsif->HB1 = 0x81;
dhdr_vsif->HB2 = 0x1D;
dhdr_vsif->HB3 = 0x13 << 2;
}
static void dp_panel_setup_misc_colorimetry(struct dp_panel *dp_panel,
u32 colorspace)
{
struct dp_panel_private *panel;
struct dp_catalog_panel *catalog;
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
catalog = panel->catalog;
catalog->misc_val &= ~0x1e;
catalog->misc_val |= (get_misc_colorimetry_val(panel,
colorspace) << 1);
}
static int dp_panel_set_colorspace(struct dp_panel *dp_panel,
u32 colorspace)
{
int rc = 0;
struct dp_panel_private *panel;
if (!dp_panel) {
pr_err("invalid input\n");
rc = -EINVAL;
goto end;
}
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
if (panel->vsc_supported)
dp_panel_setup_colorimetry_sdp(dp_panel,
colorspace);
else
dp_panel_setup_misc_colorimetry(dp_panel,
colorspace);
/*
* During the first frame update panel_on will be false and
* the colorspace will be cached in the connector's state which
* shall be used in the dp_panel_hw_cfg
*/
if (panel->panel_on) {
DP_DEBUG("panel is ON programming colorspace\n");
rc = panel->catalog->set_colorspace(panel->catalog,
panel->vsc_supported);
}
end:
return rc;
}
static int dp_panel_setup_hdr(struct dp_panel *dp_panel, static int dp_panel_setup_hdr(struct dp_panel *dp_panel,
struct drm_msm_ext_hdr_metadata *hdr_meta, struct drm_msm_ext_hdr_metadata *hdr_meta,
bool dhdr_update, u64 core_clk_rate) bool dhdr_update, u64 core_clk_rate, bool flush)
{ {
int rc = 0, max_pkts = 0; int rc = 0, max_pkts = 0;
struct dp_panel_private *panel; struct dp_panel_private *panel;
struct dp_catalog_hdr_data *hdr;
struct dp_dhdr_maxpkt_calc_input input; struct dp_dhdr_maxpkt_calc_input input;
struct drm_msm_ext_hdr_metadata *catalog_hdr_meta;
if (!dp_panel) { if (!dp_panel) {
DP_ERR("invalid input\n"); DP_ERR("invalid input\n");
@ -2667,11 +2893,12 @@ static int dp_panel_setup_hdr(struct dp_panel *dp_panel,
} }
panel = container_of(dp_panel, struct dp_panel_private, dp_panel); panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
hdr = &panel->catalog->hdr_data;
catalog_hdr_meta = &panel->catalog->hdr_meta;
/* use cached meta data in case meta data not provided */ /* use cached meta data in case meta data not provided */
if (!hdr_meta) { if (!hdr_meta) {
if (hdr->hdr_meta.hdr_state) if (catalog_hdr_meta->hdr_state)
goto cached; goto cached;
else else
goto end; goto end;
@ -2679,41 +2906,18 @@ static int dp_panel_setup_hdr(struct dp_panel *dp_panel,
panel->hdr_state = hdr_meta->hdr_state; panel->hdr_state = hdr_meta->hdr_state;
hdr->vsc_header_byte0 = 0x00; dp_panel_setup_hdr_if(panel);
hdr->vsc_header_byte1 = 0x07;
hdr->vsc_header_byte2 = 0x05;
hdr->vsc_header_byte3 = 0x13;
hdr->shdr_header_byte0 = 0x00; if (panel->hdr_state) {
hdr->shdr_header_byte1 = 0x87; memcpy(catalog_hdr_meta, hdr_meta,
hdr->shdr_header_byte2 = 0x1D; sizeof(struct drm_msm_ext_hdr_metadata));
hdr->shdr_header_byte3 = 0x13 << 2; } else {
memset(catalog_hdr_meta, 0,
/* VSC SDP Payload for DB16 */ sizeof(struct drm_msm_ext_hdr_metadata));
hdr->pixel_encoding = RGB; }
hdr->colorimetry = ITU_R_BT_2020_RGB;
/* VSC SDP Payload for DB17 */
hdr->dynamic_range = CEA;
/* VSC SDP Payload for DB18 */
hdr->content_type = GRAPHICS;
hdr->bpc = dp_panel->pinfo.bpp / 3;
hdr->version = 0x01;
hdr->length = 0x1A;
if (panel->hdr_state)
memcpy(&hdr->hdr_meta, hdr_meta, sizeof(hdr->hdr_meta));
else
memset(&hdr->hdr_meta, 0, sizeof(hdr->hdr_meta));
cached: cached:
if (dhdr_update) { if (dhdr_update) {
hdr->vscext_header_byte0 = 0x00; dp_panel_setup_dhdr_vsif(panel);
hdr->vscext_header_byte1 = 0x81;
hdr->vscext_header_byte2 = 0x1D;
hdr->vscext_header_byte3 = 0x13 << 2;
input.mdp_clk = core_clk_rate; input.mdp_clk = core_clk_rate;
input.lclk = dp_panel->link_info.rate; input.lclk = dp_panel->link_info.rate;
@ -2729,7 +2933,7 @@ cached:
if (panel->panel_on) { if (panel->panel_on) {
panel->catalog->stream_id = dp_panel->stream_id; panel->catalog->stream_id = dp_panel->stream_id;
panel->catalog->config_hdr(panel->catalog, panel->hdr_state, panel->catalog->config_hdr(panel->catalog, panel->hdr_state,
max_pkts); max_pkts, flush);
if (dhdr_update) if (dhdr_update)
panel->catalog->dhdr_flush(panel->catalog); panel->catalog->dhdr_flush(panel->catalog);
} }
@ -2808,19 +3012,29 @@ static void dp_panel_config_misc(struct dp_panel *dp_panel)
{ {
struct dp_panel_private *panel; struct dp_panel_private *panel;
struct dp_catalog_panel *catalog; struct dp_catalog_panel *catalog;
struct drm_connector *connector;
u32 misc_val; u32 misc_val;
u32 tb, cc; u32 tb, cc, colorspace;
panel = container_of(dp_panel, struct dp_panel_private, dp_panel); panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
catalog = panel->catalog; catalog = panel->catalog;
connector = dp_panel->connector;
cc = 0;
tb = panel->link->get_test_bits_depth(panel->link, dp_panel->pinfo.bpp); tb = panel->link->get_test_bits_depth(panel->link, dp_panel->pinfo.bpp);
cc = panel->link->get_colorimetry_config(panel->link); colorspace = connector->state->colorspace;
cc = (get_misc_colorimetry_val(panel, colorspace) << 1);
misc_val = cc; misc_val = cc;
misc_val |= (tb << 5); misc_val |= (tb << 5);
misc_val |= BIT(0); /* Configure clock to synchronous mode */ misc_val |= BIT(0); /* Configure clock to synchronous mode */
/* if VSC is supported then set bit 6 of MISC1 */
if (panel->vsc_supported)
misc_val |= BIT(14);
catalog->misc_val = misc_val; catalog->misc_val = misc_val;
catalog->config_misc(catalog); catalog->config_misc(catalog);
} }
@ -2862,9 +3076,21 @@ static void dp_panel_resolution_info(struct dp_panel_private *panel)
panel->link->link_params.lane_count); panel->link->link_params.lane_count);
} }
static void dp_panel_config_sdp(struct dp_panel *dp_panel,
bool en)
{
struct dp_panel_private *panel;
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
panel->catalog->stream_id = dp_panel->stream_id;
panel->catalog->config_sdp(panel->catalog, en);
}
static int dp_panel_hw_cfg(struct dp_panel *dp_panel, bool enable) static int dp_panel_hw_cfg(struct dp_panel *dp_panel, bool enable)
{ {
struct dp_panel_private *panel; struct dp_panel_private *panel;
struct drm_connector *connector;
if (!dp_panel) { if (!dp_panel) {
DP_ERR("invalid input\n"); DP_ERR("invalid input\n");
@ -2878,15 +3104,23 @@ static int dp_panel_hw_cfg(struct dp_panel *dp_panel, bool enable)
panel = container_of(dp_panel, struct dp_panel_private, dp_panel); panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
panel->catalog->stream_id = dp_panel->stream_id; panel->catalog->stream_id = dp_panel->stream_id;
connector = dp_panel->connector;
if (enable) { if (enable) {
dp_panel_config_ctrl(dp_panel); dp_panel_config_ctrl(dp_panel);
dp_panel_config_misc(dp_panel); dp_panel_config_misc(dp_panel);
dp_panel_config_msa(dp_panel); dp_panel_config_msa(dp_panel);
if (panel->vsc_supported) {
dp_panel_setup_colorimetry_sdp(dp_panel,
connector->state->colorspace);
dp_panel_config_sdp(dp_panel, true);
}
dp_panel_config_dsc(dp_panel, enable); dp_panel_config_dsc(dp_panel, enable);
dp_panel_config_tr_unit(dp_panel); dp_panel_config_tr_unit(dp_panel);
dp_panel_config_timing(dp_panel); dp_panel_config_timing(dp_panel);
dp_panel_resolution_info(panel); dp_panel_resolution_info(panel);
} else {
dp_panel_config_sdp(dp_panel, false);
} }
panel->catalog->config_dto(panel->catalog, !enable); panel->catalog->config_dto(panel->catalog, !enable);
@ -3100,6 +3334,7 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in)
dp_panel->tpg_config = dp_panel_tpg_config; dp_panel->tpg_config = dp_panel_tpg_config;
dp_panel->spd_config = dp_panel_spd_config; dp_panel->spd_config = dp_panel_spd_config;
dp_panel->setup_hdr = dp_panel_setup_hdr; dp_panel->setup_hdr = dp_panel_setup_hdr;
dp_panel->set_colorspace = dp_panel_set_colorspace;
dp_panel->hdr_supported = dp_panel_hdr_supported; dp_panel->hdr_supported = dp_panel_hdr_supported;
dp_panel->set_stream_info = dp_panel_set_stream_info; dp_panel->set_stream_info = dp_panel_set_stream_info;
dp_panel->read_sink_status = dp_panel_read_sink_sts; dp_panel->read_sink_status = dp_panel_read_sink_sts;

View File

@ -150,7 +150,9 @@ struct dp_panel {
int (*set_dpcd)(struct dp_panel *dp_panel, u8 *dpcd); int (*set_dpcd)(struct dp_panel *dp_panel, u8 *dpcd);
int (*setup_hdr)(struct dp_panel *dp_panel, int (*setup_hdr)(struct dp_panel *dp_panel,
struct drm_msm_ext_hdr_metadata *hdr_meta, struct drm_msm_ext_hdr_metadata *hdr_meta,
bool dhdr_update, u64 core_clk_rate); bool dhdr_update, u64 core_clk_rate, bool flush);
int (*set_colorspace)(struct dp_panel *dp_panel,
u32 colorspace);
void (*tpg_config)(struct dp_panel *dp_panel, bool enable); void (*tpg_config)(struct dp_panel *dp_panel, bool enable);
int (*spd_config)(struct dp_panel *dp_panel); int (*spd_config)(struct dp_panel *dp_panel);
bool (*hdr_supported)(struct dp_panel *dp_panel); bool (*hdr_supported)(struct dp_panel *dp_panel);

View File

@ -190,6 +190,7 @@ enum msm_mdp_conn_property {
CONNECTOR_PROP_ROI_V1, CONNECTOR_PROP_ROI_V1,
CONNECTOR_PROP_BL_SCALE, CONNECTOR_PROP_BL_SCALE,
CONNECTOR_PROP_SV_BL_SCALE, CONNECTOR_PROP_SV_BL_SCALE,
CONNECTOR_PROP_SUPPORTED_COLORSPACES,
/* enum/bitmask properties */ /* enum/bitmask properties */
CONNECTOR_PROP_TOPOLOGY_NAME, CONNECTOR_PROP_TOPOLOGY_NAME,

View File

@ -606,6 +606,19 @@ static int _sde_connector_update_bl_scale(struct sde_connector *c_conn)
return rc; return rc;
} }
void sde_connector_set_colorspace(struct sde_connector *c_conn)
{
int rc = 0;
if (c_conn->ops.set_colorspace)
rc = c_conn->ops.set_colorspace(&c_conn->base,
c_conn->display);
if (rc)
SDE_ERROR_CONN(c_conn, "cannot apply new colorspace %d\n", rc);
}
void sde_connector_set_qsync_params(struct drm_connector *connector) void sde_connector_set_qsync_params(struct drm_connector *connector)
{ {
struct sde_connector *c_conn = to_sde_connector(connector); struct sde_connector *c_conn = to_sde_connector(connector);
@ -680,6 +693,12 @@ static int _sde_connector_update_dirty_properties(
} }
} }
/* if colorspace needs to be updated do it first */
if (c_conn->colorspace_updated) {
c_conn->colorspace_updated = false;
sde_connector_set_colorspace(c_conn);
}
/* /*
* Special handling for postproc properties and * Special handling for postproc properties and
* for updating backlight if any unset backlight level is present * for updating backlight if any unset backlight level is present
@ -1480,6 +1499,20 @@ static void sde_connector_update_hdr_props(struct drm_connector *connector)
&hdr, sizeof(hdr), CONNECTOR_PROP_EXT_HDR_INFO); &hdr, sizeof(hdr), CONNECTOR_PROP_EXT_HDR_INFO);
} }
static void sde_connector_update_colorspace(struct drm_connector *connector)
{
int ret;
ret = msm_property_set_property(
sde_connector_get_propinfo(connector),
sde_connector_get_property_state(connector->state),
CONNECTOR_PROP_SUPPORTED_COLORSPACES,
connector->color_enc_fmt);
if (ret)
SDE_ERROR("failed to set colorspace property for connector\n");
}
static enum drm_connector_status static enum drm_connector_status
sde_connector_detect(struct drm_connector *connector, bool force) sde_connector_detect(struct drm_connector *connector, bool force)
{ {
@ -1920,6 +1953,9 @@ static int sde_connector_get_modes(struct drm_connector *connector)
if (c_conn->hdr_capable) if (c_conn->hdr_capable)
sde_connector_update_hdr_props(connector); sde_connector_update_hdr_props(connector);
if (c_conn->connector_type == DRM_MODE_CONNECTOR_DisplayPort)
sde_connector_update_colorspace(connector);
return mode_count; return mode_count;
} }
@ -2118,6 +2154,7 @@ static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
.get_modes = sde_connector_get_modes, .get_modes = sde_connector_get_modes,
.mode_valid = sde_connector_mode_valid, .mode_valid = sde_connector_mode_valid,
.best_encoder = sde_connector_best_encoder, .best_encoder = sde_connector_best_encoder,
.atomic_check = sde_connector_atomic_check,
}; };
static const struct drm_connector_helper_funcs sde_connector_helper_ops_v2 = { static const struct drm_connector_helper_funcs sde_connector_helper_ops_v2 = {
@ -2295,6 +2332,7 @@ static int _sde_connector_install_properties(struct drm_device *dev,
{ {
struct dsi_display *dsi_display; struct dsi_display *dsi_display;
int rc; int rc;
struct drm_connector *connector;
msm_property_install_blob(&c_conn->property_info, "capabilities", msm_property_install_blob(&c_conn->property_info, "capabilities",
DRM_MODE_PROP_IMMUTABLE, CONNECTOR_PROP_SDE_INFO); DRM_MODE_PROP_IMMUTABLE, CONNECTOR_PROP_SDE_INFO);
@ -2307,6 +2345,8 @@ static int _sde_connector_install_properties(struct drm_device *dev,
return rc; return rc;
} }
connector = &c_conn->base;
msm_property_install_blob(&c_conn->property_info, "mode_properties", msm_property_install_blob(&c_conn->property_info, "mode_properties",
DRM_MODE_PROP_IMMUTABLE, CONNECTOR_PROP_MODE_INFO); DRM_MODE_PROP_IMMUTABLE, CONNECTOR_PROP_MODE_INFO);
@ -2350,6 +2390,11 @@ static int _sde_connector_install_properties(struct drm_device *dev,
&hdr, &hdr,
sizeof(hdr), sizeof(hdr),
CONNECTOR_PROP_EXT_HDR_INFO); CONNECTOR_PROP_EXT_HDR_INFO);
/* create and attach colorspace property for DP */
if (!drm_mode_create_colorspace_property(connector))
drm_object_attach_property(&connector->base,
connector->colorspace_property, 0);
} }
msm_property_install_volatile_range(&c_conn->property_info, msm_property_install_volatile_range(&c_conn->property_info,
@ -2389,6 +2434,12 @@ static int _sde_connector_install_properties(struct drm_device *dev,
c_conn->bl_scale = MAX_BL_SCALE_LEVEL; c_conn->bl_scale = MAX_BL_SCALE_LEVEL;
c_conn->bl_scale_sv = MAX_SV_BL_SCALE_LEVEL; c_conn->bl_scale_sv = MAX_SV_BL_SCALE_LEVEL;
if (connector_type == DRM_MODE_CONNECTOR_DisplayPort)
msm_property_install_range(&c_conn->property_info,
"supported_colorspaces",
DRM_MODE_PROP_IMMUTABLE, 0, 0xffff, 0,
CONNECTOR_PROP_SUPPORTED_COLORSPACES);
/* enum/bitmask properties */ /* enum/bitmask properties */
msm_property_install_enum(&c_conn->property_info, "topology_name", msm_property_install_enum(&c_conn->property_info, "topology_name",
DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name, DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,

View File

@ -168,6 +168,14 @@ struct sde_connector_ops {
int (*set_backlight)(struct drm_connector *connector, int (*set_backlight)(struct drm_connector *connector,
void *display, u32 bl_lvl); void *display, u32 bl_lvl);
/**
* set_colorspace - set colorspace for connector
* @connector: Pointer to drm connector structure
* @display: Pointer to private display structure
*/
int (*set_colorspace)(struct drm_connector *connector,
void *display);
/** /**
* soft_reset - perform a soft reset on the connector * soft_reset - perform a soft reset on the connector
* @display: Pointer to private display structure * @display: Pointer to private display structure
@ -400,6 +408,7 @@ struct sde_connector_dyn_hdr_metadata {
* @allow_bl_update: Flag to indicate if BL update is allowed currently or not * @allow_bl_update: Flag to indicate if BL update is allowed currently or not
* @qsync_mode: Cached Qsync mode, 0=disabled, 1=continuous mode * @qsync_mode: Cached Qsync mode, 0=disabled, 1=continuous mode
* @qsync_updated: Qsync settings were updated * @qsync_updated: Qsync settings were updated
* @colorspace_updated: Colorspace property was updated
* last_cmd_tx_sts: status of the last command transfer * last_cmd_tx_sts: status of the last command transfer
* @hdr_capable: external hdr support present * @hdr_capable: external hdr support present
* @core_clk_rate: MDP core clk rate used for dynamic HDR packet calculation * @core_clk_rate: MDP core clk rate used for dynamic HDR packet calculation
@ -452,6 +461,8 @@ struct sde_connector {
u32 qsync_mode; u32 qsync_mode;
bool qsync_updated; bool qsync_updated;
bool colorspace_updated;
bool last_cmd_tx_sts; bool last_cmd_tx_sts;
bool hdr_capable; bool hdr_capable;
}; };

View File

@ -1222,11 +1222,13 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
.post_init = dp_connector_post_init, .post_init = dp_connector_post_init,
.detect = dp_connector_detect, .detect = dp_connector_detect,
.get_modes = dp_connector_get_modes, .get_modes = dp_connector_get_modes,
.atomic_check = dp_connector_atomic_check,
.mode_valid = dp_connector_mode_valid, .mode_valid = dp_connector_mode_valid,
.get_info = dp_connector_get_info, .get_info = dp_connector_get_info,
.get_mode_info = dp_connector_get_mode_info, .get_mode_info = dp_connector_get_mode_info,
.post_open = dp_connector_post_open, .post_open = dp_connector_post_open,
.check_status = NULL, .check_status = NULL,
.set_colorspace = dp_connector_set_colorspace,
.config_hdr = dp_connector_config_hdr, .config_hdr = dp_connector_config_hdr,
.cmd_transfer = NULL, .cmd_transfer = NULL,
.cont_splash_config = NULL, .cont_splash_config = NULL,