diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt index cc55f6e2bfa0..4d0e1d5e12a2 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt @@ -165,6 +165,9 @@ Optional properties: - qcom,mdss-dsi-border-color: Defines the border color value if border is present. 0 = default value. - qcom,mdss-dsi-pan-enable-dynamic-fps: Boolean used to enable change in frame rate dynamically. +- qcom,mdss-dsi-pan-enable-dynamic-bitclk: Boolean used to enable change in DSI clock dynamically. +- qcom,mdss-dsi-dynamic-bitclk_freq: An array of integers that specifies the DSI bit clock + frequencies supported as part of dynamic bit clock feature. - qcom,mdss-dsi-pan-fps-update: A string that specifies when to change the frame rate. "dfps_suspend_resume_mode"= FPS change request is implemented during suspend/resume. @@ -696,6 +699,9 @@ Example: qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; qcom,mdss-dsi-pan-enable-dynamic-fps; qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode"; + qcom,mdss-dsi-pan-enable-dynamic-bitclk; + qcom,mdss-dsi-dynamic-bitclk_freq = <711037824 724453632 737869440 + 751285248 764701056 778116864 791532672 804948480>; qcom,min-refresh-rate = <30>; qcom,max-refresh-rate = <60>; qcom,mdss-dsi-bl-pmic-bank-select = <0>; diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index cf34f3a9b7e1..637272a61211 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -2075,10 +2075,9 @@ static void __mdss_dsi_calc_dfps_delay(struct mdss_panel_data *pdata) } static int __mdss_dsi_dfps_calc_clks(struct mdss_panel_data *pdata, - int new_fps) + u64 new_clk_rate) { int rc = 0; - u64 clk_rate; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_panel_info *pinfo; u32 phy_rev; @@ -2098,14 +2097,9 @@ static int __mdss_dsi_dfps_calc_clks(struct mdss_panel_data *pdata, pinfo = &pdata->panel_info; phy_rev = ctrl_pdata->shared_data->phy_rev; - rc = mdss_dsi_clk_div_config - (&ctrl_pdata->panel_data.panel_info, new_fps); - if (rc) { - pr_err("%s: unable to initialize the clk dividers\n", - __func__); - return rc; - } - + pinfo->clk_rate = new_clk_rate; + pinfo->mipi.dsi_pclk_rate = mdss_dsi_get_pclk_rate(pinfo, + new_clk_rate); __mdss_dsi_dyn_refresh_config(ctrl_pdata); if (phy_rev == DSI_PHY_REV_20) @@ -2118,9 +2112,8 @@ static int __mdss_dsi_dfps_calc_clks(struct mdss_panel_data *pdata, ctrl_pdata->byte_clk_rate_bkp = ctrl_pdata->byte_clk_rate; ctrl_pdata->pclk_rate = pinfo->mipi.dsi_pclk_rate; - clk_rate = pinfo->clk_rate; - do_div(clk_rate, 8U); - ctrl_pdata->byte_clk_rate = (u32) clk_rate; + do_div(new_clk_rate, 8U); + ctrl_pdata->byte_clk_rate = (u32) new_clk_rate; pr_debug("byte_rate=%i\n", ctrl_pdata->byte_clk_rate); pr_debug("pclk_rate=%i\n", ctrl_pdata->pclk_rate); @@ -2128,8 +2121,7 @@ static int __mdss_dsi_dfps_calc_clks(struct mdss_panel_data *pdata, return rc; } -static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata, - int new_fps) +static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata) { struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_dsi_ctrl_pdata *sctrl_pdata = NULL; @@ -2280,12 +2272,6 @@ static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata, clk_disable_unprepare(ctrl_pdata->pll_byte_clk); clk_disable_unprepare(ctrl_pdata->pll_pixel_clk); - /* update new fps that at this point is already updated in hw */ - pinfo->current_fps = new_fps; - if (sctrl_pdata) { - spinfo->current_fps = new_fps; - } - return rc; dfps_timeout: @@ -2362,13 +2348,65 @@ static void mdss_dsi_avr_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata, MDSS_XLOG(ctrl_pdata->ndx, enabled, data); } -static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps) +static int __mdss_dsi_dynamic_clock_switch(struct mdss_panel_data *pdata, + u64 new_clk_rate) { int rc = 0; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_panel_info *pinfo; u32 phy_rev; - u32 frame_rate_bkp; + u64 clk_rate_bkp; + + pr_debug("%s+:\n", __func__); + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + phy_rev = ctrl_pdata->shared_data->phy_rev; + pinfo = &pdata->panel_info; + + /* get the fps configured in HW */ + clk_rate_bkp = pinfo->clk_rate; + + __mdss_dsi_mask_dfps_errors(ctrl_pdata, true); + + if (phy_rev == DSI_PHY_REV_20) { + rc = mdss_dsi_phy_calc_timing_param(pinfo, phy_rev, + new_clk_rate); + if (rc) { + pr_err("PHY calculations failed-%lld\n", new_clk_rate); + goto end_update; + } + } + + rc = __mdss_dsi_dfps_calc_clks(pdata, new_clk_rate); + if (rc) { + pr_err("error calculating clocks for %lld\n", new_clk_rate); + goto error_clks; + } + + rc = __mdss_dsi_dfps_update_clks(pdata); + if (rc) { + pr_err("Dynamic refresh failed-%lld\n", new_clk_rate); + goto error_dfps; + } + return rc; +error_dfps: + if (__mdss_dsi_dfps_calc_clks(pdata, clk_rate_bkp)) + pr_err("error reverting clock calculations for %lld\n", + clk_rate_bkp); +error_clks: + if (mdss_dsi_phy_calc_timing_param(pinfo, phy_rev, clk_rate_bkp)) + pr_err("Unable to revert phy timing-%lld\n", clk_rate_bkp); +end_update: + return rc; +} + +static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps) +{ + int rc = 0; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_panel_info *pinfo; pr_debug("%s+:\n", __func__); @@ -2385,12 +2423,8 @@ static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps) return -EINVAL; } - phy_rev = ctrl_pdata->shared_data->phy_rev; pinfo = &pdata->panel_info; - /* get the fps configured in HW */ - frame_rate_bkp = pinfo->current_fps; - if (new_fps == pinfo->current_fps) { /* * This is unlikely as mdss driver checks for previously @@ -2406,39 +2440,45 @@ static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps) __mdss_dsi_update_video_mode_total(pdata, new_fps); } else if (pinfo->dfps_update == DFPS_IMMEDIATE_CLK_UPDATE_MODE) { /* Clock update method */ + u64 new_clk_rate = mdss_dsi_calc_bitclk + (&ctrl_pdata->panel_data.panel_info, new_fps); + if (!new_clk_rate) { + pr_err("%s: unable to get the new bit clock rate\n", + __func__); + rc = -EINVAL; + goto end_update; + } - __mdss_dsi_mask_dfps_errors(ctrl_pdata, true); + rc = __mdss_dsi_dynamic_clock_switch(pdata, new_clk_rate); + if (!rc) { + struct mdss_dsi_ctrl_pdata *mctrl_pdata = NULL; + struct mdss_panel_info *mpinfo = NULL; - if (phy_rev == DSI_PHY_REV_20) { - rc = mdss_dsi_phy_calc_timing_param(pinfo, phy_rev, - new_fps); - if (rc) { - pr_err("PHY calculations failed-%d\n", new_fps); + if (mdss_dsi_is_hw_config_split + (ctrl_pdata->shared_data) && + mdss_dsi_is_ctrl_clk_master(ctrl_pdata)) goto end_update; + + if (mdss_dsi_is_hw_config_split + (ctrl_pdata->shared_data) && + mdss_dsi_is_ctrl_clk_slave(ctrl_pdata)) { + mctrl_pdata = mdss_dsi_get_ctrl_clk_master(); + if (IS_ERR_OR_NULL(mctrl_pdata)) { + pr_err("Invalid mctrl_pdata\n"); + goto end_update; + } + + mpinfo = &mctrl_pdata->panel_data.panel_info; } - } - - rc = __mdss_dsi_dfps_calc_clks(pdata, new_fps); - if (rc) { - pr_err("error calculating clocks for %d\n", new_fps); - goto error_clks; - } - - rc = __mdss_dsi_dfps_update_clks(pdata, new_fps); - if (rc) { - pr_err("Dynamic refresh failed-%d\n", new_fps); - goto error_dfps; + /* + * update new fps that at this point is already + * updated in hw + */ + pinfo->current_fps = new_fps; + if (mctrl_pdata && mpinfo) + mpinfo->current_fps = new_fps; } } - - return rc; -error_dfps: - if (__mdss_dsi_dfps_calc_clks(pdata, frame_rate_bkp)) - pr_err("error reverting clock calculations for %d\n", - frame_rate_bkp); -error_clks: - if (mdss_dsi_phy_calc_timing_param(pinfo, phy_rev, frame_rate_bkp)) - pr_err("Unable to revert phy timing-%d\n", frame_rate_bkp); end_update: return rc; } @@ -2712,6 +2752,163 @@ static void mdss_dsi_timing_db_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, MDSS_DSI_CORE_CLK, MDSS_DSI_CLK_OFF); } +static struct mdss_dsi_ctrl_pdata *mdss_dsi_get_drvdata(struct device *dev) +{ + struct msm_fb_data_type *mfd; + struct mdss_panel_data *pdata; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct fb_info *fbi = dev_get_drvdata(dev); + + if (fbi) { + mfd = (struct msm_fb_data_type *)fbi->par; + pdata = dev_get_platdata(&mfd->pdev->dev); + + ctrl_pdata = container_of(pdata, + struct mdss_dsi_ctrl_pdata, panel_data); + } + + return ctrl_pdata; +} + +static ssize_t supp_bitclk_list_sysfs_rda(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + int i = 0; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = mdss_dsi_get_drvdata(dev); + struct mdss_panel_info *pinfo = NULL; + + if (!ctrl_pdata) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + pinfo = &ctrl_pdata->panel_data.panel_info; + if (!pinfo) { + pr_err("no panel connected\n"); + return -ENODEV; + } + + if (!pinfo->dynamic_bitclk) { + pr_err_once("%s: Dynamic bitclk not enabled for this panel\n", + __func__); + return -EINVAL; + } + + buf[0] = 0; + for (i = 0; i < pinfo->supp_bitclk_len; i++) { + if (ret > 0) + ret += scnprintf(buf + ret, PAGE_SIZE - ret, + ",%d", pinfo->supp_bitclks[i]); + else + ret += scnprintf(buf + ret, PAGE_SIZE - ret, + "%d", pinfo->supp_bitclks[i]); + } + + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n"); + + return ret; +} + +static ssize_t dynamic_bitclk_sysfs_wta(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc = 0, i = 0; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = mdss_dsi_get_drvdata(dev); + struct mdss_panel_info *pinfo = NULL; + int clk_rate = 0; + + if (!ctrl_pdata) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + pinfo = &ctrl_pdata->panel_data.panel_info; + if (!pinfo) { + pr_err("no panel connected\n"); + return -ENODEV; + } + + if (!pinfo->dynamic_bitclk) { + pr_err_once("%s: Dynamic bitclk not enabled for this panel\n", + __func__); + return -EINVAL; + } + + if (mdss_panel_is_power_off(pinfo->panel_power_state)) { + pr_err_once("%s: Panel powered off!\n", __func__); + return -EINVAL; + } + + rc = kstrtoint(buf, 10, &clk_rate); + if (rc) { + pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc); + return rc; + } + + for (i = 0; i < pinfo->supp_bitclk_len; i++) { + if (pinfo->supp_bitclks[i] == clk_rate) + break; + } + if (i == pinfo->supp_bitclk_len) { + pr_err("Requested bitclk: %d not supported\n", clk_rate); + return -EINVAL; + } + + rc = __mdss_dsi_dynamic_clock_switch(&ctrl_pdata->panel_data, + clk_rate); + if (!rc && mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) { + struct mdss_dsi_ctrl_pdata *octrl = + mdss_dsi_get_other_ctrl(ctrl_pdata); + rc = __mdss_dsi_dynamic_clock_switch(&octrl->panel_data, + clk_rate); + if (rc) + pr_err("failed to switch DSI bitclk for sctrl\n"); + } else if (rc) { + pr_err("failed to switch DSI bitclk\n"); + } + + return count; +} /* dynamic_bitclk_sysfs_wta */ + +static ssize_t dynamic_bitclk_sysfs_rda(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = mdss_dsi_get_drvdata(dev); + struct mdss_panel_info *pinfo = NULL; + + if (!ctrl_pdata) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + pinfo = &ctrl_pdata->panel_data.panel_info; + if (!pinfo) { + pr_err("no panel connected\n"); + return -ENODEV; + } + + ret = snprintf(buf, PAGE_SIZE, "%llu\n", pinfo->clk_rate); + pr_debug("%s: '%llu'\n", __func__, pinfo->clk_rate); + + return ret; +} /* dynamic_bitclk_sysfs_rda */ + +static DEVICE_ATTR(dynamic_bitclk, S_IRUGO | S_IWUSR | S_IWGRP, + dynamic_bitclk_sysfs_rda, dynamic_bitclk_sysfs_wta); +static DEVICE_ATTR(supported_bitclk, S_IRUGO, supp_bitclk_list_sysfs_rda, NULL); + +static struct attribute *dynamic_bitclk_fs_attrs[] = { + &dev_attr_dynamic_bitclk.attr, + &dev_attr_supported_bitclk.attr, + NULL, +}; + +static struct attribute_group mdss_dsi_fs_attrs_group = { + .attrs = dynamic_bitclk_fs_attrs, +}; + static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, int event, void *arg) { @@ -2878,6 +3075,14 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, ctrl_pdata->kobj = &fbi->dev->kobj; ctrl_pdata->fb_node = fbi->node; + if (!mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data) || + (mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data) && + mdss_dsi_is_ctrl_clk_master(ctrl_pdata))) { + if (sysfs_create_group(&fbi->dev->kobj, + &mdss_dsi_fs_attrs_group)) + pr_err("failed to create DSI sysfs group\n"); + } + if (IS_ENABLED(CONFIG_MSM_DBA) && pdata->panel_info.is_dba_panel) { queue_delayed_work(ctrl_pdata->workq, @@ -3512,7 +3717,7 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) pinfo = &(ctrl_pdata->panel_data.panel_info); if (!(mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data) && mdss_dsi_is_ctrl_clk_slave(ctrl_pdata)) && - pinfo->dynamic_fps) { + (pinfo->dynamic_fps || pinfo->dynamic_bitclk)) { rc = mdss_dsi_shadow_clk_init(pdev, ctrl_pdata); if (rc) { @@ -4536,11 +4741,19 @@ int dsi_panel_device_register(struct platform_device *ctrl_pdev, ((mipi->mode == DSI_VIDEO_MODE) ? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL); - rc = mdss_dsi_clk_div_config(pinfo, mipi->frame_rate); - if (rc) { - pr_err("%s: unable to initialize the clk dividers\n", __func__); - return rc; + pinfo->clk_rate = mdss_dsi_calc_bitclk(pinfo, mipi->frame_rate); + if (!pinfo->clk_rate) { + pr_err("%s: unable to calculate the DSI bit clock\n", __func__); + return -EINVAL; } + + pinfo->mipi.dsi_pclk_rate = mdss_dsi_get_pclk_rate(pinfo, + pinfo->clk_rate); + if (!pinfo->mipi.dsi_pclk_rate) { + pr_err("%s: unable to calculate the DSI pclk\n", __func__); + return -EINVAL; + } + ctrl_pdata->pclk_rate = mipi->dsi_pclk_rate; clk_rate = pinfo->clk_rate; do_div(clk_rate, 8U); diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 8bd8a140773e..00895308119b 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -720,8 +720,8 @@ void disable_esd_thread(void); void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata); void mdss_dsi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata); -int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, - int frame_rate); +u64 mdss_dsi_calc_bitclk(struct mdss_panel_info *panel_info, int frame_rate); +u32 mdss_dsi_get_pclk_rate(struct mdss_panel_info *panel_info, u64 clk_rate); int mdss_dsi_clk_refresh(struct mdss_panel_data *pdata, bool update_phy); int mdss_dsi_link_clk_init(struct platform_device *pdev, struct mdss_dsi_ctrl_pdata *ctrl_pdata); diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index d66da235ea80..e683c7887f50 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,9 +10,6 @@ * GNU General Public License for more details. */ - - - #include #include #include @@ -25,11 +22,11 @@ #include #include #include - + #include "mdss_dsi.h" #include "mdss_dba_utils.h" #include "mdss_debug.h" - + #include #include #if defined(CONFIG_IRIS2P_FULL_SUPPORT) @@ -38,993 +35,988 @@ #define DT_CMD_HDR 6 #define DEFAULT_MDP_TRANSFER_TIME 14000 - + #define VSYNC_DELAY msecs_to_jiffies(17) + +DEFINE_LED_TRIGGER(bl_led_trigger); + +void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl) +{ + if (ctrl->pwm_pmi) + return; + + ctrl->pwm_bl = pwm_request(ctrl->pwm_lpg_chan, "lcd-bklt"); + if (ctrl->pwm_bl == NULL || IS_ERR(ctrl->pwm_bl)) { + pr_err("%s: Error: lpg_chan=%d pwm request failed", + __func__, ctrl->pwm_lpg_chan); + } + ctrl->pwm_enabled = 0; +} + +bool mdss_dsi_panel_pwm_enable(struct mdss_dsi_ctrl_pdata *ctrl) +{ + bool status = true; + if (!ctrl->pwm_enabled) + goto end; + + if (pwm_enable(ctrl->pwm_bl)) { + pr_err("%s: pwm_enable() failed\n", __func__); + status = false; + } + + ctrl->pwm_enabled = 1; + +end: + return status; +} + +static void mdss_dsi_panel_bklt_pwm(struct mdss_dsi_ctrl_pdata *ctrl, int level) +{ + int ret; + u32 duty; + u32 period_ns; + + if (ctrl->pwm_bl == NULL) { + pr_err("%s: no PWM\n", __func__); + return; + } + + if (level == 0) { + if (ctrl->pwm_enabled) { + ret = pwm_config_us(ctrl->pwm_bl, level, + ctrl->pwm_period); + if (ret) + pr_err("%s: pwm_config_us() failed err=%d.\n", + __func__, ret); + pwm_disable(ctrl->pwm_bl); + } + ctrl->pwm_enabled = 0; + return; + } + + duty = level * ctrl->pwm_period; + duty /= ctrl->bklt_max; + + pr_debug("%s: bklt_ctrl=%d pwm_period=%d pwm_gpio=%d pwm_lpg_chan=%d\n", + __func__, ctrl->bklt_ctrl, ctrl->pwm_period, + ctrl->pwm_pmic_gpio, ctrl->pwm_lpg_chan); + + pr_debug("%s: ndx=%d level=%d duty=%d\n", __func__, + ctrl->ndx, level, duty); + + if (ctrl->pwm_period >= USEC_PER_SEC) { + ret = pwm_config_us(ctrl->pwm_bl, duty, ctrl->pwm_period); + if (ret) { + pr_err("%s: pwm_config_us() failed err=%d.\n", + __func__, ret); + return; + } + } else { + period_ns = ctrl->pwm_period * NSEC_PER_USEC; + ret = pwm_config(ctrl->pwm_bl, + level * period_ns / ctrl->bklt_max, + period_ns); + if (ret) { + pr_err("%s: pwm_config() failed err=%d.\n", + __func__, ret); + return; + } + } + + if (!ctrl->pwm_enabled) { + ret = pwm_enable(ctrl->pwm_bl); + if (ret) + pr_err("%s: pwm_enable() failed err=%d\n", __func__, + ret); + ctrl->pwm_enabled = 1; + } +} + +static char dcs_cmd[2] = {0x54, 0x00}; /* DTYPE_DCS_READ */ +static struct dsi_cmd_desc dcs_read_cmd = { + {DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(dcs_cmd)}, + dcs_cmd +}; + +int mdss_dsi_panel_cmd_read(struct mdss_dsi_ctrl_pdata *ctrl, char cmd0, + char cmd1, void (*fxn)(int), char *rbuf, int len) +{ + struct dcs_cmd_req cmdreq; + struct mdss_panel_info *pinfo; + + pinfo = &(ctrl->panel_data.panel_info); + if (pinfo->dcs_cmd_by_left) { + if (ctrl->ndx != DSI_CTRL_LEFT) + return -EINVAL; + } + + dcs_cmd[0] = cmd0; + dcs_cmd[1] = cmd1; + memset(&cmdreq, 0, sizeof(cmdreq)); + cmdreq.cmds = &dcs_read_cmd; + cmdreq.cmds_cnt = 1; + cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT; + cmdreq.rlen = len; + cmdreq.rbuf = rbuf; + cmdreq.cb = fxn; /* call back */ + /* + * blocked here, until call back called + */ + + return mdss_dsi_cmdlist_put(ctrl, &cmdreq); +} + +static void mdss_dsi_panel_apply_settings(struct mdss_dsi_ctrl_pdata *ctrl, + struct dsi_panel_cmds *pcmds) +{ + struct dcs_cmd_req cmdreq; + struct mdss_panel_info *pinfo; + + pinfo = &(ctrl->panel_data.panel_info); + if ((pinfo->dcs_cmd_by_left) && (ctrl->ndx != DSI_CTRL_LEFT)) + return; + + memset(&cmdreq, 0, sizeof(cmdreq)); + cmdreq.cmds = pcmds->cmds; + cmdreq.cmds_cnt = pcmds->cmd_cnt; + cmdreq.flags = CMD_REQ_COMMIT; + cmdreq.rlen = 0; + cmdreq.cb = NULL; + + mdss_dsi_cmdlist_put(ctrl, &cmdreq); +} + + +static void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl, + struct dsi_panel_cmds *pcmds, u32 flags) +{ + struct dcs_cmd_req cmdreq; + struct mdss_panel_info *pinfo; + + pinfo = &(ctrl->panel_data.panel_info); + if (pinfo->dcs_cmd_by_left) { + if (ctrl->ndx != DSI_CTRL_LEFT) + return; + } + + memset(&cmdreq, 0, sizeof(cmdreq)); + cmdreq.cmds = pcmds->cmds; + cmdreq.cmds_cnt = pcmds->cmd_cnt; + cmdreq.flags = flags; + + /*Panel ON/Off commands should be sent in DSI Low Power Mode*/ + if (pcmds->link_state == DSI_LP_MODE) + cmdreq.flags |= CMD_REQ_LP_MODE; + else if (pcmds->link_state == DSI_HS_MODE) + cmdreq.flags |= CMD_REQ_HS_MODE; + + cmdreq.rlen = 0; + cmdreq.cb = NULL; + + mdss_dsi_cmdlist_put(ctrl, &cmdreq); +} + +static char led_pwm1[2] = {0x51, 0x0}; /* DTYPE_DCS_WRITE1 */ +static struct dsi_cmd_desc backlight_cmd = { + {DTYPE_DCS_WRITE1, 1, 0, 0, 1, sizeof(led_pwm1)}, + led_pwm1 +}; + +//samsung s6e3fa6 panel backlight +static char led_pwm2[3] ={0x51, 0x00, 0x00}; /* DTYPE_DCS_LWRITE */ +static struct dsi_cmd_desc backlight_cmd2 ={ + {DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(led_pwm2)}, + led_pwm2 +}; + +static void mdss_dsi_panel_bklt_dcs(struct mdss_dsi_ctrl_pdata *ctrl, int level) +{ + struct dcs_cmd_req cmdreq; + struct mdss_panel_info *pinfo; + + pinfo = &(ctrl->panel_data.panel_info); + if (pinfo->dcs_cmd_by_left) { + if (ctrl->ndx != DSI_CTRL_LEFT) + return; + } + + pr_debug("%s: level=%d\n", __func__, level); + + if (ctrl->bklt_max > 255){ + u8 ldata = 0; + u8 hdata = 0; - DEFINE_LED_TRIGGER(bl_led_trigger); - - void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl) - { - if (ctrl->pwm_pmi) - return; - - ctrl->pwm_bl = pwm_request(ctrl->pwm_lpg_chan, "lcd-bklt"); - if (ctrl->pwm_bl == NULL || IS_ERR(ctrl->pwm_bl)) { - pr_err("%s: Error: lpg_chan=%d pwm request failed", - __func__, ctrl->pwm_lpg_chan); - } - ctrl->pwm_enabled = 0; - } - - bool mdss_dsi_panel_pwm_enable(struct mdss_dsi_ctrl_pdata *ctrl) - { - bool status = true; - if (!ctrl->pwm_enabled) - goto end; - - if (pwm_enable(ctrl->pwm_bl)) { - pr_err("%s: pwm_enable() failed\n", __func__); - status = false; - } - - ctrl->pwm_enabled = 1; - - end: - return status; - } - - static void mdss_dsi_panel_bklt_pwm(struct mdss_dsi_ctrl_pdata *ctrl, int level) - { - int ret; - u32 duty; - u32 period_ns; - - if (ctrl->pwm_bl == NULL) { - pr_err("%s: no PWM\n", __func__); - return; - } - - if (level == 0) { - if (ctrl->pwm_enabled) { - ret = pwm_config_us(ctrl->pwm_bl, level, - ctrl->pwm_period); - if (ret) - pr_err("%s: pwm_config_us() failed err=%d.\n", - __func__, ret); - pwm_disable(ctrl->pwm_bl); - } - ctrl->pwm_enabled = 0; - return; - } - - duty = level * ctrl->pwm_period; - duty /= ctrl->bklt_max; - - pr_debug("%s: bklt_ctrl=%d pwm_period=%d pwm_gpio=%d pwm_lpg_chan=%d\n", - __func__, ctrl->bklt_ctrl, ctrl->pwm_period, - ctrl->pwm_pmic_gpio, ctrl->pwm_lpg_chan); - - pr_debug("%s: ndx=%d level=%d duty=%d\n", __func__, - ctrl->ndx, level, duty); - - if (ctrl->pwm_period >= USEC_PER_SEC) { - ret = pwm_config_us(ctrl->pwm_bl, duty, ctrl->pwm_period); - if (ret) { - pr_err("%s: pwm_config_us() failed err=%d.\n", - __func__, ret); - return; - } - } else { - period_ns = ctrl->pwm_period * NSEC_PER_USEC; - ret = pwm_config(ctrl->pwm_bl, - level * period_ns / ctrl->bklt_max, - period_ns); - if (ret) { - pr_err("%s: pwm_config() failed err=%d.\n", - __func__, ret); - return; - } - } - - if (!ctrl->pwm_enabled) { - ret = pwm_enable(ctrl->pwm_bl); - if (ret) - pr_err("%s: pwm_enable() failed err=%d\n", __func__, - ret); - ctrl->pwm_enabled = 1; - } - } - - static char dcs_cmd[2] = {0x54, 0x00}; /* DTYPE_DCS_READ */ - static struct dsi_cmd_desc dcs_read_cmd = { - {DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(dcs_cmd)}, - dcs_cmd - }; - - int mdss_dsi_panel_cmd_read(struct mdss_dsi_ctrl_pdata *ctrl, char cmd0, - char cmd1, void (*fxn)(int), char *rbuf, int len) - { - struct dcs_cmd_req cmdreq; - struct mdss_panel_info *pinfo; - - pinfo = &(ctrl->panel_data.panel_info); - if (pinfo->dcs_cmd_by_left) { - if (ctrl->ndx != DSI_CTRL_LEFT) - return -EINVAL; - } - - dcs_cmd[0] = cmd0; - dcs_cmd[1] = cmd1; - memset(&cmdreq, 0, sizeof(cmdreq)); - cmdreq.cmds = &dcs_read_cmd; - cmdreq.cmds_cnt = 1; - cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT; - cmdreq.rlen = len; - cmdreq.rbuf = rbuf; - cmdreq.cb = fxn; /* call back */ - /* - * blocked here, until call back called - */ - - return mdss_dsi_cmdlist_put(ctrl, &cmdreq); - } - - static void mdss_dsi_panel_apply_settings(struct mdss_dsi_ctrl_pdata *ctrl, - struct dsi_panel_cmds *pcmds) - { - struct dcs_cmd_req cmdreq; - struct mdss_panel_info *pinfo; - - pinfo = &(ctrl->panel_data.panel_info); - if ((pinfo->dcs_cmd_by_left) && (ctrl->ndx != DSI_CTRL_LEFT)) - return; - - memset(&cmdreq, 0, sizeof(cmdreq)); - cmdreq.cmds = pcmds->cmds; - cmdreq.cmds_cnt = pcmds->cmd_cnt; - cmdreq.flags = CMD_REQ_COMMIT; - cmdreq.rlen = 0; - cmdreq.cb = NULL; - - mdss_dsi_cmdlist_put(ctrl, &cmdreq); - } - - - static void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl, - struct dsi_panel_cmds *pcmds, u32 flags) - { - struct dcs_cmd_req cmdreq; - struct mdss_panel_info *pinfo; - - pinfo = &(ctrl->panel_data.panel_info); - if (pinfo->dcs_cmd_by_left) { - if (ctrl->ndx != DSI_CTRL_LEFT) - return; - } - - memset(&cmdreq, 0, sizeof(cmdreq)); - cmdreq.cmds = pcmds->cmds; - cmdreq.cmds_cnt = pcmds->cmd_cnt; - cmdreq.flags = flags; - - /*Panel ON/Off commands should be sent in DSI Low Power Mode*/ - if (pcmds->link_state == DSI_LP_MODE) - cmdreq.flags |= CMD_REQ_LP_MODE; - else if (pcmds->link_state == DSI_HS_MODE) - cmdreq.flags |= CMD_REQ_HS_MODE; - - cmdreq.rlen = 0; - cmdreq.cb = NULL; - - mdss_dsi_cmdlist_put(ctrl, &cmdreq); - } - - - - - - static char led_pwm1[2] = {0x51, 0x0}; /* DTYPE_DCS_WRITE1 */ - static struct dsi_cmd_desc backlight_cmd = { - {DTYPE_DCS_WRITE1, 1, 0, 0, 1, sizeof(led_pwm1)}, - led_pwm1 - }; - //samsung s6e3fa6 panel backlight - static char led_pwm2[3] = {0x51, 0x00, 0x00}; /* DTYPE_DCS_LWRITE */ - static struct dsi_cmd_desc backlight_cmd2 = { - {DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(led_pwm2)}, - led_pwm2 - }; - - static void mdss_dsi_panel_bklt_dcs(struct mdss_dsi_ctrl_pdata *ctrl, int level) - { - struct dcs_cmd_req cmdreq; - struct mdss_panel_info *pinfo; - - pinfo = &(ctrl->panel_data.panel_info); - if (pinfo->dcs_cmd_by_left) { - if (ctrl->ndx != DSI_CTRL_LEFT) - return; - } - - pr_debug("%s: level=%d\n", __func__, level); - - - if (ctrl->bklt_max > 255){ - u8 ldata = 0; - u8 hdata = 0; - - if (ctrl->bl_high2bit){ - ldata = level & 0x0ff; - hdata = (level >> 8) & 0x03; - led_pwm2[2] = ldata; - led_pwm2[1] = hdata; - } else{ - ldata = level & 0x03; - hdata = (level >> 2) & 0x0ff; - led_pwm2[2] = ldata; - led_pwm2[1] = hdata; - } + if (ctrl->bl_high2bit){ + ldata = level & 0x0ff; + hdata = (level >> 8) & 0x03; + led_pwm2[2] = ldata; + led_pwm2[1] = hdata; + } else{ + ldata = level & 0x03; + hdata = (level >> 2) & 0x0ff; + led_pwm2[2] = ldata; + led_pwm2[1] = hdata; + } }else - led_pwm1[1] = (unsigned char)level; + led_pwm1[1] = (unsigned char)level; - memset(&cmdreq, 0, sizeof(cmdreq)); - if (ctrl->bklt_max > 255){ - cmdreq.cmds = &backlight_cmd2; - }else - cmdreq.cmds = &backlight_cmd; - cmdreq.cmds_cnt = 1; - cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL; - cmdreq.rlen = 0; - cmdreq.cb = NULL; - mdss_dsi_cmdlist_put(ctrl, &cmdreq); - } - - - static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata) - { - int rc = 0; - - if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) { - rc = gpio_request(ctrl_pdata->disp_en_gpio, - "disp_enable"); - if (rc) { - pr_err("request disp_en gpio failed, rc=%d\n", - rc); - goto disp_en_gpio_err; - } - } - rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n"); - if (rc) { - pr_err("request reset gpio failed, rc=%d\n", - rc); - goto rst_gpio_err; - } - if (gpio_is_valid(ctrl_pdata->avdd_en_gpio)) { - rc = gpio_request(ctrl_pdata->avdd_en_gpio, - "avdd_enable"); - if (rc) { - pr_err("request avdd_en gpio failed, rc=%d\n", - rc); - goto avdd_en_gpio_err; - } - } - if (gpio_is_valid(ctrl_pdata->lcd_mode_sel_gpio)) { - rc = gpio_request(ctrl_pdata->lcd_mode_sel_gpio, "mode_sel"); - if (rc) { - pr_err("request dsc/dual mode gpio failed,rc=%d\n", - rc); - goto lcd_mode_sel_gpio_err; - } - } - - return rc; - - lcd_mode_sel_gpio_err: - if (gpio_is_valid(ctrl_pdata->avdd_en_gpio)) - gpio_free(ctrl_pdata->avdd_en_gpio); - avdd_en_gpio_err: - gpio_free(ctrl_pdata->rst_gpio); - rst_gpio_err: - if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) - gpio_free(ctrl_pdata->disp_en_gpio); - disp_en_gpio_err: - return rc; - } - - int mdss_dsi_bl_gpio_ctrl(struct mdss_panel_data *pdata, int enable) - { - struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; - int rc = 0, val = 0; - - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return -EINVAL; - } - - ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - if (ctrl_pdata == NULL) { - pr_err("%s: Invalid ctrl data\n", __func__); - return -EINVAL; - } - - /* if gpio is not valid */ - if (!gpio_is_valid(ctrl_pdata->bklt_en_gpio)) - return rc; - - pr_debug("%s: enable = %d\n", __func__, enable); - - /* - * if gpio state is false and enable (bl level) is - * non zero then toggle the gpio - */ - if (!ctrl_pdata->bklt_en_gpio_state && enable) { - rc = gpio_request(ctrl_pdata->bklt_en_gpio, "bklt_enable"); - if (rc) { - pr_err("request bklt gpio failed, rc=%d\n", rc); - goto free; - } - - if (ctrl_pdata->bklt_en_gpio_invert) - val = 0; - else - val = 1; - - rc = gpio_direction_output(ctrl_pdata->bklt_en_gpio, val); - if (rc) { - pr_err("%s: unable to set dir for bklt gpio val %d\n", - __func__, val); - goto free; - } - ctrl_pdata->bklt_en_gpio_state = true; - goto ret; - } else if (ctrl_pdata->bklt_en_gpio_state && !enable) { - /* - * if gpio state is true and enable (bl level) is - * zero then toggle the gpio - */ - if (ctrl_pdata->bklt_en_gpio_invert) - val = 1; - else - val = 0; - - rc = gpio_direction_output(ctrl_pdata->bklt_en_gpio, val); - if (rc) - pr_err("%s: unable to set dir for bklt gpio val %d\n", - __func__, val); - goto free; - } - - /* gpio state is true and bl level is non zero */ - goto ret; - - free: - pr_debug("%s: free bklt gpio\n", __func__); - ctrl_pdata->bklt_en_gpio_state = false; - gpio_free(ctrl_pdata->bklt_en_gpio); - ret: - return rc; - } - - int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) - { - struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; - struct mdss_panel_info *pinfo = NULL; - int i, rc = 0; - - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return -EINVAL; - } - - ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - - pinfo = &(ctrl_pdata->panel_data.panel_info); - if ((mdss_dsi_is_right_ctrl(ctrl_pdata) && - mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) || - pinfo->is_dba_panel) { - pr_debug("%s:%d, right ctrl gpio configuration not needed\n", - __func__, __LINE__); - return rc; - } - - if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) { - pr_debug("%s:%d, reset line not configured\n", - __func__, __LINE__); - } - - if (!gpio_is_valid(ctrl_pdata->rst_gpio)) { - pr_debug("%s:%d, reset line not configured\n", - __func__, __LINE__); - return rc; - } - - pr_debug("%s: enable = %d\n", __func__, enable); - - if (enable) { - rc = mdss_dsi_request_gpios(ctrl_pdata); - if (rc) { - pr_err("gpio request failed\n"); - return rc; - } - if (!pinfo->cont_splash_enabled) { - if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) { - rc = gpio_direction_output( - ctrl_pdata->disp_en_gpio, 1); - if (rc) { - pr_err("%s: unable to set dir for en gpio\n", - __func__); - goto exit; - } - } - - if (pdata->panel_info.rst_seq_len) { - rc = gpio_direction_output(ctrl_pdata->rst_gpio, - pdata->panel_info.rst_seq[0]); - if (rc) { - pr_err("%s: unable to set dir for rst gpio\n", - __func__); - goto exit; - } - } - - for (i = 0; i < pdata->panel_info.rst_seq_len; ++i) { - gpio_set_value((ctrl_pdata->rst_gpio), - pdata->panel_info.rst_seq[i]); - if (pdata->panel_info.rst_seq[++i]) - usleep_range(pinfo->rst_seq[i] * 1000, pinfo->rst_seq[i] * 1000); - } - - if (gpio_is_valid(ctrl_pdata->avdd_en_gpio)) { - if (ctrl_pdata->avdd_en_gpio_invert) { - rc = gpio_direction_output( - ctrl_pdata->avdd_en_gpio, 0); - } else { - rc = gpio_direction_output( - ctrl_pdata->avdd_en_gpio, 1); - } - if (rc) { - pr_err("%s: unable to set dir for avdd_en gpio\n", - __func__); - goto exit; - } - } - } - - if (gpio_is_valid(ctrl_pdata->lcd_mode_sel_gpio)) { - bool out = false; - - if ((pinfo->mode_sel_state == MODE_SEL_SINGLE_PORT) || - (pinfo->mode_sel_state == MODE_GPIO_HIGH)) - out = true; - else if ((pinfo->mode_sel_state == MODE_SEL_DUAL_PORT) - || (pinfo->mode_sel_state == MODE_GPIO_LOW)) - out = false; - - rc = gpio_direction_output( - ctrl_pdata->lcd_mode_sel_gpio, out); - if (rc) { - pr_err("%s: unable to set dir for mode gpio\n", - __func__); - goto exit; - } - } - - if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) { - pr_debug("%s: Panel Not properly turned OFF\n", - __func__); - ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT; - pr_debug("%s: Reset panel done\n", __func__); - } - } else { - if (gpio_is_valid(ctrl_pdata->avdd_en_gpio)) { - if (ctrl_pdata->avdd_en_gpio_invert) - gpio_set_value((ctrl_pdata->avdd_en_gpio), 1); - else - gpio_set_value((ctrl_pdata->avdd_en_gpio), 0); - - gpio_free(ctrl_pdata->avdd_en_gpio); - } - if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) { - gpio_set_value((ctrl_pdata->disp_en_gpio), 0); - gpio_free(ctrl_pdata->disp_en_gpio); - } - gpio_set_value((ctrl_pdata->rst_gpio), 0); - gpio_free(ctrl_pdata->rst_gpio); - if (gpio_is_valid(ctrl_pdata->lcd_mode_sel_gpio)) { - gpio_set_value(ctrl_pdata->lcd_mode_sel_gpio, 0); - gpio_free(ctrl_pdata->lcd_mode_sel_gpio); - } - } - - exit: - return rc; - } - - int mdss_dsi_px_clk_req(struct mdss_panel_data *pdata, int enable) - { - struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; - int rc = 0; - - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return -EINVAL; - } - - ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - if (enable) { - if(!IS_ERR(ctrl_pdata->px_clk_src) && (!ctrl_pdata->px_clk_enabled)){ - clk_set_rate(ctrl_pdata->px_clk_src, 19200000); - rc = clk_prepare_enable(ctrl_pdata->px_clk_src); - if (rc){ - pr_err("px clk_prepare_enable failed, rc=%d\n", rc); - } - ctrl_pdata->px_clk_enabled = 1; - } - } else{ - if(!IS_ERR(ctrl_pdata->px_clk_src) && ctrl_pdata->px_clk_enabled){ - clk_disable_unprepare(ctrl_pdata->px_clk_src); - ctrl_pdata->px_clk_enabled = 0; - } - } - return rc; - } - int mdss_dsi_disp_vci_en(struct mdss_panel_data *pdata, int enable) - { - struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; - struct mdss_panel_info *pinfo = NULL; - int rc = 0; - - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return -EINVAL; - } - - ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - - if (!gpio_is_valid(ctrl_pdata->disp_vci_en_gpio)) { - pr_debug("%s:%d, vci_en_gpio line not configured\n", - __func__, __LINE__); - return rc; - } - pr_debug("%s: vci_en_gpio enable = %d\n", __func__, enable); - pinfo = &(ctrl_pdata->panel_data.panel_info); - - if (enable) { - rc = gpio_request(ctrl_pdata->disp_vci_en_gpio, - "disp_vci_en"); - if (rc) { - pr_err("request vci_enable gpio failed, rc=%d\n", - rc); - return rc; - } - rc = gpio_direction_output(ctrl_pdata->disp_vci_en_gpio, 1); - } else { - gpio_set_value(ctrl_pdata->disp_vci_en_gpio, 0); - gpio_free(ctrl_pdata->disp_vci_en_gpio); - } - return rc; - } - int mdss_dsi_isp_1v1_en(struct mdss_panel_data *pdata, int enable) - { - struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; - struct mdss_panel_info *pinfo = NULL; - int rc = 0; - - - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return -EINVAL; - } - - ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - - if (!gpio_is_valid(ctrl_pdata->isp_1v1_en_gpio)) { - pr_debug("%s:%d, isp_1v1_en line not configured\n", - __func__, __LINE__); - return rc; - } - pr_debug("%s: isp_1v1_en enable = %d\n", __func__, enable); - pinfo = &(ctrl_pdata->panel_data.panel_info); - - if (enable) { - rc = gpio_request(ctrl_pdata->isp_1v1_en_gpio, - "isp_1v1_en_gpio"); - if (rc) { - pr_err("request isp_1v1 gpio failed, rc=%d\n", - rc); - return rc; - } - rc = gpio_direction_output(ctrl_pdata->isp_1v1_en_gpio, 1); - } else { - gpio_set_value(ctrl_pdata->isp_1v1_en_gpio, 0); - gpio_free(ctrl_pdata->isp_1v1_en_gpio); - } - return rc; - } - - int mdss_dsi_disp_poc_en(struct mdss_panel_data *pdata, int enable) - { - struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; - struct mdss_panel_info *pinfo = NULL; - int rc = 0; - - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return -EINVAL; - } - - ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - - if (!gpio_is_valid(ctrl_pdata->disp_poc_en_gpio)) { - pr_debug("%s:%d, poc_en_gpio line not configured\n", - __func__, __LINE__); - return rc; - } - pr_debug("%s: poc_en_gpio enable = %d\n", __func__, enable); - pinfo = &(ctrl_pdata->panel_data.panel_info); - - if (enable) { - rc = gpio_request(ctrl_pdata->disp_poc_en_gpio, - "disp_poc_en"); - if (rc) { - pr_err("request poc_enable gpio failed, rc=%d\n", - rc); - return rc; - } - rc = gpio_direction_output(ctrl_pdata->disp_poc_en_gpio, 1); - } else { - gpio_set_value(ctrl_pdata->disp_poc_en_gpio, 0); - gpio_free(ctrl_pdata->disp_poc_en_gpio); - } - return rc; - } - - - - /** - * mdss_dsi_roi_merge() - merge two roi into single roi - * - * Function used by partial update with only one dsi intf take 2A/2B - * (column/page) dcs commands. - */ - static int mdss_dsi_roi_merge(struct mdss_dsi_ctrl_pdata *ctrl, - struct mdss_rect *roi) - { - struct mdss_panel_info *l_pinfo; - struct mdss_rect *l_roi; - struct mdss_rect *r_roi; - struct mdss_dsi_ctrl_pdata *other = NULL; - int ans = 0; - - if (ctrl->ndx == DSI_CTRL_LEFT) { - other = mdss_dsi_get_ctrl_by_index(DSI_CTRL_RIGHT); - if (!other) - return ans; - l_pinfo = &(ctrl->panel_data.panel_info); - l_roi = &(ctrl->panel_data.panel_info.roi); - r_roi = &(other->panel_data.panel_info.roi); - } else { - other = mdss_dsi_get_ctrl_by_index(DSI_CTRL_LEFT); - if (!other) - return ans; - l_pinfo = &(other->panel_data.panel_info); - l_roi = &(other->panel_data.panel_info.roi); - r_roi = &(ctrl->panel_data.panel_info.roi); - } - - if (l_roi->w == 0 && l_roi->h == 0) { - /* right only */ - *roi = *r_roi; - roi->x += l_pinfo->xres;/* add left full width to x-offset */ - } else { - /* left only and left+righ */ - *roi = *l_roi; - roi->w += r_roi->w; /* add right width */ - ans = 1; - } - - return ans; - } - - static char caset[] = {0x2a, 0x00, 0x00, 0x03, 0x00}; /* DTYPE_DCS_LWRITE */ - static char paset[] = {0x2b, 0x00, 0x00, 0x05, 0x00}; /* DTYPE_DCS_LWRITE */ - - /* - * Some panels can support multiple ROIs as part of the below commands - */ - static char caset_dual[] = {0x2a, 0x00, 0x00, 0x03, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00};/* DTYPE_DCS_LWRITE */ - static char paset_dual[] = {0x2b, 0x00, 0x00, 0x05, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00};/* DTYPE_DCS_LWRITE */ - - /* pack into one frame before sent */ - static struct dsi_cmd_desc set_col_page_addr_cmd[] = { - {{DTYPE_DCS_LWRITE, 0, 0, 0, 1, sizeof(caset)}, caset}, /* packed */ - {{DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(paset)}, paset}, - }; - - /* pack into one frame before sent */ - static struct dsi_cmd_desc set_dual_col_page_addr_cmd[] = { /*packed*/ - {{DTYPE_DCS_LWRITE, 0, 0, 0, 1, sizeof(caset_dual)}, caset_dual}, - {{DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(paset_dual)}, paset_dual}, - }; - - - static void __mdss_dsi_send_col_page_addr(struct mdss_dsi_ctrl_pdata *ctrl, - struct mdss_rect *roi, bool dual_roi) - { - if (dual_roi) { - struct mdss_rect *first, *second; - - first = &ctrl->panel_data.panel_info.dual_roi.first_roi; - second = &ctrl->panel_data.panel_info.dual_roi.second_roi; - - caset_dual[1] = (((first->x) & 0xFF00) >> 8); - caset_dual[2] = (((first->x) & 0xFF)); - caset_dual[3] = (((first->x - 1 + first->w) & 0xFF00) >> 8); - caset_dual[4] = (((first->x - 1 + first->w) & 0xFF)); - /* skip the MPU setting byte*/ - caset_dual[6] = (((second->x) & 0xFF00) >> 8); - caset_dual[7] = (((second->x) & 0xFF)); - caset_dual[8] = (((second->x - 1 + second->w) & 0xFF00) >> 8); - caset_dual[9] = (((second->x - 1 + second->w) & 0xFF)); - set_dual_col_page_addr_cmd[0].payload = caset_dual; - - paset_dual[1] = (((first->y) & 0xFF00) >> 8); - paset_dual[2] = (((first->y) & 0xFF)); - paset_dual[3] = (((first->y - 1 + first->h) & 0xFF00) >> 8); - paset_dual[4] = (((first->y - 1 + first->h) & 0xFF)); - /* skip the MPU setting byte */ - paset_dual[6] = (((second->y) & 0xFF00) >> 8); - paset_dual[7] = (((second->y) & 0xFF)); - paset_dual[8] = (((second->y - 1 + second->h) & 0xFF00) >> 8); - paset_dual[9] = (((second->y - 1 + second->h) & 0xFF)); - set_dual_col_page_addr_cmd[1].payload = paset_dual; - } else { - caset[1] = (((roi->x) & 0xFF00) >> 8); - caset[2] = (((roi->x) & 0xFF)); - caset[3] = (((roi->x - 1 + roi->w) & 0xFF00) >> 8); - caset[4] = (((roi->x - 1 + roi->w) & 0xFF)); - set_col_page_addr_cmd[0].payload = caset; - - paset[1] = (((roi->y) & 0xFF00) >> 8); - paset[2] = (((roi->y) & 0xFF)); - paset[3] = (((roi->y - 1 + roi->h) & 0xFF00) >> 8); - paset[4] = (((roi->y - 1 + roi->h) & 0xFF)); - set_col_page_addr_cmd[1].payload = paset; - } - pr_debug("%s Sending 2A 2B cmnd with dual_roi=%d\n", __func__, - dual_roi); - - } - static void mdss_dsi_send_col_page_addr(struct mdss_dsi_ctrl_pdata *ctrl, - struct mdss_rect *roi, int unicast) - { - struct dcs_cmd_req cmdreq; - struct mdss_panel_info *pinfo = &ctrl->panel_data.panel_info; - bool dual_roi = pinfo->dual_roi.enabled; - - __mdss_dsi_send_col_page_addr(ctrl, roi, dual_roi); - - memset(&cmdreq, 0, sizeof(cmdreq)); - cmdreq.cmds_cnt = 2; - cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL; - if (unicast) - cmdreq.flags |= CMD_REQ_UNICAST; - cmdreq.rlen = 0; - cmdreq.cb = NULL; - - /* Send default or dual roi 2A/2B cmd */ - cmdreq.cmds = dual_roi ? set_dual_col_page_addr_cmd : - set_col_page_addr_cmd; - mdss_dsi_cmdlist_put(ctrl, &cmdreq); - } - - static int mdss_dsi_set_col_page_addr(struct mdss_panel_data *pdata, - bool force_send) - { - struct mdss_panel_info *pinfo; - struct mdss_rect roi = {0}; - struct mdss_rect *p_roi; - struct mdss_rect *c_roi; - struct mdss_dsi_ctrl_pdata *ctrl = NULL; - struct mdss_dsi_ctrl_pdata *other = NULL; - int left_or_both = 0; - - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return -EINVAL; - } - - ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - - pinfo = &pdata->panel_info; - p_roi = &pinfo->roi; - - /* - * to avoid keep sending same col_page info to panel, - * if roi_merge enabled, the roi of left ctrl is used - * to compare against new merged roi and saved new - * merged roi to it after comparing. - * if roi_merge disabled, then the calling ctrl's roi - * and pinfo's roi are used to compare. - */ - if (pinfo->partial_update_roi_merge) { - left_or_both = mdss_dsi_roi_merge(ctrl, &roi); - other = mdss_dsi_get_ctrl_by_index(DSI_CTRL_LEFT); - c_roi = &other->roi; - } else { - c_roi = &ctrl->roi; - roi = *p_roi; - } - - /* roi had changed, do col_page update */ - if (force_send || !mdss_rect_cmp(c_roi, &roi)) { - pr_debug("%s: ndx=%d x=%d y=%d w=%d h=%d\n", - __func__, ctrl->ndx, p_roi->x, - p_roi->y, p_roi->w, p_roi->h); - - *c_roi = roi; /* keep to ctrl */ - if (c_roi->w == 0 || c_roi->h == 0) { - /* no new frame update */ - pr_debug("%s: ctrl=%d, no partial roi set\n", - __func__, ctrl->ndx); - return 0; - } - - if (pinfo->dcs_cmd_by_left) { - if (left_or_both && ctrl->ndx == DSI_CTRL_RIGHT) { - /* 2A/2B sent by left already */ - return 0; - } - } - - if (!mdss_dsi_sync_wait_enable(ctrl)) { - if (pinfo->dcs_cmd_by_left) - ctrl = mdss_dsi_get_ctrl_by_index( - DSI_CTRL_LEFT); - mdss_dsi_send_col_page_addr(ctrl, &roi, 0); - } else { - /* - * when sync_wait_broadcast enabled, - * need trigger at right ctrl to - * start both dcs cmd transmission - */ - other = mdss_dsi_get_other_ctrl(ctrl); - if (!other) - goto end; - - if (mdss_dsi_is_left_ctrl(ctrl)) { - if (pinfo->partial_update_roi_merge) { - /* - * roi is the one after merged - * to dsi-1 only - */ - mdss_dsi_send_col_page_addr(other, - &roi, 0); - } else { - mdss_dsi_send_col_page_addr(ctrl, - &ctrl->roi, 1); - mdss_dsi_send_col_page_addr(other, - &other->roi, 1); - } - } else { - if (pinfo->partial_update_roi_merge) { - /* - * roi is the one after merged - * to dsi-1 only - */ - mdss_dsi_send_col_page_addr(ctrl, - &roi, 0); - } else { - mdss_dsi_send_col_page_addr(other, - &other->roi, 1); - mdss_dsi_send_col_page_addr(ctrl, - &ctrl->roi, 1); - } - } - } - } - - end: - return 0; - } - - static int mdss_dsi_panel_apply_display_setting(struct mdss_panel_data *pdata, - u32 mode) - { - struct mdss_dsi_ctrl_pdata *ctrl = NULL; - struct dsi_panel_cmds *lp_on_cmds; - struct dsi_panel_cmds *lp_off_cmds; - - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return -EINVAL; - } - - ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - - lp_on_cmds = &ctrl->lp_on_cmds; - lp_off_cmds = &ctrl->lp_off_cmds; - - /* Apply display settings for low-persistence mode */ - if ((mode == MDSS_PANEL_LOW_PERSIST_MODE_ON) && - (lp_on_cmds->cmd_cnt)) - mdss_dsi_panel_apply_settings(ctrl, lp_on_cmds); - else if ((mode == MDSS_PANEL_LOW_PERSIST_MODE_OFF) && - (lp_on_cmds->cmd_cnt)) - mdss_dsi_panel_apply_settings(ctrl, lp_off_cmds); - else - return -EINVAL; - - pr_debug("%s: Persistence mode %d applied\n", __func__, mode); - return 0; - } - - static void mdss_dsi_panel_switch_mode(struct mdss_panel_data *pdata, - int mode) - { - struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; - struct mipi_panel_info *mipi; - struct dsi_panel_cmds *pcmds; - u32 flags = 0; - - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return; - } - - mipi = &pdata->panel_info.mipi; - - if (!mipi->dms_mode) - return; - - ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - - if (mipi->dms_mode != DYNAMIC_MODE_RESOLUTION_SWITCH_IMMEDIATE) { - flags |= CMD_REQ_COMMIT; - if (mode == SWITCH_TO_CMD_MODE) - pcmds = &ctrl_pdata->video2cmd; + memset(&cmdreq, 0, sizeof(cmdreq)); + if (ctrl->bklt_max > 255){ + cmdreq.cmds = &backlight_cmd2; + }else + cmdreq.cmds = &backlight_cmd; + cmdreq.cmds_cnt = 1; + cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL; + cmdreq.rlen = 0; + cmdreq.cb = NULL; + mdss_dsi_cmdlist_put(ctrl, &cmdreq); +} + +static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + int rc = 0; + + if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) { + rc = gpio_request(ctrl_pdata->disp_en_gpio, + "disp_enable"); + if (rc) { + pr_err("request disp_en gpio failed, rc=%d\n", + rc); + goto disp_en_gpio_err; + } + } + rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n"); + if (rc) { + pr_err("request reset gpio failed, rc=%d\n", + rc); + goto rst_gpio_err; + } + if (gpio_is_valid(ctrl_pdata->avdd_en_gpio)) { + rc = gpio_request(ctrl_pdata->avdd_en_gpio, + "avdd_enable"); + if (rc) { + pr_err("request avdd_en gpio failed, rc=%d\n", + rc); + goto avdd_en_gpio_err; + } + } + if (gpio_is_valid(ctrl_pdata->lcd_mode_sel_gpio)) { + rc = gpio_request(ctrl_pdata->lcd_mode_sel_gpio, "mode_sel"); + if (rc) { + pr_err("request dsc/dual mode gpio failed,rc=%d\n", + rc); + goto lcd_mode_sel_gpio_err; + } + } + + return rc; + +lcd_mode_sel_gpio_err: + if (gpio_is_valid(ctrl_pdata->avdd_en_gpio)) + gpio_free(ctrl_pdata->avdd_en_gpio); +avdd_en_gpio_err: + gpio_free(ctrl_pdata->rst_gpio); +rst_gpio_err: + if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) + gpio_free(ctrl_pdata->disp_en_gpio); +disp_en_gpio_err: + return rc; +} + +int mdss_dsi_bl_gpio_ctrl(struct mdss_panel_data *pdata, int enable) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + int rc = 0, val = 0; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + if (ctrl_pdata == NULL) { + pr_err("%s: Invalid ctrl data\n", __func__); + return -EINVAL; + } + + /* if gpio is not valid */ + if (!gpio_is_valid(ctrl_pdata->bklt_en_gpio)) + return rc; + + pr_debug("%s: enable = %d\n", __func__, enable); + + /* + * if gpio state is false and enable (bl level) is + * non zero then toggle the gpio + */ + if (!ctrl_pdata->bklt_en_gpio_state && enable) { + rc = gpio_request(ctrl_pdata->bklt_en_gpio, "bklt_enable"); + if (rc) { + pr_err("request bklt gpio failed, rc=%d\n", rc); + goto free; + } + + if (ctrl_pdata->bklt_en_gpio_invert) + val = 0; else - pcmds = &ctrl_pdata->cmd2video; - } else if ((mipi->dms_mode == - DYNAMIC_MODE_RESOLUTION_SWITCH_IMMEDIATE) - && pdata->current_timing - && !list_empty(&pdata->timings_list)) { - struct dsi_panel_timing *pt; + val = 1; + + rc = gpio_direction_output(ctrl_pdata->bklt_en_gpio, val); + if (rc) { + pr_err("%s: unable to set dir for bklt gpio val %d\n", + __func__, val); + goto free; + } + ctrl_pdata->bklt_en_gpio_state = true; + goto ret; + } else if (ctrl_pdata->bklt_en_gpio_state && !enable) { + /* + * if gpio state is true and enable (bl level) is + * zero then toggle the gpio + */ + if (ctrl_pdata->bklt_en_gpio_invert) + val = 1; + else + val = 0; + + rc = gpio_direction_output(ctrl_pdata->bklt_en_gpio, val); + if (rc) + pr_err("%s: unable to set dir for bklt gpio val %d\n", + __func__, val); + goto free; + } + + /* gpio state is true and bl level is non zero */ + goto ret; + +free: + pr_debug("%s: free bklt gpio\n", __func__); + ctrl_pdata->bklt_en_gpio_state = false; + gpio_free(ctrl_pdata->bklt_en_gpio); +ret: + return rc; +} + +int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_panel_info *pinfo = NULL; + int i, rc = 0; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + pinfo = &(ctrl_pdata->panel_data.panel_info); + if ((mdss_dsi_is_right_ctrl(ctrl_pdata) && + mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) || + pinfo->is_dba_panel) { + pr_debug("%s:%d, right ctrl gpio configuration not needed\n", + __func__, __LINE__); + return rc; + } + + if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) { + pr_debug("%s:%d, reset line not configured\n", + __func__, __LINE__); + } + + if (!gpio_is_valid(ctrl_pdata->rst_gpio)) { + pr_debug("%s:%d, reset line not configured\n", + __func__, __LINE__); + return rc; + } + + pr_debug("%s: enable = %d\n", __func__, enable); + + if (enable) { + rc = mdss_dsi_request_gpios(ctrl_pdata); + if (rc) { + pr_err("gpio request failed\n"); + return rc; + } + if (!pinfo->cont_splash_enabled) { + if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) { + rc = gpio_direction_output( + ctrl_pdata->disp_en_gpio, 1); + if (rc) { + pr_err("%s: unable to set dir for en gpio\n", + __func__); + goto exit; + } + } + + if (pdata->panel_info.rst_seq_len) { + rc = gpio_direction_output(ctrl_pdata->rst_gpio, + pdata->panel_info.rst_seq[0]); + if (rc) { + pr_err("%s: unable to set dir for rst gpio\n", + __func__); + goto exit; + } + } + + for (i = 0; i < pdata->panel_info.rst_seq_len; ++i) { + gpio_set_value((ctrl_pdata->rst_gpio), + pdata->panel_info.rst_seq[i]); + if (pdata->panel_info.rst_seq[++i]) + usleep_range(pinfo->rst_seq[i] * 1000, pinfo->rst_seq[i] * 1000); + } + + if (gpio_is_valid(ctrl_pdata->avdd_en_gpio)) { + if (ctrl_pdata->avdd_en_gpio_invert) { + rc = gpio_direction_output( + ctrl_pdata->avdd_en_gpio, 0); + } else { + rc = gpio_direction_output( + ctrl_pdata->avdd_en_gpio, 1); + } + if (rc) { + pr_err("%s: unable to set dir for avdd_en gpio\n", + __func__); + goto exit; + } + } + } + + if (gpio_is_valid(ctrl_pdata->lcd_mode_sel_gpio)) { + bool out = false; + + if ((pinfo->mode_sel_state == MODE_SEL_SINGLE_PORT) || + (pinfo->mode_sel_state == MODE_GPIO_HIGH)) + out = true; + else if ((pinfo->mode_sel_state == MODE_SEL_DUAL_PORT) + || (pinfo->mode_sel_state == MODE_GPIO_LOW)) + out = false; + + rc = gpio_direction_output( + ctrl_pdata->lcd_mode_sel_gpio, out); + if (rc) { + pr_err("%s: unable to set dir for mode gpio\n", + __func__); + goto exit; + } + } + + if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) { + pr_debug("%s: Panel Not properly turned OFF\n", + __func__); + ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT; + pr_debug("%s: Reset panel done\n", __func__); + } + } else { + if (gpio_is_valid(ctrl_pdata->avdd_en_gpio)) { + if (ctrl_pdata->avdd_en_gpio_invert) + gpio_set_value((ctrl_pdata->avdd_en_gpio), 1); + else + gpio_set_value((ctrl_pdata->avdd_en_gpio), 0); + + gpio_free(ctrl_pdata->avdd_en_gpio); + } + if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) { + gpio_set_value((ctrl_pdata->disp_en_gpio), 0); + gpio_free(ctrl_pdata->disp_en_gpio); + } + gpio_set_value((ctrl_pdata->rst_gpio), 0); + gpio_free(ctrl_pdata->rst_gpio); + if (gpio_is_valid(ctrl_pdata->lcd_mode_sel_gpio)) { + gpio_set_value(ctrl_pdata->lcd_mode_sel_gpio, 0); + gpio_free(ctrl_pdata->lcd_mode_sel_gpio); + } + } + +exit: + return rc; +} + +int mdss_dsi_px_clk_req(struct mdss_panel_data *pdata, int enable) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + int rc = 0; - pt = container_of(pdata->current_timing, - struct dsi_panel_timing, timing); + if (pdata == NULL){ + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } - pr_debug("%s: sending switch commands\n", __func__); - pcmds = &pt->switch_cmds; - flags |= CMD_REQ_DMA_TPG; - flags |= CMD_REQ_COMMIT; - } else { - pr_warn("%s: Invalid mode switch attempted\n", __func__); - return; - } + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + if (enable){ + if(!IS_ERR(ctrl_pdata->px_clk_src) && (!ctrl_pdata->px_clk_enabled)){ + clk_set_rate(ctrl_pdata->px_clk_src, 19200000); + rc = clk_prepare_enable(ctrl_pdata->px_clk_src); + if (rc){ + pr_err("px clk_prepare_enable failed, rc=%d\n", rc); + } + ctrl_pdata->px_clk_enabled = 1; + } + } else{ + if(!IS_ERR(ctrl_pdata->px_clk_src) && ctrl_pdata->px_clk_enabled){ + clk_disable_unprepare(ctrl_pdata->px_clk_src); + ctrl_pdata->px_clk_enabled = 0; + } + } + return rc; +} + +int mdss_dsi_disp_vci_en(struct mdss_panel_data *pdata, int enable) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_panel_info *pinfo = NULL; + int rc = 0; - if ((pdata->panel_info.compression_mode == COMPRESSION_DSC) && - (pdata->panel_info.send_pps_before_switch)) - mdss_dsi_panel_dsc_pps_send(ctrl_pdata, &pdata->panel_info); + if (pdata == NULL){ + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } - mdss_dsi_panel_cmds_send(ctrl_pdata, pcmds, flags); + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); - if ((pdata->panel_info.compression_mode == COMPRESSION_DSC) && - (!pdata->panel_info.send_pps_before_switch)) - mdss_dsi_panel_dsc_pps_send(ctrl_pdata, &pdata->panel_info); - } + if (!gpio_is_valid(ctrl_pdata->disp_vci_en_gpio)){ + pr_debug("%s:%d, vci_en_gpio line not configured\n", + __func__, __LINE__); + return rc; + } + pr_debug("%s: vci_en_gpio enable = %d\n", __func__, enable); + pinfo = &(ctrl_pdata->panel_data.panel_info); + + if (enable){ + rc = gpio_request(ctrl_pdata->disp_vci_en_gpio, + "disp_vci_en"); + if (rc){ + pr_err("request vci_enable gpio failed, rc=%d\n", + rc); + return rc; + } + rc = gpio_direction_output(ctrl_pdata->disp_vci_en_gpio, 1); + } else{ + gpio_set_value(ctrl_pdata->disp_vci_en_gpio, 0); + gpio_free(ctrl_pdata->disp_vci_en_gpio); + } + return rc; +} + +int mdss_dsi_isp_1v1_en(struct mdss_panel_data *pdata, int enable) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_panel_info *pinfo = NULL; + int rc = 0; + + + if (pdata == NULL){ + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + if (!gpio_is_valid(ctrl_pdata->isp_1v1_en_gpio)){ + pr_debug("%s:%d, isp_1v1_en line not configured\n", + __func__, __LINE__); + return rc; + } + pr_debug("%s: isp_1v1_en enable = %d\n", __func__, enable); + pinfo = &(ctrl_pdata->panel_data.panel_info); + + if (enable){ + rc = gpio_request(ctrl_pdata->isp_1v1_en_gpio, + "isp_1v1_en_gpio"); + if (rc){ + pr_err("request isp_1v1 gpio failed, rc=%d\n", + rc); + return rc; + } + rc = gpio_direction_output(ctrl_pdata->isp_1v1_en_gpio, 1); + } else{ + gpio_set_value(ctrl_pdata->isp_1v1_en_gpio, 0); + gpio_free(ctrl_pdata->isp_1v1_en_gpio); + } + return rc; +} + +int mdss_dsi_disp_poc_en(struct mdss_panel_data *pdata, int enable) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_panel_info *pinfo = NULL; + int rc = 0; + + if (pdata == NULL){ + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + if (!gpio_is_valid(ctrl_pdata->disp_poc_en_gpio)){ + pr_debug("%s:%d, poc_en_gpio line not configured\n", + __func__, __LINE__); + return rc; + } + pr_debug("%s: poc_en_gpio enable = %d\n", __func__, enable); + pinfo = &(ctrl_pdata->panel_data.panel_info); + + if (enable){ + rc = gpio_request(ctrl_pdata->disp_poc_en_gpio, + "disp_poc_en"); + if (rc){ + pr_err("request poc_enable gpio failed, rc=%d\n", + rc); + return rc; + } + rc = gpio_direction_output(ctrl_pdata->disp_poc_en_gpio, 1); + } else{ + gpio_set_value(ctrl_pdata->disp_poc_en_gpio, 0); + gpio_free(ctrl_pdata->disp_poc_en_gpio); + } + return rc; +} + +/** + * mdss_dsi_roi_merge() - merge two roi into single roi + * + * Function used by partial update with only one dsi intf take 2A/2B + * (column/page) dcs commands. + */ +static int mdss_dsi_roi_merge(struct mdss_dsi_ctrl_pdata *ctrl, + struct mdss_rect *roi) +{ + struct mdss_panel_info *l_pinfo; + struct mdss_rect *l_roi; + struct mdss_rect *r_roi; + struct mdss_dsi_ctrl_pdata *other = NULL; + int ans = 0; + + if (ctrl->ndx == DSI_CTRL_LEFT) { + other = mdss_dsi_get_ctrl_by_index(DSI_CTRL_RIGHT); + if (!other) + return ans; + l_pinfo = &(ctrl->panel_data.panel_info); + l_roi = &(ctrl->panel_data.panel_info.roi); + r_roi = &(other->panel_data.panel_info.roi); + } else { + other = mdss_dsi_get_ctrl_by_index(DSI_CTRL_LEFT); + if (!other) + return ans; + l_pinfo = &(other->panel_data.panel_info); + l_roi = &(other->panel_data.panel_info.roi); + r_roi = &(ctrl->panel_data.panel_info.roi); + } + + if (l_roi->w == 0 && l_roi->h == 0) { + /* right only */ + *roi = *r_roi; + roi->x += l_pinfo->xres;/* add left full width to x-offset */ + } else { + /* left only and left+righ */ + *roi = *l_roi; + roi->w += r_roi->w; /* add right width */ + ans = 1; + } + + return ans; +} + +static char caset[] = {0x2a, 0x00, 0x00, 0x03, 0x00}; /* DTYPE_DCS_LWRITE */ +static char paset[] = {0x2b, 0x00, 0x00, 0x05, 0x00}; /* DTYPE_DCS_LWRITE */ + +/* + * Some panels can support multiple ROIs as part of the below commands + */ +static char caset_dual[] = {0x2a, 0x00, 0x00, 0x03, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00};/* DTYPE_DCS_LWRITE */ +static char paset_dual[] = {0x2b, 0x00, 0x00, 0x05, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00};/* DTYPE_DCS_LWRITE */ + +/* pack into one frame before sent */ +static struct dsi_cmd_desc set_col_page_addr_cmd[] = { + {{DTYPE_DCS_LWRITE, 0, 0, 0, 1, sizeof(caset)}, caset}, /* packed */ + {{DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(paset)}, paset}, +}; + +/* pack into one frame before sent */ +static struct dsi_cmd_desc set_dual_col_page_addr_cmd[] = { /*packed*/ + {{DTYPE_DCS_LWRITE, 0, 0, 0, 1, sizeof(caset_dual)}, caset_dual}, + {{DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(paset_dual)}, paset_dual}, +}; + + +static void __mdss_dsi_send_col_page_addr(struct mdss_dsi_ctrl_pdata *ctrl, + struct mdss_rect *roi, bool dual_roi) +{ + if (dual_roi) { + struct mdss_rect *first, *second; + + first = &ctrl->panel_data.panel_info.dual_roi.first_roi; + second = &ctrl->panel_data.panel_info.dual_roi.second_roi; + + caset_dual[1] = (((first->x) & 0xFF00) >> 8); + caset_dual[2] = (((first->x) & 0xFF)); + caset_dual[3] = (((first->x - 1 + first->w) & 0xFF00) >> 8); + caset_dual[4] = (((first->x - 1 + first->w) & 0xFF)); + /* skip the MPU setting byte*/ + caset_dual[6] = (((second->x) & 0xFF00) >> 8); + caset_dual[7] = (((second->x) & 0xFF)); + caset_dual[8] = (((second->x - 1 + second->w) & 0xFF00) >> 8); + caset_dual[9] = (((second->x - 1 + second->w) & 0xFF)); + set_dual_col_page_addr_cmd[0].payload = caset_dual; + + paset_dual[1] = (((first->y) & 0xFF00) >> 8); + paset_dual[2] = (((first->y) & 0xFF)); + paset_dual[3] = (((first->y - 1 + first->h) & 0xFF00) >> 8); + paset_dual[4] = (((first->y - 1 + first->h) & 0xFF)); + /* skip the MPU setting byte */ + paset_dual[6] = (((second->y) & 0xFF00) >> 8); + paset_dual[7] = (((second->y) & 0xFF)); + paset_dual[8] = (((second->y - 1 + second->h) & 0xFF00) >> 8); + paset_dual[9] = (((second->y - 1 + second->h) & 0xFF)); + set_dual_col_page_addr_cmd[1].payload = paset_dual; + } else { + caset[1] = (((roi->x) & 0xFF00) >> 8); + caset[2] = (((roi->x) & 0xFF)); + caset[3] = (((roi->x - 1 + roi->w) & 0xFF00) >> 8); + caset[4] = (((roi->x - 1 + roi->w) & 0xFF)); + set_col_page_addr_cmd[0].payload = caset; + + paset[1] = (((roi->y) & 0xFF00) >> 8); + paset[2] = (((roi->y) & 0xFF)); + paset[3] = (((roi->y - 1 + roi->h) & 0xFF00) >> 8); + paset[4] = (((roi->y - 1 + roi->h) & 0xFF)); + set_col_page_addr_cmd[1].payload = paset; + } + pr_debug("%s Sending 2A 2B cmnd with dual_roi=%d\n", __func__, + dual_roi); + +} +static void mdss_dsi_send_col_page_addr(struct mdss_dsi_ctrl_pdata *ctrl, + struct mdss_rect *roi, int unicast) +{ + struct dcs_cmd_req cmdreq; + struct mdss_panel_info *pinfo = &ctrl->panel_data.panel_info; + bool dual_roi = pinfo->dual_roi.enabled; + + __mdss_dsi_send_col_page_addr(ctrl, roi, dual_roi); + + memset(&cmdreq, 0, sizeof(cmdreq)); + cmdreq.cmds_cnt = 2; + cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL; + if (unicast) + cmdreq.flags |= CMD_REQ_UNICAST; + cmdreq.rlen = 0; + cmdreq.cb = NULL; + + /* Send default or dual roi 2A/2B cmd */ + cmdreq.cmds = dual_roi ? set_dual_col_page_addr_cmd : + set_col_page_addr_cmd; + mdss_dsi_cmdlist_put(ctrl, &cmdreq); +} + +static int mdss_dsi_set_col_page_addr(struct mdss_panel_data *pdata, + bool force_send) +{ + struct mdss_panel_info *pinfo; + struct mdss_rect roi = {0}; + struct mdss_rect *p_roi; + struct mdss_rect *c_roi; + struct mdss_dsi_ctrl_pdata *ctrl = NULL; + struct mdss_dsi_ctrl_pdata *other = NULL; + int left_or_both = 0; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + pinfo = &pdata->panel_info; + p_roi = &pinfo->roi; + + /* + * to avoid keep sending same col_page info to panel, + * if roi_merge enabled, the roi of left ctrl is used + * to compare against new merged roi and saved new + * merged roi to it after comparing. + * if roi_merge disabled, then the calling ctrl's roi + * and pinfo's roi are used to compare. + */ + if (pinfo->partial_update_roi_merge) { + left_or_both = mdss_dsi_roi_merge(ctrl, &roi); + other = mdss_dsi_get_ctrl_by_index(DSI_CTRL_LEFT); + c_roi = &other->roi; + } else { + c_roi = &ctrl->roi; + roi = *p_roi; + } + + /* roi had changed, do col_page update */ + if (force_send || !mdss_rect_cmp(c_roi, &roi)) { + pr_debug("%s: ndx=%d x=%d y=%d w=%d h=%d\n", + __func__, ctrl->ndx, p_roi->x, + p_roi->y, p_roi->w, p_roi->h); + + *c_roi = roi; /* keep to ctrl */ + if (c_roi->w == 0 || c_roi->h == 0) { + /* no new frame update */ + pr_debug("%s: ctrl=%d, no partial roi set\n", + __func__, ctrl->ndx); + return 0; + } + + if (pinfo->dcs_cmd_by_left) { + if (left_or_both && ctrl->ndx == DSI_CTRL_RIGHT) { + /* 2A/2B sent by left already */ + return 0; + } + } + + if (!mdss_dsi_sync_wait_enable(ctrl)) { + if (pinfo->dcs_cmd_by_left) + ctrl = mdss_dsi_get_ctrl_by_index( + DSI_CTRL_LEFT); + mdss_dsi_send_col_page_addr(ctrl, &roi, 0); + } else { + /* + * when sync_wait_broadcast enabled, + * need trigger at right ctrl to + * start both dcs cmd transmission + */ + other = mdss_dsi_get_other_ctrl(ctrl); + if (!other) + goto end; + + if (mdss_dsi_is_left_ctrl(ctrl)) { + if (pinfo->partial_update_roi_merge) { + /* + * roi is the one after merged + * to dsi-1 only + */ + mdss_dsi_send_col_page_addr(other, + &roi, 0); + } else { + mdss_dsi_send_col_page_addr(ctrl, + &ctrl->roi, 1); + mdss_dsi_send_col_page_addr(other, + &other->roi, 1); + } + } else { + if (pinfo->partial_update_roi_merge) { + /* + * roi is the one after merged + * to dsi-1 only + */ + mdss_dsi_send_col_page_addr(ctrl, + &roi, 0); + } else { + mdss_dsi_send_col_page_addr(other, + &other->roi, 1); + mdss_dsi_send_col_page_addr(ctrl, + &ctrl->roi, 1); + } + } + } + } + +end: + return 0; +} + +static int mdss_dsi_panel_apply_display_setting(struct mdss_panel_data *pdata, + u32 mode) +{ + struct mdss_dsi_ctrl_pdata *ctrl = NULL; + struct dsi_panel_cmds *lp_on_cmds; + struct dsi_panel_cmds *lp_off_cmds; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + lp_on_cmds = &ctrl->lp_on_cmds; + lp_off_cmds = &ctrl->lp_off_cmds; + + /* Apply display settings for low-persistence mode */ + if ((mode == MDSS_PANEL_LOW_PERSIST_MODE_ON) && + (lp_on_cmds->cmd_cnt)) + mdss_dsi_panel_apply_settings(ctrl, lp_on_cmds); + else if ((mode == MDSS_PANEL_LOW_PERSIST_MODE_OFF) && + (lp_on_cmds->cmd_cnt)) + mdss_dsi_panel_apply_settings(ctrl, lp_off_cmds); + else + return -EINVAL; + + pr_debug("%s: Persistence mode %d applied\n", __func__, mode); + return 0; +} + +static void mdss_dsi_panel_switch_mode(struct mdss_panel_data *pdata, + int mode) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mipi_panel_info *mipi; + struct dsi_panel_cmds *pcmds; + u32 flags = 0; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return; + } + + mipi = &pdata->panel_info.mipi; + + if (!mipi->dms_mode) + return; + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + if (mipi->dms_mode != DYNAMIC_MODE_RESOLUTION_SWITCH_IMMEDIATE) { + flags |= CMD_REQ_COMMIT; + if (mode == SWITCH_TO_CMD_MODE) + pcmds = &ctrl_pdata->video2cmd; + else + pcmds = &ctrl_pdata->cmd2video; + } else if ((mipi->dms_mode == + DYNAMIC_MODE_RESOLUTION_SWITCH_IMMEDIATE) + && pdata->current_timing + && !list_empty(&pdata->timings_list)) { + struct dsi_panel_timing *pt; + + pt = container_of(pdata->current_timing, + struct dsi_panel_timing, timing); + + pr_debug("%s: sending switch commands\n", __func__); + pcmds = &pt->switch_cmds; + flags |= CMD_REQ_DMA_TPG; + flags |= CMD_REQ_COMMIT; + } else { + pr_warn("%s: Invalid mode switch attempted\n", __func__); + return; + } + + if ((pdata->panel_info.compression_mode == COMPRESSION_DSC) && + (pdata->panel_info.send_pps_before_switch)) + mdss_dsi_panel_dsc_pps_send(ctrl_pdata, &pdata->panel_info); + + mdss_dsi_panel_cmds_send(ctrl_pdata, pcmds, flags); + + if ((pdata->panel_info.compression_mode == COMPRESSION_DSC) && + (!pdata->panel_info.send_pps_before_switch)) + mdss_dsi_panel_dsc_pps_send(ctrl_pdata, &pdata->panel_info); +} /************************************ backlight level 0-->55 ==> 0-->55 backlight level 55-->230 ==> 55-->200 @@ -1037,94 +1029,94 @@ static u32 backlight_level_remap(struct mdss_dsi_ctrl_pdata *ctrl, u32 level) if (ctrl->bklt_max == 255){ if (level < 55){ remap_level = level; - } else if ((level >= 55) && (level <= 230)){ + } else if ((level >= 55) && (level <= 230)){ remap_level = (level*29+330)/35; - }else{ + }else{ remap_level = level*11/5-306; - } - } else{ + } + } else{ remap_level = level; - } + } return remap_level; } - static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata, - u32 bl_level) - { - struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; - struct mdss_dsi_ctrl_pdata *sctrl = NULL; + +static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata, + u32 bl_level) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_dsi_ctrl_pdata *sctrl = NULL; static bool first_bl_level = true; if (first_bl_level || (bl_level == 0)){ printk("---backlight level = %d---\n", bl_level); first_bl_level = (bl_level == 0)? true : false; } - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return; - } - - ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return; + } + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + if (ctrl_pdata->high_brightness_panel){ pr_debug("%s goto backlight level remap\n", __func__); bl_level = backlight_level_remap(ctrl_pdata, bl_level); - } - /* - * Some backlight controllers specify a minimum duty cycle - * for the backlight brightness. If the brightness is less - * than it, the controller can malfunction. - */ - pr_debug("%s: bl_level:%d\n", __func__, bl_level); + } + /* + * Some backlight controllers specify a minimum duty cycle + * for the backlight brightness. If the brightness is less + * than it, the controller can malfunction. + */ + pr_debug("%s: bl_level:%d\n", __func__, bl_level); - /* do not allow backlight to change when panel in disable mode */ - if (pdata->panel_disable_mode && (bl_level != 0)) - return; - - if ((bl_level < pdata->panel_info.bl_min) && (bl_level != 0)) - bl_level = pdata->panel_info.bl_min; - - /* enable the backlight gpio if present */ - mdss_dsi_bl_gpio_ctrl(pdata, bl_level); - - switch (ctrl_pdata->bklt_ctrl) { - case BL_WLED: - led_trigger_event(bl_led_trigger, bl_level); - break; - case BL_PWM: - mdss_dsi_panel_bklt_pwm(ctrl_pdata, bl_level); - break; - case BL_DCS_CMD: - if (!mdss_dsi_sync_wait_enable(ctrl_pdata)) { - mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level); - break; - } - /* - * DCS commands to update backlight are usually sent at - * the same time to both the controllers. However, if - * sync_wait is enabled, we need to ensure that the - * dcs commands are first sent to the non-trigger - * controller so that when the commands are triggered, - * both controllers receive it at the same time. - */ - sctrl = mdss_dsi_get_other_ctrl(ctrl_pdata); - if (mdss_dsi_sync_wait_trigger(ctrl_pdata)) { - if (sctrl) - mdss_dsi_panel_bklt_dcs(sctrl, bl_level); - mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level); - } else { - mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level); - if (sctrl) - mdss_dsi_panel_bklt_dcs(sctrl, bl_level); - } - break; - default: - pr_err("%s: Unknown bl_ctrl configuration\n", - __func__); - break; - } - } + /* do not allow backlight to change when panel in disable mode */ + if (pdata->panel_disable_mode && (bl_level != 0)) + return; + if ((bl_level < pdata->panel_info.bl_min) && (bl_level != 0)) + bl_level = pdata->panel_info.bl_min; + + /* enable the backlight gpio if present */ + mdss_dsi_bl_gpio_ctrl(pdata, bl_level); + + switch (ctrl_pdata->bklt_ctrl) { + case BL_WLED: + led_trigger_event(bl_led_trigger, bl_level); + break; + case BL_PWM: + mdss_dsi_panel_bklt_pwm(ctrl_pdata, bl_level); + break; + case BL_DCS_CMD: + if (!mdss_dsi_sync_wait_enable(ctrl_pdata)) { + mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level); + break; + } + /* + * DCS commands to update backlight are usually sent at + * the same time to both the controllers. However, if + * sync_wait is enabled, we need to ensure that the + * dcs commands are first sent to the non-trigger + * controller so that when the commands are triggered, + * both controllers receive it at the same time. + */ + sctrl = mdss_dsi_get_other_ctrl(ctrl_pdata); + if (mdss_dsi_sync_wait_trigger(ctrl_pdata)) { + if (sctrl) + mdss_dsi_panel_bklt_dcs(sctrl, bl_level); + mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level); + } else { + mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level); + if (sctrl) + mdss_dsi_panel_bklt_dcs(sctrl, bl_level); + } + break; + default: + pr_err("%s: Unknown bl_ctrl configuration\n", + __func__); + break; + } +} int mdss_dsi_panel_set_srgb_mode(struct mdss_dsi_ctrl_pdata *ctrl, int level) { @@ -1132,32 +1124,33 @@ int mdss_dsi_panel_set_srgb_mode(struct mdss_dsi_ctrl_pdata *ctrl, int level) struct dsi_panel_cmds *srgb_off_cmds; mutex_lock(&ctrl->panel_mode_lock); - if (!ctrl->is_panel_on) { + if (!ctrl->is_panel_on){ mutex_unlock(&ctrl->panel_mode_lock); return 0; } srgb_on_cmds = &ctrl->srgb_on_cmds; srgb_off_cmds = &ctrl->srgb_off_cmds; - if (level) { - if (srgb_on_cmds->cmd_cnt) { + if (level){ + if (srgb_on_cmds->cmd_cnt){ mdss_dsi_panel_cmds_send(ctrl, srgb_on_cmds, CMD_REQ_COMMIT); pr_err("sRGB Mode On.\n"); - } else { + } else{ pr_err("This panel not support sRGB mode on.\n"); } - } else { - if (srgb_off_cmds->cmd_cnt) { + } else{ + if (srgb_off_cmds->cmd_cnt){ mdss_dsi_panel_cmds_send(ctrl, srgb_off_cmds, CMD_REQ_COMMIT); pr_err("sRGB Mode off.\n"); - } else { + } else{ pr_err("This panel not support sRGB mode off.\n"); } - } + } mutex_unlock(&ctrl->panel_mode_lock); return 0; } + int mdss_dsi_panel_get_srgb_mode(struct mdss_dsi_ctrl_pdata *ctrl) { return ctrl->SRGB_mode; @@ -1170,26 +1163,26 @@ int mdss_dsi_panel_set_adobe_rgb_mode(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_panel_cmds *adobe_rgb_off_cmds; mutex_lock(&ctrl->panel_mode_lock); - if (!ctrl->is_panel_on) { + if (!ctrl->is_panel_on){ mutex_unlock(&ctrl->panel_mode_lock); return 0; } adobe_rgb_on_cmds = &ctrl->Adobe_RGB_on_cmds; adobe_rgb_off_cmds = &ctrl->Adobe_RGB_off_cmds; - if (level) { - if (adobe_rgb_on_cmds->cmd_cnt) { + if (level){ + if (adobe_rgb_on_cmds->cmd_cnt){ mdss_dsi_panel_cmds_send(ctrl, adobe_rgb_on_cmds, CMD_REQ_COMMIT); pr_err("Adobe RGB Mode On.\n"); - } else { + } else{ pr_err("This Panel not support Adobe RGB mode On.\n"); } - } else { - if (adobe_rgb_off_cmds->cmd_cnt) { + } else{ + if (adobe_rgb_off_cmds->cmd_cnt){ mdss_dsi_panel_cmds_send(ctrl, adobe_rgb_off_cmds, CMD_REQ_COMMIT); pr_err("Adobe RGB Mode Off.\n"); - } else { + } else{ pr_err("This Panel not support Adobe RGB mode Off.\n"); } } @@ -1207,26 +1200,26 @@ int mdss_dsi_panel_set_dci_p3_mode(struct mdss_dsi_ctrl_pdata *ctrl, int level) struct dsi_panel_cmds *dci_p3_off_cmds; mutex_lock(&ctrl->panel_mode_lock); - if (!ctrl->is_panel_on) { + if (!ctrl->is_panel_on){ mutex_unlock(&ctrl->panel_mode_lock); return 0; - } + } dci_p3_on_cmds = &ctrl->dci_p3_on_cmds; dci_p3_off_cmds = &ctrl->dci_p3_off_cmds; - if (level) { - if (dci_p3_on_cmds->cmd_cnt) { + if (level){ + if (dci_p3_on_cmds->cmd_cnt){ mdss_dsi_panel_cmds_send(ctrl, dci_p3_on_cmds, CMD_REQ_COMMIT); pr_err("DCI-P3 Mode On.\n"); - } else { + } else{ pr_err("This Panel not support DCI-P3 mode On.\n"); } - } else { - if (dci_p3_off_cmds->cmd_cnt) { + } else{ + if (dci_p3_off_cmds->cmd_cnt){ mdss_dsi_panel_cmds_send(ctrl, dci_p3_off_cmds, CMD_REQ_COMMIT); pr_err("DCI-P3 Mode Off.\n"); - } else { + } else{ pr_err("This Panel not support DCI-P3 mode Off.\n"); } } @@ -1245,7 +1238,7 @@ int mdss_dsi_panel_set_night_mode(struct mdss_dsi_ctrl_pdata *ctrl, int level) struct dsi_panel_cmds *night_mode_off_cmds; mutex_lock(&ctrl->panel_mode_lock); - if (!ctrl->is_panel_on) { + if (!ctrl->is_panel_on){ mutex_unlock(&ctrl->panel_mode_lock); return 0; } @@ -1253,20 +1246,20 @@ int mdss_dsi_panel_set_night_mode(struct mdss_dsi_ctrl_pdata *ctrl, int level) /* night mode same as sRGB mode */ night_mode_off_cmds = &ctrl->night_mode_off_cmds; /* night mode same as sRGB mode */ - if (level) { - if (night_mode_on_cmds->cmd_cnt) { + if (level){ + if (night_mode_on_cmds->cmd_cnt){ mdss_dsi_panel_cmds_send(ctrl, night_mode_on_cmds, CMD_REQ_COMMIT); pr_err("Night Mode On (night mode).\n"); - } else { + } else{ pr_err("This panel not support Night mode on (night mode).\n"); } - } else { - if (night_mode_off_cmds->cmd_cnt) { + } else{ + if (night_mode_off_cmds->cmd_cnt){ mdss_dsi_panel_cmds_send(ctrl, night_mode_off_cmds, CMD_REQ_COMMIT); pr_err("Night Mode off (night mode).\n"); - } else { + } else{ pr_err("This panel not support night mode off (night mode).\n"); } } @@ -1284,7 +1277,7 @@ int mdss_dsi_panel_set_oneplus_mode(struct mdss_dsi_ctrl_pdata *ctrl, int level) struct dsi_panel_cmds *oneplus_mode_off_cmds; mutex_lock(&ctrl->panel_mode_lock); - if (!ctrl->is_panel_on) { + if (!ctrl->is_panel_on){ mutex_unlock(&ctrl->panel_mode_lock); return 0; } @@ -1293,20 +1286,20 @@ int mdss_dsi_panel_set_oneplus_mode(struct mdss_dsi_ctrl_pdata *ctrl, int level) oneplus_mode_off_cmds = &ctrl->oneplus_mode_off_cmds; /* night mode same as sRGB mode */ - if (level) { - if (oneplus_mode_on_cmds->cmd_cnt) { + if (level){ + if (oneplus_mode_on_cmds->cmd_cnt){ mdss_dsi_panel_cmds_send(ctrl, oneplus_mode_on_cmds, CMD_REQ_COMMIT); pr_err("oneplus Mode On (oneplus mode).\n"); - } else { + } else{ pr_err("This panel not support oneplus mode on (oneplus mode).\n"); } - } else { - if (oneplus_mode_off_cmds->cmd_cnt) { + } else{ + if (oneplus_mode_off_cmds->cmd_cnt){ mdss_dsi_panel_cmds_send(ctrl, oneplus_mode_off_cmds, CMD_REQ_COMMIT); pr_err("oneplus Mode off (oneplus mode).\n"); - } else { + } else{ pr_err("This panel not support oneplus mode off (oneplus mode).\n"); } } @@ -1326,7 +1319,7 @@ int mdss_dsi_panel_set_adaption_mode(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_panel_cmds *adaption_mode_off_cmds; mutex_lock(&ctrl->panel_mode_lock); - if (!ctrl->is_panel_on) { + if (!ctrl->is_panel_on){ mutex_unlock(&ctrl->panel_mode_lock); return 0; } @@ -1334,32 +1327,32 @@ int mdss_dsi_panel_set_adaption_mode(struct mdss_dsi_ctrl_pdata *ctrl, /* night mode same as sRGB mode */ adaption_mode_off_cmds = &ctrl->adaption_mode_off_cmds; /* night mode same as sRGB mode */ - if (level) { - if (adaption_mode_on_cmds->cmd_cnt) { + if (level){ + if (adaption_mode_on_cmds->cmd_cnt){ mdss_dsi_panel_cmds_send(ctrl, adaption_mode_on_cmds, CMD_REQ_COMMIT); pr_err("Adaption Mode On (adaption mode).\n"); - } else { + } else{ pr_err("This panel not support Adaption mode on (adaption mode).\n"); } - } else { - if (adaption_mode_off_cmds->cmd_cnt) { + } else{ + if (adaption_mode_off_cmds->cmd_cnt){ mdss_dsi_panel_cmds_send(ctrl, adaption_mode_off_cmds, CMD_REQ_COMMIT); pr_err("Adaption Mode off (adaption mode).\n"); - } else { + } else{ pr_err("This panel not support adaption mode off (adaption mode).\n"); } } mutex_unlock(&ctrl->panel_mode_lock); return 0; } + int mdss_dsi_panel_get_adaption_mode(struct mdss_dsi_ctrl_pdata *ctrl) { return ctrl->adaption_mode; } - static int mdss_dsi_panel_on(struct mdss_panel_data *pdata) { struct mdss_dsi_ctrl_pdata *ctrl = NULL; @@ -1368,13 +1361,13 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata) int ret = 0; if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return -EINVAL; + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; } - pr_err("%s start\n", __func__); + pinfo = &pdata->panel_info; ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); + panel_data); pr_debug("%s: ndx=%d\n", __func__, ctrl->ndx); @@ -1386,50 +1379,51 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata) on_cmds = &ctrl->on_cmds; if ((pinfo->mipi.dms_mode == DYNAMIC_MODE_SWITCH_IMMEDIATE) && - (pinfo->mipi.boot_mode != pinfo->mipi.mode)) + (pinfo->mipi.boot_mode != pinfo->mipi.mode)) on_cmds = &ctrl->post_dms_on_cmds; pr_debug("%s: ndx=%d cmd_cnt=%d\n", __func__, - ctrl->ndx, on_cmds->cmd_cnt); + ctrl->ndx, on_cmds->cmd_cnt); mutex_lock(&ctrl->panel_mode_lock); ctrl->is_panel_on = true; mutex_unlock(&ctrl->panel_mode_lock); - if (mdss_dsi_panel_get_srgb_mode(ctrl)) { + if (mdss_dsi_panel_get_srgb_mode(ctrl)){ mdss_dsi_panel_set_srgb_mode(ctrl, mdss_dsi_panel_get_srgb_mode(ctrl)); } - if (mdss_dsi_panel_get_adobe_rgb_mode(ctrl)) { + if (mdss_dsi_panel_get_adobe_rgb_mode(ctrl)){ mdss_dsi_panel_set_adobe_rgb_mode(ctrl, mdss_dsi_panel_get_adobe_rgb_mode(ctrl)); } - if (mdss_dsi_panel_get_dci_p3_mode(ctrl)) { + if (mdss_dsi_panel_get_dci_p3_mode(ctrl)){ mdss_dsi_panel_set_dci_p3_mode(ctrl, mdss_dsi_panel_get_dci_p3_mode(ctrl)); } - if (mdss_dsi_panel_get_night_mode(ctrl)) { + if (mdss_dsi_panel_get_night_mode(ctrl)){ mdss_dsi_panel_set_night_mode(ctrl, mdss_dsi_panel_get_night_mode(ctrl)); } - if (mdss_dsi_panel_get_oneplus_mode(ctrl)) { + if (mdss_dsi_panel_get_oneplus_mode(ctrl)){ mdss_dsi_panel_set_oneplus_mode(ctrl, mdss_dsi_panel_get_oneplus_mode(ctrl)); } - if (mdss_dsi_panel_get_adaption_mode(ctrl)) { + if (mdss_dsi_panel_get_adaption_mode(ctrl)){ mdss_dsi_panel_set_adaption_mode(ctrl, - mdss_dsi_panel_get_adaption_mode(ctrl)); + mdss_dsi_panel_get_adaption_mode(ctrl)); } + #if defined(CONFIG_IRIS2P_FULL_SUPPORT) #if !defined(WITHOUT_IRIS) iris_init(ctrl); #endif - if (on_cmds->cmd_cnt) - mdss_dsi_panel_cmds_send(ctrl, on_cmds, CMD_REQ_COMMIT); + if (on_cmds->cmd_cnt) + mdss_dsi_panel_cmds_send(ctrl, on_cmds, CMD_REQ_COMMIT); #if !defined(WITHOUT_IRIS) iris_lightup(ctrl); #endif @@ -1437,176 +1431,172 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata) if (on_cmds->cmd_cnt) mdss_dsi_panel_cmds_send(ctrl, on_cmds, CMD_REQ_COMMIT); #endif - - - if (pinfo->compression_mode == COMPRESSION_DSC) - mdss_dsi_panel_dsc_pps_send(ctrl, pinfo); - - if (ctrl->ds_registered) - mdss_dba_utils_video_on(pinfo->dba_data, pinfo); - - /* Ensure low persistence mode is set as before */ - mdss_dsi_panel_apply_display_setting(pdata, pinfo->persist_mode); - - end: - pr_debug("%s:-\n", __func__); - pr_err("%s end\n", __func__); - return ret; + + if (pinfo->compression_mode == COMPRESSION_DSC) + mdss_dsi_panel_dsc_pps_send(ctrl, pinfo); + + if (ctrl->ds_registered) + mdss_dba_utils_video_on(pinfo->dba_data, pinfo); + + /* Ensure low persistence mode is set as before */ + mdss_dsi_panel_apply_display_setting(pdata, pinfo->persist_mode); + +end: + pr_debug("%s:-\n", __func__); + return ret; } - + static int mdss_dsi_post_panel_on(struct mdss_panel_data *pdata) { - struct mdss_dsi_ctrl_pdata *ctrl = NULL; - struct mdss_panel_info *pinfo; - struct dsi_panel_cmds *cmds; - u32 vsync_period = 0; - - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return -EINVAL; - } - pr_err("%s start\n", __func__); - ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - - pr_debug("%s: ctrl=%pK ndx=%d\n", __func__, ctrl, ctrl->ndx); - - pinfo = &pdata->panel_info; - if (pinfo->dcs_cmd_by_left && ctrl->ndx != DSI_CTRL_LEFT) - goto end; - - cmds = &ctrl->post_panel_on_cmds; - if (cmds->cmd_cnt) { - msleep(VSYNC_DELAY); /* wait for a vsync passed */ - mdss_dsi_panel_cmds_send(ctrl, cmds, CMD_REQ_COMMIT); - } - - if (pinfo->is_dba_panel && pinfo->is_pluggable) { - /* ensure at least 1 frame transfers to down stream device */ - vsync_period = (MSEC_PER_SEC / pinfo->mipi.frame_rate) + 1; - msleep(vsync_period); - mdss_dba_utils_hdcp_enable(pinfo->dba_data, true); - } - - end: - pr_debug("%s:-\n", __func__); - pr_err("%s end\n", __func__); - return 0; + struct mdss_dsi_ctrl_pdata *ctrl = NULL; + struct mdss_panel_info *pinfo; + struct dsi_panel_cmds *cmds; + u32 vsync_period = 0; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + pr_debug("%s: ctrl=%pK ndx=%d\n", __func__, ctrl, ctrl->ndx); + + pinfo = &pdata->panel_info; + if (pinfo->dcs_cmd_by_left && ctrl->ndx != DSI_CTRL_LEFT) + goto end; + + cmds = &ctrl->post_panel_on_cmds; + if (cmds->cmd_cnt) { + msleep(VSYNC_DELAY); /* wait for a vsync passed */ + mdss_dsi_panel_cmds_send(ctrl, cmds, CMD_REQ_COMMIT); + } + + if (pinfo->is_dba_panel && pinfo->is_pluggable) { + /* ensure at least 1 frame transfers to down stream device */ + vsync_period = (MSEC_PER_SEC / pinfo->mipi.frame_rate) + 1; + msleep(vsync_period); + mdss_dba_utils_hdcp_enable(pinfo->dba_data, true); + } + +end: + pr_debug("%s:-\n", __func__); + return 0; } - + static int mdss_dsi_panel_off(struct mdss_panel_data *pdata) { - struct mdss_dsi_ctrl_pdata *ctrl = NULL; - struct mdss_panel_info *pinfo; - - - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return -EINVAL; - } - pr_err("%s start\n", __func__); - pinfo = &pdata->panel_info; - ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - - pr_debug("%s: ctrl=%pK ndx=%d\n", __func__, ctrl, ctrl->ndx); - - if (pinfo->dcs_cmd_by_left) { - if (ctrl->ndx != DSI_CTRL_LEFT) - goto end; - } - mutex_lock(&ctrl->panel_mode_lock); - ctrl->is_panel_on = false; - mutex_unlock(&ctrl->panel_mode_lock); + struct mdss_dsi_ctrl_pdata *ctrl = NULL; + struct mdss_panel_info *pinfo; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + pinfo = &pdata->panel_info; + ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + pr_debug("%s: ctrl=%pK ndx=%d\n", __func__, ctrl, ctrl->ndx); + + if (pinfo->dcs_cmd_by_left) { + if (ctrl->ndx != DSI_CTRL_LEFT) + goto end; + } + + mutex_lock(&ctrl->panel_mode_lock); + ctrl->is_panel_on = false; + mutex_unlock(&ctrl->panel_mode_lock); #if defined(CONFIG_IRIS2P_FULL_SUPPORT) #if !defined(WITHOUT_IRIS) - iris_lightoff(ctrl); + iris_lightoff(ctrl); #endif - if (ctrl->off_cmds.cmd_cnt) - mdss_dsi_panel_cmds_send(ctrl, &ctrl->off_cmds, CMD_REQ_COMMIT); + if (ctrl->off_cmds.cmd_cnt) + mdss_dsi_panel_cmds_send(ctrl, &ctrl->off_cmds, CMD_REQ_COMMIT); #else - if (ctrl->off_cmds.cmd_cnt) - mdss_dsi_panel_cmds_send(ctrl, &ctrl->off_cmds, CMD_REQ_COMMIT); + if (ctrl->off_cmds.cmd_cnt) + mdss_dsi_panel_cmds_send(ctrl, &ctrl->off_cmds, CMD_REQ_COMMIT); #endif - if (ctrl->ds_registered && pinfo->is_pluggable) { - mdss_dba_utils_video_off(pinfo->dba_data); - mdss_dba_utils_hdcp_enable(pinfo->dba_data, false); - } - - end: - pr_debug("%s:-\n", __func__); - pr_err("%s end\n", __func__); - return 0; + if (ctrl->ds_registered && pinfo->is_pluggable) { + mdss_dba_utils_video_off(pinfo->dba_data); + mdss_dba_utils_hdcp_enable(pinfo->dba_data, false); + } + +end: + pr_debug("%s:-\n", __func__); + return 0; } - + static int mdss_dsi_panel_low_power_config(struct mdss_panel_data *pdata, - int enable) + int enable) { - struct mdss_dsi_ctrl_pdata *ctrl = NULL; - struct mdss_panel_info *pinfo; - - if (pdata == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return -EINVAL; - } - - pinfo = &pdata->panel_info; - ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, - panel_data); - - pr_debug("%s: ctrl=%pK ndx=%d enable=%d\n", __func__, ctrl, ctrl->ndx, - enable); - - /* Any panel specific low power commands/config */ - - pr_debug("%s:-\n", __func__); - return 0; + struct mdss_dsi_ctrl_pdata *ctrl = NULL; + struct mdss_panel_info *pinfo; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + pinfo = &pdata->panel_info; + ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + pr_debug("%s: ctrl=%pK ndx=%d enable=%d\n", __func__, ctrl, ctrl->ndx, + enable); + + /* Any panel specific low power commands/config */ + + pr_debug("%s:-\n", __func__); + return 0; } - + static void mdss_dsi_parse_mdp_kickoff_threshold(struct device_node *np, - struct mdss_panel_info *pinfo) + struct mdss_panel_info *pinfo) { - int len, rc; - const u32 *src; - u32 tmp; - u32 max_delay_us; - - pinfo->mdp_koff_thshold = false; - src = of_get_property(np, "qcom,mdss-mdp-kickoff-threshold", &len); - if (!src || (len == 0)) - return; - - rc = of_property_read_u32(np, "qcom,mdss-mdp-kickoff-delay", &tmp); - if (!rc) - pinfo->mdp_koff_delay = tmp; - else - return; - - if (pinfo->mipi.frame_rate == 0) { - pr_err("cannot enable guard window, unexpected panel fps\n"); - return; - } - - pinfo->mdp_koff_thshold_low = be32_to_cpu(src[0]); - pinfo->mdp_koff_thshold_high = be32_to_cpu(src[1]); - max_delay_us = 1000000 / pinfo->mipi.frame_rate; - - /* enable the feature if threshold is valid */ - if ((pinfo->mdp_koff_thshold_low < pinfo->mdp_koff_thshold_high) && - ((pinfo->mdp_koff_delay > 0) || - (pinfo->mdp_koff_delay < max_delay_us))) - pinfo->mdp_koff_thshold = true; - - pr_debug("panel kickoff thshold:[%d, %d] delay:%d (max:%d) enable:%d\n", - pinfo->mdp_koff_thshold_low, - pinfo->mdp_koff_thshold_high, - pinfo->mdp_koff_delay, - max_delay_us, - pinfo->mdp_koff_thshold); + int len, rc; + const u32 *src; + u32 tmp; + u32 max_delay_us; + + pinfo->mdp_koff_thshold = false; + src = of_get_property(np, "qcom,mdss-mdp-kickoff-threshold", &len); + if (!src || (len == 0)) + return; + + rc = of_property_read_u32(np, "qcom,mdss-mdp-kickoff-delay", &tmp); + if (!rc) + pinfo->mdp_koff_delay = tmp; + else + return; + + if (pinfo->mipi.frame_rate == 0) { + pr_err("cannot enable guard window, unexpected panel fps\n"); + return; + } + + pinfo->mdp_koff_thshold_low = be32_to_cpu(src[0]); + pinfo->mdp_koff_thshold_high = be32_to_cpu(src[1]); + max_delay_us = 1000000 / pinfo->mipi.frame_rate; + + /* enable the feature if threshold is valid */ + if ((pinfo->mdp_koff_thshold_low < pinfo->mdp_koff_thshold_high) && + ((pinfo->mdp_koff_delay > 0) || + (pinfo->mdp_koff_delay < max_delay_us))) + pinfo->mdp_koff_thshold = true; + + pr_debug("panel kickoff thshold:[%d, %d] delay:%d (max:%d) enable:%d\n", + pinfo->mdp_koff_thshold_low, + pinfo->mdp_koff_thshold_high, + pinfo->mdp_koff_delay, + max_delay_us, + pinfo->mdp_koff_thshold); } - + static void mdss_dsi_parse_trigger(struct device_node *np, char *trigger, - char *trigger_key) + char *trigger_key) { const char *data; @@ -1623,10 +1613,10 @@ static void mdss_dsi_parse_trigger(struct device_node *np, char *trigger, *trigger = DSI_CMD_TRIGGER_SW_TE; } } - + static int mdss_dsi_parse_dcs_cmds(struct device_node *np, - struct dsi_panel_cmds *pcmds, char *cmd_key, char *link_key) + struct dsi_panel_cmds *pcmds, char *cmd_key, char *link_key) { const char *data; int blen = 0, len; @@ -1664,13 +1654,13 @@ static int mdss_dsi_parse_dcs_cmds(struct device_node *np, len -= dchdr->dlen; cnt++; } - + if (len != 0) { pr_err("%s: dcs_cmd=%x len=%d error!", __func__, buf[0], blen); goto exit_free; } - + pcmds->cmds = kzalloc(cnt * sizeof(struct dsi_cmd_desc), GFP_KERNEL); if (!pcmds->cmds) @@ -1691,7 +1681,7 @@ static int mdss_dsi_parse_dcs_cmds(struct device_node *np, bp += dchdr->dlen; len -= dchdr->dlen; } - + /*Set default link state to LP Mode*/ pcmds->link_state = DSI_LP_MODE; @@ -1712,13 +1702,12 @@ exit_free: kfree(buf); return -ENOMEM; } - - + + int mdss_panel_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing, - char *dst_format) + char *dst_format) { int rc = 0; - switch (bpp) { case 3: *dst_format = DSI_CMD_DST_FORMAT_RGB111; @@ -1743,7 +1732,6 @@ int mdss_panel_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing, } break; case 18: - switch (mipi_mode) { case DSI_VIDEO_MODE: if (pixel_packing == 0) @@ -1781,1668 +1769,1690 @@ int mdss_panel_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing, } return rc; } - - static int mdss_dsi_parse_fbc_params(struct device_node *np, - struct mdss_panel_timing *timing) - { - int rc, fbc_enabled = 0; - u32 tmp; - struct fbc_panel_info *fbc = &timing->fbc; - - fbc_enabled = of_property_read_bool(np, "qcom,mdss-dsi-fbc-enable"); - if (fbc_enabled) { - pr_debug("%s:%d FBC panel enabled.\n", __func__, __LINE__); - fbc->enabled = 1; - rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-bpp", &tmp); - fbc->target_bpp = (!rc ? tmp : 24); - rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-packing", - &tmp); - fbc->comp_mode = (!rc ? tmp : 0); - fbc->qerr_enable = of_property_read_bool(np, - "qcom,mdss-dsi-fbc-quant-error"); - rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-bias", &tmp); - fbc->cd_bias = (!rc ? tmp : 0); - fbc->pat_enable = of_property_read_bool(np, - "qcom,mdss-dsi-fbc-pat-mode"); - fbc->vlc_enable = of_property_read_bool(np, - "qcom,mdss-dsi-fbc-vlc-mode"); - fbc->bflc_enable = of_property_read_bool(np, - "qcom,mdss-dsi-fbc-bflc-mode"); - rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-h-line-budget", - &tmp); - fbc->line_x_budget = (!rc ? tmp : 0); - rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-budget-ctrl", - &tmp); - fbc->block_x_budget = (!rc ? tmp : 0); - rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-block-budget", - &tmp); - fbc->block_budget = (!rc ? tmp : 0); - rc = of_property_read_u32(np, - "qcom,mdss-dsi-fbc-lossless-threshold", &tmp); - fbc->lossless_mode_thd = (!rc ? tmp : 0); - rc = of_property_read_u32(np, - "qcom,mdss-dsi-fbc-lossy-threshold", &tmp); - fbc->lossy_mode_thd = (!rc ? tmp : 0); - rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-rgb-threshold", - &tmp); - fbc->lossy_rgb_thd = (!rc ? tmp : 0); - rc = of_property_read_u32(np, - "qcom,mdss-dsi-fbc-lossy-mode-idx", &tmp); - fbc->lossy_mode_idx = (!rc ? tmp : 0); - rc = of_property_read_u32(np, - "qcom,mdss-dsi-fbc-slice-height", &tmp); - fbc->slice_height = (!rc ? tmp : 0); - fbc->pred_mode = of_property_read_bool(np, - "qcom,mdss-dsi-fbc-2d-pred-mode"); - fbc->enc_mode = of_property_read_bool(np, - "qcom,mdss-dsi-fbc-ver2-mode"); - rc = of_property_read_u32(np, - "qcom,mdss-dsi-fbc-max-pred-err", &tmp); - fbc->max_pred_err = (!rc ? tmp : 0); - - timing->compression_mode = COMPRESSION_FBC; - } else { - pr_debug("%s:%d Panel does not support FBC.\n", - __func__, __LINE__); - fbc->enabled = 0; - fbc->target_bpp = 24; - } - return 0; - } - - void mdss_dsi_panel_dsc_pps_send(struct mdss_dsi_ctrl_pdata *ctrl, - struct mdss_panel_info *pinfo) - { - struct dsi_panel_cmds pcmds; - struct dsi_cmd_desc cmd; - - if (!pinfo || (pinfo->compression_mode != COMPRESSION_DSC)) - return; - - memset(&pcmds, 0, sizeof(pcmds)); - memset(&cmd, 0, sizeof(cmd)); - - cmd.dchdr.dlen = mdss_panel_dsc_prepare_pps_buf(&pinfo->dsc, - ctrl->pps_buf, 0); - cmd.dchdr.dtype = DTYPE_PPS; - cmd.dchdr.last = 1; - cmd.dchdr.wait = 10; - cmd.dchdr.vc = 0; - cmd.dchdr.ack = 0; - cmd.payload = ctrl->pps_buf; - - pcmds.cmd_cnt = 1; - pcmds.cmds = &cmd; - pcmds.link_state = DSI_LP_MODE; - - mdss_dsi_panel_cmds_send(ctrl, &pcmds, CMD_REQ_COMMIT); - } - - static int mdss_dsi_parse_hdr_settings(struct device_node *np, - struct mdss_panel_info *pinfo) - { - int rc = 0; - struct mdss_panel_hdr_properties *hdr_prop; - - 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; - } - - hdr_prop = &pinfo->hdr_properties; - hdr_prop->hdr_enabled = of_property_read_bool(np, - "qcom,mdss-dsi-panel-hdr-enabled"); - - if (hdr_prop->hdr_enabled) { - rc = of_property_read_u32_array(np, - "qcom,mdss-dsi-panel-hdr-color-primaries", - hdr_prop->display_primaries, - DISPLAY_PRIMARIES_COUNT); - if (rc) { - pr_info("%s:%d, Unable to read color primaries,rc:%u", - __func__, __LINE__, - hdr_prop->hdr_enabled = false); - } - - rc = of_property_read_u32(np, - "qcom,mdss-dsi-panel-peak-brightness", - &(hdr_prop->peak_brightness)); - if (rc) { - pr_info("%s:%d, Unable to read hdr brightness, rc:%u", - __func__, __LINE__, rc); - hdr_prop->hdr_enabled = false; - } - - rc = of_property_read_u32(np, - "qcom,mdss-dsi-panel-blackness-level", - &(hdr_prop->blackness_level)); - if (rc) { - pr_info("%s:%d, Unable to read hdr brightness, rc:%u", - __func__, __LINE__, rc); - hdr_prop->hdr_enabled = false; - } - } - 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) - { - u32 data; - int rc = 0; - struct dsc_desc *dsc = &timing->dsc; - - rc = of_property_read_u32(np, "qcom,mdss-dsc-version", &data); - if (rc) { - dsc->version = 0x11; - rc = 0; - } else { - dsc->version = data & 0xff; - /* only support DSC 1.1 rev */ - if (dsc->version != 0x11) { - pr_err("%s: DSC version:%d not supported\n", __func__, - dsc->version); - rc = -EINVAL; - goto end; - } - } - - rc = of_property_read_u32(np, "qcom,mdss-dsc-scr-version", &data); - if (rc) { - dsc->scr_rev = 0x0; - rc = 0; - } else { - dsc->scr_rev = data & 0xff; - /* only one scr rev supported */ - if (dsc->scr_rev > 0x1) { - pr_err("%s: DSC scr version:%d not supported\n", - __func__, dsc->scr_rev); - rc = -EINVAL; - goto end; - } - } - - end: - return rc; - } - - static int mdss_dsi_parse_dsc_params(struct device_node *np, - struct mdss_panel_timing *timing, bool is_split_display) - { - u32 data, intf_width; - int rc = 0; - struct dsc_desc *dsc = &timing->dsc; - - if (!np) { - pr_err("%s: device node pointer is NULL\n", __func__); - return -EINVAL; - } - - rc = of_property_read_u32(np, "qcom,mdss-dsc-encoders", &data); - if (rc) { - if (!of_find_property(np, "qcom,mdss-dsc-encoders", NULL)) { - /* property is not defined, default to 1 */ - data = 1; - } else { - pr_err("%s: Error parsing qcom,mdss-dsc-encoders\n", - __func__); - goto end; - } - } - - timing->dsc_enc_total = data; - - if (is_split_display && (timing->dsc_enc_total > 1)) { - pr_err("%s: Error: for split displays, more than 1 dsc encoder per panel is not allowed.\n", - __func__); - goto end; - } - - rc = of_property_read_u32(np, "qcom,mdss-dsc-slice-height", &data); - if (rc) - goto end; - dsc->slice_height = data; - - rc = of_property_read_u32(np, "qcom,mdss-dsc-slice-width", &data); - if (rc) - goto end; - dsc->slice_width = data; - intf_width = timing->xres; - - if (intf_width % dsc->slice_width) { - pr_err("%s: Error: multiple of slice-width:%d should match panel-width:%d\n", - __func__, dsc->slice_width, intf_width); - goto end; - } - - data = intf_width / dsc->slice_width; - if (((timing->dsc_enc_total > 1) && ((data != 2) && (data != 4))) || - ((timing->dsc_enc_total == 1) && (data > 2))) { - pr_err("%s: Error: max 2 slice per encoder. slice-width:%d should match panel-width:%d dsc_enc_total:%d\n", - __func__, dsc->slice_width, - intf_width, timing->dsc_enc_total); - goto end; - } - - rc = of_property_read_u32(np, "qcom,mdss-dsc-slice-per-pkt", &data); - if (rc) - goto end; - dsc->slice_per_pkt = data; - - /* - * slice_per_pkt can be either 1 or all slices_per_intf - */ - if ((dsc->slice_per_pkt > 1) && (dsc->slice_per_pkt != - DIV_ROUND_UP(intf_width, dsc->slice_width))) { - pr_err("Error: slice_per_pkt can be either 1 or all slices_per_intf\n"); - pr_err("%s: slice_per_pkt=%d, slice_width=%d intf_width=%d\n", - __func__, - dsc->slice_per_pkt, dsc->slice_width, intf_width); - rc = -EINVAL; - goto end; - } - - pr_debug("%s: num_enc:%d :slice h=%d w=%d s_pkt=%d\n", __func__, - timing->dsc_enc_total, dsc->slice_height, - dsc->slice_width, dsc->slice_per_pkt); - - rc = of_property_read_u32(np, "qcom,mdss-dsc-bit-per-component", &data); - if (rc) - goto end; - dsc->bpc = data; - - rc = of_property_read_u32(np, "qcom,mdss-dsc-bit-per-pixel", &data); - if (rc) - goto end; - dsc->bpp = data; - - pr_debug("%s: bpc=%d bpp=%d\n", __func__, - dsc->bpc, dsc->bpp); - - dsc->block_pred_enable = of_property_read_bool(np, - "qcom,mdss-dsc-block-prediction-enable"); - - dsc->enable_422 = 0; - dsc->convert_rgb = 1; - dsc->vbr_enable = 0; - - dsc->config_by_manufacture_cmd = of_property_read_bool(np, - "qcom,mdss-dsc-config-by-manufacture-cmd"); - - mdss_panel_dsc_parameters_calc(&timing->dsc); - mdss_panel_dsc_pclk_param_calc(&timing->dsc, intf_width); - - timing->dsc.full_frame_slices = - DIV_ROUND_UP(intf_width, timing->dsc.slice_width); - - timing->compression_mode = COMPRESSION_DSC; - - end: - return rc; - } - - static struct device_node *mdss_dsi_panel_get_dsc_cfg_np( - struct device_node *np, struct mdss_panel_data *panel_data, - bool default_timing) - { - struct device_node *dsc_cfg_np = NULL; - - - /* Read the dsc config node specified by command line */ - if (default_timing) { - dsc_cfg_np = of_get_child_by_name(np, - panel_data->dsc_cfg_np_name); - if (!dsc_cfg_np) - pr_warn_once("%s: cannot find dsc config node:%s\n", - __func__, panel_data->dsc_cfg_np_name); - } - - /* - * Fall back to default from DT as nothing is specified - * in command line. - */ - if (!dsc_cfg_np && of_find_property(np, "qcom,config-select", NULL)) { - dsc_cfg_np = of_parse_phandle(np, "qcom,config-select", 0); - if (!dsc_cfg_np) - pr_warn_once("%s:err parsing qcom,config-select\n", - __func__); - } - - return dsc_cfg_np; - } - - static int mdss_dsi_parse_topology_config(struct device_node *np, - struct dsi_panel_timing *pt, struct mdss_panel_data *panel_data, - bool default_timing) - { - int rc = 0; - bool is_split_display = panel_data->panel_info.is_split_display; - const char *data; - struct mdss_panel_timing *timing = &pt->timing; - struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; - struct mdss_panel_info *pinfo; - struct device_node *cfg_np = NULL; - - ctrl_pdata = container_of(panel_data, struct mdss_dsi_ctrl_pdata, - panel_data); - pinfo = &ctrl_pdata->panel_data.panel_info; - - cfg_np = mdss_dsi_panel_get_dsc_cfg_np(np, - &ctrl_pdata->panel_data, default_timing); - - if (cfg_np) { - if (!of_property_read_u32_array(cfg_np, "qcom,lm-split", - timing->lm_widths, 2)) { - if (mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data) - && (timing->lm_widths[1] != 0)) { - pr_err("%s: lm-split not allowed with split display\n", - __func__); - rc = -EINVAL; - goto end; - } - } - - if (!of_property_read_string(cfg_np, "qcom,split-mode", - &data) && !strcmp(data, "pingpong-split")) - pinfo->use_pingpong_split = true; - - if (((timing->lm_widths[0]) || (timing->lm_widths[1])) && - pinfo->use_pingpong_split) { - pr_err("%s: pingpong_split cannot be used when lm-split[%d,%d] is specified\n", - __func__, - timing->lm_widths[0], timing->lm_widths[1]); - return -EINVAL; - } - - pr_info("%s: cfg_node name %s lm_split:%dx%d pp_split:%s\n", - __func__, cfg_np->name, - timing->lm_widths[0], timing->lm_widths[1], - pinfo->use_pingpong_split ? "yes" : "no"); - } - - if (!pinfo->use_pingpong_split && - (timing->lm_widths[0] == 0) && (timing->lm_widths[1] == 0)) - timing->lm_widths[0] = pt->timing.xres; - - data = of_get_property(np, "qcom,compression-mode", NULL); - if (data) { - if (cfg_np && !strcmp(data, "dsc")) { - rc = mdss_dsi_parse_dsc_version(np, &pt->timing); - if (rc) - goto end; - - pinfo->send_pps_before_switch = - of_property_read_bool(np, - "qcom,mdss-dsi-send-pps-before-switch"); - - rc = mdss_dsi_parse_dsc_params(cfg_np, &pt->timing, - is_split_display); - } else if (!strcmp(data, "fbc")) { - rc = mdss_dsi_parse_fbc_params(np, &pt->timing); - } - } - - end: - of_node_put(cfg_np); - return rc; - } - - static void mdss_panel_parse_te_params(struct device_node *np, - struct mdss_panel_timing *timing) - { - struct mdss_mdp_pp_tear_check *te = &timing->te; - u32 tmp; - int rc = 0; - /* - * TE default: dsi byte clock calculated base on 70 fps; - * around 14 ms to complete a kickoff cycle if te disabled; - * vclk_line base on 60 fps; write is faster than read; - * init == start == rdptr; - */ - te->tear_check_en = - !of_property_read_bool(np, "qcom,mdss-tear-check-disable"); - rc = of_property_read_u32 - (np, "qcom,mdss-tear-check-sync-cfg-height", &tmp); - te->sync_cfg_height = (!rc ? tmp : 0xfff0); - rc = of_property_read_u32 - (np, "qcom,mdss-tear-check-sync-init-val", &tmp); - te->vsync_init_val = (!rc ? tmp : timing->yres); - rc = of_property_read_u32 - (np, "qcom,mdss-tear-check-sync-threshold-start", &tmp); - te->sync_threshold_start = (!rc ? tmp : 4); - rc = of_property_read_u32 - (np, "qcom,mdss-tear-check-sync-threshold-continue", &tmp); - te->sync_threshold_continue = (!rc ? tmp : 4); - rc = of_property_read_u32(np, "qcom,mdss-tear-check-frame-rate", &tmp); - te->refx100 = (!rc ? tmp : 6000); - rc = of_property_read_u32 - (np, "qcom,mdss-tear-check-start-pos", &tmp); - te->start_pos = (!rc ? tmp : timing->yres); - rc = of_property_read_u32 - (np, "qcom,mdss-tear-check-rd-ptr-trigger-intr", &tmp); - te->rd_ptr_irq = (!rc ? tmp : timing->yres + 1); - te->wr_ptr_irq = 0; - } - - - static int mdss_dsi_parse_reset_seq(struct device_node *np, - u32 rst_seq[MDSS_DSI_RST_SEQ_LEN], u32 *rst_len, - const char *name) - { - int num = 0, i; - int rc; - struct property *data; - u32 tmp[MDSS_DSI_RST_SEQ_LEN]; - *rst_len = 0; - data = of_find_property(np, name, &num); - num /= sizeof(u32); - if (!data || !num || num > MDSS_DSI_RST_SEQ_LEN || num % 2) { - pr_debug("%s:%d, error reading %s, length found = %d\n", - __func__, __LINE__, name, num); - } else { - rc = of_property_read_u32_array(np, name, tmp, num); - if (rc) - pr_debug("%s:%d, error reading %s, rc = %d\n", - __func__, __LINE__, name, rc); - else { - for (i = 0; i < num; ++i) - rst_seq[i] = tmp[i]; - *rst_len = num; - } - } - return 0; - } - - static bool mdss_dsi_cmp_panel_reg_v2(struct mdss_dsi_ctrl_pdata *ctrl) - { - int i, j = 0; - int len = 0, *lenp; - int group = 0; - - lenp = ctrl->status_valid_params ?: ctrl->status_cmds_rlen; - - for (i = 0; i < ctrl->status_cmds.cmd_cnt; i++) - len += lenp[i]; - - for (i = 0; i < len; i++) { - pr_debug("[%i] return:0x%x status:0x%x\n", - i, (unsigned int)ctrl->return_buf[i], - (unsigned int)ctrl->status_value[j + i]); - MDSS_XLOG(ctrl->ndx, ctrl->return_buf[i], - ctrl->status_value[j + i]); - j += len; - } - - for (j = 0; j < ctrl->groups; ++j) { - for (i = 0; i < len; ++i) { - if (ctrl->return_buf[i] != - ctrl->status_value[group + i]) - break; - } - - if (i == len) - return true; - group += len; - } - - return false; - } - - static int mdss_dsi_gen_read_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata) - { - if (!mdss_dsi_cmp_panel_reg_v2(ctrl_pdata)) { - pr_err("%s: Read back value from panel is incorrect\n", - __func__); - return -EINVAL; - } else { - return 1; - } - } - - static int mdss_dsi_nt35596_read_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata) - { - if (!mdss_dsi_cmp_panel_reg(ctrl_pdata->status_buf, - ctrl_pdata->status_value, 0)) { - ctrl_pdata->status_error_count = 0; - pr_err("%s: Read back value from panel is incorrect\n", - __func__); - return -EINVAL; - } else { - if (!mdss_dsi_cmp_panel_reg(ctrl_pdata->status_buf, - ctrl_pdata->status_value, 3)) { - ctrl_pdata->status_error_count = 0; - } else { - if (mdss_dsi_cmp_panel_reg(ctrl_pdata->status_buf, - ctrl_pdata->status_value, 4) || - mdss_dsi_cmp_panel_reg(ctrl_pdata->status_buf, - ctrl_pdata->status_value, 5)) - ctrl_pdata->status_error_count = 0; - else - ctrl_pdata->status_error_count++; - if (ctrl_pdata->status_error_count >= - ctrl_pdata->max_status_error_count) { - ctrl_pdata->status_error_count = 0; - pr_err("%s: Read value bad. Error_cnt = %i\n", - __func__, - ctrl_pdata->status_error_count); - return -EINVAL; - } - } - return 1; - } - } - - static void mdss_dsi_parse_roi_alignment(struct device_node *np, - struct dsi_panel_timing *pt) - { - int len = 0; - u32 value[6]; - struct property *data; - struct mdss_panel_timing *timing = &pt->timing; - - data = of_find_property(np, "qcom,panel-roi-alignment", &len); - len /= sizeof(u32); - if (!data || (len != 6)) { - pr_debug("%s: Panel roi alignment not found", __func__); - } else { - int rc = of_property_read_u32_array(np, - "qcom,panel-roi-alignment", value, len); - if (rc) - pr_debug("%s: Error reading panel roi alignment values", - __func__); - else { - timing->roi_alignment.xstart_pix_align = value[0]; - timing->roi_alignment.ystart_pix_align = value[1]; - timing->roi_alignment.width_pix_align = value[2]; - timing->roi_alignment.height_pix_align = value[3]; - timing->roi_alignment.min_width = value[4]; - timing->roi_alignment.min_height = value[5]; - } - - pr_debug("%s: ROI alignment: [%d, %d, %d, %d, %d, %d]", - __func__, timing->roi_alignment.xstart_pix_align, - timing->roi_alignment.width_pix_align, - timing->roi_alignment.ystart_pix_align, - timing->roi_alignment.height_pix_align, - timing->roi_alignment.min_width, - timing->roi_alignment.min_height); - } - } - - static void mdss_dsi_parse_dms_config(struct device_node *np, - struct mdss_dsi_ctrl_pdata *ctrl) - { - struct mdss_panel_info *pinfo = &ctrl->panel_data.panel_info; - const char *data; - bool dms_enabled; - - dms_enabled = of_property_read_bool(np, - "qcom,dynamic-mode-switch-enabled"); - - if (!dms_enabled) { - pinfo->mipi.dms_mode = DYNAMIC_MODE_SWITCH_DISABLED; - goto exit; - } - - /* default mode is suspend_resume */ - pinfo->mipi.dms_mode = DYNAMIC_MODE_SWITCH_SUSPEND_RESUME; - data = of_get_property(np, "qcom,dynamic-mode-switch-type", NULL); - if (data && !strcmp(data, "dynamic-resolution-switch-immediate")) { - if (!list_empty(&ctrl->panel_data.timings_list)) - pinfo->mipi.dms_mode = - DYNAMIC_MODE_RESOLUTION_SWITCH_IMMEDIATE; - else - pinfo->mipi.dms_mode = - DYNAMIC_MODE_SWITCH_DISABLED; - goto exit; - } - - if (data && !strcmp(data, "dynamic-switch-immediate")) - pinfo->mipi.dms_mode = DYNAMIC_MODE_SWITCH_IMMEDIATE; - else - pr_debug("%s: default dms suspend/resume\n", __func__); - - mdss_dsi_parse_dcs_cmds(np, &ctrl->video2cmd, - "qcom,video-to-cmd-mode-switch-commands", - "qcom,mode-switch-commands-state"); - - mdss_dsi_parse_dcs_cmds(np, &ctrl->cmd2video, - "qcom,cmd-to-video-mode-switch-commands", - "qcom,mode-switch-commands-state"); - - mdss_dsi_parse_dcs_cmds(np, &ctrl->post_dms_on_cmds, - "qcom,mdss-dsi-post-mode-switch-on-command", - "qcom,mdss-dsi-post-mode-switch-on-command-state"); - - if (pinfo->mipi.dms_mode == DYNAMIC_MODE_SWITCH_IMMEDIATE && - !ctrl->post_dms_on_cmds.cmd_cnt) { - pr_warn("%s: No post dms on cmd specified\n", __func__); - pinfo->mipi.dms_mode = DYNAMIC_MODE_SWITCH_DISABLED; - } - - if (!ctrl->video2cmd.cmd_cnt || !ctrl->cmd2video.cmd_cnt) { - pr_warn("%s: No commands specified for dynamic switch\n", - __func__); - pinfo->mipi.dms_mode = DYNAMIC_MODE_SWITCH_DISABLED; - } - exit: - pr_info("%s: dynamic switch feature enabled: %d\n", __func__, - pinfo->mipi.dms_mode); - return; - } - - /* the length of all the valid values to be checked should not be great - * than the length of returned data from read command. - */ - static bool - mdss_dsi_parse_esd_check_valid_params(struct mdss_dsi_ctrl_pdata *ctrl) - { - int i; - - for (i = 0; i < ctrl->status_cmds.cmd_cnt; ++i) { - if (ctrl->status_valid_params[i] > ctrl->status_cmds_rlen[i]) { - pr_debug("%s: ignore valid params!\n", __func__); - return false; - } - } - - return true; - } - - static bool mdss_dsi_parse_esd_status_len(struct device_node *np, - char *prop_key, u32 **target, u32 cmd_cnt) - { - int tmp; - - if (!of_find_property(np, prop_key, &tmp)) - return false; - - tmp /= sizeof(u32); - if (tmp != cmd_cnt) { - pr_err("%s: request property number(%d) not match command count(%d)\n", - __func__, tmp, cmd_cnt); - return false; - } - - *target = kcalloc(tmp, sizeof(u32), GFP_KERNEL); - if (IS_ERR_OR_NULL(*target)) { - pr_err("%s: Error allocating memory for property\n", - __func__); - return false; - } - - if (of_property_read_u32_array(np, prop_key, *target, tmp)) { - pr_err("%s: cannot get values from dts\n", __func__); - kfree(*target); - *target = NULL; - return false; - } - - return true; - } - - static void mdss_dsi_parse_esd_params(struct device_node *np, - struct mdss_dsi_ctrl_pdata *ctrl) - { - u32 tmp; - u32 i, status_len, *lenp; - int rc; - struct property *data; - const char *string; - struct mdss_panel_info *pinfo = &ctrl->panel_data.panel_info; - - pinfo->esd_check_enabled = of_property_read_bool(np, - "qcom,esd-check-enabled"); - - if (!pinfo->esd_check_enabled) - return; - - ctrl->status_mode = ESD_MAX; - rc = of_property_read_string(np, - "qcom,mdss-dsi-panel-status-check-mode", &string); - if (!rc) { - if (!strcmp(string, "bta_check")) { - ctrl->status_mode = ESD_BTA; - } else if (!strcmp(string, "reg_read")) { - ctrl->status_mode = ESD_REG; - ctrl->check_read_status = - mdss_dsi_gen_read_status; - } else if (!strcmp(string, "reg_read_nt35596")) { - ctrl->status_mode = ESD_REG_NT35596; - ctrl->status_error_count = 0; - ctrl->check_read_status = - mdss_dsi_nt35596_read_status; - } else if (!strcmp(string, "te_signal_check")) { - if (pinfo->mipi.mode == DSI_CMD_MODE) { - ctrl->status_mode = ESD_TE; - } else { - pr_err("TE-ESD not valid for video mode\n"); - goto error; - } - } else { - pr_err("No valid panel-status-check-mode string\n"); - goto error; - } - } - - if ((ctrl->status_mode == ESD_BTA) || (ctrl->status_mode == ESD_TE) || - (ctrl->status_mode == ESD_MAX)) - return; - - mdss_dsi_parse_dcs_cmds(np, &ctrl->status_cmds, - "qcom,mdss-dsi-panel-status-command", - "qcom,mdss-dsi-panel-status-command-state"); - - rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-max-error-count", - &tmp); - ctrl->max_status_error_count = (!rc ? tmp : 0); - - if (!mdss_dsi_parse_esd_status_len(np, - "qcom,mdss-dsi-panel-status-read-length", - &ctrl->status_cmds_rlen, ctrl->status_cmds.cmd_cnt)) { - pinfo->esd_check_enabled = false; - return; - } - - if (mdss_dsi_parse_esd_status_len(np, - "qcom,mdss-dsi-panel-status-valid-params", - &ctrl->status_valid_params, ctrl->status_cmds.cmd_cnt)) { - if (!mdss_dsi_parse_esd_check_valid_params(ctrl)) - goto error1; - } - - status_len = 0; - lenp = ctrl->status_valid_params ?: ctrl->status_cmds_rlen; - for (i = 0; i < ctrl->status_cmds.cmd_cnt; ++i) - status_len += lenp[i]; - - data = of_find_property(np, "qcom,mdss-dsi-panel-status-value", &tmp); - tmp /= sizeof(u32); - if (!IS_ERR_OR_NULL(data) && tmp != 0 && (tmp % status_len) == 0) { - ctrl->groups = tmp / status_len; - } else { - pr_err("%s: Error parse panel-status-value\n", __func__); - goto error1; - } - - ctrl->status_value = kzalloc(sizeof(u32) * status_len * ctrl->groups, - GFP_KERNEL); - if (!ctrl->status_value) - goto error1; - - ctrl->return_buf = kcalloc(status_len * ctrl->groups, - sizeof(unsigned char), GFP_KERNEL); - if (!ctrl->return_buf) - goto error2; - - rc = of_property_read_u32_array(np, - "qcom,mdss-dsi-panel-status-value", - ctrl->status_value, ctrl->groups * status_len); - if (rc) { - pr_debug("%s: Error reading panel status values\n", - __func__); - memset(ctrl->status_value, 0, ctrl->groups * status_len); - } - - return; - - error2: - kfree(ctrl->status_value); - error1: - kfree(ctrl->status_valid_params); - kfree(ctrl->status_cmds_rlen); - error: - pinfo->esd_check_enabled = false; - } - - static void mdss_dsi_parse_partial_update_caps(struct device_node *np, - struct mdss_dsi_ctrl_pdata *ctrl) - { - struct mdss_panel_info *pinfo; - const char *data; - - pinfo = &ctrl->panel_data.panel_info; - - data = of_get_property(np, "qcom,partial-update-enabled", NULL); - if (data && !strcmp(data, "single_roi")) - pinfo->partial_update_supported = - PU_SINGLE_ROI; - else if (data && !strcmp(data, "dual_roi")) - pinfo->partial_update_supported = - PU_DUAL_ROI; - else if (data && !strcmp(data, "none")) - pinfo->partial_update_supported = - PU_NOT_SUPPORTED; - else - pinfo->partial_update_supported = - PU_NOT_SUPPORTED; - - if (pinfo->mipi.mode == DSI_CMD_MODE) { - pinfo->partial_update_enabled = pinfo->partial_update_supported; - pr_info("%s: partial_update_enabled=%d\n", __func__, - pinfo->partial_update_enabled); - ctrl->set_col_page_addr = mdss_dsi_set_col_page_addr; - if (pinfo->partial_update_enabled) { - pinfo->partial_update_roi_merge = - of_property_read_bool(np, - "qcom,partial-update-roi-merge"); - } - } - } - - static int mdss_dsi_parse_panel_features(struct device_node *np, - struct mdss_dsi_ctrl_pdata *ctrl) - { - struct mdss_panel_info *pinfo; - - if (!np || !ctrl) { - pr_err("%s: Invalid arguments\n", __func__); - return -ENODEV; - } - - pinfo = &ctrl->panel_data.panel_info; - - mdss_dsi_parse_partial_update_caps(np, ctrl); - - pinfo->dcs_cmd_by_left = of_property_read_bool(np, - "qcom,dcs-cmd-by-left"); - - pinfo->ulps_feature_enabled = of_property_read_bool(np, - "qcom,ulps-enabled"); - pr_info("%s: ulps feature %s\n", __func__, - (pinfo->ulps_feature_enabled ? "enabled" : "disabled")); - - pinfo->ulps_suspend_enabled = of_property_read_bool(np, - "qcom,suspend-ulps-enabled"); - pr_info("%s: ulps during suspend feature %s", __func__, - (pinfo->ulps_suspend_enabled ? "enabled" : "disabled")); - - mdss_dsi_parse_dms_config(np, ctrl); - - pinfo->panel_ack_disabled = pinfo->sim_panel_mode ? - 1 : of_property_read_bool(np, "qcom,panel-ack-disabled"); - - pinfo->allow_phy_power_off = of_property_read_bool(np, - "qcom,panel-allow-phy-poweroff"); - - mdss_dsi_parse_esd_params(np, ctrl); - - if (pinfo->panel_ack_disabled && pinfo->esd_check_enabled) { - pr_warn("ESD should not be enabled if panel ACK is disabled\n"); - pinfo->esd_check_enabled = false; - } - - if (ctrl->disp_en_gpio <= 0) { - ctrl->disp_en_gpio = of_get_named_gpio( - np, - "qcom,5v-boost-gpio", 0); - - if (!gpio_is_valid(ctrl->disp_en_gpio)) - pr_debug("%s:%d, Disp_en gpio not specified\n", - __func__, __LINE__); - } - - mdss_dsi_parse_dcs_cmds(np, &ctrl->lp_on_cmds, - "qcom,mdss-dsi-lp-mode-on", NULL); - - mdss_dsi_parse_dcs_cmds(np, &ctrl->lp_off_cmds, - "qcom,mdss-dsi-lp-mode-off", NULL); - - return 0; - } - - static void mdss_dsi_parse_panel_horizintal_line_idle(struct device_node *np, - struct mdss_dsi_ctrl_pdata *ctrl) - { - const u32 *src; - int i, len, cnt; - struct panel_horizontal_idle *kp; - - if (!np || !ctrl) { - pr_err("%s: Invalid arguments\n", __func__); - return; - } - - src = of_get_property(np, "qcom,mdss-dsi-hor-line-idle", &len); - if (!src || len == 0) - return; - - cnt = len % 3; /* 3 fields per entry */ - if (cnt) { - pr_err("%s: invalid horizontal idle len=%d\n", __func__, len); - return; - } - - cnt = len / sizeof(u32); - - kp = kzalloc(sizeof(*kp) * (cnt / 3), GFP_KERNEL); - if (kp == NULL) { - pr_err("%s: No memory\n", __func__); - return; - } - - ctrl->line_idle = kp; - for (i = 0; i < cnt; i += 3) { - kp->min = be32_to_cpu(src[i]); - kp->max = be32_to_cpu(src[i+1]); - kp->idle = be32_to_cpu(src[i+2]); - kp++; - ctrl->horizontal_idle_cnt++; - } - - /* - * idle is enabled for this controller, this will be used to - * enable/disable burst mode since both features are mutually - * exclusive. - */ - ctrl->idle_enabled = true; - - pr_debug("%s: horizontal_idle_cnt=%d\n", __func__, - ctrl->horizontal_idle_cnt); - } - - static int mdss_dsi_set_refresh_rate_range(struct device_node *pan_node, - struct mdss_panel_info *pinfo) - { - int rc = 0; - rc = of_property_read_u32(pan_node, - "qcom,mdss-dsi-min-refresh-rate", - &pinfo->min_fps); - if (rc) { - pr_warn("%s:%d, Unable to read min refresh rate\n", - __func__, __LINE__); - - /* - * If min refresh rate is not specified, set it to the - * default panel refresh rate. - */ - pinfo->min_fps = pinfo->mipi.frame_rate; - rc = 0; - } - - rc = of_property_read_u32(pan_node, - "qcom,mdss-dsi-max-refresh-rate", - &pinfo->max_fps); - if (rc) { - pr_warn("%s:%d, Unable to read max refresh rate\n", - __func__, __LINE__); - - /* - * Since max refresh rate was not specified when dynamic - * fps is enabled, using the default panel refresh rate - * as max refresh rate supported. - */ - pinfo->max_fps = pinfo->mipi.frame_rate; - rc = 0; - } - - pr_info("dyn_fps: min = %d, max = %d\n", - pinfo->min_fps, pinfo->max_fps); - return rc; - } - - static void mdss_dsi_parse_dfps_config(struct device_node *pan_node, - struct mdss_dsi_ctrl_pdata *ctrl_pdata) - { - const char *data; - bool dynamic_fps; - struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info); - - dynamic_fps = of_property_read_bool(pan_node, - "qcom,mdss-dsi-pan-enable-dynamic-fps"); - - if (!dynamic_fps) - return; - - pinfo->dynamic_fps = true; - data = of_get_property(pan_node, "qcom,mdss-dsi-pan-fps-update", NULL); - if (data) { - if (!strcmp(data, "dfps_suspend_resume_mode")) { - pinfo->dfps_update = DFPS_SUSPEND_RESUME_MODE; - pr_debug("dfps mode: suspend/resume\n"); - } else if (!strcmp(data, "dfps_immediate_clk_mode")) { - pinfo->dfps_update = DFPS_IMMEDIATE_CLK_UPDATE_MODE; - pr_debug("dfps mode: Immediate clk\n"); - } else if (!strcmp(data, "dfps_immediate_porch_mode_hfp")) { - pinfo->dfps_update = - DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP; - pr_debug("dfps mode: Immediate porch HFP\n"); - } else if (!strcmp(data, "dfps_immediate_porch_mode_vfp")) { - pinfo->dfps_update = - DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP; - pr_debug("dfps mode: Immediate porch VFP\n"); - } else { - pinfo->dfps_update = DFPS_SUSPEND_RESUME_MODE; - pr_debug("default dfps mode: suspend/resume\n"); - } - } else { - pinfo->dynamic_fps = false; - pr_debug("dfps update mode not configured: disable\n"); - } - pinfo->new_fps = pinfo->mipi.frame_rate; - pinfo->current_fps = pinfo->mipi.frame_rate; - - return; - } - - int mdss_panel_parse_bl_settings(struct device_node *np, - struct mdss_dsi_ctrl_pdata *ctrl_pdata) - { - const char *data; - int rc = 0; - u32 tmp; - - ctrl_pdata->bklt_ctrl = UNKNOWN_CTRL; - data = of_get_property(np, "qcom,mdss-dsi-bl-pmic-control-type", NULL); - if (data) { - if (!strcmp(data, "bl_ctrl_wled")) { - led_trigger_register_simple("bkl-trigger", - &bl_led_trigger); - pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", - __func__); - ctrl_pdata->bklt_ctrl = BL_WLED; - } else if (!strcmp(data, "bl_ctrl_pwm")) { - ctrl_pdata->bklt_ctrl = BL_PWM; - ctrl_pdata->pwm_pmi = of_property_read_bool(np, - "qcom,mdss-dsi-bl-pwm-pmi"); - rc = of_property_read_u32(np, - "qcom,mdss-dsi-bl-pmic-pwm-frequency", &tmp); - if (rc) { - pr_err("%s:%d, Error, panel pwm_period\n", - __func__, __LINE__); - return -EINVAL; - } - ctrl_pdata->pwm_period = tmp; - if (ctrl_pdata->pwm_pmi) { - ctrl_pdata->pwm_bl = of_pwm_get(np, NULL); - if (IS_ERR(ctrl_pdata->pwm_bl)) { - pr_err("%s: Error, pwm device\n", - __func__); - ctrl_pdata->pwm_bl = NULL; - return -EINVAL; - } - } else { - rc = of_property_read_u32(np, - "qcom,mdss-dsi-bl-pmic-bank-select", - &tmp); - if (rc) { - pr_err("%s:%d, Error, lpg channel\n", - __func__, __LINE__); - return -EINVAL; - } - ctrl_pdata->pwm_lpg_chan = tmp; - tmp = of_get_named_gpio(np, - "qcom,mdss-dsi-pwm-gpio", 0); - ctrl_pdata->pwm_pmic_gpio = tmp; - pr_debug("%s: Configured PWM bklt ctrl\n", - __func__); - } - } else if (!strcmp(data, "bl_ctrl_dcs")) { - ctrl_pdata->bklt_ctrl = BL_DCS_CMD; - data = of_get_property(np, - "qcom,mdss-dsi-bl-dcs-command-state", NULL); - if (data && !strcmp(data, "dsi_hs_mode")) - ctrl_pdata->bklt_dcs_op_mode = DSI_HS_MODE; - else - ctrl_pdata->bklt_dcs_op_mode = DSI_LP_MODE; - - pr_debug("%s: Configured DCS_CMD bklt ctrl\n", - __func__); - } - } - return 0; - } - - int mdss_dsi_panel_timing_switch(struct mdss_dsi_ctrl_pdata *ctrl, - struct mdss_panel_timing *timing) - { - struct dsi_panel_timing *pt; - struct mdss_panel_info *pinfo = &ctrl->panel_data.panel_info; - int i; - - if (!timing) - return -EINVAL; - - if (timing == ctrl->panel_data.current_timing) { - pr_warn("%s: panel timing \"%s\" already set\n", __func__, - timing->name); - return 0; /* nothing to do */ - } - - pr_debug("%s: ndx=%d switching to panel timing \"%s\"\n", __func__, - ctrl->ndx, timing->name); - - mdss_panel_info_from_timing(timing, pinfo); - - pt = container_of(timing, struct dsi_panel_timing, timing); - pinfo->mipi.t_clk_pre = pt->t_clk_pre; - pinfo->mipi.t_clk_post = pt->t_clk_post; - - for (i = 0; i < ARRAY_SIZE(pt->phy_timing); i++) - pinfo->mipi.dsi_phy_db.timing[i] = pt->phy_timing[i]; - - for (i = 0; i < ARRAY_SIZE(pt->phy_timing_8996); i++) - pinfo->mipi.dsi_phy_db.timing_8996[i] = pt->phy_timing_8996[i]; - - ctrl->on_cmds = pt->on_cmds; - ctrl->post_panel_on_cmds = pt->post_panel_on_cmds; - - ctrl->panel_data.current_timing = timing; - if (!timing->clk_rate) - ctrl->refresh_clk_rate = true; - mdss_dsi_clk_refresh(&ctrl->panel_data, ctrl->update_phy_timing); - - return 0; - } - - void mdss_dsi_unregister_bl_settings(struct mdss_dsi_ctrl_pdata *ctrl_pdata) - { - if (ctrl_pdata->bklt_ctrl == BL_WLED) - led_trigger_unregister_simple(bl_led_trigger); - } - - static int mdss_dsi_panel_timing_from_dt(struct device_node *np, - struct dsi_panel_timing *pt, - struct mdss_panel_data *panel_data) - { - u32 tmp; - u64 tmp64; - int rc, i, len; - const char *data; - struct mdss_dsi_ctrl_pdata *ctrl_pdata; - struct mdss_panel_info *pinfo; - bool phy_timings_present = false; - - pinfo = &panel_data->panel_info; - - ctrl_pdata = container_of(panel_data, struct mdss_dsi_ctrl_pdata, - panel_data); - - rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-width", &tmp); - if (rc) { - pr_err("%s:%d, panel width not specified\n", - __func__, __LINE__); - return -EINVAL; - } - pt->timing.xres = tmp; - - rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-height", &tmp); - if (rc) { - pr_err("%s:%d, panel height not specified\n", - __func__, __LINE__); - return -EINVAL; - } - pt->timing.yres = tmp; - - rc = of_property_read_u32(np, "qcom,mdss-dsi-h-front-porch", &tmp); - pt->timing.h_front_porch = (!rc ? tmp : 6); - rc = of_property_read_u32(np, "qcom,mdss-dsi-h-back-porch", &tmp); - pt->timing.h_back_porch = (!rc ? tmp : 6); - rc = of_property_read_u32(np, "qcom,mdss-dsi-h-pulse-width", &tmp); - pt->timing.h_pulse_width = (!rc ? tmp : 2); - rc = of_property_read_u32(np, "qcom,mdss-dsi-h-sync-skew", &tmp); - pt->timing.hsync_skew = (!rc ? tmp : 0); - rc = of_property_read_u32(np, "qcom,mdss-dsi-v-back-porch", &tmp); - pt->timing.v_back_porch = (!rc ? tmp : 6); - rc = of_property_read_u32(np, "qcom,mdss-dsi-v-front-porch", &tmp); - pt->timing.v_front_porch = (!rc ? tmp : 6); - rc = of_property_read_u32(np, "qcom,mdss-dsi-v-pulse-width", &tmp); - pt->timing.v_pulse_width = (!rc ? tmp : 2); - - rc = of_property_read_u32(np, "qcom,mdss-dsi-h-left-border", &tmp); - pt->timing.border_left = !rc ? tmp : 0; - rc = of_property_read_u32(np, "qcom,mdss-dsi-h-right-border", &tmp); - pt->timing.border_right = !rc ? tmp : 0; - - /* overriding left/right borders for split display cases */ - if (mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) { - if (panel_data->next) - pt->timing.border_right = 0; - else - pt->timing.border_left = 0; - } - - rc = of_property_read_u32(np, "qcom,mdss-dsi-v-top-border", &tmp); - pt->timing.border_top = !rc ? tmp : 0; - rc = of_property_read_u32(np, "qcom,mdss-dsi-v-bottom-border", &tmp); - pt->timing.border_bottom = !rc ? tmp : 0; - - rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-framerate", &tmp); - pt->timing.frame_rate = !rc ? tmp : DEFAULT_FRAME_RATE; - rc = of_property_read_u64(np, "qcom,mdss-dsi-panel-clockrate", &tmp64); - if (rc == -EOVERFLOW) { - tmp64 = 0; - rc = of_property_read_u32(np, - "qcom,mdss-dsi-panel-clockrate", (u32 *)&tmp64); - } - pt->timing.clk_rate = !rc ? tmp64 : 0; - - data = of_get_property(np, "qcom,mdss-dsi-panel-timings", &len); - if ((!data) || (len != 12)) { - pr_debug("%s:%d, Unable to read Phy timing settings", + +static int mdss_dsi_parse_fbc_params(struct device_node *np, + struct mdss_panel_timing *timing) +{ + int rc, fbc_enabled = 0; + u32 tmp; + struct fbc_panel_info *fbc = &timing->fbc; + + fbc_enabled = of_property_read_bool(np, "qcom,mdss-dsi-fbc-enable"); + if (fbc_enabled) { + pr_debug("%s:%d FBC panel enabled.\n", __func__, __LINE__); + fbc->enabled = 1; + rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-bpp", &tmp); + fbc->target_bpp = (!rc ? tmp : 24); + rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-packing", + &tmp); + fbc->comp_mode = (!rc ? tmp : 0); + fbc->qerr_enable = of_property_read_bool(np, + "qcom,mdss-dsi-fbc-quant-error"); + rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-bias", &tmp); + fbc->cd_bias = (!rc ? tmp : 0); + fbc->pat_enable = of_property_read_bool(np, + "qcom,mdss-dsi-fbc-pat-mode"); + fbc->vlc_enable = of_property_read_bool(np, + "qcom,mdss-dsi-fbc-vlc-mode"); + fbc->bflc_enable = of_property_read_bool(np, + "qcom,mdss-dsi-fbc-bflc-mode"); + rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-h-line-budget", + &tmp); + fbc->line_x_budget = (!rc ? tmp : 0); + rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-budget-ctrl", + &tmp); + fbc->block_x_budget = (!rc ? tmp : 0); + rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-block-budget", + &tmp); + fbc->block_budget = (!rc ? tmp : 0); + rc = of_property_read_u32(np, + "qcom,mdss-dsi-fbc-lossless-threshold", &tmp); + fbc->lossless_mode_thd = (!rc ? tmp : 0); + rc = of_property_read_u32(np, + "qcom,mdss-dsi-fbc-lossy-threshold", &tmp); + fbc->lossy_mode_thd = (!rc ? tmp : 0); + rc = of_property_read_u32(np, "qcom,mdss-dsi-fbc-rgb-threshold", + &tmp); + fbc->lossy_rgb_thd = (!rc ? tmp : 0); + rc = of_property_read_u32(np, + "qcom,mdss-dsi-fbc-lossy-mode-idx", &tmp); + fbc->lossy_mode_idx = (!rc ? tmp : 0); + rc = of_property_read_u32(np, + "qcom,mdss-dsi-fbc-slice-height", &tmp); + fbc->slice_height = (!rc ? tmp : 0); + fbc->pred_mode = of_property_read_bool(np, + "qcom,mdss-dsi-fbc-2d-pred-mode"); + fbc->enc_mode = of_property_read_bool(np, + "qcom,mdss-dsi-fbc-ver2-mode"); + rc = of_property_read_u32(np, + "qcom,mdss-dsi-fbc-max-pred-err", &tmp); + fbc->max_pred_err = (!rc ? tmp : 0); + + timing->compression_mode = COMPRESSION_FBC; + } else { + pr_debug("%s:%d Panel does not support FBC.\n", __func__, __LINE__); - } else { - for (i = 0; i < len; i++) - pt->phy_timing[i] = data[i]; - phy_timings_present = true; - } - - data = of_get_property(np, "qcom,mdss-dsi-panel-timings-phy-v2", &len); - if ((!data) || (len != 40)) { - pr_debug("%s:%d, Unable to read phy-v2 lane timing settings", + fbc->enabled = 0; + fbc->target_bpp = 24; + } + return 0; +} + +void mdss_dsi_panel_dsc_pps_send(struct mdss_dsi_ctrl_pdata *ctrl, + struct mdss_panel_info *pinfo) +{ + struct dsi_panel_cmds pcmds; + struct dsi_cmd_desc cmd; + + if (!pinfo || (pinfo->compression_mode != COMPRESSION_DSC)) + return; + + memset(&pcmds, 0, sizeof(pcmds)); + memset(&cmd, 0, sizeof(cmd)); + + cmd.dchdr.dlen = mdss_panel_dsc_prepare_pps_buf(&pinfo->dsc, + ctrl->pps_buf, 0); + cmd.dchdr.dtype = DTYPE_PPS; + cmd.dchdr.last = 1; + cmd.dchdr.wait = 10; + cmd.dchdr.vc = 0; + cmd.dchdr.ack = 0; + cmd.payload = ctrl->pps_buf; + + pcmds.cmd_cnt = 1; + pcmds.cmds = &cmd; + pcmds.link_state = DSI_LP_MODE; + + mdss_dsi_panel_cmds_send(ctrl, &pcmds, CMD_REQ_COMMIT); +} + +static int mdss_dsi_parse_hdr_settings(struct device_node *np, + struct mdss_panel_info *pinfo) +{ + int rc = 0; + struct mdss_panel_hdr_properties *hdr_prop; + + 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; + } + + hdr_prop = &pinfo->hdr_properties; + hdr_prop->hdr_enabled = of_property_read_bool(np, + "qcom,mdss-dsi-panel-hdr-enabled"); + + if (hdr_prop->hdr_enabled) { + rc = of_property_read_u32_array(np, + "qcom,mdss-dsi-panel-hdr-color-primaries", + hdr_prop->display_primaries, + DISPLAY_PRIMARIES_COUNT); + if (rc) { + pr_info("%s:%d, Unable to read color primaries,rc:%u", + __func__, __LINE__, + hdr_prop->hdr_enabled = false); + } + + rc = of_property_read_u32(np, + "qcom,mdss-dsi-panel-peak-brightness", + &(hdr_prop->peak_brightness)); + if (rc) { + pr_info("%s:%d, Unable to read hdr brightness, rc:%u", + __func__, __LINE__, rc); + hdr_prop->hdr_enabled = false; + } + + rc = of_property_read_u32(np, + "qcom,mdss-dsi-panel-blackness-level", + &(hdr_prop->blackness_level)); + if (rc) { + pr_info("%s:%d, Unable to read hdr brightness, rc:%u", + __func__, __LINE__, rc); + hdr_prop->hdr_enabled = false; + } + } + 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) +{ + u32 data; + int rc = 0; + struct dsc_desc *dsc = &timing->dsc; + + rc = of_property_read_u32(np, "qcom,mdss-dsc-version", &data); + if (rc) { + dsc->version = 0x11; + rc = 0; + } else { + dsc->version = data & 0xff; + /* only support DSC 1.1 rev */ + if (dsc->version != 0x11) { + pr_err("%s: DSC version:%d not supported\n", __func__, + dsc->version); + rc = -EINVAL; + goto end; + } + } + + rc = of_property_read_u32(np, "qcom,mdss-dsc-scr-version", &data); + if (rc) { + dsc->scr_rev = 0x0; + rc = 0; + } else { + dsc->scr_rev = data & 0xff; + /* only one scr rev supported */ + if (dsc->scr_rev > 0x1) { + pr_err("%s: DSC scr version:%d not supported\n", + __func__, dsc->scr_rev); + rc = -EINVAL; + goto end; + } + } + +end: + return rc; +} + +static int mdss_dsi_parse_dsc_params(struct device_node *np, + struct mdss_panel_timing *timing, bool is_split_display) +{ + u32 data, intf_width; + int rc = 0; + struct dsc_desc *dsc = &timing->dsc; + + if (!np) { + pr_err("%s: device node pointer is NULL\n", __func__); + return -EINVAL; + } + + rc = of_property_read_u32(np, "qcom,mdss-dsc-encoders", &data); + if (rc) { + if (!of_find_property(np, "qcom,mdss-dsc-encoders", NULL)) { + /* property is not defined, default to 1 */ + data = 1; + } else { + pr_err("%s: Error parsing qcom,mdss-dsc-encoders\n", + __func__); + goto end; + } + } + + timing->dsc_enc_total = data; + + if (is_split_display && (timing->dsc_enc_total > 1)) { + pr_err("%s: Error: for split displays, more than 1 dsc encoder per panel is not allowed.\n", + __func__); + goto end; + } + + rc = of_property_read_u32(np, "qcom,mdss-dsc-slice-height", &data); + if (rc) + goto end; + dsc->slice_height = data; + + rc = of_property_read_u32(np, "qcom,mdss-dsc-slice-width", &data); + if (rc) + goto end; + dsc->slice_width = data; + intf_width = timing->xres; + + if (intf_width % dsc->slice_width) { + pr_err("%s: Error: multiple of slice-width:%d should match panel-width:%d\n", + __func__, dsc->slice_width, intf_width); + goto end; + } + + data = intf_width / dsc->slice_width; + if (((timing->dsc_enc_total > 1) && ((data != 2) && (data != 4))) || + ((timing->dsc_enc_total == 1) && (data > 2))) { + pr_err("%s: Error: max 2 slice per encoder. slice-width:%d should match panel-width:%d dsc_enc_total:%d\n", + __func__, dsc->slice_width, + intf_width, timing->dsc_enc_total); + goto end; + } + + rc = of_property_read_u32(np, "qcom,mdss-dsc-slice-per-pkt", &data); + if (rc) + goto end; + dsc->slice_per_pkt = data; + + /* + * slice_per_pkt can be either 1 or all slices_per_intf + */ + if ((dsc->slice_per_pkt > 1) && (dsc->slice_per_pkt != + DIV_ROUND_UP(intf_width, dsc->slice_width))) { + pr_err("Error: slice_per_pkt can be either 1 or all slices_per_intf\n"); + pr_err("%s: slice_per_pkt=%d, slice_width=%d intf_width=%d\n", + __func__, + dsc->slice_per_pkt, dsc->slice_width, intf_width); + rc = -EINVAL; + goto end; + } + + pr_debug("%s: num_enc:%d :slice h=%d w=%d s_pkt=%d\n", __func__, + timing->dsc_enc_total, dsc->slice_height, + dsc->slice_width, dsc->slice_per_pkt); + + rc = of_property_read_u32(np, "qcom,mdss-dsc-bit-per-component", &data); + if (rc) + goto end; + dsc->bpc = data; + + rc = of_property_read_u32(np, "qcom,mdss-dsc-bit-per-pixel", &data); + if (rc) + goto end; + dsc->bpp = data; + + pr_debug("%s: bpc=%d bpp=%d\n", __func__, + dsc->bpc, dsc->bpp); + + dsc->block_pred_enable = of_property_read_bool(np, + "qcom,mdss-dsc-block-prediction-enable"); + + dsc->enable_422 = 0; + dsc->convert_rgb = 1; + dsc->vbr_enable = 0; + + dsc->config_by_manufacture_cmd = of_property_read_bool(np, + "qcom,mdss-dsc-config-by-manufacture-cmd"); + + mdss_panel_dsc_parameters_calc(&timing->dsc); + mdss_panel_dsc_pclk_param_calc(&timing->dsc, intf_width); + + timing->dsc.full_frame_slices = + DIV_ROUND_UP(intf_width, timing->dsc.slice_width); + + timing->compression_mode = COMPRESSION_DSC; + +end: + return rc; +} + +static struct device_node *mdss_dsi_panel_get_dsc_cfg_np( + struct device_node *np, struct mdss_panel_data *panel_data, + bool default_timing) +{ + struct device_node *dsc_cfg_np = NULL; + + + /* Read the dsc config node specified by command line */ + if (default_timing) { + dsc_cfg_np = of_get_child_by_name(np, + panel_data->dsc_cfg_np_name); + if (!dsc_cfg_np) + pr_warn_once("%s: cannot find dsc config node:%s\n", + __func__, panel_data->dsc_cfg_np_name); + } + + /* + * Fall back to default from DT as nothing is specified + * in command line. + */ + if (!dsc_cfg_np && of_find_property(np, "qcom,config-select", NULL)) { + dsc_cfg_np = of_parse_phandle(np, "qcom,config-select", 0); + if (!dsc_cfg_np) + pr_warn_once("%s:err parsing qcom,config-select\n", + __func__); + } + + return dsc_cfg_np; +} + +static int mdss_dsi_parse_topology_config(struct device_node *np, + struct dsi_panel_timing *pt, struct mdss_panel_data *panel_data, + bool default_timing) +{ + int rc = 0; + bool is_split_display = panel_data->panel_info.is_split_display; + const char *data; + struct mdss_panel_timing *timing = &pt->timing; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_panel_info *pinfo; + struct device_node *cfg_np = NULL; + + ctrl_pdata = container_of(panel_data, struct mdss_dsi_ctrl_pdata, + panel_data); + pinfo = &ctrl_pdata->panel_data.panel_info; + + cfg_np = mdss_dsi_panel_get_dsc_cfg_np(np, + &ctrl_pdata->panel_data, default_timing); + + if (cfg_np) { + if (!of_property_read_u32_array(cfg_np, "qcom,lm-split", + timing->lm_widths, 2)) { + if (mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data) + && (timing->lm_widths[1] != 0)) { + pr_err("%s: lm-split not allowed with split display\n", + __func__); + rc = -EINVAL; + goto end; + } + } + + if (!of_property_read_string(cfg_np, "qcom,split-mode", + &data) && !strcmp(data, "pingpong-split")) + pinfo->use_pingpong_split = true; + + if (((timing->lm_widths[0]) || (timing->lm_widths[1])) && + pinfo->use_pingpong_split) { + pr_err("%s: pingpong_split cannot be used when lm-split[%d,%d] is specified\n", + __func__, + timing->lm_widths[0], timing->lm_widths[1]); + return -EINVAL; + } + + pr_info("%s: cfg_node name %s lm_split:%dx%d pp_split:%s\n", + __func__, cfg_np->name, + timing->lm_widths[0], timing->lm_widths[1], + pinfo->use_pingpong_split ? "yes" : "no"); + } + + if (!pinfo->use_pingpong_split && + (timing->lm_widths[0] == 0) && (timing->lm_widths[1] == 0)) + timing->lm_widths[0] = pt->timing.xres; + + data = of_get_property(np, "qcom,compression-mode", NULL); + if (data) { + if (cfg_np && !strcmp(data, "dsc")) { + rc = mdss_dsi_parse_dsc_version(np, &pt->timing); + if (rc) + goto end; + + pinfo->send_pps_before_switch = + of_property_read_bool(np, + "qcom,mdss-dsi-send-pps-before-switch"); + + rc = mdss_dsi_parse_dsc_params(cfg_np, &pt->timing, + is_split_display); + } else if (!strcmp(data, "fbc")) { + rc = mdss_dsi_parse_fbc_params(np, &pt->timing); + } + } + +end: + of_node_put(cfg_np); + return rc; +} + +static void mdss_panel_parse_te_params(struct device_node *np, + struct mdss_panel_timing *timing) +{ + struct mdss_mdp_pp_tear_check *te = &timing->te; + u32 tmp; + int rc = 0; + /* + * TE default: dsi byte clock calculated base on 70 fps; + * around 14 ms to complete a kickoff cycle if te disabled; + * vclk_line base on 60 fps; write is faster than read; + * init == start == rdptr; + */ + te->tear_check_en = + !of_property_read_bool(np, "qcom,mdss-tear-check-disable"); + rc = of_property_read_u32 + (np, "qcom,mdss-tear-check-sync-cfg-height", &tmp); + te->sync_cfg_height = (!rc ? tmp : 0xfff0); + rc = of_property_read_u32 + (np, "qcom,mdss-tear-check-sync-init-val", &tmp); + te->vsync_init_val = (!rc ? tmp : timing->yres); + rc = of_property_read_u32 + (np, "qcom,mdss-tear-check-sync-threshold-start", &tmp); + te->sync_threshold_start = (!rc ? tmp : 4); + rc = of_property_read_u32 + (np, "qcom,mdss-tear-check-sync-threshold-continue", &tmp); + te->sync_threshold_continue = (!rc ? tmp : 4); + rc = of_property_read_u32(np, "qcom,mdss-tear-check-frame-rate", &tmp); + te->refx100 = (!rc ? tmp : 6000); + rc = of_property_read_u32 + (np, "qcom,mdss-tear-check-start-pos", &tmp); + te->start_pos = (!rc ? tmp : timing->yres); + rc = of_property_read_u32 + (np, "qcom,mdss-tear-check-rd-ptr-trigger-intr", &tmp); + te->rd_ptr_irq = (!rc ? tmp : timing->yres + 1); + te->wr_ptr_irq = 0; +} + + +static int mdss_dsi_parse_reset_seq(struct device_node *np, + u32 rst_seq[MDSS_DSI_RST_SEQ_LEN], u32 *rst_len, + const char *name) +{ + int num = 0, i; + int rc; + struct property *data; + u32 tmp[MDSS_DSI_RST_SEQ_LEN]; + *rst_len = 0; + data = of_find_property(np, name, &num); + num /= sizeof(u32); + if (!data || !num || num > MDSS_DSI_RST_SEQ_LEN || num % 2) { + pr_debug("%s:%d, error reading %s, length found = %d\n", + __func__, __LINE__, name, num); + } else { + rc = of_property_read_u32_array(np, name, tmp, num); + if (rc) + pr_debug("%s:%d, error reading %s, rc = %d\n", + __func__, __LINE__, name, rc); + else { + for (i = 0; i < num; ++i) + rst_seq[i] = tmp[i]; + *rst_len = num; + } + } + return 0; +} + +static bool mdss_dsi_cmp_panel_reg_v2(struct mdss_dsi_ctrl_pdata *ctrl) +{ + int i, j = 0; + int len = 0, *lenp; + int group = 0; + + lenp = ctrl->status_valid_params ?: ctrl->status_cmds_rlen; + + for (i = 0; i < ctrl->status_cmds.cmd_cnt; i++) + len += lenp[i]; + + for (j = 0; j < ctrl->groups; ++j) { + for (i = 0; i < len; ++i) { + pr_debug("[%i] return:0x%x status:0x%x\n", + i, ctrl->return_buf[i], + (unsigned int)ctrl->status_value[group + i]); + MDSS_XLOG(ctrl->ndx, ctrl->return_buf[i], + ctrl->status_value[group + i]); + if (ctrl->return_buf[i] != + ctrl->status_value[group + i]) + break; + } + + if (i == len) + return true; + group += len; + } + + return false; +} + +static int mdss_dsi_gen_read_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + if (!mdss_dsi_cmp_panel_reg_v2(ctrl_pdata)) { + pr_err("%s: Read back value from panel is incorrect\n", + __func__); + return -EINVAL; + } else { + return 1; + } +} + +static int mdss_dsi_nt35596_read_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + if (!mdss_dsi_cmp_panel_reg(ctrl_pdata->status_buf, + ctrl_pdata->status_value, 0)) { + ctrl_pdata->status_error_count = 0; + pr_err("%s: Read back value from panel is incorrect\n", + __func__); + return -EINVAL; + } else { + if (!mdss_dsi_cmp_panel_reg(ctrl_pdata->status_buf, + ctrl_pdata->status_value, 3)) { + ctrl_pdata->status_error_count = 0; + } else { + if (mdss_dsi_cmp_panel_reg(ctrl_pdata->status_buf, + ctrl_pdata->status_value, 4) || + mdss_dsi_cmp_panel_reg(ctrl_pdata->status_buf, + ctrl_pdata->status_value, 5)) + ctrl_pdata->status_error_count = 0; + else + ctrl_pdata->status_error_count++; + if (ctrl_pdata->status_error_count >= + ctrl_pdata->max_status_error_count) { + ctrl_pdata->status_error_count = 0; + pr_err("%s: Read value bad. Error_cnt = %i\n", + __func__, + ctrl_pdata->status_error_count); + return -EINVAL; + } + } + return 1; + } +} + +static void mdss_dsi_parse_roi_alignment(struct device_node *np, + struct dsi_panel_timing *pt) +{ + int len = 0; + u32 value[6]; + struct property *data; + struct mdss_panel_timing *timing = &pt->timing; + + data = of_find_property(np, "qcom,panel-roi-alignment", &len); + len /= sizeof(u32); + if (!data || (len != 6)) { + pr_debug("%s: Panel roi alignment not found", __func__); + } else { + int rc = of_property_read_u32_array(np, + "qcom,panel-roi-alignment", value, len); + if (rc) + pr_debug("%s: Error reading panel roi alignment values", + __func__); + else { + timing->roi_alignment.xstart_pix_align = value[0]; + timing->roi_alignment.ystart_pix_align = value[1]; + timing->roi_alignment.width_pix_align = value[2]; + timing->roi_alignment.height_pix_align = value[3]; + timing->roi_alignment.min_width = value[4]; + timing->roi_alignment.min_height = value[5]; + } + + pr_debug("%s: ROI alignment: [%d, %d, %d, %d, %d, %d]", + __func__, timing->roi_alignment.xstart_pix_align, + timing->roi_alignment.width_pix_align, + timing->roi_alignment.ystart_pix_align, + timing->roi_alignment.height_pix_align, + timing->roi_alignment.min_width, + timing->roi_alignment.min_height); + } +} + +static void mdss_dsi_parse_dms_config(struct device_node *np, + struct mdss_dsi_ctrl_pdata *ctrl) +{ + struct mdss_panel_info *pinfo = &ctrl->panel_data.panel_info; + const char *data; + bool dms_enabled; + + dms_enabled = of_property_read_bool(np, + "qcom,dynamic-mode-switch-enabled"); + + if (!dms_enabled) { + pinfo->mipi.dms_mode = DYNAMIC_MODE_SWITCH_DISABLED; + goto exit; + } + + /* default mode is suspend_resume */ + pinfo->mipi.dms_mode = DYNAMIC_MODE_SWITCH_SUSPEND_RESUME; + data = of_get_property(np, "qcom,dynamic-mode-switch-type", NULL); + if (data && !strcmp(data, "dynamic-resolution-switch-immediate")) { + if (!list_empty(&ctrl->panel_data.timings_list)) + pinfo->mipi.dms_mode = + DYNAMIC_MODE_RESOLUTION_SWITCH_IMMEDIATE; + else + pinfo->mipi.dms_mode = + DYNAMIC_MODE_SWITCH_DISABLED; + goto exit; + } + + if (data && !strcmp(data, "dynamic-switch-immediate")) + pinfo->mipi.dms_mode = DYNAMIC_MODE_SWITCH_IMMEDIATE; + else + pr_debug("%s: default dms suspend/resume\n", __func__); + + mdss_dsi_parse_dcs_cmds(np, &ctrl->video2cmd, + "qcom,video-to-cmd-mode-switch-commands", + "qcom,mode-switch-commands-state"); + + mdss_dsi_parse_dcs_cmds(np, &ctrl->cmd2video, + "qcom,cmd-to-video-mode-switch-commands", + "qcom,mode-switch-commands-state"); + + mdss_dsi_parse_dcs_cmds(np, &ctrl->post_dms_on_cmds, + "qcom,mdss-dsi-post-mode-switch-on-command", + "qcom,mdss-dsi-post-mode-switch-on-command-state"); + + if (pinfo->mipi.dms_mode == DYNAMIC_MODE_SWITCH_IMMEDIATE && + !ctrl->post_dms_on_cmds.cmd_cnt) { + pr_warn("%s: No post dms on cmd specified\n", __func__); + pinfo->mipi.dms_mode = DYNAMIC_MODE_SWITCH_DISABLED; + } + + if (!ctrl->video2cmd.cmd_cnt || !ctrl->cmd2video.cmd_cnt) { + pr_warn("%s: No commands specified for dynamic switch\n", + __func__); + pinfo->mipi.dms_mode = DYNAMIC_MODE_SWITCH_DISABLED; + } +exit: + pr_info("%s: dynamic switch feature enabled: %d\n", __func__, + pinfo->mipi.dms_mode); + return; +} + +/* the length of all the valid values to be checked should not be great + * than the length of returned data from read command. + */ +static bool +mdss_dsi_parse_esd_check_valid_params(struct mdss_dsi_ctrl_pdata *ctrl) +{ + int i; + + for (i = 0; i < ctrl->status_cmds.cmd_cnt; ++i) { + if (ctrl->status_valid_params[i] > ctrl->status_cmds_rlen[i]) { + pr_debug("%s: ignore valid params!\n", __func__); + return false; + } + } + + return true; +} + +static bool mdss_dsi_parse_esd_status_len(struct device_node *np, + char *prop_key, u32 **target, u32 cmd_cnt) +{ + int tmp; + + if (!of_find_property(np, prop_key, &tmp)) + return false; + + tmp /= sizeof(u32); + if (tmp != cmd_cnt) { + pr_err("%s: request property number(%d) not match command count(%d)\n", + __func__, tmp, cmd_cnt); + return false; + } + + *target = kcalloc(tmp, sizeof(u32), GFP_KERNEL); + if (IS_ERR_OR_NULL(*target)) { + pr_err("%s: Error allocating memory for property\n", + __func__); + return false; + } + + if (of_property_read_u32_array(np, prop_key, *target, tmp)) { + pr_err("%s: cannot get values from dts\n", __func__); + kfree(*target); + *target = NULL; + return false; + } + + return true; +} + +static void mdss_dsi_parse_esd_params(struct device_node *np, + struct mdss_dsi_ctrl_pdata *ctrl) +{ + u32 tmp; + u32 i, status_len, *lenp; + int rc; + struct property *data; + const char *string; + struct mdss_panel_info *pinfo = &ctrl->panel_data.panel_info; + + pinfo->esd_check_enabled = of_property_read_bool(np, + "qcom,esd-check-enabled"); + + if (!pinfo->esd_check_enabled) + return; + + ctrl->status_mode = ESD_MAX; + rc = of_property_read_string(np, + "qcom,mdss-dsi-panel-status-check-mode", &string); + if (!rc) { + if (!strcmp(string, "bta_check")) { + ctrl->status_mode = ESD_BTA; + } else if (!strcmp(string, "reg_read")) { + ctrl->status_mode = ESD_REG; + ctrl->check_read_status = + mdss_dsi_gen_read_status; + } else if (!strcmp(string, "reg_read_nt35596")) { + ctrl->status_mode = ESD_REG_NT35596; + ctrl->status_error_count = 0; + ctrl->check_read_status = + mdss_dsi_nt35596_read_status; + } else if (!strcmp(string, "te_signal_check")) { + if (pinfo->mipi.mode == DSI_CMD_MODE) { + ctrl->status_mode = ESD_TE; + } else { + pr_err("TE-ESD not valid for video mode\n"); + goto error; + } + } else { + pr_err("No valid panel-status-check-mode string\n"); + goto error; + } + } + + if ((ctrl->status_mode == ESD_BTA) || (ctrl->status_mode == ESD_TE) || + (ctrl->status_mode == ESD_MAX)) + return; + + mdss_dsi_parse_dcs_cmds(np, &ctrl->status_cmds, + "qcom,mdss-dsi-panel-status-command", + "qcom,mdss-dsi-panel-status-command-state"); + + rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-max-error-count", + &tmp); + ctrl->max_status_error_count = (!rc ? tmp : 0); + + if (!mdss_dsi_parse_esd_status_len(np, + "qcom,mdss-dsi-panel-status-read-length", + &ctrl->status_cmds_rlen, ctrl->status_cmds.cmd_cnt)) { + pinfo->esd_check_enabled = false; + return; + } + + if (mdss_dsi_parse_esd_status_len(np, + "qcom,mdss-dsi-panel-status-valid-params", + &ctrl->status_valid_params, ctrl->status_cmds.cmd_cnt)) { + if (!mdss_dsi_parse_esd_check_valid_params(ctrl)) + goto error1; + } + + status_len = 0; + lenp = ctrl->status_valid_params ?: ctrl->status_cmds_rlen; + for (i = 0; i < ctrl->status_cmds.cmd_cnt; ++i) + status_len += lenp[i]; + + data = of_find_property(np, "qcom,mdss-dsi-panel-status-value", &tmp); + tmp /= sizeof(u32); + if (!IS_ERR_OR_NULL(data) && tmp != 0 && (tmp % status_len) == 0) { + ctrl->groups = tmp / status_len; + } else { + pr_err("%s: Error parse panel-status-value\n", __func__); + goto error1; + } + + ctrl->status_value = kzalloc(sizeof(u32) * status_len * ctrl->groups, + GFP_KERNEL); + if (!ctrl->status_value) + goto error1; + + ctrl->return_buf = kcalloc(status_len * ctrl->groups, + sizeof(unsigned char), GFP_KERNEL); + if (!ctrl->return_buf) + goto error2; + + rc = of_property_read_u32_array(np, + "qcom,mdss-dsi-panel-status-value", + ctrl->status_value, ctrl->groups * status_len); + if (rc) { + pr_debug("%s: Error reading panel status values\n", + __func__); + memset(ctrl->status_value, 0, ctrl->groups * status_len); + } + + return; + +error2: + kfree(ctrl->status_value); +error1: + kfree(ctrl->status_valid_params); + kfree(ctrl->status_cmds_rlen); +error: + pinfo->esd_check_enabled = false; +} + +static void mdss_dsi_parse_partial_update_caps(struct device_node *np, + struct mdss_dsi_ctrl_pdata *ctrl) +{ + struct mdss_panel_info *pinfo; + const char *data; + + pinfo = &ctrl->panel_data.panel_info; + + data = of_get_property(np, "qcom,partial-update-enabled", NULL); + if (data && !strcmp(data, "single_roi")) + pinfo->partial_update_supported = + PU_SINGLE_ROI; + else if (data && !strcmp(data, "dual_roi")) + pinfo->partial_update_supported = + PU_DUAL_ROI; + else if (data && !strcmp(data, "none")) + pinfo->partial_update_supported = + PU_NOT_SUPPORTED; + else + pinfo->partial_update_supported = + PU_NOT_SUPPORTED; + + if (pinfo->mipi.mode == DSI_CMD_MODE) { + pinfo->partial_update_enabled = pinfo->partial_update_supported; + pr_info("%s: partial_update_enabled=%d\n", __func__, + pinfo->partial_update_enabled); + ctrl->set_col_page_addr = mdss_dsi_set_col_page_addr; + if (pinfo->partial_update_enabled) { + pinfo->partial_update_roi_merge = + of_property_read_bool(np, + "qcom,partial-update-roi-merge"); + } + } +} + +static int mdss_dsi_parse_panel_features(struct device_node *np, + struct mdss_dsi_ctrl_pdata *ctrl) +{ + struct mdss_panel_info *pinfo; + + if (!np || !ctrl) { + pr_err("%s: Invalid arguments\n", __func__); + return -ENODEV; + } + + pinfo = &ctrl->panel_data.panel_info; + + mdss_dsi_parse_partial_update_caps(np, ctrl); + + pinfo->dcs_cmd_by_left = of_property_read_bool(np, + "qcom,dcs-cmd-by-left"); + + pinfo->ulps_feature_enabled = of_property_read_bool(np, + "qcom,ulps-enabled"); + pr_info("%s: ulps feature %s\n", __func__, + (pinfo->ulps_feature_enabled ? "enabled" : "disabled")); + + pinfo->ulps_suspend_enabled = of_property_read_bool(np, + "qcom,suspend-ulps-enabled"); + pr_info("%s: ulps during suspend feature %s", __func__, + (pinfo->ulps_suspend_enabled ? "enabled" : "disabled")); + + mdss_dsi_parse_dms_config(np, ctrl); + + pinfo->panel_ack_disabled = pinfo->sim_panel_mode ? + 1 : of_property_read_bool(np, "qcom,panel-ack-disabled"); + + pinfo->allow_phy_power_off = of_property_read_bool(np, + "qcom,panel-allow-phy-poweroff"); + + mdss_dsi_parse_esd_params(np, ctrl); + + if (pinfo->panel_ack_disabled && pinfo->esd_check_enabled) { + pr_warn("ESD should not be enabled if panel ACK is disabled\n"); + pinfo->esd_check_enabled = false; + } + + if (ctrl->disp_en_gpio <= 0) { + ctrl->disp_en_gpio = of_get_named_gpio( + np, + "qcom,5v-boost-gpio", 0); + + if (!gpio_is_valid(ctrl->disp_en_gpio)) + pr_debug("%s:%d, Disp_en gpio not specified\n", + __func__, __LINE__); + } + + mdss_dsi_parse_dcs_cmds(np, &ctrl->lp_on_cmds, + "qcom,mdss-dsi-lp-mode-on", NULL); + + mdss_dsi_parse_dcs_cmds(np, &ctrl->lp_off_cmds, + "qcom,mdss-dsi-lp-mode-off", NULL); + + return 0; +} + +static void mdss_dsi_parse_panel_horizintal_line_idle(struct device_node *np, + struct mdss_dsi_ctrl_pdata *ctrl) +{ + const u32 *src; + int i, len, cnt; + struct panel_horizontal_idle *kp; + + if (!np || !ctrl) { + pr_err("%s: Invalid arguments\n", __func__); + return; + } + + src = of_get_property(np, "qcom,mdss-dsi-hor-line-idle", &len); + if (!src || len == 0) + return; + + cnt = len % 3; /* 3 fields per entry */ + if (cnt) { + pr_err("%s: invalid horizontal idle len=%d\n", __func__, len); + return; + } + + cnt = len / sizeof(u32); + + kp = kzalloc(sizeof(*kp) * (cnt / 3), GFP_KERNEL); + if (kp == NULL) { + pr_err("%s: No memory\n", __func__); + return; + } + + ctrl->line_idle = kp; + for (i = 0; i < cnt; i += 3) { + kp->min = be32_to_cpu(src[i]); + kp->max = be32_to_cpu(src[i+1]); + kp->idle = be32_to_cpu(src[i+2]); + kp++; + ctrl->horizontal_idle_cnt++; + } + + /* + * idle is enabled for this controller, this will be used to + * enable/disable burst mode since both features are mutually + * exclusive. + */ + ctrl->idle_enabled = true; + + pr_debug("%s: horizontal_idle_cnt=%d\n", __func__, + ctrl->horizontal_idle_cnt); +} + +static int mdss_dsi_set_refresh_rate_range(struct device_node *pan_node, + struct mdss_panel_info *pinfo) +{ + int rc = 0; + rc = of_property_read_u32(pan_node, + "qcom,mdss-dsi-min-refresh-rate", + &pinfo->min_fps); + if (rc) { + pr_warn("%s:%d, Unable to read min refresh rate\n", __func__, __LINE__); - } else { - for (i = 0; i < len; i++) - pt->phy_timing_8996[i] = data[i]; - phy_timings_present = true; - } - if (!phy_timings_present) { - pr_err("%s: phy timing settings not present\n", __func__); - return -EINVAL; - } - - rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-pre", &tmp); - pt->t_clk_pre = (!rc ? tmp : 0x24); - rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-post", &tmp); - pt->t_clk_post = (!rc ? tmp : 0x03); - - if (np->name) { - pt->timing.name = kstrdup(np->name, GFP_KERNEL); - pr_info("%s: found new timing \"%s\" (%pK)\n", __func__, - np->name, &pt->timing); - } - - return 0; - } - - static int mdss_dsi_panel_config_res_properties(struct device_node *np, - struct dsi_panel_timing *pt, - struct mdss_panel_data *panel_data, - bool default_timing) - { - int rc = 0; - - mdss_dsi_parse_roi_alignment(np, pt); - - mdss_dsi_parse_dcs_cmds(np, &pt->on_cmds, - "qcom,mdss-dsi-on-command", - "qcom,mdss-dsi-on-command-state"); - - mdss_dsi_parse_dcs_cmds(np, &pt->post_panel_on_cmds, - "qcom,mdss-dsi-post-panel-on-command", NULL); - - mdss_dsi_parse_dcs_cmds(np, &pt->switch_cmds, - "qcom,mdss-dsi-timing-switch-command", - "qcom,mdss-dsi-timing-switch-command-state"); - - rc = mdss_dsi_parse_topology_config(np, pt, panel_data, default_timing); - if (rc) { - pr_err("%s: parsing compression params failed. rc:%d\n", - __func__, rc); - return rc; - } - - mdss_panel_parse_te_params(np, &pt->timing); - return rc; - } - - static int mdss_panel_parse_display_timings(struct device_node *np, - struct mdss_panel_data *panel_data) - { - struct mdss_dsi_ctrl_pdata *ctrl; - struct dsi_panel_timing *modedb; - struct device_node *timings_np; - struct device_node *entry; - int num_timings, rc; - int i = 0, active_ndx = 0; - bool default_timing = false; - - ctrl = container_of(panel_data, struct mdss_dsi_ctrl_pdata, panel_data); - - INIT_LIST_HEAD(&panel_data->timings_list); - - timings_np = of_get_child_by_name(np, "qcom,mdss-dsi-display-timings"); - if (!timings_np) { - struct dsi_panel_timing pt; - memset(&pt, 0, sizeof(struct dsi_panel_timing)); - - /* - * display timings node is not available, fallback to reading - * timings directly from root node instead - */ - pr_debug("reading display-timings from panel node\n"); - rc = mdss_dsi_panel_timing_from_dt(np, &pt, panel_data); - if (!rc) { - mdss_dsi_panel_config_res_properties(np, &pt, - panel_data, true); - rc = mdss_dsi_panel_timing_switch(ctrl, &pt.timing); - } - return rc; - } - - num_timings = of_get_child_count(timings_np); - if (num_timings == 0) { - pr_err("no timings found within display-timings\n"); - rc = -EINVAL; - goto exit; - } - - modedb = kcalloc(num_timings, sizeof(*modedb), GFP_KERNEL); - if (!modedb) { - rc = -ENOMEM; - goto exit; - } - - for_each_child_of_node(timings_np, entry) { - rc = mdss_dsi_panel_timing_from_dt(entry, (modedb + i), - panel_data); - if (rc) { - kfree(modedb); - goto exit; - } - - default_timing = of_property_read_bool(entry, - "qcom,mdss-dsi-timing-default"); - if (default_timing) - active_ndx = i; - - mdss_dsi_panel_config_res_properties(entry, (modedb + i), - panel_data, default_timing); - - list_add(&modedb[i].timing.list, - &panel_data->timings_list); - i++; - } - - /* Configure default timing settings */ - rc = mdss_dsi_panel_timing_switch(ctrl, &modedb[active_ndx].timing); - if (rc) - pr_err("unable to configure default timing settings\n"); - - exit: - of_node_put(timings_np); - - return rc; - } - - static int mdss_panel_parse_dt(struct device_node *np, - struct mdss_dsi_ctrl_pdata *ctrl_pdata) - { - u32 tmp; - int rc, len = 0; - const char *data; - static const char *pdest; - const char *bridge_chip_name; - struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info); - - if (mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) - pinfo->is_split_display = true; - - rc = of_property_read_u32(np, - "qcom,mdss-pan-physical-width-dimension", &tmp); - pinfo->physical_width = (!rc ? tmp : 0); - rc = of_property_read_u32(np, - "qcom,mdss-pan-physical-height-dimension", &tmp); - pinfo->physical_height = (!rc ? tmp : 0); - - rc = of_property_read_u32(np, "qcom,mdss-dsi-bpp", &tmp); - if (rc) { - pr_err("%s:%d, bpp not specified\n", __func__, __LINE__); - return -EINVAL; - } - pinfo->bpp = (!rc ? tmp : 24); - pinfo->mipi.mode = DSI_VIDEO_MODE; - data = of_get_property(np, "qcom,mdss-dsi-panel-type", NULL); - if (data && !strncmp(data, "dsi_cmd_mode", 12)) - pinfo->mipi.mode = DSI_CMD_MODE; - pinfo->mipi.boot_mode = pinfo->mipi.mode; - tmp = 0; - data = of_get_property(np, "qcom,mdss-dsi-pixel-packing", NULL); - if (data && !strcmp(data, "loose")) - pinfo->mipi.pixel_packing = 1; - else - pinfo->mipi.pixel_packing = 0; - rc = mdss_panel_get_dst_fmt(pinfo->bpp, - pinfo->mipi.mode, pinfo->mipi.pixel_packing, - &(pinfo->mipi.dst_format)); - if (rc) { - pr_debug("%s: problem determining dst format. Set Default\n", - __func__); - pinfo->mipi.dst_format = - DSI_VIDEO_DST_FORMAT_RGB888; - } - pdest = of_get_property(np, - "qcom,mdss-dsi-panel-destination", NULL); - - rc = of_property_read_u32(np, - "qcom,mdss-dsi-underflow-color", &tmp); - pinfo->lcdc.underflow_clr = (!rc ? tmp : 0xff); - rc = of_property_read_u32(np, - "qcom,mdss-dsi-border-color", &tmp); - pinfo->lcdc.border_clr = (!rc ? tmp : 0); - data = of_get_property(np, "qcom,mdss-dsi-panel-orientation", NULL); - if (data) { - pr_debug("panel orientation is %s\n", data); - if (!strcmp(data, "180")) - pinfo->panel_orientation = MDP_ROT_180; - else if (!strcmp(data, "hflip")) - pinfo->panel_orientation = MDP_FLIP_LR; - else if (!strcmp(data, "vflip")) - pinfo->panel_orientation = MDP_FLIP_UD; - } - - rc = of_property_read_u32(np, "qcom,mdss-brightness-max-level", &tmp); - pinfo->brightness_max = (!rc ? tmp : MDSS_MAX_BL_BRIGHTNESS); - rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-min-level", &tmp); - pinfo->bl_min = (!rc ? tmp : 0); - rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-max-level", &tmp); - pinfo->bl_max = (!rc ? tmp : 255); - ctrl_pdata->bklt_max = pinfo->bl_max; - - rc = of_property_read_u32(np, "qcom,mdss-dsi-interleave-mode", &tmp); - pinfo->mipi.interleave_mode = (!rc ? tmp : 0); - - pinfo->mipi.vsync_enable = of_property_read_bool(np, - "qcom,mdss-dsi-te-check-enable"); - - if (pinfo->sim_panel_mode == SIM_SW_TE_MODE) - pinfo->mipi.hw_vsync_mode = false; - else - pinfo->mipi.hw_vsync_mode = of_property_read_bool(np, - "qcom,mdss-dsi-te-using-te-pin"); - - rc = of_property_read_u32(np, - "qcom,mdss-dsi-h-sync-pulse", &tmp); - pinfo->mipi.pulse_mode_hsa_he = (!rc ? tmp : false); - - pinfo->mipi.hfp_power_stop = of_property_read_bool(np, - "qcom,mdss-dsi-hfp-power-mode"); - pinfo->mipi.hsa_power_stop = of_property_read_bool(np, - "qcom,mdss-dsi-hsa-power-mode"); - pinfo->mipi.hbp_power_stop = of_property_read_bool(np, - "qcom,mdss-dsi-hbp-power-mode"); - pinfo->mipi.last_line_interleave_en = of_property_read_bool(np, - "qcom,mdss-dsi-last-line-interleave"); - pinfo->mipi.bllp_power_stop = of_property_read_bool(np, - "qcom,mdss-dsi-bllp-power-mode"); - pinfo->mipi.eof_bllp_power_stop = of_property_read_bool( - np, "qcom,mdss-dsi-bllp-eof-power-mode"); - pinfo->mipi.traffic_mode = DSI_NON_BURST_SYNCH_PULSE; - data = of_get_property(np, "qcom,mdss-dsi-traffic-mode", NULL); - if (data) { - if (!strcmp(data, "non_burst_sync_event")) - pinfo->mipi.traffic_mode = DSI_NON_BURST_SYNCH_EVENT; - else if (!strcmp(data, "burst_mode")) - pinfo->mipi.traffic_mode = DSI_BURST_MODE; - } - rc = of_property_read_u32(np, - "qcom,mdss-dsi-te-dcs-command", &tmp); - pinfo->mipi.insert_dcs_cmd = - (!rc ? tmp : 1); - rc = of_property_read_u32(np, - "qcom,mdss-dsi-wr-mem-continue", &tmp); - pinfo->mipi.wr_mem_continue = - (!rc ? tmp : 0x3c); - rc = of_property_read_u32(np, - "qcom,mdss-dsi-wr-mem-start", &tmp); - pinfo->mipi.wr_mem_start = - (!rc ? tmp : 0x2c); - rc = of_property_read_u32(np, - "qcom,mdss-dsi-te-pin-select", &tmp); - pinfo->mipi.te_sel = - (!rc ? tmp : 1); - rc = of_property_read_u32(np, "qcom,mdss-dsi-virtual-channel-id", &tmp); - pinfo->mipi.vc = (!rc ? tmp : 0); - pinfo->mipi.rgb_swap = DSI_RGB_SWAP_RGB; - data = of_get_property(np, "qcom,mdss-dsi-color-order", NULL); - if (data) { - if (!strcmp(data, "rgb_swap_rbg")) - pinfo->mipi.rgb_swap = DSI_RGB_SWAP_RBG; - else if (!strcmp(data, "rgb_swap_bgr")) - pinfo->mipi.rgb_swap = DSI_RGB_SWAP_BGR; - else if (!strcmp(data, "rgb_swap_brg")) - pinfo->mipi.rgb_swap = DSI_RGB_SWAP_BRG; - else if (!strcmp(data, "rgb_swap_grb")) - pinfo->mipi.rgb_swap = DSI_RGB_SWAP_GRB; - else if (!strcmp(data, "rgb_swap_gbr")) - pinfo->mipi.rgb_swap = DSI_RGB_SWAP_GBR; - } - pinfo->mipi.data_lane0 = of_property_read_bool(np, - "qcom,mdss-dsi-lane-0-state"); - pinfo->mipi.data_lane1 = of_property_read_bool(np, - "qcom,mdss-dsi-lane-1-state"); - pinfo->mipi.data_lane2 = of_property_read_bool(np, - "qcom,mdss-dsi-lane-2-state"); - 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; - - pinfo->mipi.rx_eot_ignore = of_property_read_bool(np, - "qcom,mdss-dsi-rx-eot-ignore"); - pinfo->mipi.tx_eot_append = of_property_read_bool(np, - "qcom,mdss-dsi-tx-eot-append"); - - rc = of_property_read_u32(np, "qcom,mdss-dsi-stream", &tmp); - pinfo->mipi.stream = (!rc ? tmp : 0); - - data = of_get_property(np, "qcom,mdss-dsi-mode-sel-gpio-state", NULL); - if (data) { - if (!strcmp(data, "single_port")) - pinfo->mode_sel_state = MODE_SEL_SINGLE_PORT; - else if (!strcmp(data, "dual_port")) - pinfo->mode_sel_state = MODE_SEL_DUAL_PORT; - else if (!strcmp(data, "high")) - pinfo->mode_sel_state = MODE_GPIO_HIGH; - else if (!strcmp(data, "low")) - pinfo->mode_sel_state = MODE_GPIO_LOW; - } else { - /* Set default mode as SPLIT mode */ - pinfo->mode_sel_state = MODE_SEL_DUAL_PORT; - } - - rc = of_property_read_u32(np, "qcom,mdss-mdp-transfer-time-us", &tmp); - pinfo->mdp_transfer_time_us = (!rc ? tmp : DEFAULT_MDP_TRANSFER_TIME); - - mdss_dsi_parse_mdp_kickoff_threshold(np, pinfo); - - pinfo->mipi.lp11_init = of_property_read_bool(np, - "qcom,mdss-dsi-lp11-init"); - rc = of_property_read_u32(np, "qcom,mdss-dsi-init-delay-us", &tmp); - pinfo->mipi.init_delay = (!rc ? tmp : 0); - - rc = of_property_read_u32(np, "qcom,mdss-dsi-post-init-delay", &tmp); - pinfo->mipi.post_init_delay = (!rc ? tmp : 0); - - mdss_dsi_parse_trigger(np, &(pinfo->mipi.mdp_trigger), - "qcom,mdss-dsi-mdp-trigger"); - - mdss_dsi_parse_trigger(np, &(pinfo->mipi.dma_trigger), - "qcom,mdss-dsi-dma-trigger"); - - mdss_dsi_parse_reset_seq(np, pinfo->rst_seq, &(pinfo->rst_seq_len), - "qcom,mdss-dsi-reset-sequence"); - - mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->off_cmds, - "qcom,mdss-dsi-off-command", "qcom,mdss-dsi-off-command-state"); - - rc = of_property_read_u32(np, "qcom,adjust-timer-wakeup-ms", &tmp); - pinfo->adjust_timer_delay_ms = (!rc ? tmp : 0); - - pinfo->mipi.force_clk_lane_hs = of_property_read_bool(np, - "qcom,mdss-dsi-force-clock-lane-hs"); - - rc = mdss_dsi_parse_panel_features(np, ctrl_pdata); - if (rc) { - pr_err("%s: failed to parse panel features\n", __func__); - goto error; - } - - mdss_dsi_parse_panel_horizintal_line_idle(np, ctrl_pdata); - - mdss_dsi_parse_dfps_config(np, ctrl_pdata); - - mdss_dsi_set_refresh_rate_range(np, pinfo); - - pinfo->is_dba_panel = of_property_read_bool(np, - "qcom,dba-panel"); + + /* + * If min refresh rate is not specified, set it to the + * default panel refresh rate. + */ + pinfo->min_fps = pinfo->mipi.frame_rate; + rc = 0; + } + + rc = of_property_read_u32(pan_node, + "qcom,mdss-dsi-max-refresh-rate", + &pinfo->max_fps); + if (rc) { + pr_warn("%s:%d, Unable to read max refresh rate\n", + __func__, __LINE__); + + /* + * Since max refresh rate was not specified when dynamic + * fps is enabled, using the default panel refresh rate + * as max refresh rate supported. + */ + pinfo->max_fps = pinfo->mipi.frame_rate; + rc = 0; + } + + pr_info("dyn_fps: min = %d, max = %d\n", + pinfo->min_fps, pinfo->max_fps); + return rc; +} + +static void mdss_dsi_parse_dfps_config(struct device_node *pan_node, + struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + const char *data; + bool dynamic_fps, dynamic_bitclk; + struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info); + int rc = 0; + + dynamic_fps = of_property_read_bool(pan_node, + "qcom,mdss-dsi-pan-enable-dynamic-fps"); + + if (!dynamic_fps) + goto dynamic_bitclk; + + pinfo->dynamic_fps = true; + data = of_get_property(pan_node, "qcom,mdss-dsi-pan-fps-update", NULL); + if (data) { + if (!strcmp(data, "dfps_suspend_resume_mode")) { + pinfo->dfps_update = DFPS_SUSPEND_RESUME_MODE; + pr_debug("dfps mode: suspend/resume\n"); + } else if (!strcmp(data, "dfps_immediate_clk_mode")) { + pinfo->dfps_update = DFPS_IMMEDIATE_CLK_UPDATE_MODE; + pr_debug("dfps mode: Immediate clk\n"); + } else if (!strcmp(data, "dfps_immediate_porch_mode_hfp")) { + pinfo->dfps_update = + DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP; + pr_debug("dfps mode: Immediate porch HFP\n"); + } else if (!strcmp(data, "dfps_immediate_porch_mode_vfp")) { + pinfo->dfps_update = + DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP; + pr_debug("dfps mode: Immediate porch VFP\n"); + } else { + pinfo->dfps_update = DFPS_SUSPEND_RESUME_MODE; + pr_debug("default dfps mode: suspend/resume\n"); + } + } else { + pinfo->dynamic_fps = false; + pr_debug("dfps update mode not configured: disable\n"); + } + pinfo->new_fps = pinfo->mipi.frame_rate; + pinfo->current_fps = pinfo->mipi.frame_rate; + +dynamic_bitclk: + dynamic_bitclk = of_property_read_bool(pan_node, + "qcom,mdss-dsi-pan-enable-dynamic-bitclk"); + if (!dynamic_bitclk) + return; + + of_find_property(pan_node, "qcom,mdss-dsi-dynamic-bitclk_freq", + &pinfo->supp_bitclk_len); + pinfo->supp_bitclk_len = pinfo->supp_bitclk_len/sizeof(u32); + if (pinfo->supp_bitclk_len < 1) + return; + + pinfo->supp_bitclks = kzalloc((sizeof(u32) * pinfo->supp_bitclk_len), + GFP_KERNEL); + if (!pinfo->supp_bitclks) + return; + + rc = of_property_read_u32_array(pan_node, + "qcom,mdss-dsi-dynamic-bitclk_freq", pinfo->supp_bitclks, + pinfo->supp_bitclk_len); + if (rc) { + pr_err("Error from dynamic bitclk freq u64 array read\n"); + return; + } + pinfo->dynamic_bitclk = true; + return; +} + +int mdss_panel_parse_bl_settings(struct device_node *np, + struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + const char *data; + int rc = 0; + u32 tmp; + + ctrl_pdata->bklt_ctrl = UNKNOWN_CTRL; + data = of_get_property(np, "qcom,mdss-dsi-bl-pmic-control-type", NULL); + if (data) { + if (!strcmp(data, "bl_ctrl_wled")) { + led_trigger_register_simple("bkl-trigger", + &bl_led_trigger); + pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", + __func__); + ctrl_pdata->bklt_ctrl = BL_WLED; + } else if (!strcmp(data, "bl_ctrl_pwm")) { + ctrl_pdata->bklt_ctrl = BL_PWM; + ctrl_pdata->pwm_pmi = of_property_read_bool(np, + "qcom,mdss-dsi-bl-pwm-pmi"); + rc = of_property_read_u32(np, + "qcom,mdss-dsi-bl-pmic-pwm-frequency", &tmp); + if (rc) { + pr_err("%s:%d, Error, panel pwm_period\n", + __func__, __LINE__); + return -EINVAL; + } + ctrl_pdata->pwm_period = tmp; + if (ctrl_pdata->pwm_pmi) { + ctrl_pdata->pwm_bl = of_pwm_get(np, NULL); + if (IS_ERR(ctrl_pdata->pwm_bl)) { + pr_err("%s: Error, pwm device\n", + __func__); + ctrl_pdata->pwm_bl = NULL; + return -EINVAL; + } + } else { + rc = of_property_read_u32(np, + "qcom,mdss-dsi-bl-pmic-bank-select", + &tmp); + if (rc) { + pr_err("%s:%d, Error, lpg channel\n", + __func__, __LINE__); + return -EINVAL; + } + ctrl_pdata->pwm_lpg_chan = tmp; + tmp = of_get_named_gpio(np, + "qcom,mdss-dsi-pwm-gpio", 0); + ctrl_pdata->pwm_pmic_gpio = tmp; + pr_debug("%s: Configured PWM bklt ctrl\n", + __func__); + } + } else if (!strcmp(data, "bl_ctrl_dcs")) { + ctrl_pdata->bklt_ctrl = BL_DCS_CMD; + data = of_get_property(np, + "qcom,mdss-dsi-bl-dcs-command-state", NULL); + if (data && !strcmp(data, "dsi_hs_mode")) + ctrl_pdata->bklt_dcs_op_mode = DSI_HS_MODE; + else + ctrl_pdata->bklt_dcs_op_mode = DSI_LP_MODE; + + pr_debug("%s: Configured DCS_CMD bklt ctrl\n", + __func__); + } + } + return 0; +} + +int mdss_dsi_panel_timing_switch(struct mdss_dsi_ctrl_pdata *ctrl, + struct mdss_panel_timing *timing) +{ + struct dsi_panel_timing *pt; + struct mdss_panel_info *pinfo = &ctrl->panel_data.panel_info; + int i; + + if (!timing) + return -EINVAL; + + if (timing == ctrl->panel_data.current_timing) { + pr_warn("%s: panel timing \"%s\" already set\n", __func__, + timing->name); + return 0; /* nothing to do */ + } + + pr_debug("%s: ndx=%d switching to panel timing \"%s\"\n", __func__, + ctrl->ndx, timing->name); + + mdss_panel_info_from_timing(timing, pinfo); + + pt = container_of(timing, struct dsi_panel_timing, timing); + pinfo->mipi.t_clk_pre = pt->t_clk_pre; + pinfo->mipi.t_clk_post = pt->t_clk_post; + + for (i = 0; i < ARRAY_SIZE(pt->phy_timing); i++) + pinfo->mipi.dsi_phy_db.timing[i] = pt->phy_timing[i]; + + for (i = 0; i < ARRAY_SIZE(pt->phy_timing_8996); i++) + pinfo->mipi.dsi_phy_db.timing_8996[i] = pt->phy_timing_8996[i]; + + ctrl->on_cmds = pt->on_cmds; + ctrl->post_panel_on_cmds = pt->post_panel_on_cmds; + + ctrl->panel_data.current_timing = timing; + if (!timing->clk_rate) + ctrl->refresh_clk_rate = true; + mdss_dsi_clk_refresh(&ctrl->panel_data, ctrl->update_phy_timing); + + return 0; +} + +void mdss_dsi_unregister_bl_settings(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + if (ctrl_pdata->bklt_ctrl == BL_WLED) + led_trigger_unregister_simple(bl_led_trigger); +} + +static int mdss_dsi_panel_timing_from_dt(struct device_node *np, + struct dsi_panel_timing *pt, + struct mdss_panel_data *panel_data) +{ + u32 tmp; + u64 tmp64; + int rc, i, len; + const char *data; + struct mdss_dsi_ctrl_pdata *ctrl_pdata; + struct mdss_panel_info *pinfo; + bool phy_timings_present = false; + + pinfo = &panel_data->panel_info; + + ctrl_pdata = container_of(panel_data, struct mdss_dsi_ctrl_pdata, + panel_data); + + rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-width", &tmp); + if (rc) { + pr_err("%s:%d, panel width not specified\n", + __func__, __LINE__); + return -EINVAL; + } + pt->timing.xres = tmp; + + rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-height", &tmp); + if (rc) { + pr_err("%s:%d, panel height not specified\n", + __func__, __LINE__); + return -EINVAL; + } + pt->timing.yres = tmp; + + rc = of_property_read_u32(np, "qcom,mdss-dsi-h-front-porch", &tmp); + pt->timing.h_front_porch = (!rc ? tmp : 6); + rc = of_property_read_u32(np, "qcom,mdss-dsi-h-back-porch", &tmp); + pt->timing.h_back_porch = (!rc ? tmp : 6); + rc = of_property_read_u32(np, "qcom,mdss-dsi-h-pulse-width", &tmp); + pt->timing.h_pulse_width = (!rc ? tmp : 2); + rc = of_property_read_u32(np, "qcom,mdss-dsi-h-sync-skew", &tmp); + pt->timing.hsync_skew = (!rc ? tmp : 0); + rc = of_property_read_u32(np, "qcom,mdss-dsi-v-back-porch", &tmp); + pt->timing.v_back_porch = (!rc ? tmp : 6); + rc = of_property_read_u32(np, "qcom,mdss-dsi-v-front-porch", &tmp); + pt->timing.v_front_porch = (!rc ? tmp : 6); + rc = of_property_read_u32(np, "qcom,mdss-dsi-v-pulse-width", &tmp); + pt->timing.v_pulse_width = (!rc ? tmp : 2); + + rc = of_property_read_u32(np, "qcom,mdss-dsi-h-left-border", &tmp); + pt->timing.border_left = !rc ? tmp : 0; + rc = of_property_read_u32(np, "qcom,mdss-dsi-h-right-border", &tmp); + pt->timing.border_right = !rc ? tmp : 0; + + /* overriding left/right borders for split display cases */ + if (mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) { + if (panel_data->next) + pt->timing.border_right = 0; + else + pt->timing.border_left = 0; + } + + rc = of_property_read_u32(np, "qcom,mdss-dsi-v-top-border", &tmp); + pt->timing.border_top = !rc ? tmp : 0; + rc = of_property_read_u32(np, "qcom,mdss-dsi-v-bottom-border", &tmp); + pt->timing.border_bottom = !rc ? tmp : 0; + + rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-framerate", &tmp); + pt->timing.frame_rate = !rc ? tmp : DEFAULT_FRAME_RATE; + rc = of_property_read_u64(np, "qcom,mdss-dsi-panel-clockrate", &tmp64); + if (rc == -EOVERFLOW) { + tmp64 = 0; + rc = of_property_read_u32(np, + "qcom,mdss-dsi-panel-clockrate", (u32 *)&tmp64); + } + pt->timing.clk_rate = !rc ? tmp64 : 0; + + data = of_get_property(np, "qcom,mdss-dsi-panel-timings", &len); + if ((!data) || (len != 12)) { + pr_debug("%s:%d, Unable to read Phy timing settings", + __func__, __LINE__); + } else { + for (i = 0; i < len; i++) + pt->phy_timing[i] = data[i]; + phy_timings_present = true; + } + + data = of_get_property(np, "qcom,mdss-dsi-panel-timings-phy-v2", &len); + if ((!data) || (len != 40)) { + pr_debug("%s:%d, Unable to read phy-v2 lane timing settings", + __func__, __LINE__); + } else { + for (i = 0; i < len; i++) + pt->phy_timing_8996[i] = data[i]; + phy_timings_present = true; + } + if (!phy_timings_present) { + pr_err("%s: phy timing settings not present\n", __func__); + return -EINVAL; + } + + rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-pre", &tmp); + pt->t_clk_pre = (!rc ? tmp : 0x24); + rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-post", &tmp); + pt->t_clk_post = (!rc ? tmp : 0x03); + + if (np->name) { + pt->timing.name = kstrdup(np->name, GFP_KERNEL); + pr_info("%s: found new timing \"%s\" (%pK)\n", __func__, + np->name, &pt->timing); + } + + return 0; +} + +static int mdss_dsi_panel_config_res_properties(struct device_node *np, + struct dsi_panel_timing *pt, + struct mdss_panel_data *panel_data, + bool default_timing) +{ + int rc = 0; + + mdss_dsi_parse_roi_alignment(np, pt); + + mdss_dsi_parse_dcs_cmds(np, &pt->on_cmds, + "qcom,mdss-dsi-on-command", + "qcom,mdss-dsi-on-command-state"); + + mdss_dsi_parse_dcs_cmds(np, &pt->post_panel_on_cmds, + "qcom,mdss-dsi-post-panel-on-command", NULL); + + mdss_dsi_parse_dcs_cmds(np, &pt->switch_cmds, + "qcom,mdss-dsi-timing-switch-command", + "qcom,mdss-dsi-timing-switch-command-state"); + + rc = mdss_dsi_parse_topology_config(np, pt, panel_data, default_timing); + if (rc) { + pr_err("%s: parsing compression params failed. rc:%d\n", + __func__, rc); + return rc; + } + + mdss_panel_parse_te_params(np, &pt->timing); + return rc; +} + +static int mdss_panel_parse_display_timings(struct device_node *np, + struct mdss_panel_data *panel_data) +{ + struct mdss_dsi_ctrl_pdata *ctrl; + struct dsi_panel_timing *modedb; + struct device_node *timings_np; + struct device_node *entry; + int num_timings, rc; + int i = 0, active_ndx = 0; + bool default_timing = false; + + ctrl = container_of(panel_data, struct mdss_dsi_ctrl_pdata, panel_data); + + INIT_LIST_HEAD(&panel_data->timings_list); + + timings_np = of_get_child_by_name(np, "qcom,mdss-dsi-display-timings"); + if (!timings_np) { + struct dsi_panel_timing pt; + memset(&pt, 0, sizeof(struct dsi_panel_timing)); + + /* + * display timings node is not available, fallback to reading + * timings directly from root node instead + */ + pr_debug("reading display-timings from panel node\n"); + rc = mdss_dsi_panel_timing_from_dt(np, &pt, panel_data); + if (!rc) { + mdss_dsi_panel_config_res_properties(np, &pt, + panel_data, true); + rc = mdss_dsi_panel_timing_switch(ctrl, &pt.timing); + } + return rc; + } + + num_timings = of_get_child_count(timings_np); + if (num_timings == 0) { + pr_err("no timings found within display-timings\n"); + rc = -EINVAL; + goto exit; + } + + modedb = kcalloc(num_timings, sizeof(*modedb), GFP_KERNEL); + if (!modedb) { + rc = -ENOMEM; + goto exit; + } + + for_each_child_of_node(timings_np, entry) { + rc = mdss_dsi_panel_timing_from_dt(entry, (modedb + i), + panel_data); + if (rc) { + kfree(modedb); + goto exit; + } + + default_timing = of_property_read_bool(entry, + "qcom,mdss-dsi-timing-default"); + if (default_timing) + active_ndx = i; + + mdss_dsi_panel_config_res_properties(entry, (modedb + i), + panel_data, default_timing); + + list_add(&modedb[i].timing.list, + &panel_data->timings_list); + i++; + } + + /* Configure default timing settings */ + rc = mdss_dsi_panel_timing_switch(ctrl, &modedb[active_ndx].timing); + if (rc) + pr_err("unable to configure default timing settings\n"); + +exit: + of_node_put(timings_np); + + return rc; +} + +static int mdss_panel_parse_dt(struct device_node *np, + struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + u32 tmp; + int rc, len = 0; + const char *data; + static const char *pdest; + const char *bridge_chip_name; + struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info); + + if (mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) + pinfo->is_split_display = true; + + rc = of_property_read_u32(np, + "qcom,mdss-pan-physical-width-dimension", &tmp); + pinfo->physical_width = (!rc ? tmp : 0); + rc = of_property_read_u32(np, + "qcom,mdss-pan-physical-height-dimension", &tmp); + pinfo->physical_height = (!rc ? tmp : 0); + + rc = of_property_read_u32(np, "qcom,mdss-dsi-bpp", &tmp); + if (rc) { + pr_err("%s:%d, bpp not specified\n", __func__, __LINE__); + return -EINVAL; + } + pinfo->bpp = (!rc ? tmp : 24); + pinfo->mipi.mode = DSI_VIDEO_MODE; + data = of_get_property(np, "qcom,mdss-dsi-panel-type", NULL); + if (data && !strncmp(data, "dsi_cmd_mode", 12)) + pinfo->mipi.mode = DSI_CMD_MODE; + pinfo->mipi.boot_mode = pinfo->mipi.mode; + tmp = 0; + data = of_get_property(np, "qcom,mdss-dsi-pixel-packing", NULL); + if (data && !strcmp(data, "loose")) + pinfo->mipi.pixel_packing = 1; + else + pinfo->mipi.pixel_packing = 0; + rc = mdss_panel_get_dst_fmt(pinfo->bpp, + pinfo->mipi.mode, pinfo->mipi.pixel_packing, + &(pinfo->mipi.dst_format)); + if (rc) { + pr_debug("%s: problem determining dst format. Set Default\n", + __func__); + pinfo->mipi.dst_format = + DSI_VIDEO_DST_FORMAT_RGB888; + } + pdest = of_get_property(np, + "qcom,mdss-dsi-panel-destination", NULL); + + rc = of_property_read_u32(np, + "qcom,mdss-dsi-underflow-color", &tmp); + pinfo->lcdc.underflow_clr = (!rc ? tmp : 0xff); + rc = of_property_read_u32(np, + "qcom,mdss-dsi-border-color", &tmp); + pinfo->lcdc.border_clr = (!rc ? tmp : 0); + data = of_get_property(np, "qcom,mdss-dsi-panel-orientation", NULL); + if (data) { + pr_debug("panel orientation is %s\n", data); + if (!strcmp(data, "180")) + pinfo->panel_orientation = MDP_ROT_180; + else if (!strcmp(data, "hflip")) + pinfo->panel_orientation = MDP_FLIP_LR; + else if (!strcmp(data, "vflip")) + pinfo->panel_orientation = MDP_FLIP_UD; + } + + rc = of_property_read_u32(np, "qcom,mdss-brightness-max-level", &tmp); + pinfo->brightness_max = (!rc ? tmp : MDSS_MAX_BL_BRIGHTNESS); + rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-min-level", &tmp); + pinfo->bl_min = (!rc ? tmp : 0); + rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-max-level", &tmp); + pinfo->bl_max = (!rc ? tmp : 255); + ctrl_pdata->bklt_max = pinfo->bl_max; + + rc = of_property_read_u32(np, "qcom,mdss-dsi-interleave-mode", &tmp); + pinfo->mipi.interleave_mode = (!rc ? tmp : 0); + + pinfo->mipi.vsync_enable = of_property_read_bool(np, + "qcom,mdss-dsi-te-check-enable"); + + if (pinfo->sim_panel_mode == SIM_SW_TE_MODE) + pinfo->mipi.hw_vsync_mode = false; + else + pinfo->mipi.hw_vsync_mode = of_property_read_bool(np, + "qcom,mdss-dsi-te-using-te-pin"); + + rc = of_property_read_u32(np, + "qcom,mdss-dsi-h-sync-pulse", &tmp); + pinfo->mipi.pulse_mode_hsa_he = (!rc ? tmp : false); + + pinfo->mipi.hfp_power_stop = of_property_read_bool(np, + "qcom,mdss-dsi-hfp-power-mode"); + pinfo->mipi.hsa_power_stop = of_property_read_bool(np, + "qcom,mdss-dsi-hsa-power-mode"); + pinfo->mipi.hbp_power_stop = of_property_read_bool(np, + "qcom,mdss-dsi-hbp-power-mode"); + pinfo->mipi.last_line_interleave_en = of_property_read_bool(np, + "qcom,mdss-dsi-last-line-interleave"); + pinfo->mipi.bllp_power_stop = of_property_read_bool(np, + "qcom,mdss-dsi-bllp-power-mode"); + pinfo->mipi.eof_bllp_power_stop = of_property_read_bool( + np, "qcom,mdss-dsi-bllp-eof-power-mode"); + pinfo->mipi.traffic_mode = DSI_NON_BURST_SYNCH_PULSE; + data = of_get_property(np, "qcom,mdss-dsi-traffic-mode", NULL); + if (data) { + if (!strcmp(data, "non_burst_sync_event")) + pinfo->mipi.traffic_mode = DSI_NON_BURST_SYNCH_EVENT; + else if (!strcmp(data, "burst_mode")) + pinfo->mipi.traffic_mode = DSI_BURST_MODE; + } + rc = of_property_read_u32(np, + "qcom,mdss-dsi-te-dcs-command", &tmp); + pinfo->mipi.insert_dcs_cmd = + (!rc ? tmp : 1); + rc = of_property_read_u32(np, + "qcom,mdss-dsi-wr-mem-continue", &tmp); + pinfo->mipi.wr_mem_continue = + (!rc ? tmp : 0x3c); + rc = of_property_read_u32(np, + "qcom,mdss-dsi-wr-mem-start", &tmp); + pinfo->mipi.wr_mem_start = + (!rc ? tmp : 0x2c); + rc = of_property_read_u32(np, + "qcom,mdss-dsi-te-pin-select", &tmp); + pinfo->mipi.te_sel = + (!rc ? tmp : 1); + rc = of_property_read_u32(np, "qcom,mdss-dsi-virtual-channel-id", &tmp); + pinfo->mipi.vc = (!rc ? tmp : 0); + pinfo->mipi.rgb_swap = DSI_RGB_SWAP_RGB; + data = of_get_property(np, "qcom,mdss-dsi-color-order", NULL); + if (data) { + if (!strcmp(data, "rgb_swap_rbg")) + pinfo->mipi.rgb_swap = DSI_RGB_SWAP_RBG; + else if (!strcmp(data, "rgb_swap_bgr")) + pinfo->mipi.rgb_swap = DSI_RGB_SWAP_BGR; + else if (!strcmp(data, "rgb_swap_brg")) + pinfo->mipi.rgb_swap = DSI_RGB_SWAP_BRG; + else if (!strcmp(data, "rgb_swap_grb")) + pinfo->mipi.rgb_swap = DSI_RGB_SWAP_GRB; + else if (!strcmp(data, "rgb_swap_gbr")) + pinfo->mipi.rgb_swap = DSI_RGB_SWAP_GBR; + } + pinfo->mipi.data_lane0 = of_property_read_bool(np, + "qcom,mdss-dsi-lane-0-state"); + pinfo->mipi.data_lane1 = of_property_read_bool(np, + "qcom,mdss-dsi-lane-1-state"); + pinfo->mipi.data_lane2 = of_property_read_bool(np, + "qcom,mdss-dsi-lane-2-state"); + 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; + + pinfo->mipi.rx_eot_ignore = of_property_read_bool(np, + "qcom,mdss-dsi-rx-eot-ignore"); + pinfo->mipi.tx_eot_append = of_property_read_bool(np, + "qcom,mdss-dsi-tx-eot-append"); + + rc = of_property_read_u32(np, "qcom,mdss-dsi-stream", &tmp); + pinfo->mipi.stream = (!rc ? tmp : 0); + + data = of_get_property(np, "qcom,mdss-dsi-mode-sel-gpio-state", NULL); + if (data) { + if (!strcmp(data, "single_port")) + pinfo->mode_sel_state = MODE_SEL_SINGLE_PORT; + else if (!strcmp(data, "dual_port")) + pinfo->mode_sel_state = MODE_SEL_DUAL_PORT; + else if (!strcmp(data, "high")) + pinfo->mode_sel_state = MODE_GPIO_HIGH; + else if (!strcmp(data, "low")) + pinfo->mode_sel_state = MODE_GPIO_LOW; + } else { + /* Set default mode as SPLIT mode */ + pinfo->mode_sel_state = MODE_SEL_DUAL_PORT; + } + + rc = of_property_read_u32(np, "qcom,mdss-mdp-transfer-time-us", &tmp); + pinfo->mdp_transfer_time_us = (!rc ? tmp : DEFAULT_MDP_TRANSFER_TIME); + + mdss_dsi_parse_mdp_kickoff_threshold(np, pinfo); + + pinfo->mipi.lp11_init = of_property_read_bool(np, + "qcom,mdss-dsi-lp11-init"); + rc = of_property_read_u32(np, "qcom,mdss-dsi-init-delay-us", &tmp); + pinfo->mipi.init_delay = (!rc ? tmp : 0); + + rc = of_property_read_u32(np, "qcom,mdss-dsi-post-init-delay", &tmp); + pinfo->mipi.post_init_delay = (!rc ? tmp : 0); + + mdss_dsi_parse_trigger(np, &(pinfo->mipi.mdp_trigger), + "qcom,mdss-dsi-mdp-trigger"); + + mdss_dsi_parse_trigger(np, &(pinfo->mipi.dma_trigger), + "qcom,mdss-dsi-dma-trigger"); + + mdss_dsi_parse_reset_seq(np, pinfo->rst_seq, &(pinfo->rst_seq_len), + "qcom,mdss-dsi-reset-sequence"); + + mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->off_cmds, + "qcom,mdss-dsi-off-command", "qcom,mdss-dsi-off-command-state"); + + rc = of_property_read_u32(np, "qcom,adjust-timer-wakeup-ms", &tmp); + pinfo->adjust_timer_delay_ms = (!rc ? tmp : 0); + + pinfo->mipi.force_clk_lane_hs = of_property_read_bool(np, + "qcom,mdss-dsi-force-clock-lane-hs"); + + rc = mdss_dsi_parse_panel_features(np, ctrl_pdata); + if (rc) { + pr_err("%s: failed to parse panel features\n", __func__); + goto error; + } + + mdss_dsi_parse_panel_horizintal_line_idle(np, ctrl_pdata); + + mdss_dsi_parse_dfps_config(np, ctrl_pdata); + + mdss_dsi_set_refresh_rate_range(np, pinfo); + + pinfo->is_dba_panel = of_property_read_bool(np, + "qcom,dba-panel"); #if defined(CONFIG_IRIS2P_FULL_SUPPORT) - iris_init_params_parse(np, ctrl_pdata); - iris_init_cmd_setup(ctrl_pdata); + iris_init_params_parse(np, ctrl_pdata); + iris_init_cmd_setup(ctrl_pdata); #endif mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->srgb_on_cmds, @@ -3476,108 +3486,106 @@ int mdss_panel_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing, "qcom,mdss-dsi-panel-dci-p3-off-command", "qcom,mdss-dsi-dci-p3-command-state"); - ctrl_pdata->high_brightness_panel= of_property_read_bool(np, "qcom,mdss-dsi-high-brightness-panel"); pr_err("high brightness panel: %d\n", ctrl_pdata->high_brightness_panel); ctrl_pdata->bl_high2bit = of_property_read_bool(np, "qcom,mdss-bl-high2bit"); - if (pinfo->is_dba_panel) { - bridge_chip_name = of_get_property(np, - "qcom,bridge-name", &len); - if (!bridge_chip_name || len <= 0) { - pr_err("%s:%d Unable to read qcom,bridge_name, data=%pK,len=%d\n", - __func__, __LINE__, bridge_chip_name, len); - rc = -EINVAL; - goto error; - } - strlcpy(ctrl_pdata->bridge_name, bridge_chip_name, - MSM_DBA_CHIP_NAME_MAX_LEN); - } - - rc = of_property_read_u32(np, - "qcom,mdss-dsi-host-esc-clk-freq-hz", - &pinfo->esc_clk_rate_hz); - if (rc) - pinfo->esc_clk_rate_hz = MDSS_DSI_MAX_ESC_CLK_RATE_HZ; - pr_debug("%s: esc clk %d\n", __func__, pinfo->esc_clk_rate_hz); - - return 0; - - error: - return -EINVAL; - } - - int mdss_dsi_panel_init(struct device_node *node, - struct mdss_dsi_ctrl_pdata *ctrl_pdata, - int ndx) - { - int rc = 0; - static const char *panel_name; - struct mdss_panel_info *pinfo; + if (pinfo->is_dba_panel) { + bridge_chip_name = of_get_property(np, + "qcom,bridge-name", &len); + if (!bridge_chip_name || len <= 0) { + pr_err("%s:%d Unable to read qcom,bridge_name, data=%pK,len=%d\n", + __func__, __LINE__, bridge_chip_name, len); + rc = -EINVAL; + goto error; + } + strlcpy(ctrl_pdata->bridge_name, bridge_chip_name, + MSM_DBA_CHIP_NAME_MAX_LEN); + } + + rc = of_property_read_u32(np, + "qcom,mdss-dsi-host-esc-clk-freq-hz", + &pinfo->esc_clk_rate_hz); + if (rc) + pinfo->esc_clk_rate_hz = MDSS_DSI_MAX_ESC_CLK_RATE_HZ; + pr_debug("%s: esc clk %d\n", __func__, pinfo->esc_clk_rate_hz); + + return 0; + +error: + return -EINVAL; +} + +int mdss_dsi_panel_init(struct device_node *node, + struct mdss_dsi_ctrl_pdata *ctrl_pdata, + int ndx) +{ + int rc = 0; + static const char *panel_name; + struct mdss_panel_info *pinfo; static const char *panel_manufacture; static const char *panel_version; static const char *backlight_manufacture; static const char *backlight_version; - - if (!node || !ctrl_pdata) { - pr_err("%s: Invalid arguments\n", __func__); - return -ENODEV; - } - - pinfo = &ctrl_pdata->panel_data.panel_info; - - pr_debug("%s:%d\n", __func__, __LINE__); - pinfo->panel_name[0] = '\0'; - panel_name = of_get_property(node, "qcom,mdss-dsi-panel-name", NULL); - if (!panel_name) { - pr_info("%s:%d, Panel name not specified\n", - __func__, __LINE__); - } else { - pr_info("%s: Panel Name = %s\n", __func__, panel_name); - strlcpy(&pinfo->panel_name[0], panel_name, MDSS_MAX_PANEL_LEN); - } - panel_manufacture = of_get_property(node, - "qcom,mdss-dsi-panel-manufacture", NULL); - if (!panel_manufacture) - pr_info("%s:%d, panel manufacture not specified\n", __func__, __LINE__); - panel_version = of_get_property(node, "qcom,mdss-dsi-panel-version", NULL); - if (!panel_version) - pr_info("%s:%d, panel version not specified\n", __func__, __LINE__); - push_component_info(LCD, (char *)panel_version, - (char *)panel_manufacture); - backlight_manufacture = of_get_property(node, - "qcom,mdss-dsi-backlight-manufacture", NULL); - if (!backlight_manufacture) - pr_info("%s:%d, backlight manufacture not specified\n", __func__, __LINE__); - backlight_version = of_get_property(node, - "qcom,mdss-dsi-backlight-version", NULL); - if (!backlight_version) - pr_info("%s:%d, backlight version not specified\n", __func__, __LINE__); - push_component_info(BACKLIGHT, (char *)backlight_version, - (char *)backlight_manufacture); - mutex_init(&ctrl_pdata->panel_mode_lock); - - rc = mdss_panel_parse_dt(node, ctrl_pdata); - if (rc) { - pr_err("%s:%d panel dt parse failed\n", __func__, __LINE__); - return rc; - } - - pinfo->dynamic_switch_pending = false; - pinfo->is_lpm_mode = false; - pinfo->esd_rdy = false; - pinfo->persist_mode = false; - - ctrl_pdata->on = mdss_dsi_panel_on; - ctrl_pdata->post_panel_on = mdss_dsi_post_panel_on; - ctrl_pdata->off = mdss_dsi_panel_off; - ctrl_pdata->low_power_config = mdss_dsi_panel_low_power_config; - ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl; - ctrl_pdata->panel_data.apply_display_setting = - mdss_dsi_panel_apply_display_setting; - ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode; - - return 0; - } + if (!node || !ctrl_pdata) { + pr_err("%s: Invalid arguments\n", __func__); + return -ENODEV; + } + + pinfo = &ctrl_pdata->panel_data.panel_info; + + pr_debug("%s:%d\n", __func__, __LINE__); + pinfo->panel_name[0] = '\0'; + panel_name = of_get_property(node, "qcom,mdss-dsi-panel-name", NULL); + if (!panel_name) { + pr_info("%s:%d, Panel name not specified\n", + __func__, __LINE__); + } else { + pr_info("%s: Panel Name = %s\n", __func__, panel_name); + strlcpy(&pinfo->panel_name[0], panel_name, MDSS_MAX_PANEL_LEN); + } + panel_manufacture = of_get_property(node, + "qcom,mdss-dsi-panel-manufacture", NULL); + if (!panel_manufacture) + pr_info("%s:%d, panel manufacture not specified\n", __func__, __LINE__); + panel_version = of_get_property(node, "qcom,mdss-dsi-panel-version", NULL); + if (!panel_version) + pr_info("%s:%d, panel version not specified\n", __func__, __LINE__); + push_component_info(LCD, (char *)panel_version, + (char *)panel_manufacture); + backlight_manufacture = of_get_property(node, + "qcom,mdss-dsi-backlight-manufacture", NULL); + if (!backlight_manufacture) + pr_info("%s:%d, backlight manufacture not specified\n", __func__, __LINE__); + backlight_version = of_get_property(node, + "qcom,mdss-dsi-backlight-version", NULL); + if (!backlight_version) + pr_info("%s:%d, backlight version not specified\n", __func__, __LINE__); + push_component_info(BACKLIGHT, (char *)backlight_version, + (char *)backlight_manufacture); + mutex_init(&ctrl_pdata->panel_mode_lock); + + rc = mdss_panel_parse_dt(node, ctrl_pdata); + if (rc) { + pr_err("%s:%d panel dt parse failed\n", __func__, __LINE__); + return rc; + } + + pinfo->dynamic_switch_pending = false; + pinfo->is_lpm_mode = false; + pinfo->esd_rdy = false; + pinfo->persist_mode = false; + + ctrl_pdata->on = mdss_dsi_panel_on; + ctrl_pdata->post_panel_on = mdss_dsi_post_panel_on; + ctrl_pdata->off = mdss_dsi_panel_off; + ctrl_pdata->low_power_config = mdss_dsi_panel_low_power_config; + ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl; + ctrl_pdata->panel_data.apply_display_setting = + mdss_dsi_panel_apply_display_setting; + ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode; + + return 0; +} diff --git a/drivers/video/fbdev/msm/mdss_dsi_phy.c b/drivers/video/fbdev/msm/mdss_dsi_phy.c index 2d2498643c3f..e8e903e6ce88 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_phy.c +++ b/drivers/video/fbdev/msm/mdss_dsi_phy.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1034,15 +1034,10 @@ static void mdss_dsi_phy_update_timing_param_v3(struct mdss_panel_info *pinfo, } int mdss_dsi_phy_calc_timing_param(struct mdss_panel_info *pinfo, u32 phy_rev, - u32 frate_hz) + u64 clk_rate) { struct dsi_phy_t_clk_param t_clk; struct dsi_phy_timing t_param; - int hsync_period; - int vsync_period; - unsigned long inter_num; - uint32_t lane_config = 0; - unsigned long x, y; int rc = 0; if (!pinfo) { @@ -1050,30 +1045,12 @@ int mdss_dsi_phy_calc_timing_param(struct mdss_panel_info *pinfo, u32 phy_rev, return -EINVAL; } - hsync_period = mdss_panel_get_htotal(pinfo, true); - vsync_period = mdss_panel_get_vtotal(pinfo); - - inter_num = pinfo->bpp * frate_hz; - - if (pinfo->mipi.data_lane0) - lane_config++; - if (pinfo->mipi.data_lane1) - lane_config++; - if (pinfo->mipi.data_lane2) - lane_config++; - if (pinfo->mipi.data_lane3) - lane_config++; - - x = mult_frac(vsync_period * hsync_period, inter_num, lane_config); - y = rounddown(x, 1); - t_clk.bitclk_mbps = rounddown(mult_frac(y, 1, 1000000), 1); + t_clk.bitclk_mbps = rounddown((uint32_t) div_u64(clk_rate, 1000000), 1); t_clk.escclk_numer = ESC_CLK_MHZ; t_clk.escclk_denom = ESCCLK_MMSS_CC_PREDIV; t_clk.tlpx_numer_ns = TLPX_NUMER; t_clk.treot_ns = TR_EOT; - pr_debug("hperiod=%d, vperiod=%d, inter_num=%lu, lane_cfg=%d\n", - hsync_period, vsync_period, inter_num, lane_config); - pr_debug("x=%lu, y=%lu, bitrate=%d\n", x, y, t_clk.bitclk_mbps); + pr_debug("bitrate=%d\n", t_clk.bitclk_mbps); rc = mdss_dsi_phy_initialize_defaults(&t_clk, &t_param, phy_rev); if (rc) { diff --git a/drivers/video/fbdev/msm/mdss_dsi_phy.h b/drivers/video/fbdev/msm/mdss_dsi_phy.h index 03df17d81f69..b0f7d68556d5 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_phy.h +++ b/drivers/video/fbdev/msm/mdss_dsi_phy.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -42,7 +42,7 @@ enum phy_mode { * @frate_hz - Frame rate for which phy timing parameters are to be calculated. */ int mdss_dsi_phy_calc_timing_param(struct mdss_panel_info *pinfo, u32 phy_rev, - u32 frate_hz); + u64 clk_rate); /* * mdss_dsi_phy_v3_init() - initialization sequence for DSI PHY rev v3 diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 672547acbd91..28279ccdabaf 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -1,7 +1,7 @@ /* * Core MDSS framebuffer driver. * - * Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2007 Google Incorporated * * This software is licensed under the terms of the GNU General Public @@ -610,7 +610,7 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev, "red_chromaticity_x=%d\nred_chromaticity_y=%d\n" "green_chromaticity_x=%d\ngreen_chromaticity_y=%d\n" "blue_chromaticity_x=%d\nblue_chromaticity_y=%d\n" - "panel_orientation=%d\n", + "panel_orientation=%d\ndyn_bitclk_en=%d\n", pinfo->partial_update_enabled, pinfo->roi_alignment.xstart_pix_align, pinfo->roi_alignment.width_pix_align, @@ -636,7 +636,7 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev, pinfo->hdr_properties.display_primaries[5], pinfo->hdr_properties.display_primaries[6], pinfo->hdr_properties.display_primaries[7], - pinfo->panel_orientation); + pinfo->panel_orientation, pinfo->dynamic_bitclk); return ret; } diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index 3340496100d5..439fea65e822 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -818,6 +818,9 @@ struct mdss_panel_info { int pwm_lpg_chan; int pwm_period; bool dynamic_fps; + bool dynamic_bitclk; + u32 *supp_bitclks; + u32 supp_bitclk_len; bool ulps_feature_enabled; bool ulps_suspend_enabled; bool panel_ack_disabled; diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c index bb3b4b3fa929..922c4440ba82 100644 --- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c +++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1489,13 +1489,19 @@ int mdss_dsi_clk_refresh(struct mdss_panel_data *pdata, bool update_phy) __func__, pinfo->mipi.frame_rate); } - rc = mdss_dsi_clk_div_config(&pdata->panel_info, - pdata->panel_info.mipi.frame_rate); - if (rc) { - pr_err("%s: unable to initialize the clk dividers\n", - __func__); - return rc; + pinfo->clk_rate = mdss_dsi_calc_bitclk(pinfo, pinfo->mipi.frame_rate); + if (!pinfo->clk_rate) { + pr_err("%s: unable to calculate the DSI bit clock\n", __func__); + return -EINVAL; } + + pinfo->mipi.dsi_pclk_rate = mdss_dsi_get_pclk_rate(pinfo, + pinfo->clk_rate); + if (!pinfo->mipi.dsi_pclk_rate) { + pr_err("%s: unable to calculate the DSI pclk\n", __func__); + return -EINVAL; + } + ctrl_pdata->refresh_clk_rate = false; ctrl_pdata->pclk_rate = pdata->panel_info.mipi.dsi_pclk_rate; ctrl_pdata->byte_clk_rate = pdata->panel_info.clk_rate / 8; @@ -1524,7 +1530,7 @@ int mdss_dsi_clk_refresh(struct mdss_panel_data *pdata, bool update_phy) /* phy panel timing calaculation */ rc = mdss_dsi_phy_calc_timing_param(pinfo, ctrl_pdata->shared_data->phy_rev, - pinfo->mipi.frame_rate); + pdata->panel_info.clk_rate); if (rc) { pr_err("Error in calculating phy timings\n"); return rc; @@ -1811,16 +1817,9 @@ bool is_diff_frame_rate(struct mdss_panel_info *panel_info, return (frame_rate != panel_info->mipi.frame_rate); } -int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, - int frame_rate) +static u8 mdss_dsi_get_lane_cnt(struct mdss_panel_info *panel_info) { - struct mdss_panel_data *pdata = container_of(panel_info, - struct mdss_panel_data, panel_info); - struct mdss_dsi_ctrl_pdata *ctrl_pdata = container_of(pdata, - struct mdss_dsi_ctrl_pdata, panel_data); - u64 h_period, v_period, clk_rate; - u32 dsi_pclk_rate; - u8 lanes = 0, bpp; + u8 lanes = 0; if (!panel_info) return -EINVAL; @@ -1834,7 +1833,17 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, if (panel_info->mipi.data_lane0) lanes += 1; - switch (panel_info->mipi.dst_format) { + if (!lanes) + lanes = 1; + + return lanes; +} + +static u8 mdss_dsi_get_bpp(char dst_format) +{ + u8 bpp = 0; + + switch (dst_format) { case DSI_CMD_DST_FORMAT_RGB888: case DSI_VIDEO_DST_FORMAT_RGB888: case DSI_VIDEO_DST_FORMAT_RGB666_LOOSE: @@ -1848,6 +1857,21 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, bpp = 3; /* Default format set to RGB888 */ break; } + return bpp; +} + +u64 mdss_dsi_calc_bitclk(struct mdss_panel_info *panel_info, int frame_rate) +{ + struct mdss_panel_data *pdata = container_of(panel_info, + struct mdss_panel_data, panel_info); + struct mdss_dsi_ctrl_pdata *ctrl_pdata = container_of(pdata, + struct mdss_dsi_ctrl_pdata, panel_data); + u64 h_period, v_period, clk_rate = 0; + u8 lanes = 0, bpp; + + lanes = mdss_dsi_get_lane_cnt(panel_info); + + bpp = mdss_dsi_get_bpp(panel_info->mipi.dst_format); h_period = mdss_panel_get_htotal(panel_info, true); if (panel_info->split_link_enabled) @@ -1855,35 +1879,40 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, v_period = mdss_panel_get_vtotal(panel_info); if (ctrl_pdata->refresh_clk_rate || is_diff_frame_rate(panel_info, - frame_rate) || (!panel_info->clk_rate)) { - if (lanes > 0) { - panel_info->clk_rate = h_period * v_period * frame_rate - * bpp * 8; - do_div(panel_info->clk_rate, lanes); - } else { - pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__); - panel_info->clk_rate = - h_period * v_period * frame_rate * bpp * 8; - } + frame_rate) || (!panel_info->clk_rate)) { + clk_rate = h_period * v_period * frame_rate * bpp * 8; + do_div(clk_rate, lanes); + } else if (panel_info->clk_rate) { + clk_rate = panel_info->clk_rate; } - if (panel_info->clk_rate == 0) - panel_info->clk_rate = 454000000; + if (clk_rate == 0) + clk_rate = 454000000; + + return clk_rate; +} + +u32 mdss_dsi_get_pclk_rate(struct mdss_panel_info *panel_info, u64 clk_rate) +{ + u8 lanes = 0, bpp; + u32 pclk_rate = 0; + + lanes = mdss_dsi_get_lane_cnt(panel_info); + + bpp = mdss_dsi_get_bpp(panel_info->mipi.dst_format); - clk_rate = panel_info->clk_rate; do_div(clk_rate, 8 * bpp); if (panel_info->split_link_enabled) - dsi_pclk_rate = (u32) clk_rate * + pclk_rate = (u32) clk_rate * panel_info->mipi.lanes_per_sublink; else - dsi_pclk_rate = (u32) clk_rate * lanes; + pclk_rate = (u32) clk_rate * lanes; - if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000)) - dsi_pclk_rate = 35000000; - panel_info->mipi.dsi_pclk_rate = dsi_pclk_rate; + if ((pclk_rate < 3300000) || (pclk_rate > 250000000)) + pclk_rate = 35000000; - return 0; + return pclk_rate; } static bool mdss_dsi_is_ulps_req_valid(struct mdss_dsi_ctrl_pdata *ctrl,