msm: mdss: dsi: configure data lane swap for newer hw revisions

Starting with DSI PHY hardware revisions 3.0 and above, data lane swap
configurations need to be programmed via the DSI PHY interface. In other
cases, a new register interface has been introduced to program the lane
swap configuration for DSI controller revision 2.0 and above. Refactor
the existing implementation to account for these hardware changes.

Change-Id: I3772c614bfee0ed13f30a38535bb814158d23226
Signed-off-by: Aravind Venkateswaran <aravindh@codeaurora.org>
This commit is contained in:
Aravind Venkateswaran 2016-06-14 17:38:17 -07:00 committed by Kyle Yan
parent 195ae4dadc
commit d7a02e724c
5 changed files with 217 additions and 24 deletions

View file

@ -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.

View file

@ -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)
{
const char *data;
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;
}
*dlane_swap = DSI_LANE_MAP_0123;
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;
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;
}
/* Check if an older version of the binding is present */
data = of_get_property(np, "qcom,lane-map", NULL);
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");

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */