Merge "msm: mdss: add split link panel support in mdss"
This commit is contained in:
commit
2fce80230e
11 changed files with 381 additions and 70 deletions
|
@ -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>;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue