diff options
-rw-r--r-- | Documentation/devicetree/bindings/fb/mdss-dsi.txt | 22 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.c | 137 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.h | 49 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_host.c | 17 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_phy_v3.c | 12 |
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 */ |