From bd37954d5dc32ba1ddaa521fcc5579a683d370bb Mon Sep 17 00:00:00 2001 From: Aravind Venkateswaran Date: Fri, 22 May 2015 15:36:27 -0700 Subject: [PATCH] msm: ndss: dsi: fix PLL source configuration for branch clocks The PLL source for the DSI clocks can be specified using the pll_src_config DTSI binding. However, this binding is optional and whenever it is not specified, the default configuration should be programmed based on the underlying hardware configuration. If the hardware configuration is split-dsi, then both branches should source from the same PLL, otherwise they should source from their corresponding PLLs. Change-Id: Idc1c003fede7440bad10311fe1f3bc44cc627053 Signed-off-by: Aravind Venkateswaran --- drivers/video/fbdev/msm/mdss_dsi.c | 68 +++++++++++++++++++++--------- drivers/video/fbdev/msm/mdss_dsi.h | 32 ++++++++++++-- 2 files changed, 77 insertions(+), 23 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index ceb25b1224bc..0012c00a9067 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -59,7 +59,29 @@ static void mdss_dsi_config_clk_src(struct platform_device *pdev) return; } - if (!mdss_dsi_is_hw_config_dual(sdata)) { + if (mdss_dsi_is_pll_src_default(sdata)) { + /* + * Default Mapping: + * 1. dual-dsi/single-dsi: + * DSI0 <--> PLL0 + * DSI1 <--> PLL1 + * 2. split-dsi: + * DSI0 <--> PLL0 + * DSI1 <--> PLL0 + */ + sdata->byte0_parent = sdata->ext_byte0_clk; + sdata->pixel0_parent = sdata->ext_pixel0_clk; + + if (mdss_dsi_is_hw_config_split(sdata)) { + sdata->byte1_parent = sdata->byte0_parent; + sdata->pixel1_parent = sdata->pixel0_parent; + } else { + sdata->byte1_parent = sdata->ext_byte1_clk; + sdata->pixel1_parent = sdata->ext_pixel1_clk; + } + pr_debug("%s: default: DSI0 <--> PLL0, DSI1 <--> %s", __func__, + mdss_dsi_is_hw_config_split(sdata) ? "PLL0" : "PLL1"); + } else { /* * For split-dsi and single-dsi use cases, map the PLL source * based on the pll source configuration. It is possible that @@ -72,25 +94,13 @@ static void mdss_dsi_config_clk_src(struct platform_device *pdev) pr_debug("%s: single source: PLL0", __func__); sdata->byte0_parent = sdata->ext_byte0_clk; sdata->pixel0_parent = sdata->ext_pixel0_clk; - } else { + } else if (mdss_dsi_is_pll_src_pll1(sdata)) { pr_debug("%s: single source: PLL1", __func__); sdata->byte0_parent = sdata->ext_byte1_clk; sdata->pixel0_parent = sdata->ext_pixel1_clk; } sdata->byte1_parent = sdata->byte0_parent; sdata->pixel1_parent = sdata->pixel0_parent; - } else { - /* - * For dual-dsi use cases, map: - * DSI0 <--> PLL0 - * DSI1 <--> PLL1 - */ - pr_debug("%s: dual-dsi: DSI0 <--> PLL0, DSI1 <--> PLL1", - __func__); - sdata->byte0_parent = sdata->ext_byte0_clk; - sdata->byte1_parent = sdata->ext_byte1_clk; - sdata->pixel0_parent = sdata->ext_pixel0_clk; - sdata->pixel1_parent = sdata->ext_pixel1_clk; } return; @@ -2284,6 +2294,12 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) disable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); } pr_debug("%s: Dsi Ctrl->%d initialized\n", __func__, index); + + if (index == 0) + ctrl_pdata->shared_data->dsi0_active = true; + else + ctrl_pdata->shared_data->dsi1_active = true; + return 0; error_pan_node: @@ -2499,7 +2515,7 @@ static void mdss_dsi_parse_pll_src_cfg(struct platform_device *pdev) const char *data; struct dsi_shared_data *sdata = mdss_dsi_res->shared_data; - sdata->pll_src_config = PLL_SRC_0; + sdata->pll_src_config = PLL_SRC_DEFAULT; data = of_get_property(pdev->dev.of_node, "pll-src-config", NULL); if (data) { if (!strcmp(data, "PLL0")) @@ -2507,11 +2523,10 @@ static void mdss_dsi_parse_pll_src_cfg(struct platform_device *pdev) else if (!strcmp(data, "PLL1")) sdata->pll_src_config = PLL_SRC_1; else - pr_err("%s: invalid pll src config %s. Using PLL_SRC_0 as default\n", + pr_err("%s: invalid pll src config %s\n", __func__, data); } else { - pr_debug("%s: PLL src config not present. Using PLL0 by default\n", - __func__); + pr_debug("%s: PLL src config not specified\n", __func__); } pr_debug("%s: pll_src_config = %d", __func__, sdata->pll_src_config); @@ -2531,7 +2546,6 @@ static int mdss_dsi_validate_pll_src_config(struct dsi_shared_data *sdata) * - For single dsi, it is not possible to source the clocks for * DSI0 from PLL1. */ - if (mdss_dsi_is_hw_config_split(sdata) && mdss_dsi_is_pll_src_pll1(sdata)) { pr_err("%s: unsupported PLL config: using PLL1 for split-dsi\n", @@ -2540,7 +2554,21 @@ static int mdss_dsi_validate_pll_src_config(struct dsi_shared_data *sdata) goto error; } - /* todo: enforce remaining checks */ + if (mdss_dsi_is_hw_config_dual(sdata) && + !mdss_dsi_is_pll_src_default(sdata)) { + pr_debug("%s: pll src config not applicable for dual-dsi\n", + __func__); + sdata->pll_src_config = PLL_SRC_DEFAULT; + } + + if (mdss_dsi_is_hw_config_single(sdata) && + mdss_dsi_is_dsi0_active(sdata) && + mdss_dsi_is_pll_src_pll1(sdata)) { + pr_err("%s: unsupported PLL config: using PLL1 for DSI1\n", + __func__); + rc = -EINVAL; + goto error; + } error: return rc; diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 05148337e762..2600590a24af 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -228,6 +228,8 @@ struct dsi_shared_data { bool timing_db_mode; bool cmd_clk_ln_recovery_en; + bool dsi0_active; + bool dsi1_active; /* DSI bus clocks */ struct clk *mdp_core_clk; @@ -284,6 +286,7 @@ enum mdss_dsi_hw_config { * @PLL_SRC_1: The link clocks are sourced out of PLL1. */ enum mdss_dsi_pll_src_config { + PLL_SRC_DEFAULT, PLL_SRC_0, PLL_SRC_1, }; @@ -594,11 +597,24 @@ static inline bool mdss_dsi_is_hw_config_dual(struct dsi_shared_data *sdata) return mdss_dsi_get_hw_config(sdata) == DUAL_DSI; } -static inline u32 mdss_dsi_get_pll_src_config(struct dsi_shared_data *sdata) +static inline bool mdss_dsi_get_pll_src_config(struct dsi_shared_data *sdata) { return sdata->pll_src_config; } +/* + * mdss_dsi_is_pll_src_default: Check if the DSI device uses default PLL src + * For single-dsi and dual-dsi configuration, PLL source need not be + * explicitly specified. In this case, the default PLL source configuration + * is assumed. + * + * @sdata: pointer to DSI shared data structure + */ +static inline bool mdss_dsi_is_pll_src_default(struct dsi_shared_data *sdata) +{ + return sdata->pll_src_config == PLL_SRC_DEFAULT; +} + /* * mdss_dsi_is_pll_src_pll0: Check if the PLL source for a DSI device is PLL0 * The function is only valid if the DSI configuration is single/split DSI. @@ -606,7 +622,7 @@ static inline u32 mdss_dsi_get_pll_src_config(struct dsi_shared_data *sdata) * * @sdata: pointer to DSI shared data structure */ -static inline u32 mdss_dsi_is_pll_src_pll0(struct dsi_shared_data *sdata) +static inline bool mdss_dsi_is_pll_src_pll0(struct dsi_shared_data *sdata) { return sdata->pll_src_config == PLL_SRC_0; } @@ -618,11 +634,21 @@ static inline u32 mdss_dsi_is_pll_src_pll0(struct dsi_shared_data *sdata) * * @sdata: pointer to DSI shared data structure */ -static inline u32 mdss_dsi_is_pll_src_pll1(struct dsi_shared_data *sdata) +static inline bool mdss_dsi_is_pll_src_pll1(struct dsi_shared_data *sdata) { return sdata->pll_src_config == PLL_SRC_1; } +static inline bool mdss_dsi_is_dsi0_active(struct dsi_shared_data *sdata) +{ + return sdata->dsi0_active; +} + +static inline bool mdss_dsi_is_dsi1_active(struct dsi_shared_data *sdata) +{ + return sdata->dsi1_active; +} + static inline bool mdss_dsi_sync_wait_enable(struct mdss_dsi_ctrl_pdata *ctrl) { return ctrl->cmd_sync_wait_broadcast;