summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev
diff options
context:
space:
mode:
authorKuogee Hsieh <khsieh@codeaurora.org>2015-01-21 15:58:51 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:37:42 -0700
commit3c235789a79cfe557e4e88c232c05ff532d1995e (patch)
tree96dbcfad65fe93bfdc9de22470b21ac290efa213 /drivers/video/fbdev
parentb685d84bf97030a3a17d61b59525de95e9d29eb8 (diff)
msm: mdss: add thulium dsi phy support
Add dsi phy related supporting functions to configure timing registers of both data and clock lanes of phy interface. Change-Id: I185c26ff2b9f11d9b30f4fee42bc730b69098f0f Signed-off-by: Kuogee Hsieh <khsieh@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c33
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h3
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_host.c25
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c11
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c14
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h15
-rw-r--r--drivers/video/fbdev/msm/msm_mdss_io_8974.c239
7 files changed, 288 insertions, 52 deletions
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index d9a7c7c5e18b..f6f26dceb0ff 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -641,6 +641,7 @@ int mdss_dsi_on(struct mdss_panel_data *pdata)
* to be restored to allow dcs command be
* sent to panel
*/
+ mdss_dsi_read_hw_revision(ctrl_pdata);
mdss_dsi_restore_intr_mask(ctrl_pdata);
pr_debug("%s: panel already on\n", __func__);
goto end;
@@ -664,6 +665,7 @@ int mdss_dsi_on(struct mdss_panel_data *pdata)
*/
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
mdss_dsi_sw_reset(ctrl_pdata, true);
+ mdss_dsi_read_hw_revision(ctrl_pdata);
/*
* Issue hardware reset line after enabling the DSI clocks and data
@@ -1813,27 +1815,29 @@ int dsi_panel_device_register(struct device_node *pan_node,
data = of_get_property(ctrl_pdev->dev.of_node,
"qcom,platform-strength-ctrl", &len);
- if ((!data) || (len != 2)) {
+ if (!data) {
pr_err("%s:%d, Unable to read Phy Strength ctrl settings\n",
__func__, __LINE__);
return -EINVAL;
+ } else {
+ pinfo->mipi.dsi_phy_db.strength_len = len;
+ for (i = 0; i < len; i++)
+ pinfo->mipi.dsi_phy_db.strength[i] = data[i];
}
- pinfo->mipi.dsi_phy_db.strength[0] = data[0];
- pinfo->mipi.dsi_phy_db.strength[1] = data[1];
pinfo->mipi.dsi_phy_db.reg_ldo_mode = of_property_read_bool(
ctrl_pdev->dev.of_node, "qcom,regulator-ldo-mode");
data = of_get_property(ctrl_pdev->dev.of_node,
"qcom,platform-regulator-settings", &len);
- if ((!data) || (len != 7)) {
+ if (!data) {
pr_err("%s:%d, Unable to read Phy regulator settings\n",
__func__, __LINE__);
return -EINVAL;
- }
- for (i = 0; i < len; i++) {
- pinfo->mipi.dsi_phy_db.regulator[i]
- = data[i];
+ } else {
+ pinfo->mipi.dsi_phy_db.regulator_len = len;
+ for (i = 0; i < len; i++)
+ pinfo->mipi.dsi_phy_db.regulator[i] = data[i];
}
data = of_get_property(ctrl_pdev->dev.of_node,
@@ -1844,20 +1848,19 @@ int dsi_panel_device_register(struct device_node *pan_node,
return -EINVAL;
}
for (i = 0; i < len; i++) {
- pinfo->mipi.dsi_phy_db.bistctrl[i]
- = data[i];
+ pinfo->mipi.dsi_phy_db.bistctrl[i] = data[i];
}
data = of_get_property(ctrl_pdev->dev.of_node,
"qcom,platform-lane-config", &len);
- if ((!data) || (len != 45)) {
+ if (!data) {
pr_err("%s:%d, Unable to read Phy lane configure settings\n",
__func__, __LINE__);
return -EINVAL;
- }
- for (i = 0; i < len; i++) {
- pinfo->mipi.dsi_phy_db.lanecfg[i] =
- data[i];
+ } else {
+ pinfo->mipi.dsi_phy_db.lanecfg_len = len;
+ for (i = 0; i < len; i++)
+ pinfo->mipi.dsi_phy_db.lanecfg[i] = data[i];
}
rc = of_property_read_u32(ctrl_pdev->dev.of_node,
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index 22eac8623751..2f2d9ab9eb8b 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -53,6 +53,7 @@
#define MDSS_DSI_HW_REV_102 0x10020000 /* 8084 */
#define MDSS_DSI_HW_REV_103 0x10030000 /* 8994 */
#define MDSS_DSI_HW_REV_103_1 0x10030001 /* 8916/8936 */
+#define MDSS_DSI_HW_REV_104 0x10040000 /* thulium */
#define NONE_PANEL "none"
@@ -297,6 +298,7 @@ struct mdss_dsi_ctrl_pdata {
void (*switch_mode) (struct mdss_panel_data *pdata, int mode);
struct mdss_panel_data panel_data;
unsigned char *ctrl_base;
+ u32 hw_rev;
struct dss_io_data ctrl_io;
struct dss_io_data mmss_misc_io;
struct dss_io_data phy_io;
@@ -408,6 +410,7 @@ struct dsi_status_data {
struct msm_fb_data_type *mfd;
};
+void mdss_dsi_read_hw_revision(struct mdss_dsi_ctrl_pdata *ctrl);
int dsi_panel_device_register(struct device_node *pan_node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata);
diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c
index b947cadb1364..b7b584b4e9b7 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -242,6 +242,15 @@ void mdss_dsi_cmd_test_pattern(struct mdss_dsi_ctrl_pdata *ctrl)
MIPI_OUTP((ctrl->ctrl_base) + 0x015c, 0x0);
}
+void mdss_dsi_read_hw_revision(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ /* clock must be on */
+ ctrl->hw_rev = MIPI_INP(ctrl->ctrl_base);
+
+ pr_debug("%s: ndx=%d hw_rev=%x\n", __func__,
+ ctrl->ndx, ctrl->hw_rev);
+}
+
void mdss_dsi_host_init(struct mdss_panel_data *pdata)
{
u32 dsi_ctrl, intr_ctrl;
@@ -1293,7 +1302,6 @@ int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
int short_response, diff, pkt_size, ret = 0;
struct dsi_buf *tp, *rp;
char cmd;
- u32 ctrl_rev;
struct mdss_dsi_ctrl_pdata *mctrl = NULL;
@@ -1331,7 +1339,6 @@ int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
}
do_send:
- ctrl_rev = MIPI_INP(ctrl->ctrl_base);
ctrl->cmd_cfg_restore = __mdss_dsi_cmd_mode_config(ctrl, 1);
if (rlen <= 2) {
@@ -1393,7 +1400,7 @@ do_send:
goto end;
}
- if (ctrl_rev >= MDSS_DSI_HW_REV_101) {
+ if (ctrl->hw_rev >= MDSS_DSI_HW_REV_101) {
/* clear the RDBK_DATA registers */
MIPI_OUTP(ctrl->ctrl_base + 0x01d4, 0x1);
wmb(); /* make sure the RDBK registers are cleared */
@@ -1593,7 +1600,7 @@ static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_buf *rp, int rx_byte)
{
- u32 *lp, *temp, data, ctrl_rev;
+ u32 *lp, *temp, data;
int i, j = 0, off, cnt;
bool ack_error = false;
char reg[16];
@@ -1605,12 +1612,10 @@ static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl,
cnt += 3;
cnt >>= 2;
- ctrl_rev = MIPI_INP(ctrl->ctrl_base);
-
if (cnt > 4)
cnt = 4; /* 4 x 32 bits registers only */
- if (ctrl_rev >= MDSS_DSI_HW_REV_101) {
+ if (ctrl->hw_rev >= MDSS_DSI_HW_REV_101) {
rp->read_cnt = (MIPI_INP((ctrl->ctrl_base) + 0x01d4) >> 16);
pr_debug("%s: bytes read:%d\n", __func__, rp->read_cnt);
@@ -1958,7 +1963,6 @@ static int dsi_event_thread(void *data)
struct sched_param param;
u32 todo = 0, ln_status;
int ret;
- u32 ctrl_rev;
param.sched_priority = 16;
ret = sched_setscheduler_nocheck(current, SCHED_FIFO, &param);
@@ -2006,7 +2010,6 @@ static int dsi_event_thread(void *data)
mdss_dsi_sw_reset(ctrl, true);
if (todo & DSI_EV_DLNx_FIFO_OVERFLOW) {
- ctrl_rev = MIPI_INP(ctrl->ctrl_base);
mutex_lock(&dsi_mtx);
/*
* For targets other than msm8994,
@@ -2018,7 +2021,7 @@ static int dsi_event_thread(void *data)
pr_debug("%s: lane_status: 0x%x\n",
__func__, ln_status);
if (ctrl->recovery
- && (ctrl_rev != MDSS_DSI_HW_REV_103)
+ && (ctrl->hw_rev != MDSS_DSI_HW_REV_103)
&& (ln_status
& DSI_DATA_LANES_STOP_STATE)
&& !(ln_status
@@ -2031,7 +2034,7 @@ static int dsi_event_thread(void *data)
DSI_INTR_ERROR_MASK, 1);
mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 0);
} else if (ctrl->recovery
- && (ctrl_rev
+ && (ctrl->hw_rev
== MDSS_DSI_HW_REV_103)) {
pr_debug("%s: Handle overflow->Rev_103\n",
__func__);
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index 514ee605b574..62cd76a844fa 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-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, 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
@@ -1695,6 +1695,15 @@ static int mdss_panel_parse_dt(struct device_node *np,
for (i = 0; i < len; i++)
pinfo->mipi.dsi_phy_db.timing[i] = data[i];
+ data = of_get_property(np, "qcom,mdss-dsi-panel-timings-thulium", &len);
+ if ((!data) || (len != 40)) {
+ pr_debug("%s:%d, Unable to read thulium Phy lane timing settings",
+ __func__, __LINE__);
+ } else {
+ for (i = 0; i < len; i++)
+ pinfo->mipi.dsi_phy_db.timing_thulium[i] = data[i];
+ }
+
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);
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index d3f4d709e402..0b8f65abe569 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -2986,13 +2986,19 @@ static int mdss_fb_check_var(struct fb_var_screeninfo *var,
return -EINVAL;
if (mfd->panel_info) {
- struct mdss_panel_info panel_info;
+ struct mdss_panel_info *pinfo;
int rc;
- memcpy(&panel_info, mfd->panel_info, sizeof(panel_info));
- mdss_fb_var_to_panelinfo(var, &panel_info);
+ pinfo = kmalloc(sizeof(struct mdss_panel_info), GFP_KERNEL);
+ if (!pinfo) {
+ pr_err("unable to allocate memory for pinfo\n");
+ return -ENOMEM;
+ }
+ memcpy(pinfo, mfd->panel_info, sizeof(*pinfo));
+ mdss_fb_var_to_panelinfo(var, pinfo);
rc = mdss_fb_send_panel_event(mfd, MDSS_EVENT_CHECK_PARAMS,
- &panel_info);
+ pinfo);
+ kfree(pinfo);
if (IS_ERR_VALUE(rc))
return rc;
mfd->panel_reconfig = rc;
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index 7d4152057de2..d58e23bf40d3 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -231,14 +231,19 @@ struct lcd_panel_info {
/* DSI PHY configuration */
struct mdss_dsi_phy_ctrl {
- uint32_t regulator[7];
- uint32_t timing[12];
- uint32_t ctrl[4];
- uint32_t strength[2];
+ char regulator[7]; /* thulium, 1 * 5 */
+ char timing[12];
+ char ctrl[4];
+ char strength[10]; /* thulium, 2 * 5 */
char bistctrl[6];
uint32_t pll[21];
- char lanecfg[45];
+ char lanecfg[45]; /* thulium, 4 * 5 */
bool reg_ldo_mode;
+
+ char timing_thulium[40];/* thulium, 8 * 5 */
+ char regulator_len;
+ char strength_len;
+ char lanecfg_len;
};
struct mipi_panel_info {
diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
index 461ccbe587ce..285e24c70642 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-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, 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
@@ -40,11 +40,20 @@
#define SW_RESET_PLL BIT(0)
#define PWRDN_B BIT(7)
+/* thulium */
+#define DATALANE_OFFSET_FROM_BASE_THULIUM 0x100
+#define DATALANE_SIZE_THULIUM 0x80
+
+#define DSIPHY_CMN_GLBL_TEST_CTRL 0x0018
+#define DSIPHY_CMN_CTRL_0 0x001c
+#define DSIPHY_CMN_CTRL_1 0x0020
+#define DSIPHY_CMN_LDO_CNTRL 0x004c
+#define DSIPHY_PLL_CLKBUFLR_EN 0x041c
+
static struct dsi_clk_desc dsi_pclk;
static void mdss_dsi_phy_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl)
{
- u32 ctrl_rev;
if (ctrl == NULL) {
pr_err("%s: Invalid input data\n", __func__);
return;
@@ -64,8 +73,7 @@ static void mdss_dsi_phy_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl)
* Need to turn off the PLL1 to avoid current leakage issues
*/
if (ctrl->ndx == DSI_CTRL_1) {
- ctrl_rev = MIPI_INP(ctrl->ctrl_base);
- if (ctrl_rev == MDSS_DSI_HW_REV_103) {
+ if (ctrl->hw_rev == MDSS_DSI_HW_REV_103) {
pr_debug("Turn off PLL 1 registers\n");
clk_set_rate(ctrl->vco_clk, 1);
}
@@ -74,10 +82,32 @@ static void mdss_dsi_phy_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl)
static void mdss_dsi_phy_regulator_disable(struct mdss_dsi_ctrl_pdata *ctrl)
{
+ if (!ctrl) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return;
+ }
+
+ if (ctrl->hw_rev == MDSS_DSI_HW_REV_104)
+ return;
+
MIPI_OUTP(ctrl->shared_ctrl_data->phy_regulator_io.base
+ 0x018, 0x000);
}
+static void mdss_dsi_phy_lane_shutdown(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ if (!ctrl) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return;
+ }
+
+ if (ctrl->hw_rev == MDSS_DSI_HW_REV_104)
+ MIPI_OUTP(ctrl->phy_io.base + DSIPHY_CMN_CTRL_0, 0x0000);
+ else
+ MIPI_OUTP(ctrl->phy_io.base + MDSS_DSI_DSIPHY_CTRL_0, 0x000);
+
+}
+
void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl)
{
struct mdss_dsi_ctrl_pdata *other_ctrl;
@@ -98,10 +128,9 @@ void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl)
other_ctrl = mdss_dsi_get_other_ctrl(ctrl);
if (other_ctrl)
- MIPI_OUTP(other_ctrl->phy_io.base +
- MDSS_DSI_DSIPHY_CTRL_0, 0x000);
+ mdss_dsi_phy_lane_shutdown(other_ctrl);
- MIPI_OUTP(ctrl->phy_io.base + MDSS_DSI_DSIPHY_CTRL_0, 0x000);
+ mdss_dsi_phy_lane_shutdown(ctrl);
mdss_dsi_phy_regulator_disable(ctrl);
@@ -125,6 +154,14 @@ void mdss_dsi_lp_cd_rx(struct mdss_dsi_ctrl_pdata *ctrl)
{
struct mdss_dsi_phy_ctrl *pd;
+ if (!ctrl) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return;
+ }
+
+ if (ctrl->hw_rev == MDSS_DSI_HW_REV_104)
+ return;
+
pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
/* Strength ctrl 1, LP Rx + CD Rxcontention detection */
@@ -200,7 +237,6 @@ static void mdss_dsi_28nm_phy_init(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
struct mdss_dsi_phy_ctrl *pd;
int i, off, ln, offset;
- u32 ctrl_rev;
if (!ctrl_pdata) {
pr_err("%s: Invalid input data\n", __func__);
@@ -244,11 +280,9 @@ static void mdss_dsi_28nm_phy_init(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0170, 0x5f);
wmb();
- ctrl_rev = MIPI_INP(ctrl_pdata->ctrl_base);
-
/* DSI_0_PHY_DSIPHY_GLBL_TEST_CTRL */
if (((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1) ||
- (ctrl_rev == MDSS_DSI_HW_REV_103_1))
+ (ctrl_pdata->hw_rev == MDSS_DSI_HW_REV_103_1))
MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x01d4, 0x01);
else
MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x01d4, 0x00);
@@ -272,6 +306,11 @@ static void mdss_dsi_20nm_phy_regulator_enable(struct mdss_dsi_ctrl_pdata
pd = &(((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db);
phy_io_base = ctrl_pdata->shared_ctrl_data->phy_regulator_io.base;
+ if (pd->regulator_len != 7) {
+ pr_err("%s: wrong regulator settings\n", __func__);
+ return;
+ }
+
if (pd->reg_ldo_mode) {
MIPI_OUTP(phy_io_base + MDSS_DSI_DSIPHY_LDO_CNTRL, 0x1d);
} else {
@@ -298,12 +337,22 @@ static void mdss_dsi_20nm_phy_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
pd = &(((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db);
+ if (pd->strength_len != 2) {
+ pr_err("%s: wrong strength ctrl\n", __func__);
+ return;
+ }
+
MIPI_OUTP((ctrl_pdata->phy_io.base) + MDSS_DSI_DSIPHY_STRENGTH_CTRL_0,
pd->strength[0]);
MIPI_OUTP((ctrl_pdata->phy_io.base) + MDSS_DSI_DSIPHY_GLBL_TEST_CTRL,
0x00);
+ if (pd->lanecfg_len != 45) {
+ pr_err("%s: wrong lane cfg\n", __func__);
+ return;
+ }
+
/* 4 lanes + clk lane configuration */
/* lane config n * (0 - 4) & DataPath setup */
for (ln = 0; ln < 5; ln++) {
@@ -331,6 +380,150 @@ static void mdss_dsi_20nm_phy_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
MIPI_OUTP((ctrl_pdata->phy_io.base) + MDSS_DSI_DSIPHY_CTRL_0, 0x7f);
}
+static void mdss_dsi_thulium_pll_source_standalone(
+ struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ u32 data;
+
+ /*
+ * pll right output enabled
+ * bit clk select from left
+ */
+ MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_PLL_CLKBUFLR_EN, 0x01);
+ data = MIPI_INP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL);
+ data &= ~BIT(2);
+ MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL, data);
+}
+
+static void mdss_dsi_thulium_pll_source_from_right(
+ struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ u32 data;
+
+ /*
+ * pll left + right output disabled
+ * bit clk select from right
+ */
+ MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_PLL_CLKBUFLR_EN, 0x00);
+ data = MIPI_INP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL);
+ data |= BIT(2);
+ MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL, data);
+}
+
+static void mdss_dsi_thulium_pll_source_from_left(
+ struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ u32 data;
+
+ /*
+ * pll left + right output enabled
+ * bit clk select from left
+ */
+ MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_PLL_CLKBUFLR_EN, 0x03);
+ data = MIPI_INP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL);
+ data &= ~BIT(2);
+ MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL, data);
+}
+
+static void mdss_dsi_thulium_phy_config(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct mdss_dsi_phy_ctrl *pd;
+ int j, off, ln, cnt, ln_off;
+ u32 data;
+ char *ip;
+ void __iomem *base;
+
+ pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
+
+ MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_LDO_CNTRL, 0x1c);
+
+ /* clk_en */
+ data = MIPI_INP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL);
+ data |= BIT(0);
+ MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL, data);
+
+ if (pd->lanecfg_len != 20) {
+ pr_err("%s: wrong lane cfg\n", __func__);
+ return;
+ }
+
+ if (pd->strength_len != 10) {
+ pr_err("%s: wrong strength ctrl\n", __func__);
+ return;
+ }
+
+ if (pd->regulator_len != 5) {
+ pr_err("%s: wrong regulator setting\n", __func__);
+ return;
+ }
+
+ /* 4 lanes + clk lane configuration */
+ for (ln = 0; ln < 5; ln++) {
+ /*
+ * data lane offset frome base: 0x100
+ * data lane size: 0x80
+ */
+ base = ctrl->phy_io.base +
+ DATALANE_OFFSET_FROM_BASE_THULIUM;
+ base += (ln * DATALANE_SIZE_THULIUM); /* lane base */
+
+ /* lane cfg, 4 * 5 */
+ cnt = 4;
+ ln_off = cnt * ln;
+ ip = &pd->lanecfg[ln_off];
+ off = 0x0;
+ for (j = 0; j < cnt; j++) {
+ MIPI_OUTP(base + off, *ip++);
+ off += 4;
+ }
+
+ /* test str */
+ MIPI_OUTP(base + 0x14, 0x0088); /* fixed */
+
+ /* phy timing, 8 * 5 */
+ cnt = 8;
+ ln_off = cnt * ln;
+ ip = &pd->timing_thulium[ln_off];
+ off = 0x18;
+ for (j = 0; j < cnt; j++, off += 4)
+ MIPI_OUTP(base + off, *ip++);
+
+ /* strength, 2 * 5 */
+ cnt = 2;
+ ln_off = cnt * ln;
+ ip = &pd->strength[ln_off];
+ off = 0x38;
+ for (j = 0; j < cnt; j++, off += 4)
+ MIPI_OUTP(base + off, *ip++);
+
+ /* vreg ctrl, 1 * 5 */
+ cnt = 1;
+ ln_off = cnt * ln;
+ ip = &pd->regulator[ln_off];
+ off = 0x64;
+ for (j = 0; j < cnt; j++, off += 4)
+ MIPI_OUTP(base + off, *ip++);
+ }
+
+ wmb(); /* make sure registers committed */
+
+ /* reset digital block */
+ MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_CTRL_1, 0x80);
+ udelay(100);
+ MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_CTRL_1, 0x00);
+
+ if (mdss_dsi_sync_wait_enable(ctrl)) {
+ if (mdss_dsi_is_left_ctrl(ctrl))
+ mdss_dsi_thulium_pll_source_from_left(ctrl);
+ else
+ mdss_dsi_thulium_pll_source_from_right(ctrl);
+ } else {
+ mdss_dsi_thulium_pll_source_standalone(ctrl);
+ }
+
+ wmb(); /* make sure registers committed */
+}
+
static void mdss_dsi_20nm_phy_init(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
if (!ctrl_pdata) {
@@ -343,20 +536,34 @@ static void mdss_dsi_20nm_phy_init(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
mdss_dsi_20nm_phy_config(ctrl_pdata);
}
-static void mdss_dsi_phy_init(struct mdss_dsi_ctrl_pdata *ctrl)
+static void mdss_dsi_thulium_phy_init(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
- u32 ctrl_rev;
+ if (!ctrl_pdata) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return;
+ }
+
+ mdss_dsi_thulium_phy_config(ctrl_pdata);
+}
+static void mdss_dsi_phy_init(struct mdss_dsi_ctrl_pdata *ctrl)
+{
if (!ctrl) {
pr_err("%s: Invalid input data\n", __func__);
return;
}
- ctrl_rev = MIPI_INP(ctrl->ctrl_base);
- if (ctrl_rev == MDSS_DSI_HW_REV_103)
+ switch (ctrl->hw_rev) {
+ case MDSS_DSI_HW_REV_104:
+ mdss_dsi_thulium_phy_init(ctrl);
+ break;
+ case MDSS_DSI_HW_REV_103:
mdss_dsi_20nm_phy_init(ctrl);
- else
+ break;
+ default:
mdss_dsi_28nm_phy_init(ctrl);
+ break;
+ }
}
int mdss_dsi_clk_init(struct platform_device *pdev,