Merge "msm: mdss: add split link panel support in mdss"

This commit is contained in:
Linux Build Service Account 2017-04-13 21:52:15 -07:00 committed by Gerrit - the friendly Code Review server
commit 2fce80230e
11 changed files with 381 additions and 70 deletions

View file

@ -581,6 +581,15 @@ Additional properties added to the second level nodes that represent timings pro
commands.
"dsi_lp_mode" = DSI low power mode (default)
"dsi_hs_mode" = DSI high speed mode
- qcom,sublinks-count: An integer value indicates the number of sublinks in the panel.
Default value is 1. This property is used only if qcom,split-link-enabled
is defined.
- qcom,lanes-per-sublink: An integer value indicates the number of data lanes per sublink in the panel.
Default value is 1. This property is used only if qcom,split-link-enabled
is defined.
- qcom,split-link-enabled: A boolean value to enable/disable the split link feature. If qcom,sublinks-count
or qcom,lanes-per-sublink are not defined, default values are used.
Note, if a given optional qcom,* binding is not present, then the driver will configure
the default values specified.
@ -808,6 +817,10 @@ Example:
qcom,mdss-dsc-version = <0x11>;
qcom,mdss-dsc-scr-version = <0x1>;
qcom,split-link-enabled;
qcom,sublinks-count = <2>;
qcom,lanes-per-sublink = <2>;
dsi_sim_vid_config0: config0 {
qcom,lm-split = <360 360>;
qcom,mdss-dsc-encoders = <2>;

View file

@ -1311,6 +1311,31 @@ void mdss_dsi_set_burst_mode(struct mdss_dsi_ctrl_pdata *ctrl)
}
static void mdss_dsi_split_link_setup(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
u32 data = 0;
struct mdss_panel_info *pinfo;
if (!ctrl_pdata)
return;
pinfo = &ctrl_pdata->panel_data.panel_info;
if (!pinfo->split_link_enabled)
return;
pr_debug("%s: enable split link\n", __func__);
data = MIPI_INP((ctrl_pdata->ctrl_base) + 0x330);
/* DMA_LINK_SEL */
data |= 0x3 << 12;
/* MDP0_LINK_SEL */
data |= 0x5 << 20;
/* EN */
data |= 0x1;
/* DSI_SPLIT_LINK_CTRL */
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x330, data);
}
static void mdss_dsi_mode_setup(struct mdss_panel_data *pdata)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
@ -1429,6 +1454,8 @@ static void mdss_dsi_mode_setup(struct mdss_panel_data *pdata)
}
mdss_dsi_dsc_config(ctrl_pdata, dsc);
mdss_dsi_split_link_setup(ctrl_pdata);
}
void mdss_dsi_ctrl_setup(struct mdss_dsi_ctrl_pdata *ctrl)

View file

@ -1350,6 +1350,44 @@ static int mdss_dsi_parse_hdr_settings(struct device_node *np,
return 0;
}
static int mdss_dsi_parse_split_link_settings(struct device_node *np,
struct mdss_panel_info *pinfo)
{
u32 tmp;
int rc = 0;
if (!np) {
pr_err("%s: device node pointer is NULL\n", __func__);
return -EINVAL;
}
if (!pinfo) {
pr_err("%s: panel info is NULL\n", __func__);
return -EINVAL;
}
pinfo->split_link_enabled = of_property_read_bool(np,
"qcom,split-link-enabled");
if (pinfo->split_link_enabled) {
rc = of_property_read_u32(np,
"qcom,sublinks-count", &tmp);
/* default num of sublink is 1*/
pinfo->mipi.num_of_sublinks = (!rc ? tmp : 1);
rc = of_property_read_u32(np,
"qcom,lanes-per-sublink", &tmp);
/* default num of lanes per sublink is 1 */
pinfo->mipi.lanes_per_sublink = (!rc ? tmp : 1);
}
pr_info("%s: enable %d sublinks-count %d lanes per sublink %d\n",
__func__, pinfo->split_link_enabled,
pinfo->mipi.num_of_sublinks,
pinfo->mipi.lanes_per_sublink);
return 0;
}
static int mdss_dsi_parse_dsc_version(struct device_node *np,
struct mdss_panel_timing *timing)
{
@ -2734,9 +2772,15 @@ static int mdss_panel_parse_dt(struct device_node *np,
pinfo->mipi.data_lane3 = of_property_read_bool(np,
"qcom,mdss-dsi-lane-3-state");
/* parse split link properties */
rc = mdss_dsi_parse_split_link_settings(np, pinfo);
if (rc)
return rc;
rc = mdss_panel_parse_display_timings(np, &ctrl_pdata->panel_data);
if (rc)
return rc;
rc = mdss_dsi_parse_hdr_settings(np, pinfo);
if (rc)
return rc;

View file

@ -374,7 +374,8 @@ static int mdss_fb_get_panel_xres(struct mdss_panel_info *pinfo)
xres = pinfo->xres;
if (pdata->next && pdata->next->active)
xres += mdss_fb_get_panel_xres(&pdata->next->panel_info);
if (pinfo->split_link_enabled)
xres = xres * pinfo->mipi.num_of_sublinks;
return xres;
}

View file

@ -392,6 +392,12 @@ static inline void mdss_fb_update_notify_update(struct msm_fb_data_type *mfd)
}
}
/* Function returns true for split link */
static inline bool is_panel_split_link(struct msm_fb_data_type *mfd)
{
return mfd && mfd->panel_info && mfd->panel_info->split_link_enabled;
}
/* Function returns true for either any kind of dual display */
static inline bool is_panel_split(struct msm_fb_data_type *mfd)
{

View file

@ -1267,6 +1267,8 @@ static inline u32 get_panel_width(struct mdss_mdp_ctl *ctl)
width = get_panel_xres(&ctl->panel_data->panel_info);
if (ctl->panel_data->next && is_pingpong_split(ctl->mfd))
width += get_panel_xres(&ctl->panel_data->next->panel_info);
else if (is_panel_split_link(ctl->mfd))
width *= (ctl->panel_data->panel_info.mipi.num_of_sublinks);
return width;
}

View file

@ -709,6 +709,8 @@ int mdss_mdp_get_panel_params(struct mdss_mdp_pipe *pipe,
*h_total += mdss_panel_get_htotal(
&mixer->ctl->panel_data->next->panel_info,
false);
else if (is_panel_split_link(mixer->ctl->mfd))
*h_total *= pinfo->mipi.num_of_sublinks;
} else {
*v_total = mixer->height;
*xres = mixer->width;
@ -4108,6 +4110,9 @@ static void mdss_mdp_ctl_split_display_enable(int enable,
}
}
}
if (is_panel_split_link(main_ctl->mfd))
upper = lower = 0;
writel_relaxed(upper, main_ctl->mdata->mdp_base +
MDSS_MDP_REG_SPLIT_DISPLAY_UPPER_PIPE_CTRL);
writel_relaxed(lower, main_ctl->mdata->mdp_base +
@ -4276,7 +4281,8 @@ void mdss_mdp_ctl_restore(bool locked)
if (sctl) {
mdss_mdp_ctl_restore_sub(sctl);
mdss_mdp_ctl_split_display_enable(1, ctl, sctl);
} else if (is_pingpong_split(ctl->mfd)) {
} else if (is_pingpong_split(ctl->mfd) ||
is_panel_split_link(ctl->mfd)) {
mdss_mdp_ctl_pp_split_display_enable(1, ctl);
}
@ -4403,6 +4409,8 @@ int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff)
} else if (is_pingpong_split(ctl->mfd)) {
ctl->slave_intf_num = (ctl->intf_num + 1);
mdss_mdp_ctl_pp_split_display_enable(true, ctl);
} else if (is_panel_split_link(ctl->mfd)) {
mdss_mdp_ctl_pp_split_display_enable(true, ctl);
}
}

View file

@ -850,4 +850,8 @@ enum mdss_mdp_pingpong_index {
#define MDSS_MDP_REG_TRAFFIC_SHAPER_WR_CLIENT(num) (0x060 + (num * 4))
#define MDSS_MDP_REG_TRAFFIC_SHAPER_FIXPOINT_FACTOR 4
#define MDSS_MDP_REG_SPLIT_LINK 0x00060
#define MDSS_MDP_REG_SPLIT_LINK_LEFT_LINK_EN BIT(1)
#define MDSS_MDP_REG_SPLIT_LINK_RIGHT_LINK_EN BIT(2)
#endif

View file

@ -1682,6 +1682,16 @@ static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
mdss_bus_bandwidth_ctrl(true);
/* configure the split link to both sublinks */
if (is_panel_split_link(ctl->mfd)) {
mdp_video_write(ctx, MDSS_MDP_REG_SPLIT_LINK, 0x3);
/*
* ensure split link register is written before
* enabling timegen
*/
wmb();
}
mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
wmb();

View file

@ -533,6 +533,8 @@ struct mipi_panel_info {
char lp11_init;
u32 init_delay;
u32 post_init_delay;
u32 num_of_sublinks;
u32 lanes_per_sublink;
};
struct edp_panel_info {
@ -847,6 +849,7 @@ struct mdss_panel_info {
bool is_lpm_mode;
bool is_split_display; /* two DSIs in one display, pp split or not */
bool use_pingpong_split;
bool split_link_enabled;
/*
* index[0] = left layer mixer, value of 0 not valid

View file

@ -38,16 +38,23 @@
#define MDSS_DSI_DSIPHY_GLBL_TEST_CTRL 0x1d4
#define MDSS_DSI_DSIPHY_CTRL_0 0x170
#define MDSS_DSI_DSIPHY_CTRL_1 0x174
#define MDSS_DSI_DSIPHY_CMN_CLK_CFG0 0x0010
#define MDSS_DSI_DSIPHY_CMN_CLK_CFG1 0x0014
#define MDSS_DSI_NUM_DATA_LANES 0x04
#define MDSS_DSI_NUM_CLK_LANES 0x01
#define SW_RESET BIT(2)
#define SW_RESET_PLL BIT(0)
#define PWRDN_B BIT(7)
/* 8996 */
#define DATALANE_OFFSET_FROM_BASE_8996 0x100
#define DSIPHY_CMN_PLL_CNTRL 0x0048
#define DATALANE_OFFSET_FROM_BASE_8996 0x100
#define CLKLANE_OFFSET_FROM_BASE_8996 0x300
#define DATALANE_SIZE_8996 0x80
#define CLKLANE_SIZE_8996 0x80
#define DSIPHY_CMN_PLL_CNTRL 0x0048
#define DSIPHY_CMN_GLBL_TEST_CTRL 0x0018
#define DSIPHY_CMN_CTRL_0 0x001c
#define DSIPHY_CMN_CTRL_1 0x0020
@ -55,6 +62,24 @@
#define DSIPHY_PLL_CLKBUFLR_EN 0x041c
#define DSIPHY_PLL_PLL_BANDGAP 0x0508
#define DSIPHY_LANE_STRENGTH_CTRL_NUM 0x0002
#define DSIPHY_LANE_STRENGTH_CTRL_OFFSET 0x0004
#define DSIPHY_LANE_STRENGTH_CTRL_BASE 0x0038
#define DSIPHY_LANE_CFG_NUM 0x0004
#define DSIPHY_LANE_CFG_OFFSET 0x0004
#define DSIPHY_LANE_CFG_BASE 0x0000
#define DSIPHY_LANE_VREG_NUM 0x0001
#define DSIPHY_LANE_VREG_OFFSET 0x0004
#define DSIPHY_LANE_VREG_BASE 0x0064
#define DSIPHY_LANE_TIMING_CTRL_NUM 0x0008
#define DSIPHY_LANE_TIMING_CTRL_OFFSET 0x0004
#define DSIPHY_LANE_TIMING_CTRL_BASE 0x0018
#define DSIPHY_LANE_TEST_STR 0x0014
#define DSIPHY_LANE_STRENGTH_CTRL_1 0x003c
#define DSIPHY_LANE_VREG_CNTRL 0x0064
@ -131,6 +156,8 @@
#define DSIPHY_PLL_RESETSM_CNTRL5 0x043c
#define DSIPHY_CMN_CLK_CFG1_SPLIT_LINK 0x1
#define PLL_CALC_DATA(addr0, addr1, data0, data1) \
(((data1) << 24) | ((((addr1)/4) & 0xFF) << 16) | \
((data0) << 8) | (((addr0)/4) & 0xFF))
@ -911,35 +938,59 @@ static void mdss_dsi_8996_phy_regulator_enable(
int j, off, ln, cnt, ln_off;
char *ip;
void __iomem *base;
struct mdss_panel_info *panel_info;
if (!ctrl) {
pr_warn("%s: null ctrl pdata\n", __func__);
return;
}
panel_info = &((ctrl->panel_data).panel_info);
pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
if (pd->regulator_len != 5) {
if (pd->regulator_len != (MDSS_DSI_NUM_DATA_LANES +
MDSS_DSI_NUM_CLK_LANES)) {
pr_warn("%s: invalid regulator settings\n", __func__);
return;
}
/* 4 lanes + clk lane configuration */
for (ln = 0; ln < 5; ln++) {
/*
* data lane offset frome base: 0x100
* data lane size: 0x80
*/
base = ctrl->phy_io.base +
DATALANE_OFFSET_FROM_BASE_8996;
base += (ln * DATALANE_SIZE_8996); /* lane base */
/* vreg ctrl, 1 * 5 */
cnt = 1;
/*
* data lane offset from base: 0x100
* data lane size: 0x80
*/
base = ctrl->phy_io.base + DATALANE_OFFSET_FROM_BASE_8996;
/* data lanes configuration */
for (ln = 0; ln < MDSS_DSI_NUM_DATA_LANES; ln++) {
/* vreg ctrl, 1 * MDSS_DSI_NUM_DATA_LANES */
cnt = DSIPHY_LANE_VREG_NUM;
off = DSIPHY_LANE_VREG_BASE;
ln_off = cnt * ln;
ip = &pd->regulator[ln_off];
off = 0x64;
for (j = 0; j < cnt; j++, off += 4)
for (j = 0; j < cnt; j++) {
MIPI_OUTP(base + off, *ip++);
off += DSIPHY_LANE_VREG_OFFSET;
}
base += DATALANE_SIZE_8996; /* next lane */
}
wmb(); /* make sure registers committed */
/*
* clk lane offset from base: 0x300
* clk lane size: 0x80
*/
base = ctrl->phy_io.base + CLKLANE_OFFSET_FROM_BASE_8996;
/*
* clk lane configuration for vreg ctrl
* for split link there are two clock lanes, one
* clock lane per sublink needs to be configured
*/
off = DSIPHY_LANE_VREG_BASE;
ln_off = MDSS_DSI_NUM_DATA_LANES;
ip = &pd->regulator[ln_off];
MIPI_OUTP(base + off, *ip);
if (panel_info->split_link_enabled)
MIPI_OUTP(base + CLKLANE_SIZE_8996 + off, *ip);
wmb(); /* make sure registers committed */
}
static void mdss_dsi_8996_phy_power_off(
@ -948,31 +999,51 @@ static void mdss_dsi_8996_phy_power_off(
int ln;
void __iomem *base;
u32 data;
struct mdss_panel_info *panel_info;
if (ctrl) {
panel_info = &((ctrl->panel_data).panel_info);
} else {
pr_warn("%s: null ctrl pdata\n", __func__);
return;
}
/* Turn off PLL power */
data = MIPI_INP(ctrl->phy_io.base + DSIPHY_CMN_CTRL_0);
MIPI_OUTP(ctrl->phy_io.base + DSIPHY_CMN_CTRL_0, data & ~BIT(7));
/* 4 lanes + clk lane configuration */
for (ln = 0; ln < 5; ln++) {
base = ctrl->phy_io.base +
DATALANE_OFFSET_FROM_BASE_8996;
base += (ln * DATALANE_SIZE_8996); /* lane base */
/* data lanes configuration */
base = ctrl->phy_io.base + DATALANE_OFFSET_FROM_BASE_8996;
for (ln = 0; ln < MDSS_DSI_NUM_DATA_LANES; ln++) {
/* turn off phy ldo */
MIPI_OUTP(base + DSIPHY_LANE_VREG_CNTRL, 0x1c);
MIPI_OUTP(base + DSIPHY_LANE_VREG_BASE, 0x1c);
base += DATALANE_SIZE_8996; /* next lane */
}
/* clk lane configuration */
base = ctrl->phy_io.base + CLKLANE_OFFSET_FROM_BASE_8996;
/* turn off phy ldo */
MIPI_OUTP(base + DSIPHY_LANE_VREG_BASE, 0x1c);
if (panel_info->split_link_enabled)
MIPI_OUTP(base + CLKLANE_SIZE_8996 +
DSIPHY_LANE_VREG_BASE, 0x1c);
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_LDO_CNTRL, 0x1c);
/* 4 lanes + clk lane configuration */
for (ln = 0; ln < 5; ln++) {
base = ctrl->phy_io.base +
DATALANE_OFFSET_FROM_BASE_8996;
base += (ln * DATALANE_SIZE_8996); /* lane base */
/* data lanes configuration */
base = ctrl->phy_io.base + DATALANE_OFFSET_FROM_BASE_8996;
for (ln = 0; ln < MDSS_DSI_NUM_DATA_LANES; ln++) {
MIPI_OUTP(base + DSIPHY_LANE_STRENGTH_CTRL_1, 0x0);
base += DATALANE_SIZE_8996; /* next lane */
}
/* clk lane configuration */
base = ctrl->phy_io.base + CLKLANE_OFFSET_FROM_BASE_8996;
MIPI_OUTP(base + DSIPHY_LANE_STRENGTH_CTRL_1, 0x0);
if (panel_info->split_link_enabled)
MIPI_OUTP(base + CLKLANE_SIZE_8996 +
DSIPHY_LANE_STRENGTH_CTRL_1, 0x0);
wmb(); /* make sure registers committed */
}
@ -1008,22 +1079,46 @@ static void mdss_dsi_8996_phy_power_on(
struct mdss_dsi_phy_ctrl *pd;
char *ip;
u32 data;
struct mdss_panel_info *panel_info;
if (ctrl) {
panel_info = &((ctrl->panel_data).panel_info);
} else {
pr_warn("%s: null ctrl pdata\n", __func__);
return;
}
pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
/* 4 lanes + clk lane configuration */
for (ln = 0; ln < 5; ln++) {
base = ctrl->phy_io.base +
DATALANE_OFFSET_FROM_BASE_8996;
base += (ln * DATALANE_SIZE_8996); /* lane base */
/* strength, 2 * 5 */
cnt = 2;
/* data lanes configuration */
base = ctrl->phy_io.base + DATALANE_OFFSET_FROM_BASE_8996;
for (ln = 0; ln < MDSS_DSI_NUM_DATA_LANES; ln++) {
/* strength, 2 * MDSS_DSI_NUM_DATA_LANES */
cnt = DSIPHY_LANE_STRENGTH_CTRL_NUM;
ln_off = cnt * ln;
ip = &pd->strength[ln_off];
off = 0x38;
for (j = 0; j < cnt; j++, off += 4)
off = DSIPHY_LANE_STRENGTH_CTRL_BASE;
for (j = 0; j < cnt; j++,
off += DSIPHY_LANE_STRENGTH_CTRL_OFFSET)
MIPI_OUTP(base + off, *ip++);
base += DATALANE_SIZE_8996; /* next lane */
}
/*
* clk lane configuration for strength ctrl
* for split link there are two clock lanes, one
* clock lane per sublink needs to be configured
*/
base = ctrl->phy_io.base + CLKLANE_OFFSET_FROM_BASE_8996;
cnt = DSIPHY_LANE_STRENGTH_CTRL_NUM;
ln_off = MDSS_DSI_NUM_DATA_LANES;
ip = &pd->strength[ln_off];
off = DSIPHY_LANE_STRENGTH_CTRL_BASE;
for (j = 0; j < cnt; j++,
off += DSIPHY_LANE_STRENGTH_CTRL_OFFSET) {
MIPI_OUTP(base + off, *ip);
if (panel_info->split_link_enabled)
MIPI_OUTP(base + CLKLANE_SIZE_8996 + off, *ip);
}
mdss_dsi_8996_phy_regulator_enable(ctrl);
@ -1051,67 +1146,126 @@ static void mdss_dsi_8996_phy_config(struct mdss_dsi_ctrl_pdata *ctrl)
int j, off, ln, cnt, ln_off;
char *ip;
void __iomem *base;
struct mdss_panel_info *panel_info;
int num_of_lanes = 0;
if (ctrl) {
panel_info = &((ctrl->panel_data).panel_info);
} else {
pr_warn("%s: null ctrl pdata\n", __func__);
return;
}
pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
num_of_lanes = MDSS_DSI_NUM_DATA_LANES + MDSS_DSI_NUM_CLK_LANES;
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_LDO_CNTRL, 0x1c);
/* clk_en */
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL, 0x1);
if (pd->lanecfg_len != 20) {
if (pd->lanecfg_len != (num_of_lanes * DSIPHY_LANE_CFG_NUM)) {
pr_err("%s: wrong lane cfg\n", __func__);
return;
}
if (pd->strength_len != 10) {
if (pd->strength_len != (num_of_lanes *
DSIPHY_LANE_STRENGTH_CTRL_NUM)) {
pr_err("%s: wrong strength ctrl\n", __func__);
return;
}
if (pd->regulator_len != 5) {
if (pd->regulator_len != (num_of_lanes * DSIPHY_LANE_VREG_NUM)) {
pr_err("%s: wrong regulator setting\n", __func__);
return;
}
/* 4 lanes + clk lane configuration */
for (ln = 0; ln < 5; ln++) {
/*
* data lane offset frome base: 0x100
* data lane size: 0x80
*/
base = ctrl->phy_io.base +
DATALANE_OFFSET_FROM_BASE_8996;
base += (ln * DATALANE_SIZE_8996); /* lane base */
/* lane cfg, 4 * 5 */
cnt = 4;
/* data lanes configuration */
base = ctrl->phy_io.base + DATALANE_OFFSET_FROM_BASE_8996;
for (ln = 0; ln < MDSS_DSI_NUM_DATA_LANES; ln++) {
/* lane cfg, 4 * MDSS_DSI_NUM_DATA_LANES */
cnt = DSIPHY_LANE_CFG_NUM;
off = DSIPHY_LANE_CFG_BASE;
ln_off = cnt * ln;
ip = &pd->lanecfg[ln_off];
off = 0x0;
for (j = 0; j < cnt; j++) {
MIPI_OUTP(base + off, *ip++);
off += 4;
off += DSIPHY_LANE_CFG_OFFSET;
}
/* test str */
MIPI_OUTP(base + 0x14, 0x0088); /* fixed */
MIPI_OUTP(base + DSIPHY_LANE_TEST_STR, 0x88); /* fixed */
/* phy timing, 8 * 5 */
cnt = 8;
/* phy timing, 8 * MDSS_DSI_NUM_DATA_LANES */
cnt = DSIPHY_LANE_TIMING_CTRL_NUM;
off = DSIPHY_LANE_TIMING_CTRL_BASE;
ln_off = cnt * ln;
ip = &pd->timing_8996[ln_off];
off = 0x18;
for (j = 0; j < cnt; j++, off += 4)
for (j = 0; j < cnt; j++) {
MIPI_OUTP(base + off, *ip++);
off += DSIPHY_LANE_TIMING_CTRL_OFFSET;
}
/* strength, 2 * 5 */
cnt = 2;
/* strength, 2 * MDSS_DSI_NUM_DATA_LANES */
cnt = DSIPHY_LANE_STRENGTH_CTRL_NUM;
off = DSIPHY_LANE_STRENGTH_CTRL_BASE;
ln_off = cnt * ln;
ip = &pd->strength[ln_off];
off = 0x38;
for (j = 0; j < cnt; j++, off += 4)
for (j = 0; j < cnt; j++) {
MIPI_OUTP(base + off, *ip++);
off += DSIPHY_LANE_STRENGTH_CTRL_OFFSET;
}
base += DATALANE_SIZE_8996; /* next lane */
}
/*
* clk lane configuration
* for split link there are two clock lanes, one
* clock lane per sublink needs to be configured
*/
base = ctrl->phy_io.base + CLKLANE_OFFSET_FROM_BASE_8996;
cnt = DSIPHY_LANE_CFG_NUM;
off = DSIPHY_LANE_CFG_BASE;
ln_off = cnt * MDSS_DSI_NUM_DATA_LANES;
ip = &pd->lanecfg[ln_off];
for (j = 0; j < cnt; j++, *ip++) {
MIPI_OUTP(base + off, *ip);
if (panel_info->split_link_enabled)
MIPI_OUTP(base + CLKLANE_SIZE_8996 + off, *ip);
off += DSIPHY_LANE_CFG_OFFSET;
}
/* test str */
MIPI_OUTP(base + DSIPHY_LANE_TEST_STR, 0x88); /* fixed */
if (panel_info->split_link_enabled)
MIPI_OUTP(base + CLKLANE_SIZE_8996 + off, 0x88);
cnt = DSIPHY_LANE_TIMING_CTRL_NUM;
off = DSIPHY_LANE_TIMING_CTRL_BASE;
ln_off = cnt * MDSS_DSI_NUM_DATA_LANES;
ip = &pd->timing_8996[ln_off];
for (j = 0; j < cnt; j++, *ip++) {
MIPI_OUTP(base + off, *ip);
if (panel_info->split_link_enabled)
MIPI_OUTP(base + CLKLANE_SIZE_8996 + off, *ip);
off += DSIPHY_LANE_TIMING_CTRL_OFFSET;
}
/*
* clk lane configuration for timing
* for split link there are two clock lanes, one
* clock lane per sublink needs to be configured
*/
cnt = DSIPHY_LANE_STRENGTH_CTRL_NUM;
off = DSIPHY_LANE_STRENGTH_CTRL_BASE;
ln_off = cnt * MDSS_DSI_NUM_DATA_LANES;
ip = &pd->strength[ln_off];
for (j = 0; j < cnt; j++, *ip++) {
MIPI_OUTP(base + off, *ip);
if (panel_info->split_link_enabled)
MIPI_OUTP(base + CLKLANE_SIZE_8996 + off, *ip);
off += DSIPHY_LANE_STRENGTH_CTRL_OFFSET;
}
wmb(); /* make sure registers committed */
@ -1665,6 +1819,9 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
u32 dsi_pclk_rate;
u8 lanes = 0, bpp;
if (!panel_info)
return -EINVAL;
if (panel_info->mipi.data_lane3)
lanes += 1;
if (panel_info->mipi.data_lane2)
@ -1690,6 +1847,8 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
}
h_period = mdss_panel_get_htotal(panel_info, true);
if (panel_info->split_link_enabled)
h_period *= panel_info->mipi.num_of_sublinks;
v_period = mdss_panel_get_vtotal(panel_info);
if (ctrl_pdata->refresh_clk_rate || is_diff_frame_rate(panel_info,
@ -1710,7 +1869,12 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
clk_rate = panel_info->clk_rate;
do_div(clk_rate, 8 * bpp);
dsi_pclk_rate = (u32) clk_rate * lanes;
if (panel_info->split_link_enabled)
dsi_pclk_rate = (u32) clk_rate *
panel_info->mipi.lanes_per_sublink;
else
dsi_pclk_rate = (u32) clk_rate * lanes;
if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000))
dsi_pclk_rate = 35000000;
@ -2320,6 +2484,32 @@ int mdss_dsi_pre_clkoff_cb(void *priv,
return rc;
}
static void mdss_dsi_split_link_clk_cfg(struct mdss_dsi_ctrl_pdata *ctrl,
int enable)
{
struct mdss_panel_data *pdata = NULL;
void __iomem *base;
u32 data = 0;
if (ctrl)
pdata = &ctrl->panel_data;
else {
pr_err("%s: ctrl pdata is NULL\n", __func__);
return;
}
/*
* for split link there are two clock lanes, and
* both clock lanes needs to be enabled
*/
if (pdata->panel_info.split_link_enabled) {
base = ctrl->phy_io.base;
data = MIPI_INP(base + MDSS_DSI_DSIPHY_CMN_CLK_CFG1);
data |= (enable << DSIPHY_CMN_CLK_CFG1_SPLIT_LINK);
MIPI_OUTP(base + MDSS_DSI_DSIPHY_CMN_CLK_CFG1, data);
}
}
int mdss_dsi_post_clkon_cb(void *priv,
enum mdss_dsi_clk_type clk,
enum mdss_dsi_clk_state curr_state)
@ -2393,6 +2583,9 @@ int mdss_dsi_post_clkon_cb(void *priv,
}
if (pdata->panel_info.mipi.force_clk_lane_hs)
mdss_dsi_cfg_lane_ctrl(ctrl, BIT(28), 1);
/* enable split link for cmn clk cfg1 */
mdss_dsi_split_link_clk_cfg(ctrl, 1);
}
error:
return rc;