summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/fb/mdss-dsi.txt22
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c137
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h49
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_host.c17
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_phy_v3.c12
5 files changed, 215 insertions, 22 deletions
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi.txt b/Documentation/devicetree/bindings/fb/mdss-dsi.txt
index 4aeabcdd45b1..31994cf28b27 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi.txt
@@ -125,6 +125,28 @@ Optional properties:
"lane_map_1032" = <1 0 3 2>
"lane_map_2103" = <2 1 0 3>
"lane_map_3210" = <3 2 1 0>
+ where lane_map_ABCD means:
+ Logical_Lane_A = Physical_Lane_0
+ Logical_Lane_B = Physical_Lane_1
+ Logical_Lane_C = Physical_Lane_2
+ Logical_Lane_D = Physical_Lane_3
+ The lane map can vary between multiple instances
+ of the DSI controller and should be set accordingly in all
+ of them based on the board configuration.
+- qcom,lane-map-v2: An array of size 4 uint8s specifying the corresponding
+ mapping for each of the logical data lanes.
+ For example, a value of <A B C D> means
+ Logical_Lane_0 = Physical_Lane_A
+ Logical_Lane_1 = Physical_Lane_B
+ Logical_Lane_2 = Physical_Lane_C
+ Logical_Lane_3 = Physical_Lane_D
+ The default lane mapping is <0 1 2 3>.
+ Since the values are of type uint8, they need to be
+ specified as below:
+ qcom,lane-map-v2 = /bits/ 8 <0 1 2 3>
+ This binding supersedes qcom,lane-map binding and will
+ override any lane swap setting specified by qcom,lane-map.
+ Refer to qcom,lane-map for additional notes.
- qcom,pluggable Boolean to enable hotplug feature.
- qcom,timing-db-mode: Boolean specifies dsi timing mode registers are supported or not.
- qcom,display-id A string indicates the display ID for the controller.
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index 054f48fa0005..8f1ab774044d 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -3037,10 +3037,32 @@ end:
return rc;
}
+static void mdss_dsi_ctrl_validate_lane_swap_config(
+ struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct mipi_panel_info *mipi = &ctrl->panel_data.panel_info.mipi;
+
+ if (!mipi->data_lane0)
+ ctrl->lane_map[DSI_LOGICAL_LANE_0] = DSI_PHYSICAL_LANE_INVALID;
+ if (!mipi->data_lane1)
+ ctrl->lane_map[DSI_LOGICAL_LANE_1] = DSI_PHYSICAL_LANE_INVALID;
+ if (!mipi->data_lane2)
+ ctrl->lane_map[DSI_LOGICAL_LANE_2] = DSI_PHYSICAL_LANE_INVALID;
+ if (!mipi->data_lane3)
+ ctrl->lane_map[DSI_LOGICAL_LANE_3] = DSI_PHYSICAL_LANE_INVALID;
+}
+
static int mdss_dsi_ctrl_validate_config(struct mdss_dsi_ctrl_pdata *ctrl)
{
int rc = 0;
+ if (!ctrl) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ mdss_dsi_ctrl_validate_lane_swap_config(ctrl);
+
/*
* check to make sure that the byte interface clock is specified for
* DSI ctrl version 2 and above.
@@ -3052,6 +3074,7 @@ static int mdss_dsi_ctrl_validate_config(struct mdss_dsi_ctrl_pdata *ctrl)
rc = -EINVAL;
}
+error:
return rc;
}
@@ -3807,28 +3830,105 @@ static int mdss_dsi_irq_init(struct device *dev, int irq_no,
return ret;
}
-static void mdss_dsi_parse_lane_swap(struct device_node *np, char *dlane_swap)
+static void __set_lane_map(struct mdss_dsi_ctrl_pdata *ctrl,
+ enum dsi_physical_lane_id lane0,
+ enum dsi_physical_lane_id lane1,
+ enum dsi_physical_lane_id lane2,
+ enum dsi_physical_lane_id lane3)
+{
+ ctrl->lane_map[DSI_LOGICAL_LANE_0] = lane0;
+ ctrl->lane_map[DSI_LOGICAL_LANE_1] = lane1;
+ ctrl->lane_map[DSI_LOGICAL_LANE_2] = lane2;
+ ctrl->lane_map[DSI_LOGICAL_LANE_3] = lane3;
+}
+
+static void mdss_dsi_parse_lane_swap(struct device_node *np,
+ struct mdss_dsi_ctrl_pdata *ctrl)
{
+ int rc;
const char *data;
+ u8 temp[DSI_LOGICAL_LANE_MAX];
+ int i;
+
+ /* First, check for the newer version of the binding */
+ rc = of_property_read_u8_array(np, "qcom,lane-map-v2", temp,
+ DSI_LOGICAL_LANE_MAX);
+ if (!rc) {
+ for (i = DSI_LOGICAL_LANE_0; i < DSI_LOGICAL_LANE_MAX; i++)
+ ctrl->lane_map[i] = BIT(temp[i]);
+ return;
+ } else if (rc != -EINVAL) {
+ pr_warn("%s: invalid lane map specfied. Defaulting to <0 1 2 3>\n",
+ __func__);
+ goto set_default;
+ }
- *dlane_swap = DSI_LANE_MAP_0123;
+ /* Check if an older version of the binding is present */
data = of_get_property(np, "qcom,lane-map", NULL);
- if (data) {
- if (!strcmp(data, "lane_map_3012"))
- *dlane_swap = DSI_LANE_MAP_3012;
- else if (!strcmp(data, "lane_map_2301"))
- *dlane_swap = DSI_LANE_MAP_2301;
- else if (!strcmp(data, "lane_map_1230"))
- *dlane_swap = DSI_LANE_MAP_1230;
- else if (!strcmp(data, "lane_map_0321"))
- *dlane_swap = DSI_LANE_MAP_0321;
- else if (!strcmp(data, "lane_map_1032"))
- *dlane_swap = DSI_LANE_MAP_1032;
- else if (!strcmp(data, "lane_map_2103"))
- *dlane_swap = DSI_LANE_MAP_2103;
- else if (!strcmp(data, "lane_map_3210"))
- *dlane_swap = DSI_LANE_MAP_3210;
+ if (!data)
+ goto set_default;
+
+ if (!strcmp(data, "lane_map_3012")) {
+ ctrl->dlane_swap = DSI_LANE_MAP_3012;
+ __set_lane_map(ctrl,
+ DSI_PHYSICAL_LANE_1,
+ DSI_PHYSICAL_LANE_2,
+ DSI_PHYSICAL_LANE_3,
+ DSI_PHYSICAL_LANE_0);
+ } else if (!strcmp(data, "lane_map_2301")) {
+ ctrl->dlane_swap = DSI_LANE_MAP_2301;
+ __set_lane_map(ctrl,
+ DSI_PHYSICAL_LANE_2,
+ DSI_PHYSICAL_LANE_3,
+ DSI_PHYSICAL_LANE_0,
+ DSI_PHYSICAL_LANE_1);
+ } else if (!strcmp(data, "lane_map_1230")) {
+ ctrl->dlane_swap = DSI_LANE_MAP_1230;
+ __set_lane_map(ctrl,
+ DSI_PHYSICAL_LANE_3,
+ DSI_PHYSICAL_LANE_0,
+ DSI_PHYSICAL_LANE_1,
+ DSI_PHYSICAL_LANE_2);
+ } else if (!strcmp(data, "lane_map_0321")) {
+ ctrl->dlane_swap = DSI_LANE_MAP_0321;
+ __set_lane_map(ctrl,
+ DSI_PHYSICAL_LANE_0,
+ DSI_PHYSICAL_LANE_3,
+ DSI_PHYSICAL_LANE_2,
+ DSI_PHYSICAL_LANE_1);
+ } else if (!strcmp(data, "lane_map_1032")) {
+ ctrl->dlane_swap = DSI_LANE_MAP_1032;
+ __set_lane_map(ctrl,
+ DSI_PHYSICAL_LANE_1,
+ DSI_PHYSICAL_LANE_0,
+ DSI_PHYSICAL_LANE_3,
+ DSI_PHYSICAL_LANE_2);
+ } else if (!strcmp(data, "lane_map_2103")) {
+ ctrl->dlane_swap = DSI_LANE_MAP_2103;
+ __set_lane_map(ctrl,
+ DSI_PHYSICAL_LANE_2,
+ DSI_PHYSICAL_LANE_1,
+ DSI_PHYSICAL_LANE_0,
+ DSI_PHYSICAL_LANE_3);
+ } else if (!strcmp(data, "lane_map_3210")) {
+ ctrl->dlane_swap = DSI_LANE_MAP_3210;
+ __set_lane_map(ctrl,
+ DSI_PHYSICAL_LANE_3,
+ DSI_PHYSICAL_LANE_2,
+ DSI_PHYSICAL_LANE_1,
+ DSI_PHYSICAL_LANE_0);
+ } else {
+ pr_warn("%s: invalid lane map %s specified. defaulting to lane_map0123\n",
+ __func__, data);
}
+
+ return;
+
+set_default:
+ /* default lane mapping */
+ __set_lane_map(ctrl, DSI_PHYSICAL_LANE_0, DSI_PHYSICAL_LANE_1,
+ DSI_PHYSICAL_LANE_2, DSI_PHYSICAL_LANE_3);
+ ctrl->dlane_swap = DSI_LANE_MAP_0123;
}
static int mdss_dsi_parse_ctrl_params(struct platform_device *ctrl_pdev,
@@ -3904,8 +4004,7 @@ static int mdss_dsi_parse_ctrl_params(struct platform_device *ctrl_pdev,
ctrl_pdata->cmd_sync_wait_broadcast,
ctrl_pdata->cmd_sync_wait_trigger);
- mdss_dsi_parse_lane_swap(ctrl_pdev->dev.of_node,
- &(ctrl_pdata->dlane_swap));
+ mdss_dsi_parse_lane_swap(ctrl_pdev->dev.of_node, ctrl_pdata);
pinfo->is_pluggable = of_property_read_bool(ctrl_pdev->dev.of_node,
"qcom,pluggable");
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index 6be44e070205..ecffc12ecd72 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -127,6 +127,22 @@ enum dsi_lane_map_type {
DSI_LANE_MAP_3210,
};
+enum dsi_logical_lane_id {
+ DSI_LOGICAL_LANE_0 = 0,
+ DSI_LOGICAL_LANE_1,
+ DSI_LOGICAL_LANE_2,
+ DSI_LOGICAL_LANE_3,
+ DSI_LOGICAL_LANE_MAX,
+};
+
+enum dsi_physical_lane_id {
+ DSI_PHYSICAL_LANE_INVALID = 0,
+ DSI_PHYSICAL_LANE_0 = BIT(0),
+ DSI_PHYSICAL_LANE_1 = BIT(1),
+ DSI_PHYSICAL_LANE_2 = BIT(2),
+ DSI_PHYSICAL_LANE_3 = BIT(3),
+};
+
enum dsi_pm_type {
/* PANEL_PM not used as part of power_data in dsi_shared_data */
DSI_PANEL_PM,
@@ -503,7 +519,17 @@ struct mdss_dsi_ctrl_pdata {
bool ulps;
bool core_power;
bool mmss_clamp;
- char dlane_swap; /* data lane swap */
+
+ /*
+ * Data lane swap (logical to physical lane map):
+ * dlane_swap: used for DSI controller versions < 2.0, where
+ * dlane_swap is of type enum dsi_lane_map_type
+ * lane_map: used for DSI controller versions > 2.0, where
+ * lane_map[logical_lane_id] = physical_lane_id
+ */
+ char dlane_swap;
+ uint8_t lane_map[DSI_LOGICAL_LANE_MAX];
+
bool is_phyreg_enabled;
bool burst_mode_enabled;
@@ -879,4 +905,25 @@ static inline bool mdss_dsi_cmp_panel_reg(struct dsi_buf status_buf,
return status_buf.data[i] == status_val[i];
}
+static inline enum dsi_logical_lane_id mdss_dsi_physical_to_logical_lane(
+ struct mdss_dsi_ctrl_pdata *ctrl, enum dsi_physical_lane_id id)
+{
+ int i;
+
+ for (i = DSI_LOGICAL_LANE_0; i < DSI_LOGICAL_LANE_MAX; i++)
+ if (ctrl->lane_map[i] == id)
+ break;
+
+ return i;
+}
+
+static inline enum dsi_physical_lane_id mdss_dsi_logical_to_physical_lane(
+ struct mdss_dsi_ctrl_pdata *ctrl, enum dsi_logical_lane_id id)
+{
+ if (id >= DSI_LOGICAL_LANE_MAX)
+ return DSI_PHYSICAL_LANE_INVALID;
+
+ return ctrl->lane_map[id];
+}
+
#endif /* MDSS_DSI_H */
diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c
index 39b014b90e28..3785a701e3c1 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -38,6 +38,8 @@
#define LANE_STATUS 0xA8
#define MDSS_DSI_INT_CTRL 0x0110
+#define LANE_SWAP_CTRL 0x0B0
+#define LOGICAL_LANE_SWAP_CTRL 0x310
struct mdss_dsi_ctrl_pdata *ctrl_list[DSI_CTRL_MAX];
@@ -303,6 +305,18 @@ void mdss_dsi_read_phy_revision(struct mdss_dsi_ctrl_pdata *ctrl)
ctrl->shared_data->phy_rev = DSI_PHY_REV_UNKNOWN;
}
+static void mdss_dsi_config_data_lane_swap(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ if (ctrl->shared_data->hw_rev < MDSS_DSI_HW_REV_200)
+ MIPI_OUTP((ctrl->ctrl_base) + LANE_SWAP_CTRL, ctrl->dlane_swap);
+ else
+ MIPI_OUTP(ctrl->ctrl_base + LOGICAL_LANE_SWAP_CTRL,
+ ctrl->lane_map[DSI_LOGICAL_LANE_0] |
+ ctrl->lane_map[DSI_LOGICAL_LANE_1] << 4 |
+ ctrl->lane_map[DSI_LOGICAL_LANE_2] << 8 |
+ ctrl->lane_map[DSI_LOGICAL_LANE_3] << 12);
+}
+
void mdss_dsi_host_init(struct mdss_panel_data *pdata)
{
u32 dsi_ctrl, intr_ctrl;
@@ -400,8 +414,7 @@ void mdss_dsi_host_init(struct mdss_panel_data *pdata)
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0084,
data); /* DSI_TRIG_CTRL */
- /* DSI_LAN_SWAP_CTRL */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x00b0, ctrl_pdata->dlane_swap);
+ mdss_dsi_config_data_lane_swap(ctrl_pdata);
/* clock out ctrl */
data = pinfo->t_clk_post & 0x3f; /* 6 bits */
diff --git a/drivers/video/fbdev/msm/mdss_dsi_phy_v3.c b/drivers/video/fbdev/msm/mdss_dsi_phy_v3.c
index 0c4dcf9db216..9f419c91661c 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_phy_v3.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_phy_v3.c
@@ -118,6 +118,16 @@ static void mdss_dsi_phy_v3_set_pll_source(
DSI_PHY_W32(ctrl->phy_io.base, CMN_CLK_CFG1, reg);
}
+static void mdss_dsi_phy_v3_lane_swap_config(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ DSI_PHY_W32(ctrl->phy_io.base, CMN_LANE_CFG0,
+ ctrl->lane_map[DSI_LOGICAL_LANE_0] |
+ ctrl->lane_map[DSI_LOGICAL_LANE_1] << 4);
+ DSI_PHY_W32(ctrl->phy_io.base, CMN_LANE_CFG1,
+ ctrl->lane_map[DSI_LOGICAL_LANE_2] |
+ ctrl->lane_map[DSI_LOGICAL_LANE_3] << 4);
+}
+
static void mdss_dsi_phy_v3_lanes_disable(struct mdss_dsi_ctrl_pdata *ctrl)
{
u32 data = DSI_PHY_R32(ctrl->phy_io.base, CMN_CTRL_0);
@@ -343,6 +353,8 @@ int mdss_dsi_phy_v3_init(struct mdss_dsi_ctrl_pdata *ctrl,
/* Enable LDO */
DSI_PHY_W32(ctrl->phy_io.base, CMN_VREG_CTRL, 0x59);
+ mdss_dsi_phy_v3_lane_swap_config(ctrl);
+
mdss_dsi_phy_v3_config_timings(ctrl);
/* Remove power down from all blocks */