drm/msm/dp: add dsc-over-dp implementation

Add changes in all dp submodules to enable
dsc-over-dp feature. Update parser module to
extract the dsc and fec capabilities, debug
module to control dsc on/off per hpd session,
panel module to decode sink device's dsc caps
and to prepare the dsc configuration data.

CRs-Fixed: 2325207
Change-Id: I9dcc066950d3e427e69fd955ae7f0f49e9828657
Signed-off-by: Govinda Rajulu Chenna <gchenna@codeaurora.org>
tirimbino
Govinda Rajulu Chenna 6 years ago committed by Gerrit - the friendly Code Review server
parent 1afe095279
commit a94ae9ff4a
  1. 145
      drivers/gpu/drm/msm/dp/dp_catalog.c
  2. 26
      drivers/gpu/drm/msm/dp/dp_catalog.h
  3. 40
      drivers/gpu/drm/msm/dp/dp_ctrl.c
  4. 3
      drivers/gpu/drm/msm/dp/dp_ctrl.h
  5. 16
      drivers/gpu/drm/msm/dp/dp_debug.c
  6. 26
      drivers/gpu/drm/msm/dp/dp_display.c
  7. 2
      drivers/gpu/drm/msm/dp/dp_display.h
  8. 31
      drivers/gpu/drm/msm/dp/dp_drm.c
  9. 9
      drivers/gpu/drm/msm/dp/dp_drm.h
  10. 1
      drivers/gpu/drm/msm/dp/dp_mst_drm.c
  11. 825
      drivers/gpu/drm/msm/dp/dp_panel.c
  12. 25
      drivers/gpu/drm/msm/dp/dp_panel.h
  13. 33
      drivers/gpu/drm/msm/dp/dp_parser.c
  14. 8
      drivers/gpu/drm/msm/dp/dp_parser.h
  15. 67
      drivers/gpu/drm/msm/dp/dp_reg.h
  16. 1
      drivers/gpu/drm/msm/sde/sde_kms.c

@ -779,6 +779,7 @@ static void dp_catalog_panel_config_dto(struct dp_catalog_panel *panel,
{
struct dp_catalog_private *catalog;
struct dp_io_data *io_data;
u32 dsc_dto;
if (!panel) {
pr_err("invalid input\n");
@ -805,7 +806,12 @@ static void dp_catalog_panel_config_dto(struct dp_catalog_panel *panel,
return;
}
dp_write(catalog->exe_mode, io_data, MMSS_DP_DSC_DTO, ack << 1);
dsc_dto = dp_read(catalog->exe_mode, io_data, MMSS_DP_DSC_DTO);
if (ack)
dsc_dto = BIT(1);
else
dsc_dto &= ~BIT(1);
dp_write(catalog->exe_mode, io_data, MMSS_DP_DSC_DTO, dsc_dto);
}
static void dp_catalog_ctrl_lane_mapping(struct dp_catalog_ctrl *ctrl,
@ -1126,6 +1132,107 @@ static void dp_catalog_panel_tpg_cfg(struct dp_catalog_panel *panel,
wmb(); /* ensure Timing generator is turned on */
}
static void dp_catalog_panel_dsc_cfg(struct dp_catalog_panel *panel)
{
struct dp_catalog_private *catalog;
struct dp_io_data *io_data;
u32 reg, offset;
int i;
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);
if (panel->stream_id == DP_STREAM_0)
io_data = catalog->io.dp_p0;
else
io_data = catalog->io.dp_p1;
dp_write(catalog->exe_mode, io_data, MMSS_DP_DSC_DTO_COUNT,
panel->dsc.dto_count);
reg = dp_read(catalog->exe_mode, io_data, MMSS_DP_DSC_DTO);
if (panel->dsc.dto_en) {
reg |= BIT(0);
reg |= (panel->dsc.dto_n << 8);
reg |= (panel->dsc.dto_d << 16);
}
dp_write(catalog->exe_mode, io_data, MMSS_DP_DSC_DTO, reg);
io_data = catalog->io.dp_link;
if (panel->stream_id == DP_STREAM_0)
offset = 0;
else
offset = DP1_COMPRESSION_MODE_CTRL - DP_COMPRESSION_MODE_CTRL;
dp_write(catalog->exe_mode, io_data, DP_PPS_HB_0_3 + offset, 0x7F1000);
dp_write(catalog->exe_mode, io_data, DP_PPS_PB_0_3 + offset, 0xA22300);
for (i = 0; i < panel->dsc.parity_word_len; i++)
dp_write(catalog->exe_mode, io_data,
DP_PPS_PB_4_7 + (i << 2) + offset,
panel->dsc.parity_word[i]);
for (i = 0; i < panel->dsc.pps_word_len; i++)
dp_write(catalog->exe_mode, io_data,
DP_PPS_PPS_0_3 + (i << 2) + offset,
panel->dsc.pps_word[i]);
reg = 0;
if (panel->dsc.dsc_en) {
reg = BIT(0);
reg |= (panel->dsc.eol_byte_num << 3);
reg |= (panel->dsc.slice_per_pkt << 5);
reg |= (panel->dsc.bytes_per_pkt << 16);
reg |= (panel->dsc.be_in_lane << 10);
}
dp_write(catalog->exe_mode, io_data,
DP_COMPRESSION_MODE_CTRL + offset, reg);
pr_debug("compression:0x%x for stream:%d\n",
reg, panel->stream_id);
}
static void dp_catalog_panel_pps_flush(struct dp_catalog_panel *panel)
{
struct dp_catalog_private *catalog;
struct dp_io_data *io_data;
u32 dp_flush, offset;
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_0)
offset = 0;
else
offset = MMSS_DP1_FLUSH - MMSS_DP_FLUSH;
dp_flush = dp_read(catalog->exe_mode, io_data, MMSS_DP_FLUSH + offset);
dp_flush |= BIT(0);
dp_write(catalog->exe_mode, io_data, MMSS_DP_FLUSH + offset, dp_flush);
pr_debug("pps flush for stream:%d\n", panel->stream_id);
}
static void dp_catalog_ctrl_reset(struct dp_catalog_ctrl *ctrl)
{
u32 sw_reset;
@ -1457,6 +1564,39 @@ static u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog_ctrl *ctrl)
return dp_read(catalog->exe_mode, io_data, DP_MAINLINK_READY);
}
static void dp_catalog_ctrl_fec_config(struct dp_catalog_ctrl *ctrl,
bool enable)
{
struct dp_catalog_private *catalog;
struct dp_io_data *io_data = NULL;
u32 reg;
if (!ctrl) {
pr_err("invalid input\n");
return;
}
catalog = dp_catalog_get_priv(ctrl);
io_data = catalog->io.dp_link;
reg = dp_read(catalog->exe_mode, io_data, DP_MAINLINK_CTRL);
/*
* fec_en = BIT(12)
* fec_seq_mode = BIT(22)
* sde_flush = BIT(23) | BIT(24)
* fb_boundary_sel = BIT(25)
*/
if (enable)
reg |= BIT(12) | BIT(22) | BIT(23) | BIT(24) | BIT(25);
else
reg &= ~BIT(12);
dp_write(catalog->exe_mode, io_data, DP_MAINLINK_CTRL, reg);
/* make sure mainlink configuration is updated with fec sequence */
wmb();
}
static int dp_catalog_reg_dump(struct dp_catalog *dp_catalog,
char *name, u8 **out_buf, u32 *out_buf_len)
{
@ -2276,6 +2416,7 @@ struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_parser *parser)
.channel_alloc = dp_catalog_ctrl_channel_alloc,
.update_rg = dp_catalog_ctrl_update_rg,
.channel_dealloc = dp_catalog_ctrl_channel_dealloc,
.fec_config = dp_catalog_ctrl_fec_config,
};
struct dp_catalog_audio audio = {
.init = dp_catalog_audio_init,
@ -2296,6 +2437,8 @@ struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_parser *parser)
.update_transfer_unit = dp_catalog_panel_update_transfer_unit,
.config_ctrl = dp_catalog_panel_config_ctrl,
.config_dto = dp_catalog_panel_config_dto,
.dsc_cfg = dp_catalog_panel_dsc_cfg,
.pps_flush = dp_catalog_panel_pps_flush,
};
if (!dev || !parser) {

@ -128,6 +128,7 @@ struct dp_catalog_ctrl {
u32 y_frac_enum);
void (*channel_dealloc)(struct dp_catalog_ctrl *ctrl,
u32 ch, u32 ch_start_timeslot, u32 tot_ch_cnt);
void (*fec_config)(struct dp_catalog_ctrl *ctrl, bool enable);
};
#define HEADER_BYTE_2_BIT 0
@ -169,6 +170,26 @@ struct dp_catalog_audio {
void (*safe_to_exit_level)(struct dp_catalog_audio *audio);
};
struct dp_dsc_cfg_data {
bool dsc_en;
char pps[128];
u32 pps_len;
u32 pps_word[32];
u32 pps_word_len;
u8 parity[32];
u8 parity_len;
u32 parity_word[8];
u32 parity_word_len;
u32 slice_per_pkt;
u32 bytes_per_pkt;
u32 eol_byte_num;
u32 be_in_lane;
u32 dto_en;
u32 dto_n;
u32 dto_d;
u32 dto_count;
};
struct dp_catalog_panel {
u32 total;
u32 sync_start;
@ -198,6 +219,7 @@ struct dp_catalog_panel {
enum dp_stream_id stream_id;
bool widebus_en;
struct dp_dsc_cfg_data dsc;
int (*timing_cfg)(struct dp_catalog_panel *panel);
void (*config_hdr)(struct dp_catalog_panel *panel, bool en);
@ -209,6 +231,8 @@ struct dp_catalog_panel {
void (*update_transfer_unit)(struct dp_catalog_panel *panel);
void (*config_ctrl)(struct dp_catalog_panel *panel, u32 cfg);
void (*config_dto)(struct dp_catalog_panel *panel, bool ack);
void (*dsc_cfg)(struct dp_catalog_panel *panel);
void (*pps_flush)(struct dp_catalog_panel *panel);
};
struct dp_catalog;
@ -281,7 +305,7 @@ static inline u8 dp_header_get_parity(u32 data)
u8 iData = 0;
u8 i = 0;
u8 parity_byte;
u8 num_byte = (data & 0xFF00) > 0 ? 8 : 2;
u8 num_byte = (data > 0xFF) ? 8 : 2;
for (i = 0; i < num_byte; i++) {
iData = (data >> i*4) & 0xF;

@ -76,6 +76,7 @@ struct dp_ctrl_private {
bool orientation;
bool power_on;
bool mst_mode;
bool fec_mode;
atomic_t aborted;
@ -502,6 +503,7 @@ end:
static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl)
{
int ret = 0;
const unsigned int fec_cfg_dpcd = 0x120;
if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
goto end;
@ -513,6 +515,9 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl)
*/
ctrl->catalog->reset(ctrl->catalog);
if (ctrl->fec_mode)
drm_dp_dpcd_writeb(ctrl->aux->drm_aux, fec_cfg_dpcd, 0x01);
ret = dp_ctrl_link_train(ctrl);
end:
@ -801,7 +806,8 @@ static void dp_ctrl_process_phy_test_request(struct dp_ctrl *dp_ctrl)
ctrl->aux->init(ctrl->aux, ctrl->parser->aux_cfg);
ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl, ctrl->mst_mode, false);
ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl, ctrl->mst_mode,
ctrl->fec_mode, false);
if (ret)
pr_err("failed to enable DP controller\n");
@ -991,6 +997,30 @@ static void dp_ctrl_mst_stream_setup(struct dp_ctrl_private *ctrl,
lanes, bw_code, x_int, y_frac_enum);
}
static void dp_ctrl_fec_dsc_setup(struct dp_ctrl_private *ctrl)
{
u8 fec_sts = 0;
int rlen;
u32 dsc_enable;
const unsigned int fec_sts_dpcd = 0x280;
if (ctrl->stream_count || !ctrl->fec_mode)
return;
ctrl->catalog->fec_config(ctrl->catalog, ctrl->fec_mode);
/* wait for controller to start fec sequence */
usleep_range(900, 1000);
drm_dp_dpcd_readb(ctrl->aux->drm_aux, fec_sts_dpcd, &fec_sts);
pr_debug("sink fec status:%d\n", fec_sts);
dsc_enable = ctrl->fec_mode ? 1 : 0;
rlen = drm_dp_dpcd_writeb(ctrl->aux->drm_aux, DP_DSC_ENABLE,
dsc_enable);
if (rlen < 1)
pr_debug("failed to enable sink dsc\n");
}
static int dp_ctrl_stream_on(struct dp_ctrl *dp_ctrl, struct dp_panel *panel)
{
int rc = 0;
@ -1026,6 +1056,8 @@ static int dp_ctrl_stream_on(struct dp_ctrl *dp_ctrl, struct dp_panel *panel)
dp_ctrl_wait4video_ready(ctrl);
dp_ctrl_fec_dsc_setup(ctrl);
ctrl->stream_count++;
link_ready = ctrl->catalog->mainlink_ready(ctrl->catalog);
@ -1098,7 +1130,8 @@ static void dp_ctrl_stream_off(struct dp_ctrl *dp_ctrl, struct dp_panel *panel)
ctrl->stream_count--;
}
static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode, bool shallow)
static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode,
bool fec_mode, bool shallow)
{
int rc = 0;
struct dp_ctrl_private *ctrl;
@ -1120,6 +1153,7 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode, bool shallow)
}
ctrl->mst_mode = mst_mode;
ctrl->fec_mode = fec_mode;
rate = ctrl->panel->link_info.rate;
if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
@ -1165,6 +1199,7 @@ static void dp_ctrl_off(struct dp_ctrl *dp_ctrl)
dp_ctrl_disable_link_clock(ctrl);
ctrl->mst_mode = false;
ctrl->fec_mode = false;
ctrl->power_on = false;
memset(&ctrl->mst_ch_info, 0, sizeof(ctrl->mst_ch_info));
pr_debug("DP off done\n");
@ -1242,6 +1277,7 @@ struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in)
ctrl->catalog = in->catalog;
ctrl->dev = in->dev;
ctrl->mst_mode = false;
ctrl->fec_mode = false;
dp_ctrl = &ctrl->dp_ctrl;

@ -25,7 +25,8 @@
struct dp_ctrl {
int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool reset);
void (*deinit)(struct dp_ctrl *dp_ctrl);
int (*on)(struct dp_ctrl *dp_ctrl, bool mst_mode, bool shallow);
int (*on)(struct dp_ctrl *dp_ctrl, bool mst_mode, bool fec_en,
bool shallow);
void (*off)(struct dp_ctrl *dp_ctrl);
void (*abort)(struct dp_ctrl *dp_ctrl);
void (*isr)(struct dp_ctrl *dp_ctrl);

@ -1927,6 +1927,22 @@ static int dp_debug_init(struct dp_debug *dp_debug)
goto error_remove_dir;
}
file = debugfs_create_bool("dsc_feature_enable", 0644, dir,
&debug->parser->dsc_feature_enable);
if (IS_ERR_OR_NULL(file)) {
rc = PTR_ERR(file);
pr_err("[%s] debugfs dsc_feature failed, rc=%d\n",
DEBUG_NAME, rc);
}
file = debugfs_create_bool("fec_feature_enable", 0644, dir,
&debug->parser->fec_feature_enable);
if (IS_ERR_OR_NULL(file)) {
rc = PTR_ERR(file);
pr_err("[%s] debugfs fec_feature_enable failed, rc=%d\n",
DEBUG_NAME, rc);
}
file = debugfs_create_file("widebus_mode", 0644, dir,
debug, &widebus_mode_fops);
if (IS_ERR_OR_NULL(file)) {

@ -686,7 +686,8 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
dp_display_process_mst_hpd_high(dp);
mutex_lock(&dp->session_lock);
rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, false);
rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active,
dp->panel->fec_en, false);
if (rc) {
mutex_unlock(&dp->session_lock);
goto end;
@ -1400,7 +1401,7 @@ static int dp_display_prepare(struct dp_display *dp_display, void *panel)
* So, we execute in shallow mode here to do only minimal
* and required things.
*/
rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, true);
rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, dp_panel->fec_en, true);
if (rc)
goto end;
@ -2202,6 +2203,26 @@ static int dp_display_mst_connector_update_edid(struct dp_display *dp_display,
return rc;
}
static int dp_display_update_pps(struct dp_display *dp_display,
struct drm_connector *connector, char *pps_cmd)
{
struct sde_connector *sde_conn;
struct dp_panel *dp_panel;
struct dp_display_private *dp;
dp = container_of(dp_display, struct dp_display_private, dp_display);
sde_conn = to_sde_connector(connector);
if (!sde_conn->drv_panel) {
pr_err("invalid panel for connector:%d\n", connector->base.id);
return -EINVAL;
}
dp_panel = sde_conn->drv_panel;
dp_panel->update_pps(dp_panel, pps_cmd);
return 0;
}
static int dp_display_get_mst_caps(struct dp_display *dp_display,
struct dp_mst_caps *mst_caps)
{
@ -2287,6 +2308,7 @@ static int dp_display_probe(struct platform_device *pdev)
dp_display_mst_connector_update_edid;
g_dp_display->get_mst_caps = dp_display_get_mst_caps;
g_dp_display->set_stream_info = dp_display_set_stream_info;
g_dp_display->update_pps = dp_display_update_pps;
g_dp_display->convert_to_dp_mode = dp_display_convert_to_dp_mode;
g_dp_display->mst_get_connector_info =
dp_display_mst_get_connector_info;

@ -118,6 +118,8 @@ struct dp_display {
void (*convert_to_dp_mode)(struct dp_display *dp_display, void *panel,
const struct drm_display_mode *drm_mode,
struct dp_display_mode *dp_mode);
int (*update_pps)(struct dp_display *dp_display,
struct drm_connector *connector, char *pps_cmd);
};
int dp_display_get_num_of_displays(void);

@ -374,6 +374,7 @@ int dp_connector_get_mode_info(struct drm_connector *connector,
struct msm_display_topology *topology;
struct sde_connector *sde_conn;
struct dp_panel *dp_panel;
struct dp_display_mode dp_mode;
if (!drm_mode || !mode_info || !max_mixer_width || !connector) {
pr_err("invalid params\n");
@ -396,6 +397,15 @@ int dp_connector_get_mode_info(struct drm_connector *connector,
mode_info->wide_bus_en = dp_panel->widebus_en;
if (dp_panel->dsc_en) {
dp_panel->convert_to_dp_mode(dp_panel, drm_mode, &dp_mode);
memcpy(&mode_info->comp_info,
&dp_mode.timing.comp_info,
sizeof(mode_info->comp_info));
topology->num_enc = topology->num_lm;
}
return 0;
}
@ -596,3 +606,24 @@ enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector,
return dp_disp->validate_mode(dp_disp, sde_conn->drv_panel, mode);
}
int dp_connector_update_pps(struct drm_connector *connector,
char *pps_cmd, void *display)
{
struct dp_display *dp_disp;
struct sde_connector *sde_conn;
if (!display || !connector) {
pr_err("invalid params\n");
return -EINVAL;
}
sde_conn = to_sde_connector(connector);
if (!sde_conn->drv_panel) {
pr_err("invalid dp panel\n");
return MODE_ERROR;
}
dp_disp = display;
return dp_disp->update_pps(dp_disp, connector, pps_cmd);
}

@ -127,6 +127,15 @@ void dp_drm_bridge_deinit(void *display);
void convert_to_drm_mode(const struct dp_display_mode *dp_mode,
struct drm_display_mode *drm_mode);
/**
* dp_connector_update_pps - update pps for given connector
* @dp_mode: Point to dp mode
* @pps_cmd: PPS packet
* @display: Pointer to private display structure
*/
int dp_connector_update_pps(struct drm_connector *connector,
char *pps_cmd, void *display);
/**
* dp_mst_drm_bridge_init - initialize mst bridge
* @display: Pointer to private display structure

@ -1299,6 +1299,7 @@ dp_mst_add_connector(struct drm_dp_mst_topology_mgr *mgr,
.atomic_check = dp_mst_connector_atomic_check,
.config_hdr = dp_mst_connector_config_hdr,
.pre_destroy = dp_mst_connector_pre_destroy,
.update_pps = dp_connector_update_pps,
};
struct dp_mst_private *dp_mst;
struct drm_device *dev;

@ -885,11 +885,21 @@ static void dp_panel_calc_tu_parameters(struct dp_panel *dp_panel,
in.nlanes = panel->link->link_params.lane_count;
in.bpp = pinfo->bpp;
in.pixel_enc = 444;
in.dsc_en = 0;
in.dsc_en = dp_panel->dsc_en;
in.async_en = 0;
in.fec_en = 0;
in.compress_ratio = 0;
in.num_of_dsc_slices = 0;
in.fec_en = dp_panel->fec_en;
in.num_of_dsc_slices = pinfo->comp_info.dsc_info.slice_per_pkt;
switch (pinfo->comp_info.comp_ratio) {
case MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1:
in.compress_ratio = 200;
break;
case MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1:
in.compress_ratio = 300;
break;
default:
in.compress_ratio = 100;
}
_dp_panel_calc_tu(&in, tu_table);
}
@ -943,6 +953,603 @@ static void dp_panel_config_tr_unit(struct dp_panel *dp_panel)
catalog->update_transfer_unit(catalog);
}
enum dp_dsc_ratio_type {
DSC_8BPC_8BPP,
DSC_10BPC_8BPP,
DSC_12BPC_8BPP,
DSC_RATIO_TYPE_MAX
};
static u32 dp_dsc_rc_buf_thresh[] = {0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54,
0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e};
/*
* DSC 1.1
* Rate control - Min QP values for each ratio type in dp_dsc_ratio_type
*/
static char dp_dsc_rc_range_min_qp_1_1[][15] = {
{0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 13},
{0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 17},
{0, 4, 9, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 21},
};
/*
* DSC 1.1 SCR
* Rate control - Min QP values for each ratio type in dp_dsc_ratio_type
*/
static char dp_dsc_rc_range_min_qp_1_1_scr1[][15] = {
{0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 12},
{0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 16},
{0, 4, 9, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 17, 20},
};
/*
* DSC 1.1
* Rate control - Max QP values for each ratio type in dp_dsc_ratio_type
*/
static char dp_dsc_rc_range_max_qp_1_1[][15] = {
{4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11, 12, 13, 13, 15},
{8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 15, 16, 17, 17, 19},
{12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 19, 20, 21, 21, 23},
};
/*
* DSC 1.1 SCR
* Rate control - Max QP values for each ratio type in dp_dsc_ratio_type
*/
static char dp_dsc_rc_range_max_qp_1_1_scr1[][15] = {
{4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13},
{8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17},
{12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21},
};
/*
* DSC 1.1 and DSC 1.1 SCR
* Rate control - bpg offset values
*/
static char dp_dsc_rc_range_bpg_offset[] = {2, 0, 0, -2, -4, -6, -8, -8,
-8, -10, -10, -12, -12, -12, -12};
struct dp_dsc_dto_data {
enum msm_display_compression_ratio comp_ratio;
u32 org_bpp; /* bits */
u32 dto_numerator;
u32 dto_denominator;
};
struct dp_dsc_dto_data dto_tbl[] = {
{MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1, 24, 1, 2},
{MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1, 30, 5, 8},
{MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1, 24, 1, 3},
{MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1, 30, 5, 12},
};
static void _dp_panel_get_dto_m_n(enum msm_display_compression_ratio ratio,
u32 org_bpp, u32 *dto_n, u32 *dto_d)
{
u32 idx;
for (idx = 0; idx < ARRAY_SIZE(dto_tbl); idx++) {
if (ratio == dto_tbl[idx].comp_ratio &&
org_bpp == dto_tbl[idx].org_bpp) {
*dto_n = dto_tbl[idx].dto_numerator;
*dto_d = dto_tbl[idx].dto_denominator;
return;
}
}
}
static int dp_panel_dsc_create_pps_buf_cmd(struct msm_display_dsc_info *dsc,
char *buf, int pps_id)
{
char *bp = buf;
char data;
int i, bpp;
*bp++ = (dsc->version & 0xff); /* pps0 */
*bp++ = (pps_id & 0xff); /* pps1 */
bp++; /* pps2, reserved */
data = dsc->line_buf_depth & 0x0f;
data |= ((dsc->bpc & 0xf) << 4);
*bp++ = data; /* pps3 */
bpp = dsc->bpp;
bpp <<= 4; /* 4 fraction bits */
data = (bpp >> 8);
data &= 0x03; /* upper two bits */
data |= ((dsc->block_pred_enable & 0x1) << 5);
data |= ((dsc->convert_rgb & 0x1) << 4);
data |= ((dsc->enable_422 & 0x1) << 3);
data |= ((dsc->vbr_enable & 0x1) << 2);
*bp++ = data; /* pps4 */
*bp++ = (bpp & 0xff); /* pps5 */
*bp++ = ((dsc->pic_height >> 8) & 0xff); /* pps6 */
*bp++ = (dsc->pic_height & 0x0ff); /* pps7 */
*bp++ = ((dsc->pic_width >> 8) & 0xff); /* pps8 */
*bp++ = (dsc->pic_width & 0x0ff); /* pps9 */
*bp++ = ((dsc->slice_height >> 8) & 0xff);/* pps10 */
*bp++ = (dsc->slice_height & 0x0ff); /* pps11 */
*bp++ = ((dsc->slice_width >> 8) & 0xff); /* pps12 */
*bp++ = (dsc->slice_width & 0x0ff); /* pps13 */
*bp++ = ((dsc->chunk_size >> 8) & 0xff);/* pps14 */
*bp++ = (dsc->chunk_size & 0x0ff); /* pps15 */
*bp++ = (dsc->initial_xmit_delay >> 8) & 0x3; /* pps16*/
*bp++ = (dsc->initial_xmit_delay & 0xff);/* pps17 */
*bp++ = ((dsc->initial_dec_delay >> 8) & 0xff); /* pps18 */
*bp++ = (dsc->initial_dec_delay & 0xff);/* pps19 */
bp++; /* pps20, reserved */
*bp++ = (dsc->initial_scale_value & 0x3f); /* pps21 */
*bp++ = ((dsc->scale_increment_interval >> 8) & 0xff); /* pps22 */
*bp++ = (dsc->scale_increment_interval & 0xff); /* pps23 */
*bp++ = ((dsc->scale_decrement_interval >> 8) & 0xf); /* pps24 */
*bp++ = (dsc->scale_decrement_interval & 0x0ff);/* pps25 */
bp++; /* pps26, reserved */
*bp++ = (dsc->first_line_bpg_offset & 0x1f);/* pps27 */
*bp++ = ((dsc->nfl_bpg_offset >> 8) & 0xff);/* pps28 */
*bp++ = (dsc->nfl_bpg_offset & 0x0ff); /* pps29 */
*bp++ = ((dsc->slice_bpg_offset >> 8) & 0xff);/* pps30 */
*bp++ = (dsc->slice_bpg_offset & 0x0ff);/* pps31 */
*bp++ = ((dsc->initial_offset >> 8) & 0xff);/* pps32 */
*bp++ = (dsc->initial_offset & 0x0ff); /* pps33 */
*bp++ = ((dsc->final_offset >> 8) & 0xff);/* pps34 */
*bp++ = (dsc->final_offset & 0x0ff); /* pps35 */
*bp++ = (dsc->min_qp_flatness & 0x1f); /* pps36 */
*bp++ = (dsc->max_qp_flatness & 0x1f); /* pps37 */
*bp++ = ((dsc->rc_model_size >> 8) & 0xff);/* pps38 */
*bp++ = (dsc->rc_model_size & 0x0ff); /* pps39 */
*bp++ = (dsc->edge_factor & 0x0f); /* pps40 */
*bp++ = (dsc->quant_incr_limit0 & 0x1f); /* pps41 */
*bp++ = (dsc->quant_incr_limit1 & 0x1f); /* pps42 */
data = ((dsc->tgt_offset_hi & 0xf) << 4);
data |= (dsc->tgt_offset_lo & 0x0f);
*bp++ = data; /* pps43 */
for (i = 0; i < ARRAY_SIZE(dp_dsc_rc_buf_thresh); i++)
*bp++ = (dsc->buf_thresh[i] & 0xff); /* pps44 - pps57 */
for (i = 0; i < 15; i++) { /* pps58 - pps87 */
data = (dsc->range_min_qp[i] & 0x1f);
data <<= 3;
data |= ((dsc->range_max_qp[i] >> 2) & 0x07);
*bp++ = data;
data = (dsc->range_max_qp[i] & 0x03);
data <<= 6;
data |= (dsc->range_bpg_offset[i] & 0x3f);
*bp++ = data;
}
return 88;
}
static void dp_panel_dsc_prepare_pps_packet(struct dp_panel *dp_panel)
{
struct dp_panel_private *panel;
struct dp_dsc_cfg_data *dsc;
u8 *pps, *parity;
u32 *pps_word, *parity_word;
int i, index_4;
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
dsc = &panel->catalog->dsc;
pps = dsc->pps;
pps_word = dsc->pps_word;
parity = dsc->parity;
parity_word = dsc->parity_word;
memset(parity, 0, sizeof(dsc->parity));
dsc->pps_word_len = dsc->pps_len >> 2;
dsc->parity_len = dsc->pps_word_len;
dsc->parity_word_len = (dsc->parity_len >> 2) + 1;
for (i = 0; i < dsc->pps_word_len; i++) {
index_4 = i << 2;
pps_word[i] = pps[index_4 + 0] << 0 |
pps[index_4 + 1] << 8 |
pps[index_4 + 2] << 16 |
pps[index_4 + 3] << 24;
parity[i] = dp_header_get_parity(pps_word[i]);
}
for (i = 0; i < dsc->parity_word_len; i++) {
index_4 = i << 2;
parity_word[i] = parity[index_4 + 0] << 0 |
parity[index_4 + 1] << 8 |
parity[index_4 + 2] << 16 |
parity[index_4 + 3] << 24;
}
}
static void _dp_panel_dsc_get_num_extra_pclk(struct msm_display_dsc_info *dsc,
enum msm_display_compression_ratio ratio)
{
unsigned int dto_n, dto_d, remainder;
int ack_required, last_few_ack_required, accum_ack;
int last_few_pclk, last_few_pclk_required;
int start, temp, line_width = dsc->pic_width/2;
s64 temp1_fp, temp2_fp;
_dp_panel_get_dto_m_n(ratio, dsc->bpc * 3, &dto_n, &dto_d);
ack_required = dsc->pclk_per_line;
/* number of pclk cycles left outside of the complete DTO set */
last_few_pclk = line_width % dto_d;
/* number of pclk cycles outside of the complete dto */
temp1_fp = drm_fixp_from_fraction(line_width, dto_d);
temp2_fp = drm_fixp_from_fraction(dto_n, 1);
temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
temp = drm_fixp2int(temp1_fp);
last_few_ack_required = ack_required - temp;
/*
* check how many more pclk is needed to
* accommodate the last few ack required
*/
remainder = dto_n;
accum_ack = 0;
last_few_pclk_required = 0;
while (accum_ack < last_few_ack_required) {
last_few_pclk_required++;
if (remainder >= dto_n)
start = remainder;
else
start = remainder + dto_d;
remainder = start - dto_n;
if (remainder < dto_n)
accum_ack++;
}
/* if fewer pclk than required */
if (last_few_pclk < last_few_pclk_required)
dsc->extra_width = last_few_pclk_required - last_few_pclk;
else
dsc->extra_width = 0;
pr_debug("extra pclks required: %d\n", dsc->extra_width);
}
static void _dp_panel_dsc_bw_overhead_calc(struct dp_panel *dp_panel,
struct msm_display_dsc_info *dsc,
struct dp_display_mode *dp_mode, u32 dsc_byte_cnt)
{
int num_slices, tot_num_eoc_symbols;
int tot_num_hor_bytes, tot_num_dummy_bytes;
int dwidth_dsc_bytes, eoc_bytes;
u32 num_lanes;
num_lanes = dp_panel->link_info.num_lanes;
num_slices = dsc->slice_per_pkt;
eoc_bytes = dsc_byte_cnt % num_lanes;
tot_num_eoc_symbols = num_lanes * num_slices;
tot_num_hor_bytes = dsc_byte_cnt * num_slices;
tot_num_dummy_bytes = (num_lanes - eoc_bytes) * num_slices;
if (!eoc_bytes)
tot_num_dummy_bytes = 0;
dwidth_dsc_bytes = tot_num_hor_bytes + tot_num_eoc_symbols +
tot_num_dummy_bytes;
dp_mode->dsc_overhead_fp = drm_fixp_from_fraction(dwidth_dsc_bytes,
tot_num_hor_bytes);
}
static void dp_panel_dsc_pclk_param_calc(struct dp_panel *dp_panel,
struct msm_display_dsc_info *dsc,
enum msm_display_compression_ratio ratio,
struct dp_display_mode *dp_mode)
{
int slice_per_pkt, slice_per_intf, intf_width;
int bytes_in_slice, total_bytes_per_intf;
int comp_ratio;
s64 temp1_fp, temp2_fp;
s64 numerator_fp, denominator_fp;
s64 dsc_byte_count_fp;
u32 dsc_byte_count, temp1, temp2;
intf_width = dp_mode->timing.h_active;
if (!dsc || !dsc->slice_width || !dsc->slice_per_pkt ||
(intf_width < dsc->slice_width))
return;
slice_per_pkt = dsc->slice_per_pkt;
slice_per_intf = DIV_ROUND_UP(intf_width, dsc->slice_width);
if (slice_per_pkt > slice_per_intf)
slice_per_pkt = 1;
bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bpp, 8);
total_bytes_per_intf = bytes_in_slice * slice_per_intf;
dsc->bytes_in_slice = bytes_in_slice;
dsc->bytes_per_pkt = bytes_in_slice * slice_per_pkt;
dsc->pkt_per_line = slice_per_intf / slice_per_pkt;
switch (ratio) {
case MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1:
comp_ratio = 200;
break;
case MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1:
comp_ratio = 300;
break;
default:
comp_ratio = 100;
break;
}
temp1_fp = drm_fixp_from_fraction(comp_ratio, 100);
temp2_fp = drm_fixp_from_fraction(slice_per_pkt * 8, 1);
denominator_fp = drm_fixp_mul(temp1_fp, temp2_fp);
numerator_fp = drm_fixp_from_fraction(intf_width * dsc->bpc * 3, 1);
dsc_byte_count_fp = drm_fixp_div(numerator_fp, denominator_fp);
dsc_byte_count = drm_fixp2int_ceil(dsc_byte_count_fp);
temp1 = dsc_byte_count * slice_per_intf;
temp2 = temp1;
if (temp1 % 3 != 0)
temp1 += 3 - (temp1 % 3);
dsc->eol_byte_num = temp1 - temp2;
temp1_fp = drm_fixp_from_fraction(slice_per_intf, 6);
temp2_fp = drm_fixp_mul(dsc_byte_count_fp, temp1_fp);
dsc->pclk_per_line = drm_fixp2int_ceil(temp2_fp);
_dp_panel_dsc_get_num_extra_pclk(dsc, ratio);
dsc->pclk_per_line--;
_dp_panel_dsc_bw_overhead_calc(dp_panel, dsc, dp_mode, dsc_byte_count);
}
static void dp_panel_dsc_populate_static_params(
struct msm_display_dsc_info *dsc)
{
int bpp, bpc;
int mux_words_size;
int groups_per_line, groups_total;
int min_rate_buffer_size;
int hrd_delay;
int pre_num_extra_mux_bits, num_extra_mux_bits;
int slice_bits;
int data;
int final_value, final_scale;
int ratio_index, mod_offset;
dsc->version = 0x11;
dsc->scr_rev = 0;
dsc->rc_model_size = 8192;
if (dsc->version == 0x11 && dsc->scr_rev == 0x1)
dsc->first_line_bpg_offset = 15;
else
dsc->first_line_bpg_offset = 12;
dsc->edge_factor = 6;
dsc->tgt_offset_hi = 3;
dsc->tgt_offset_lo = 3;
dsc->enable_422 = 0;
dsc->convert_rgb = 1;
dsc->vbr_enable = 0;
dsc->buf_thresh = dp_dsc_rc_buf_thresh;
bpp = dsc->bpp;
bpc = dsc->bpc;
if (bpc == 12)
ratio_index = DSC_12BPC_8BPP;
else if (bpc == 10)
ratio_index = DSC_10BPC_8BPP;
else
ratio_index = DSC_8BPC_8BPP;
if (dsc->version == 0x11 && dsc->scr_rev == 0x1) {
dsc->range_min_qp =
dp_dsc_rc_range_min_qp_1_1_scr1[ratio_index];
dsc->range_max_qp =
dp_dsc_rc_range_max_qp_1_1_scr1[ratio_index];
} else {
dsc->range_min_qp = dp_dsc_rc_range_min_qp_1_1[ratio_index];
dsc->range_max_qp = dp_dsc_rc_range_max_qp_1_1[ratio_index];
}
dsc->range_bpg_offset = dp_dsc_rc_range_bpg_offset;
if (bpp <= 10)
dsc->initial_offset = 6144;
else
dsc->initial_offset = 2048; /* bpp = 12 */
if (bpc == 12)
mux_words_size = 64;
else
mux_words_size = 48; /* bpc == 8/10 */
dsc->line_buf_depth = bpc + 1;
if (bpc == 8) {
dsc->input_10_bits = 0;
dsc->min_qp_flatness = 3;
dsc->max_qp_flatness = 12;
dsc->quant_incr_limit0 = 11;
dsc->quant_incr_limit1 = 11;
} else if (bpc == 10) { /* 10bpc */
dsc->input_10_bits = 1;
dsc->min_qp_flatness = 7;
dsc->max_qp_flatness = 16;
dsc->quant_incr_limit0 = 15;
dsc->quant_incr_limit1 = 15;
} else { /* 12 bpc */
dsc->input_10_bits = 0;
dsc->min_qp_flatness = 11;
dsc->max_qp_flatness = 20;
dsc->quant_incr_limit0 = 19;
dsc->quant_incr_limit1 = 19;
}
mod_offset = dsc->slice_width % 3;
switch (mod_offset) {
case 0:
dsc->slice_last_group_size = 2;
break;
case 1:
dsc->slice_last_group_size = 0;
break;
case 2:
dsc->slice_last_group_size = 1;
break;
default:
break;
}
dsc->det_thresh_flatness = 2 << (bpc - 8);
dsc->initial_xmit_delay = dsc->rc_model_size / (2 * bpp);
groups_per_line = DIV_ROUND_UP(dsc->slice_width, 3);
dsc->chunk_size = dsc->slice_width * bpp / 8;
if ((dsc->slice_width * bpp) % 8)
dsc->chunk_size++;
/* rbs-min */
min_rate_buffer_size = dsc->rc_model_size - dsc->initial_offset +
dsc->initial_xmit_delay * bpp +
groups_per_line * dsc->first_line_bpg_offset;
hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, bpp);
dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay;
dsc->initial_scale_value = 8 * dsc->rc_model_size /
(dsc->rc_model_size - dsc->initial_offset);
slice_bits = 8 * dsc->chunk_size * dsc->slice_height;
groups_total = groups_per_line * dsc->slice_height;
data = dsc->first_line_bpg_offset * 2048;
dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1));
pre_num_extra_mux_bits = 3 * (mux_words_size + (4 * bpc + 4) - 2);
num_extra_mux_bits = pre_num_extra_mux_bits - (mux_words_size -
((slice_bits - pre_num_extra_mux_bits) % mux_words_size));
data = 2048 * (dsc->rc_model_size - dsc->initial_offset
+ num_extra_mux_bits);
dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total);
data = dsc->initial_xmit_delay * bpp;
final_value = dsc->rc_model_size - data + num_extra_mux_bits;
final_scale = 8 * dsc->rc_model_size /
(dsc->rc_model_size - final_value);
dsc->final_offset = final_value;
data = (final_scale - 9) * (dsc->nfl_bpg_offset +
dsc->slice_bpg_offset);
dsc->scale_increment_interval = (2048 * dsc->final_offset) / data;
dsc->scale_decrement_interval = groups_per_line /
(dsc->initial_scale_value - 8);
}
struct dp_dsc_slices_per_line {
u32 min_ppr;
u32 max_ppr;
u8 num_slices;
};
struct dp_dsc_slices_per_line slice_per_line_tbl[] = {
{0, 340, 1 },
{340, 680, 2 },
{680, 1360, 4 },
{1360, 3200, 8 },
{3200, 4800, 12 },
{4800, 6400, 16 },
{6400, 8000, 20 },
{8000, 9600, 24 }
};
static int dp_panel_dsc_prepare_basic_params(
struct msm_compression_info *comp_info,
const struct dp_display_mode *dp_mode,
struct dp_panel *dp_panel)
{
int i;
struct dp_dsc_slices_per_line *rec;
int slice_width;
u32 ppr = dp_mode->timing.pixel_clk_khz/1000;
comp_info->dsc_info.slice_per_pkt = 0;
for (i = 0; i < ARRAY_SIZE(slice_per_line_tbl); i++) {
rec = &slice_per_line_tbl[i];
if ((ppr > rec->min_ppr) && (ppr <= rec->max_ppr)) {
comp_info->dsc_info.slice_per_pkt = rec->num_slices;
break;
}
}
if (comp_info->dsc_info.slice_per_pkt == 0)
return -EINVAL;
slice_width = (dp_mode->timing.h_active /
comp_info->dsc_info.slice_per_pkt);
comp_info->dsc_info.block_pred_enable =
dp_panel->sink_dsc_caps.block_pred_en;
comp_info->dsc_info.vbr_enable = 0;
comp_info->dsc_info.enable_422 = 0;
comp_info->dsc_info.convert_rgb = 1;
comp_info->dsc_info.input_10_bits = 0;
comp_info->dsc_info.pic_width = dp_mode->timing.h_active;
comp_info->dsc_info.pic_height = dp_mode->timing.v_active;
comp_info->dsc_info.slice_width = slice_width;
if (comp_info->dsc_info.pic_height % 16)
comp_info->dsc_info.slice_height = 12;
else
comp_info->dsc_info.slice_height = 16;
comp_info->dsc_info.bpc = dp_mode->timing.bpp / 3;
comp_info->dsc_info.bpp = comp_info->dsc_info.bpc;
comp_info->dsc_info.full_frame_slices =
DIV_ROUND_UP(dp_mode->timing.h_active, slice_width);
comp_info->comp_type = MSM_DISPLAY_COMPRESSION_DSC;
comp_info->comp_ratio = MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1;
return 0;
}
static int dp_panel_read_dpcd(struct dp_panel *dp_panel, bool multi_func)
{
int rlen, rc = 0;
@ -1166,6 +1773,77 @@ end:
return ret;
}
static void dp_panel_decode_dsc_dpcd(struct dp_panel *dp_panel)
{
s64 fec_overhead_fp = drm_fixp_from_fraction(1, 1);
if (!dp_panel->dsc_feature_enable || !dp_panel->fec_feature_enable) {
pr_debug("source dsc is not supported\n");
return;
}
if (dp_panel->dsc_dpcd[0] && dp_panel->fec_dpcd) {
dp_panel->sink_dsc_caps.dsc_capable = true;
dp_panel->sink_dsc_caps.version = dp_panel->dsc_dpcd[1];
dp_panel->sink_dsc_caps.block_pred_en =
dp_panel->dsc_dpcd[6] ? true : false;
if (dp_panel->sink_dsc_caps.version >= 0x11)
dp_panel->dsc_en = true;
} else {
dp_panel->sink_dsc_caps.dsc_capable = false;
dp_panel->dsc_en = false;
}
dp_panel->fec_en = dp_panel->dsc_en;
dp_panel->widebus_en = dp_panel->dsc_en;
/* fec_overhead = 1.00 / 0.7488664 */
if (dp_panel->fec_en)
fec_overhead_fp = drm_fixp_from_fraction(10000000, 7488664);
dp_panel->fec_overhead_fp = fec_overhead_fp;
}
static void dp_panel_read_sink_dsc_caps(struct dp_panel *dp_panel)
{
int rlen;
struct dp_panel_private *panel;
const int fec_cap = 0x90;
if (!dp_panel) {
pr_err("invalid input\n");
return;
}
dp_panel->dsc_en = false;
dp_panel->fec_en = false;
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
if (panel->parser->dsc_feature_enable) {
rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_DSC_SUPPORT,
dp_panel->dsc_dpcd, (DP_RECEIVER_DSC_CAP_SIZE + 1));
if (rlen < (DP_RECEIVER_DSC_CAP_SIZE + 1)) {
pr_debug("dsc dpcd read failed, rlen=%d\n", rlen);
return;
}
print_hex_dump(KERN_DEBUG, "[drm-dp] SINK DSC DPCD: ",
DUMP_PREFIX_NONE, 8, 1, dp_panel->dsc_dpcd, rlen,
false);
rlen = drm_dp_dpcd_read(panel->aux->drm_aux, fec_cap,
&dp_panel->fec_dpcd, 1);
if (rlen < 1) {
pr_err("fec dpcd read failed, rlen=%d\n", rlen);
return;
}
dp_panel_decode_dsc_dpcd(dp_panel);
}
}
static int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
struct drm_connector *connector, bool multi_func)
{
@ -1219,6 +1897,10 @@ static int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
}
dp_panel->widebus_en = panel->parser->has_widebus;
dp_panel->dsc_feature_enable = panel->parser->dsc_feature_enable;
dp_panel->fec_feature_enable = panel->parser->fec_feature_enable;
dp_panel_read_sink_dsc_caps(dp_panel);
end:
return rc;
}
@ -1479,6 +2161,101 @@ end:
return rc;
}
static u32 _dp_panel_calc_be_in_lane(struct dp_panel *dp_panel)
{
struct dp_panel_info *pinfo;
struct msm_compression_info *comp_info;
u32 dsc_htot_byte_cnt, mod_result;
u32 numerator, denominator;
s64 temp_fp;
u32 be_in_lane = 10;
pinfo = &dp_panel->pinfo;
comp_info = &pinfo->comp_info;
if (!dp_panel->mst_state)
return be_in_lane;
switch (pinfo->comp_info.comp_ratio) {
case MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1:
denominator = 16; /* 2 * bits-in-byte */
break;
case MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1:
denominator = 24; /* 3 * bits-in-byte */
break;
default:
denominator = 8; /* 1 * bits-in-byte */
}
numerator = (pinfo->h_active + pinfo->h_back_porch +
pinfo->h_front_porch + pinfo->h_sync_width) *
pinfo->bpp;
temp_fp = drm_fixp_from_fraction(numerator, denominator);
dsc_htot_byte_cnt = drm_fixp2int_ceil(temp_fp);
mod_result = dsc_htot_byte_cnt % 12;
if (mod_result == 0)
be_in_lane = 8;
else if (mod_result <= 3)
be_in_lane = 1;
else if (mod_result <= 6)
be_in_lane = 2;
else if (mod_result <= 9)
be_in_lane = 4;
else if (mod_result <= 11)
be_in_lane = 8;
else
be_in_lane = 10;
return be_in_lane;
}
static void dp_panel_config_dsc(struct dp_panel *dp_panel, bool enable)
{
struct dp_catalog_panel *catalog;
struct dp_panel_private *panel;
struct dp_panel_info *pinfo;
struct msm_compression_info *comp_info;
struct dp_dsc_cfg_data *dsc;
int pps_len;
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
catalog = panel->catalog;
dsc = &catalog->dsc;
pinfo = &dp_panel->pinfo;
comp_info = &pinfo->comp_info;
if (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC && enable) {
pps_len = dp_panel_dsc_create_pps_buf_cmd(&comp_info->dsc_info,
dsc->pps, 0);
dsc->pps_len = pps_len;
dp_panel_dsc_prepare_pps_packet(dp_panel);
dsc->slice_per_pkt = comp_info->dsc_info.slice_per_pkt - 1;
dsc->bytes_per_pkt = comp_info->dsc_info.bytes_per_pkt;
dsc->eol_byte_num = comp_info->dsc_info.eol_byte_num;
dsc->dto_count = comp_info->dsc_info.pclk_per_line;
dsc->be_in_lane = _dp_panel_calc_be_in_lane(dp_panel);
dsc->dsc_en = true;
dsc->dto_en = true;
_dp_panel_get_dto_m_n(comp_info->comp_ratio, pinfo->bpp,
&dsc->dto_n, &dsc->dto_d);
} else {
dsc->dsc_en = false;
dsc->dto_en = false;
dsc->dto_n = 0;
dsc->dto_d = 0;
}
catalog->stream_id = dp_panel->stream_id;
catalog->dsc_cfg(catalog);
if (catalog->dsc.dsc_en && enable)
catalog->pps_flush(catalog);
}
static int dp_panel_edid_register(struct dp_panel_private *panel)
{
int rc = 0;
@ -1852,6 +2629,7 @@ static int dp_panel_hw_cfg(struct dp_panel *dp_panel, bool enable)
dp_panel_config_ctrl(dp_panel);
dp_panel_config_misc(dp_panel);
dp_panel_config_msa(dp_panel);
dp_panel_config_dsc(dp_panel, enable);
dp_panel_config_tr_unit(dp_panel);
dp_panel_config_timing(dp_panel);
}
@ -1926,6 +2704,7 @@ static void dp_panel_convert_to_dp_mode(struct dp_panel *dp_panel,
struct dp_display_mode *dp_mode)
{
const u32 num_components = 3, default_bpp = 24;
struct msm_compression_info *comp_info;
dp_mode->timing.h_active = drm_mode->hdisplay;
dp_mode->timing.h_back_porch = drm_mode->htotal - drm_mode->hsync_end;
@ -1962,6 +2741,35 @@ static void dp_panel_convert_to_dp_mode(struct dp_panel *dp_panel,
dp_mode->timing.bpp, dp_mode->timing.pixel_clk_khz);
dp_mode->timing.widebus_en = dp_panel->widebus_en;
if (dp_panel->dsc_en) {
comp_info = &dp_mode->timing.comp_info;
if (dp_panel_dsc_prepare_basic_params(comp_info,
dp_mode, dp_panel)) {
pr_debug("prepare DSC basic params failed\n");
return;
}
dp_panel_dsc_populate_static_params(&comp_info->dsc_info);
dp_panel_dsc_pclk_param_calc(dp_panel,
&comp_info->dsc_info,
comp_info->comp_ratio,
dp_mode);
}
dp_mode->fec_overhead_fp = dp_panel->fec_overhead_fp;
}
static void dp_panel_update_pps(struct dp_panel *dp_panel, char *pps_cmd)
{
struct dp_catalog_panel *catalog;
struct dp_panel_private *panel;
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
catalog = panel->catalog;
catalog->stream_id = dp_panel->stream_id;
catalog->pps_flush(catalog);
}
struct dp_panel *dp_panel_get(struct dp_panel_in *in)
@ -1997,13 +2805,19 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in)
memcpy(panel->spd_product_description, product_desc, (sizeof(u8) * 16));
dp_panel->connector = in->connector;
dp_panel->widebus_en = panel->parser->has_widebus;
dp_panel->dsc_feature_enable = panel->parser->dsc_feature_enable;
dp_panel->fec_feature_enable = panel->parser->fec_feature_enable;
if (in->base_panel) {
memcpy(dp_panel->dpcd, in->base_panel->dpcd,
DP_RECEIVER_CAP_SIZE + 1);
memcpy(&dp_panel->link_info, &in->base_panel->link_info,
sizeof(dp_panel->link_info));
dp_panel->mst_state = in->base_panel->mst_state;
dp_panel->widebus_en = in->base_panel->widebus_en;
dp_panel->fec_en = in->base_panel->fec_en;
dp_panel->dsc_en = in->base_panel->dsc_en;
dp_panel->fec_overhead_fp = in->base_panel->fec_overhead_fp;
}
dp_panel->init = dp_panel_init_panel_info;
@ -2025,6 +2839,7 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in)
dp_panel->update_edid = dp_panel_update_edid;
dp_panel->read_mst_cap = dp_panel_read_mst_cap;
dp_panel->convert_to_dp_mode = dp_panel_convert_to_dp_mode;
dp_panel->update_pps = dp_panel_update_pps;
sde_conn = to_sde_connector(dp_panel->connector);
sde_conn->drv_panel = dp_panel;

@ -22,6 +22,10 @@
#include "dp_usbpd.h"
#include "sde_edid_parser.h"
#include "sde_connector.h"
#include "msm_drv.h"
#define DP_RECEIVER_DSC_CAP_SIZE 15
#define DP_RECEIVER_FEC_STATUS_SIZE 3
/*
* A source initiated power down flag is set
@ -57,11 +61,14 @@ struct dp_panel_info {
u32 pixel_clk_khz;
u32 bpp;
bool widebus_en;
struct msm_compression_info comp_info;
};
struct dp_display_mode {
struct dp_panel_info timing;
u32 capabilities;
s64 fec_overhead_fp;
s64 dsc_overhead_fp;
};
struct dp_panel;
@ -76,12 +83,21 @@ struct dp_panel_in {
struct dp_parser *parser;
};
struct dp_dsc_caps {
bool dsc_capable;
u8 version;
bool block_pred_en;
};
struct dp_audio;
struct dp_panel {
/* dpcd raw data */
u8 dpcd[DP_RECEIVER_CAP_SIZE + 1];
u8 ds_ports[DP_MAX_DOWNSTREAM_PORTS];
u8 dsc_dpcd[DP_RECEIVER_DSC_CAP_SIZE + 1];
u8 fec_dpcd;
u8 fec_sts_dpcd[DP_RECEIVER_FEC_STATUS_SIZE + 1];
struct drm_dp_link link_info;
struct sde_edid_ctrl *edid_ctrl;
@ -109,9 +125,17 @@ struct dp_panel {
struct dp_audio *audio;
bool audio_supported;
struct dp_dsc_caps sink_dsc_caps;
bool dsc_feature_enable;
bool fec_feature_enable;
bool dsc_en;
bool fec_en;
bool widebus_en;
bool mst_state;
s64 fec_overhead_fp;
int (*init)(struct dp_panel *dp_panel);
int (*deinit)(struct dp_panel *dp_panel, u32 flags);
int (*hw_cfg)(struct dp_panel *dp_panel, bool enable);
@ -141,6 +165,7 @@ struct dp_panel {
void (*convert_to_dp_mode)(struct dp_panel *dp_panel,
const struct drm_display_mode *drm_mode,
struct dp_display_mode *dp_mode);
void (*update_pps)(struct dp_panel *dp_panel, char *pps_cmd);
};
struct dp_tu_calc_input {

@ -687,16 +687,37 @@ static int dp_parser_mst(struct dp_parser *parser)
return 0;
}
static int dp_parser_widebus(struct dp_parser *parser)
static void dp_parser_dsc(struct dp_parser *parser)
{
struct device *dev = &parser->pdev->dev;
parser->dsc_feature_enable = of_property_read_bool(dev->of_node,
"qcom,dsc-feature-enable");
pr_debug("dsc parsing successful. dsc:%d\n",
parser->dsc_feature_enable);
}
static void dp_parser_fec(struct dp_parser *parser)
{
struct device *dev = &parser->pdev->dev;
parser->fec_feature_enable = of_property_read_bool(dev->of_node,
"qcom,fec-feature-enable");
pr_debug("fec parsing successful. fec:%d\n",
parser->fec_feature_enable);
}
static void dp_parser_widebus(struct dp_parser *parser)
{
struct device *dev = &parser->pdev->dev;
parser->has_widebus = of_property_read_bool(dev->of_node,
"qcom,widebus-enable");
pr_debug("widebus parsing successful. dsc:%d\n", parser->has_widebus);
return 0;
pr_debug("widebus parsing successful. widebus:%d\n",
parser->has_widebus);
}
static int dp_parser_parse(struct dp_parser *parser)
@ -749,7 +770,9 @@ static int dp_parser_parse(struct dp_parser *parser)
if (rc)
goto err;
rc = dp_parser_widebus(parser);
dp_parser_dsc(parser);
dp_parser_fec(parser);
dp_parser_widebus(parser);
err:
return rc;
}

@ -189,6 +189,12 @@ static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type)
* @pinctrl: pin-control related data
* @disp_data: controller's display related data
* @hw_cfg: DP HW specific settings
* @has_mst: MST feature enable status
* @has_mst_sideband: MST sideband feature enable status
* @no_aux_switch: presence AUX switch status
* @dsc_feature_enable: DSC feature enable status
* @fec_feature_enable: FEC feature enable status
* @has_widebus: widebus (2PPC) feature eanble status
* @parse: function to be called by client to parse device tree.
* @get_io: function to be called by client to get io data.
* @get_io_buf: function to be called by client to get io buffers.
@ -209,6 +215,8 @@ struct dp_parser {
bool has_mst;
bool has_mst_sideband;
bool no_aux_switch;
bool dsc_feature_enable;
bool fec_feature_enable;
bool has_widebus;
int (*parse)(struct dp_parser *parser);

@ -99,6 +99,37 @@
#define MMSS_DP_PSR_CRC_B (0x00000158)
#define DP_COMPRESSION_MODE_CTRL (0x00000180)
#define DP_PPS_HB_0_3 (0x00000184)
#define DP_PPS_PB_0_3 (0x00000188)
#define DP_PPS_PB_4_7 (0x0000018C)
#define DP_PPS_PB_8_11 (0x00000190)
#define DP_PPS_PB_12_15 (0x00000194)
#define DP_PPS_PB_16_19 (0x00000198)
#define DP_PPS_PB_20_23 (0x0000019C)
#define DP_PPS_PB_24_27 (0x000001A0)
#define DP_PPS_PB_28_31 (0x000001A4)
#define DP_PPS_PPS_0_3 (0x000001A8)
#define DP_PPS_PPS_4_7 (0x000001AC)
#define DP_PPS_PPS_8_11 (0x000001B0)
#define DP_PPS_PPS_12_15 (0x000001B4)
#define DP_PPS_PPS_16_19 (0x000001B8)
#define DP_PPS_PPS_20_23 (0x000001BC)
#define DP_PPS_PPS_24_27 (0x000001C0)
#define DP_PPS_PPS_28_31 (0x000001C4)
#define DP_PPS_PPS_32_35 (0x000001C8)
#define DP_PPS_PPS_36_39 (0x000001CC)
#define DP_PPS_PPS_40_43 (0x000001D0)
#define DP_PPS_PPS_44_47 (0x000001D4)
#define DP_PPS_PPS_48_51 (0x000001D8)
#define DP_PPS_PPS_52_55 (0x000001DC)
#define DP_PPS_PPS_56_59 (0x000001E0)
#define DP_PPS_PPS_60_63 (0x000001E4)
#define DP_PPS_PPS_64_67 (0x000001E8)
#define DP_PPS_PPS_68_71 (0x000001EC)
#define DP_PPS_PPS_72_75 (0x000001F0)
#define DP_PPS_PPS_76_79 (0x000001F4)
#define DP_PPS_PPS_80_83 (0x000001F8)
#define DP_PPS_PPS_84_87 (0x000001FC)
#define MMSS_DP_AUDIO_CFG (0x00000200)
#define MMSS_DP_AUDIO_STATUS (0x00000204)
@ -143,6 +174,7 @@
#define MMSS_DP_AUDIO_INFOFRAME_2 (0x000002B0)
#define MMSS_DP_FLUSH (0x000002F8)
#define MMSS_DP1_FLUSH (0x000002FC)
#define MMSS_DP_GENERIC0_0 (0x00000300)
#define MMSS_DP_GENERIC0_1 (0x00000304)
@ -190,6 +222,39 @@
#define MMSS_DP1_SDP_CFG2 (0x000004E4)
#define MMSS_DP1_SDP_CFG3 (0x000004E8)
#define DP1_COMPRESSION_MODE_CTRL (0x00000560)
#define DP1_PPS_HB_0_3 (0x00000564)
#define DP1_PPS_PB_0_3 (0x00000568)
#define DP1_PPS_PB_4_7 (0x0000056C)
#define DP1_PPS_PB_8_11 (0x00000570)
#define DP1_PPS_PB_12_15 (0x00000574)
#define DP1_PPS_PB_16_19 (0x00000578)
#define DP1_PPS_PB_20_23 (0x0000057C)
#define DP1_PPS_PB_24_27 (0x00000580)
#define DP1_PPS_PB_28_31 (0x00000584)
#define DP1_PPS_PPS_0_3 (0x00000588)
#define DP1_PPS_PPS_4_7 (0x0000058C)
#define DP1_PPS_PPS_8_11 (0x00000590)
#define DP1_PPS_PPS_12_15 (0x00000594)
#define DP1_PPS_PPS_16_19 (0x00000598)
#define DP1_PPS_PPS_20_23 (0x0000059C)
#define DP1_PPS_PPS_24_27 (0x000005A0)
#define DP1_PPS_PPS_28_31 (0x000005A4)
#define DP1_PPS_PPS_32_35 (0x000005A8)
#define DP1_PPS_PPS_36_39 (0x000005AC)
#define DP1_PPS_PPS_40_43 (0x000005B0)
#define DP1_PPS_PPS_44_47 (0x000005B4)
#define DP1_PPS_PPS_48_51 (0x000005B8)
#define DP1_PPS_PPS_52_55 (0x000005BC)
#define DP1_PPS_PPS_56_59 (0x000005C0)
#define DP1_PPS_PPS_60_63 (0x000005C4)
#define DP1_PPS_PPS_64_67 (0x000005C8)
#define DP1_PPS_PPS_68_71 (0x000005CC)
#define DP1_PPS_PPS_72_75 (0x000005D0)
#define DP1_PPS_PPS_76_79 (0x000005D4)
#define DP1_PPS_PPS_80_83 (0x000005D8)
#define DP1_PPS_PPS_84_87 (0x000005DC)
#define MMSS_DP_VSCEXT_0 (0x000002D0)
#define MMSS_DP_VSCEXT_1 (0x000002D4)
#define MMSS_DP_VSCEXT_2 (0x000002D8)
@ -223,6 +288,7 @@
#define MMSS_DP_TPG_MAIN_CONTROL (0x00000060)
#define MMSS_DP_TPG_VIDEO_CONFIG (0x00000064)
#define MMSS_DP_DSC_DTO (0x0000007C)
#define MMSS_DP_DSC_DTO_COUNT (0x00000084)
#define MMSS_DP_ASYNC_FIFO_CONFIG (0x00000088)
#define MMSS_DP1_BIST_ENABLE (0x00000000)
@ -247,6 +313,7 @@
#define MMSS_DP1_TPG_MAIN_CONTROL (0x00000060)
#define MMSS_DP1_TPG_VIDEO_CONFIG (0x00000064)
#define MMSS_DP1_DSC_DTO (0x0000007C)
#define MMSS_DP1_DSC_DTO_COUNT (0x00000084)
#define MMSS_DP1_ASYNC_FIFO_CONFIG (0x00000088)
/*DP PHY Register offsets */

@ -1429,6 +1429,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
.cmd_transfer = NULL,
.cont_splash_config = NULL,
.get_panel_vfp = NULL,
.update_pps = dp_connector_update_pps,
};
struct msm_display_info info;
struct drm_encoder *encoder;

Loading…
Cancel
Save