Re: [v5 3/3] drm/msm/dsi: Add 10nm dsi phy tuning configuration support

2022-01-31 Thread Dmitry Baryshkov

On 30/01/2022 23:15, Rajeev Nandan wrote:

The clock and data lanes of the DSI PHY have a calibration circuitry
feature. As per the MSM DSI PHY tuning guidelines, the drive strength
tuning can be done by adjusting rescode offset for hstop/hsbot, and
the drive level tuning can be done by adjusting the LDO output level
for the HSTX drive.

Signed-off-by: Rajeev Nandan 


Reviewed-by: Dmitry Baryshkov 


---

Changes in v2:
  - Split into generic code and 10nm-specific part (Dmitry Baryshkov)
  - Fix the backward compatibility (Dmitry Baryshkov)

Changes in v3:
  - Address comments for phy tuning data structure (Dmitry Baryshkov)
  - Make changes as per updated dt-bindings

Changes in v4:
  - Return error in case of out of range values (Dmitry Baryshkov)
  - Return error if dt property is present but parsing is failing

Changes in v5:
  - Added missing printk arg ldo_level


  drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c | 118 +++--
  1 file changed, 112 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c 
b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
index d8128f5..86a6954 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
@@ -83,6 +83,18 @@ struct dsi_pll_10nm {
  
  #define to_pll_10nm(x)	container_of(x, struct dsi_pll_10nm, clk_hw)
  
+/**

+ * struct dsi_phy_10nm_tuning_cfg - Holds 10nm PHY tuning config parameters.
+ * @rescode_offset_top: Offset for pull-up legs rescode.
+ * @rescode_offset_bot: Offset for pull-down legs rescode.
+ * @vreg_ctrl: vreg ctrl to drive LDO level
+ */
+struct dsi_phy_10nm_tuning_cfg {
+   u8 rescode_offset_top[DSI_LANE_MAX];
+   u8 rescode_offset_bot[DSI_LANE_MAX];
+   u8 vreg_ctrl;
+};
+
  /*
   * Global list of private DSI PLL struct pointers. We need this for bonded DSI
   * mode, where the master PLL's clk_ops needs access the slave's private data
@@ -747,6 +759,7 @@ static void dsi_phy_hw_v3_0_lane_settings(struct 
msm_dsi_phy *phy)
int i;
u8 tx_dctrl[] = { 0x00, 0x00, 0x00, 0x04, 0x01 };
void __iomem *lane_base = phy->lane_base;
+   struct dsi_phy_10nm_tuning_cfg *tuning_cfg = phy->tuning_cfg;
  
  	if (phy->cfg->quirks & DSI_PHY_10NM_QUIRK_OLD_TIMINGS)

tx_dctrl[3] = 0x02;
@@ -775,10 +788,13 @@ static void dsi_phy_hw_v3_0_lane_settings(struct 
msm_dsi_phy *phy)
dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG2(i), 0x0);
dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG3(i),
  i == 4 ? 0x80 : 0x0);
-   dsi_phy_write(lane_base +
- REG_DSI_10nm_PHY_LN_OFFSET_TOP_CTRL(i), 0x0);
-   dsi_phy_write(lane_base +
- REG_DSI_10nm_PHY_LN_OFFSET_BOT_CTRL(i), 0x0);
+
+   /* platform specific dsi phy drive strength adjustment */
+   dsi_phy_write(lane_base + 
REG_DSI_10nm_PHY_LN_OFFSET_TOP_CTRL(i),
+   tuning_cfg->rescode_offset_top[i]);
+   dsi_phy_write(lane_base + 
REG_DSI_10nm_PHY_LN_OFFSET_BOT_CTRL(i),
+   tuning_cfg->rescode_offset_bot[i]);
+
dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(i),
  tx_dctrl[i]);
}
@@ -799,6 +815,7 @@ static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy,
u32 const timeout_us = 1000;
struct msm_dsi_dphy_timing *timing = >timing;
void __iomem *base = phy->base;
+   struct dsi_phy_10nm_tuning_cfg *tuning_cfg = phy->tuning_cfg;
u32 data;
  
  	DBG("");

@@ -834,8 +851,9 @@ static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy,
/* Select MS1 byte-clk */
dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_GLBL_CTRL, 0x10);
  
-	/* Enable LDO */

-   dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_VREG_CTRL, 0x59);
+   /* Enable LDO with platform specific drive level/amplitude adjustment */
+   dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_VREG_CTRL,
+ tuning_cfg->vreg_ctrl);
  
  	/* Configure PHY lane swap (TODO: we need to calculate this) */

dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CFG0, 0x21);
@@ -922,6 +940,92 @@ static void dsi_10nm_phy_disable(struct msm_dsi_phy *phy)
DBG("DSI%d PHY disabled", phy->id);
  }
  
+static int dsi_10nm_phy_parse_dt(struct msm_dsi_phy *phy)

+{
+   struct device *dev = >pdev->dev;
+   struct dsi_phy_10nm_tuning_cfg *tuning_cfg;
+   s8 offset_top[DSI_LANE_MAX] = { 0 }; /* No offset */
+   s8 offset_bot[DSI_LANE_MAX] = { 0 }; /* No offset */
+   u32 ldo_level = 400; /* 400mV */
+   u8 level;
+   int ret, i;
+
+   tuning_cfg = devm_kzalloc(dev, sizeof(*tuning_cfg), GFP_KERNEL);
+   if (!tuning_cfg)
+   return -ENOMEM;
+
+   /* Drive strength adjustment parameters */
+   ret = of_property_read_u8_array(dev->of_node, 

[v5 3/3] drm/msm/dsi: Add 10nm dsi phy tuning configuration support

2022-01-30 Thread Rajeev Nandan
The clock and data lanes of the DSI PHY have a calibration circuitry
feature. As per the MSM DSI PHY tuning guidelines, the drive strength
tuning can be done by adjusting rescode offset for hstop/hsbot, and
the drive level tuning can be done by adjusting the LDO output level
for the HSTX drive.

Signed-off-by: Rajeev Nandan 
---

Changes in v2:
 - Split into generic code and 10nm-specific part (Dmitry Baryshkov)
 - Fix the backward compatibility (Dmitry Baryshkov)

Changes in v3:
 - Address comments for phy tuning data structure (Dmitry Baryshkov)
 - Make changes as per updated dt-bindings

Changes in v4:
 - Return error in case of out of range values (Dmitry Baryshkov)
 - Return error if dt property is present but parsing is failing

Changes in v5:
 - Added missing printk arg ldo_level


 drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c | 118 +++--
 1 file changed, 112 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c 
b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
index d8128f5..86a6954 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
@@ -83,6 +83,18 @@ struct dsi_pll_10nm {
 
 #define to_pll_10nm(x) container_of(x, struct dsi_pll_10nm, clk_hw)
 
+/**
+ * struct dsi_phy_10nm_tuning_cfg - Holds 10nm PHY tuning config parameters.
+ * @rescode_offset_top: Offset for pull-up legs rescode.
+ * @rescode_offset_bot: Offset for pull-down legs rescode.
+ * @vreg_ctrl: vreg ctrl to drive LDO level
+ */
+struct dsi_phy_10nm_tuning_cfg {
+   u8 rescode_offset_top[DSI_LANE_MAX];
+   u8 rescode_offset_bot[DSI_LANE_MAX];
+   u8 vreg_ctrl;
+};
+
 /*
  * Global list of private DSI PLL struct pointers. We need this for bonded DSI
  * mode, where the master PLL's clk_ops needs access the slave's private data
@@ -747,6 +759,7 @@ static void dsi_phy_hw_v3_0_lane_settings(struct 
msm_dsi_phy *phy)
int i;
u8 tx_dctrl[] = { 0x00, 0x00, 0x00, 0x04, 0x01 };
void __iomem *lane_base = phy->lane_base;
+   struct dsi_phy_10nm_tuning_cfg *tuning_cfg = phy->tuning_cfg;
 
if (phy->cfg->quirks & DSI_PHY_10NM_QUIRK_OLD_TIMINGS)
tx_dctrl[3] = 0x02;
@@ -775,10 +788,13 @@ static void dsi_phy_hw_v3_0_lane_settings(struct 
msm_dsi_phy *phy)
dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG2(i), 0x0);
dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG3(i),
  i == 4 ? 0x80 : 0x0);
-   dsi_phy_write(lane_base +
- REG_DSI_10nm_PHY_LN_OFFSET_TOP_CTRL(i), 0x0);
-   dsi_phy_write(lane_base +
- REG_DSI_10nm_PHY_LN_OFFSET_BOT_CTRL(i), 0x0);
+
+   /* platform specific dsi phy drive strength adjustment */
+   dsi_phy_write(lane_base + 
REG_DSI_10nm_PHY_LN_OFFSET_TOP_CTRL(i),
+   tuning_cfg->rescode_offset_top[i]);
+   dsi_phy_write(lane_base + 
REG_DSI_10nm_PHY_LN_OFFSET_BOT_CTRL(i),
+   tuning_cfg->rescode_offset_bot[i]);
+
dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(i),
  tx_dctrl[i]);
}
@@ -799,6 +815,7 @@ static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy,
u32 const timeout_us = 1000;
struct msm_dsi_dphy_timing *timing = >timing;
void __iomem *base = phy->base;
+   struct dsi_phy_10nm_tuning_cfg *tuning_cfg = phy->tuning_cfg;
u32 data;
 
DBG("");
@@ -834,8 +851,9 @@ static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy,
/* Select MS1 byte-clk */
dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_GLBL_CTRL, 0x10);
 
-   /* Enable LDO */
-   dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_VREG_CTRL, 0x59);
+   /* Enable LDO with platform specific drive level/amplitude adjustment */
+   dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_VREG_CTRL,
+ tuning_cfg->vreg_ctrl);
 
/* Configure PHY lane swap (TODO: we need to calculate this) */
dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CFG0, 0x21);
@@ -922,6 +940,92 @@ static void dsi_10nm_phy_disable(struct msm_dsi_phy *phy)
DBG("DSI%d PHY disabled", phy->id);
 }
 
+static int dsi_10nm_phy_parse_dt(struct msm_dsi_phy *phy)
+{
+   struct device *dev = >pdev->dev;
+   struct dsi_phy_10nm_tuning_cfg *tuning_cfg;
+   s8 offset_top[DSI_LANE_MAX] = { 0 }; /* No offset */
+   s8 offset_bot[DSI_LANE_MAX] = { 0 }; /* No offset */
+   u32 ldo_level = 400; /* 400mV */
+   u8 level;
+   int ret, i;
+
+   tuning_cfg = devm_kzalloc(dev, sizeof(*tuning_cfg), GFP_KERNEL);
+   if (!tuning_cfg)
+   return -ENOMEM;
+
+   /* Drive strength adjustment parameters */
+   ret = of_property_read_u8_array(dev->of_node, 
"qcom,phy-rescode-offset-top",
+   offset_top, DSI_LANE_MAX);