diff options
Diffstat (limited to 'drivers/gpu/drm/msm/dsi')
-rw-r--r-- | drivers/gpu/drm/msm/dsi/dsi.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dsi/dsi.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dsi/dsi_cfg.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dsi/dsi_cfg.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dsi/dsi_host.c | 19 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dsi/dsi_manager.c | 149 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dsi/phy/dsi_phy.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c | 106 |
10 files changed, 217 insertions, 129 deletions
diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index ada942498b4e..55ea4bc2ee9c 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -242,6 +242,8 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, goto fail; } + msm_dsi_manager_setup_encoder(msm_dsi->id); + priv->bridges[priv->num_bridges++] = msm_dsi->bridge; priv->connectors[priv->num_connectors++] = msm_dsi->connector; diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index 20a5d3cb0cab..0da8a4e428ad 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -71,7 +71,6 @@ struct msm_dsi { */ struct drm_panel *panel; struct drm_bridge *external_bridge; - unsigned long device_flags; struct device *phy_dev; bool phy_enabled; @@ -89,7 +88,7 @@ struct drm_connector *msm_dsi_manager_connector_init(u8 id); struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id); int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg); bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len); -void msm_dsi_manager_attach_dsi_device(int id, u32 device_flags); +void msm_dsi_manager_setup_encoder(int id); int msm_dsi_manager_register(struct msm_dsi *msm_dsi); void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi); bool msm_dsi_manager_validate_current_config(u8 id); @@ -161,8 +160,8 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, int msm_dsi_host_power_off(struct mipi_dsi_host *host); int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host, const struct drm_display_mode *mode); -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host, - unsigned long *panel_flags); +struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host); +unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host); struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host); int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer); void msm_dsi_host_unregister(struct mipi_dsi_host *host); diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index 9ddf16380289..b7b7c1a9164a 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -110,6 +110,25 @@ static const struct msm_dsi_config msm8996_dsi_cfg = { .num_dsi = 2, }; +static const char * const dsi_msm8998_bus_clk_names[] = { + "iface", "bus", "core", +}; + +static const struct msm_dsi_config msm8998_dsi_cfg = { + .io_offset = DSI_6G_REG_SHIFT, + .reg_cfg = { + .num = 2, + .regs = { + {"vdd", 367000, 16 }, /* 0.9 V */ + {"vdda", 62800, 2 }, /* 1.2 V */ + }, + }, + .bus_clk_names = dsi_msm8998_bus_clk_names, + .num_bus_clks = ARRAY_SIZE(dsi_msm8998_bus_clk_names), + .io_start = { 0xc994000, 0xc996000 }, + .num_dsi = 2, +}; + static const char * const dsi_sdm845_bus_clk_names[] = { "iface", "bus", }; @@ -178,6 +197,8 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { &msm8916_dsi_cfg, &msm_dsi_6g_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_1, &msm8996_dsi_cfg, &msm_dsi_6g_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_0, + &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, &sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops}, }; diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h index a6a3d2bad263..e2b7a7dfbe49 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h @@ -17,6 +17,7 @@ #define MSM_DSI_6G_VER_MINOR_V1_3 0x10030000 #define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001 #define MSM_DSI_6G_VER_MINOR_V1_4_1 0x10040001 +#define MSM_DSI_6G_VER_MINOR_V2_2_0 0x20000000 #define MSM_DSI_6G_VER_MINOR_V2_2_1 0x20020001 #define MSM_DSI_V2_VER_MINOR_8064 0x0 diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index dbf490176c2c..aa35d18ab43c 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1041,7 +1041,7 @@ static void dsi_wait4video_done(struct msm_dsi_host *msm_host) ret = wait_for_completion_timeout(&msm_host->video_comp, msecs_to_jiffies(70)); - if (ret <= 0) + if (ret == 0) DRM_DEV_ERROR(dev, "wait for video done timed out\n"); dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_VIDEO_DONE, 0); @@ -1590,8 +1590,6 @@ static int dsi_host_attach(struct mipi_dsi_host *host, msm_host->format = dsi->format; msm_host->mode_flags = dsi->mode_flags; - msm_dsi_manager_attach_dsi_device(msm_host->id, dsi->mode_flags); - /* Some gpios defined in panel DT need to be controlled by host */ ret = dsi_host_init_panel_gpios(msm_host, &dsi->dev); if (ret) @@ -2434,17 +2432,14 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host, return 0; } -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host, - unsigned long *panel_flags) +struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host) { - struct msm_dsi_host *msm_host = to_msm_dsi_host(host); - struct drm_panel *panel; - - panel = of_drm_find_panel(msm_host->device_node); - if (panel_flags) - *panel_flags = msm_host->mode_flags; + return of_drm_find_panel(to_msm_dsi_host(host)->device_node); +} - return panel; +unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host) +{ + return to_msm_dsi_host(host)->mode_flags; } struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host) diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index ec6cb0f7f206..271aa7bbca92 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -225,64 +225,80 @@ static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge) return dsi_bridge->id; } -static enum drm_connector_status dsi_mgr_connector_detect( - struct drm_connector *connector, bool force) +static bool dsi_mgr_is_cmd_mode(struct msm_dsi *msm_dsi) +{ + unsigned long host_flags = msm_dsi_host_get_mode_flags(msm_dsi->host); + return !(host_flags & MIPI_DSI_MODE_VIDEO); +} + +void msm_dsi_manager_setup_encoder(int id) { - int id = dsi_mgr_connector_get_id(connector); struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); - struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id); - struct msm_drm_private *priv = connector->dev->dev_private; + struct msm_drm_private *priv = msm_dsi->dev->dev_private; struct msm_kms *kms = priv->kms; + struct drm_encoder *encoder = msm_dsi_get_encoder(msm_dsi); - DBG("id=%d", id); - if (!msm_dsi->panel) { - msm_dsi->panel = msm_dsi_host_get_panel(msm_dsi->host, - &msm_dsi->device_flags); - - /* There is only 1 panel in the global panel list - * for dual DSI mode. Therefore slave dsi should get - * the drm_panel instance from master dsi, and - * keep using the panel flags got from the current DSI link. - */ - if (!msm_dsi->panel && IS_DUAL_DSI() && - !IS_MASTER_DSI_LINK(id) && other_dsi) - msm_dsi->panel = msm_dsi_host_get_panel( - other_dsi->host, NULL); + if (encoder && kms->funcs->set_encoder_mode) + kms->funcs->set_encoder_mode(kms, encoder, + dsi_mgr_is_cmd_mode(msm_dsi)); +} +static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id) +{ + struct msm_drm_private *priv = conn->dev->dev_private; + struct msm_kms *kms = priv->kms; + struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); + struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id); + struct msm_dsi *master_dsi, *slave_dsi; + struct drm_panel *panel; - if (msm_dsi->panel && kms->funcs->set_encoder_mode) { - bool cmd_mode = !(msm_dsi->device_flags & - MIPI_DSI_MODE_VIDEO); - struct drm_encoder *encoder = - msm_dsi_get_encoder(msm_dsi); + if (IS_DUAL_DSI() && !IS_MASTER_DSI_LINK(id)) { + master_dsi = other_dsi; + slave_dsi = msm_dsi; + } else { + master_dsi = msm_dsi; + slave_dsi = other_dsi; + } - kms->funcs->set_encoder_mode(kms, encoder, cmd_mode); - } + /* + * There is only 1 panel in the global panel list for dual DSI mode. + * Therefore slave dsi should get the drm_panel instance from master + * dsi. + */ + panel = msm_dsi_host_get_panel(master_dsi->host); + if (IS_ERR(panel)) { + DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id, + PTR_ERR(panel)); + return PTR_ERR(panel); + } - if (msm_dsi->panel && IS_DUAL_DSI()) - drm_object_attach_property(&connector->base, - connector->dev->mode_config.tile_property, 0); + if (!panel || !IS_DUAL_DSI()) + goto out; - /* Set split display info to kms once dual DSI panel is - * connected to both hosts. - */ - if (msm_dsi->panel && IS_DUAL_DSI() && - other_dsi && other_dsi->panel) { - bool cmd_mode = !(msm_dsi->device_flags & - MIPI_DSI_MODE_VIDEO); - struct drm_encoder *encoder = msm_dsi_get_encoder( - dsi_mgr_get_dsi(DSI_ENCODER_MASTER)); - struct drm_encoder *slave_enc = msm_dsi_get_encoder( - dsi_mgr_get_dsi(DSI_ENCODER_SLAVE)); - - if (kms->funcs->set_split_display) - kms->funcs->set_split_display(kms, encoder, - slave_enc, cmd_mode); - else - pr_err("mdp does not support dual DSI\n"); - } + drm_object_attach_property(&conn->base, + conn->dev->mode_config.tile_property, 0); + + /* + * Set split display info to kms once dual DSI panel is connected to + * both hosts. + */ + if (other_dsi && other_dsi->panel && kms->funcs->set_split_display) { + kms->funcs->set_split_display(kms, master_dsi->encoder, + slave_dsi->encoder, + dsi_mgr_is_cmd_mode(msm_dsi)); } +out: + msm_dsi->panel = panel; + return 0; +} + +static enum drm_connector_status dsi_mgr_connector_detect( + struct drm_connector *connector, bool force) +{ + int id = dsi_mgr_connector_get_id(connector); + struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); + return msm_dsi->panel ? connector_status_connected : connector_status_disconnected; } @@ -595,7 +611,17 @@ struct drm_connector *msm_dsi_manager_connector_init(u8 id) drm_connector_attach_encoder(connector, msm_dsi->encoder); + ret = msm_dsi_manager_panel_init(connector, id); + if (ret) { + DRM_DEV_ERROR(msm_dsi->dev->dev, "init panel failed %d\n", ret); + goto fail; + } + return connector; + +fail: + connector->funcs->destroy(msm_dsi->connector); + return ERR_PTR(ret); } bool msm_dsi_manager_validate_current_config(u8 id) @@ -751,35 +777,6 @@ bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len) return true; } -void msm_dsi_manager_attach_dsi_device(int id, u32 device_flags) -{ - struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); - struct drm_device *dev = msm_dsi->dev; - struct msm_drm_private *priv; - struct msm_kms *kms; - struct drm_encoder *encoder; - bool cmd_mode; - - /* - * drm_device pointer is assigned to msm_dsi only in the modeset_init - * path. If mipi_dsi_attach() happens in DSI driver's probe path - * (generally the case when we're connected to a drm_panel of the type - * mipi_dsi_device), this would be NULL. In such cases, try to set the - * encoder mode in the DSI connector's detect() op. - */ - if (!dev) - return; - - priv = dev->dev_private; - kms = priv->kms; - encoder = msm_dsi_get_encoder(msm_dsi); - cmd_mode = !(device_flags & - MIPI_DSI_MODE_VIDEO); - - if (encoder && kms->funcs->set_encoder_mode) - kms->funcs->set_encoder_mode(kms, encoder, cmd_mode); -} - int msm_dsi_manager_register(struct msm_dsi *msm_dsi) { struct msm_dsi_manager *msm_dsim = &msm_dsim_glb; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index bc6f64b202f3..4097eca1b3ef 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -499,6 +499,8 @@ static const struct of_device_id dsi_phy_dt_match[] = { #ifdef CONFIG_DRM_MSM_DSI_10NM_PHY { .compatible = "qcom,dsi-phy-10nm", .data = &dsi_phy_10nm_cfgs }, + { .compatible = "qcom,dsi-phy-10nm-8998", + .data = &dsi_phy_10nm_8998_cfgs }, #endif {} }; @@ -608,10 +610,12 @@ static int dsi_phy_driver_probe(struct platform_device *pdev) goto fail; phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id); - if (IS_ERR_OR_NULL(phy->pll)) + if (IS_ERR_OR_NULL(phy->pll)) { DRM_DEV_INFO(dev, "%s: pll init failed: %ld, need separate pll clk driver\n", __func__, PTR_ERR(phy->pll)); + phy->pll = NULL; + } dsi_phy_disable_resource(phy); diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index 86322c88b98e..c4069ce6afe6 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -13,6 +13,9 @@ #define dsi_phy_read(offset) msm_readl((offset)) #define dsi_phy_write(offset, data) msm_writel((data), (offset)) +/* v3.0.0 10nm implementation that requires the old timings settings */ +#define V3_0_0_10NM_OLD_TIMINGS_QUIRK BIT(0) + struct msm_dsi_phy_ops { int (*init) (struct msm_dsi_phy *phy); int (*enable)(struct msm_dsi_phy *phy, int src_pll_id, @@ -33,6 +36,7 @@ struct msm_dsi_phy_cfg { bool src_pll_truthtable[DSI_MAX][DSI_MAX]; const resource_size_t io_start[DSI_MAX]; const int num_dsi_phy; + const int quirks; }; extern const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs; @@ -41,6 +45,7 @@ extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_14nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_10nm_8998_cfgs; struct msm_dsi_dphy_timing { u32 clk_pre; 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 44959e79ce28..47403d4f2d28 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c @@ -42,6 +42,9 @@ static void dsi_phy_hw_v3_0_lane_settings(struct msm_dsi_phy *phy) u8 tx_dctrl[] = { 0x00, 0x00, 0x00, 0x04, 0x01 }; void __iomem *lane_base = phy->lane_base; + if (phy->cfg->quirks & V3_0_0_10NM_OLD_TIMINGS_QUIRK) + tx_dctrl[3] = 0x02; + /* Strength ctrl settings */ for (i = 0; i < 5; i++) { dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_LPTX_STR_CTRL(i), @@ -74,9 +77,11 @@ static void dsi_phy_hw_v3_0_lane_settings(struct msm_dsi_phy *phy) tx_dctrl[i]); } - /* Toggle BIT 0 to release freeze I/0 */ - dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x05); - dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x04); + if (!(phy->cfg->quirks & V3_0_0_10NM_OLD_TIMINGS_QUIRK)) { + /* Toggle BIT 0 to release freeze I/0 */ + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x05); + dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x04); + } } static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id, @@ -221,3 +226,22 @@ const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs = { .io_start = { 0xae94400, 0xae96400 }, .num_dsi_phy = 2, }; + +const struct msm_dsi_phy_cfg dsi_phy_10nm_8998_cfgs = { + .type = MSM_DSI_PHY_10NM, + .src_pll_truthtable = { {false, false}, {true, false} }, + .reg_cfg = { + .num = 1, + .regs = { + {"vdds", 36000, 32}, + }, + }, + .ops = { + .enable = dsi_10nm_phy_enable, + .disable = dsi_10nm_phy_disable, + .init = dsi_10nm_phy_init, + }, + .io_start = { 0xc994400, 0xc996400 }, + .num_dsi_phy = 2, + .quirks = V3_0_0_10NM_OLD_TIMINGS_QUIRK, +}; diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c index aabab6311043..8f6100db90ed 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c @@ -104,8 +104,13 @@ struct dsi_pll_10nm { struct dsi_pll_regs reg_setup; /* private clocks: */ - struct clk_hw *hws[NUM_DSI_CLOCKS_MAX]; - u32 num_hws; + struct clk_hw *out_div_clk_hw; + struct clk_hw *bit_clk_hw; + struct clk_hw *byte_clk_hw; + struct clk_hw *by_2_bit_clk_hw; + struct clk_hw *post_out_div_clk_hw; + struct clk_hw *pclk_mux_hw; + struct clk_hw *out_dsiclk_hw; /* clock-provider: */ struct clk_hw_onecell_data *hw_data; @@ -617,8 +622,19 @@ static int dsi_pll_10nm_get_provider(struct msm_dsi_pll *pll, static void dsi_pll_10nm_destroy(struct msm_dsi_pll *pll) { struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); + struct device *dev = &pll_10nm->pdev->dev; DBG("DSI PLL%d", pll_10nm->id); + of_clk_del_provider(dev->of_node); + + clk_hw_unregister_divider(pll_10nm->out_dsiclk_hw); + clk_hw_unregister_mux(pll_10nm->pclk_mux_hw); + clk_hw_unregister_fixed_factor(pll_10nm->post_out_div_clk_hw); + clk_hw_unregister_fixed_factor(pll_10nm->by_2_bit_clk_hw); + clk_hw_unregister_fixed_factor(pll_10nm->byte_clk_hw); + clk_hw_unregister_divider(pll_10nm->bit_clk_hw); + clk_hw_unregister_divider(pll_10nm->out_div_clk_hw); + clk_hw_unregister(&pll_10nm->base.clk_hw); } /* @@ -639,10 +655,8 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) .ops = &clk_ops_dsi_pll_10nm_vco, }; struct device *dev = &pll_10nm->pdev->dev; - struct clk_hw **hws = pll_10nm->hws; struct clk_hw_onecell_data *hw_data; struct clk_hw *hw; - int num = 0; int ret; DBG("DSI%d", pll_10nm->id); @@ -660,8 +674,6 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) if (ret) return ret; - hws[num++] = &pll_10nm->base.clk_hw; - snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); snprintf(parent, 32, "dsi%dvco_clk", pll_10nm->id); @@ -670,10 +682,12 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); - if (IS_ERR(hw)) - return PTR_ERR(hw); + if (IS_ERR(hw)) { + ret = PTR_ERR(hw); + goto err_base_clk_hw; + } - hws[num++] = hw; + pll_10nm->out_div_clk_hw = hw; snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_10nm->id); snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); @@ -685,10 +699,12 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) REG_DSI_10nm_PHY_CMN_CLK_CFG0, 0, 4, CLK_DIVIDER_ONE_BASED, &pll_10nm->postdiv_lock); - if (IS_ERR(hw)) - return PTR_ERR(hw); + if (IS_ERR(hw)) { + ret = PTR_ERR(hw); + goto err_out_div_clk_hw; + } - hws[num++] = hw; + pll_10nm->bit_clk_hw = hw; snprintf(clk_name, 32, "dsi%d_phy_pll_out_byteclk", pll_10nm->id); snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); @@ -696,10 +712,12 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */ hw = clk_hw_register_fixed_factor(dev, clk_name, parent, CLK_SET_RATE_PARENT, 1, 8); - if (IS_ERR(hw)) - return PTR_ERR(hw); + if (IS_ERR(hw)) { + ret = PTR_ERR(hw); + goto err_bit_clk_hw; + } - hws[num++] = hw; + pll_10nm->byte_clk_hw = hw; hw_data->hws[DSI_BYTE_PLL_CLK] = hw; snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id); @@ -707,20 +725,24 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) hw = clk_hw_register_fixed_factor(dev, clk_name, parent, 0, 1, 2); - if (IS_ERR(hw)) - return PTR_ERR(hw); + if (IS_ERR(hw)) { + ret = PTR_ERR(hw); + goto err_byte_clk_hw; + } - hws[num++] = hw; + pll_10nm->by_2_bit_clk_hw = hw; snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id); snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); hw = clk_hw_register_fixed_factor(dev, clk_name, parent, 0, 1, 4); - if (IS_ERR(hw)) - return PTR_ERR(hw); + if (IS_ERR(hw)) { + ret = PTR_ERR(hw); + goto err_by_2_bit_clk_hw; + } - hws[num++] = hw; + pll_10nm->post_out_div_clk_hw = hw; snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_10nm->id); snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); @@ -734,10 +756,12 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) }, 4, 0, pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1, 0, 2, 0, NULL); - if (IS_ERR(hw)) - return PTR_ERR(hw); + if (IS_ERR(hw)) { + ret = PTR_ERR(hw); + goto err_post_out_div_clk_hw; + } - hws[num++] = hw; + pll_10nm->pclk_mux_hw = hw; snprintf(clk_name, 32, "dsi%d_phy_pll_out_dsiclk", pll_10nm->id); snprintf(parent, 32, "dsi%d_pclk_mux", pll_10nm->id); @@ -748,14 +772,14 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) REG_DSI_10nm_PHY_CMN_CLK_CFG0, 4, 4, CLK_DIVIDER_ONE_BASED, &pll_10nm->postdiv_lock); - if (IS_ERR(hw)) - return PTR_ERR(hw); + if (IS_ERR(hw)) { + ret = PTR_ERR(hw); + goto err_pclk_mux_hw; + } - hws[num++] = hw; + pll_10nm->out_dsiclk_hw = hw; hw_data->hws[DSI_PIXEL_PLL_CLK] = hw; - pll_10nm->num_hws = num; - hw_data->num = NUM_PROVIDED_CLKS; pll_10nm->hw_data = hw_data; @@ -763,10 +787,29 @@ static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) pll_10nm->hw_data); if (ret) { DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret); - return ret; + goto err_dsiclk_hw; } return 0; + +err_dsiclk_hw: + clk_hw_unregister_divider(pll_10nm->out_dsiclk_hw); +err_pclk_mux_hw: + clk_hw_unregister_mux(pll_10nm->pclk_mux_hw); +err_post_out_div_clk_hw: + clk_hw_unregister_fixed_factor(pll_10nm->post_out_div_clk_hw); +err_by_2_bit_clk_hw: + clk_hw_unregister_fixed_factor(pll_10nm->by_2_bit_clk_hw); +err_byte_clk_hw: + clk_hw_unregister_fixed_factor(pll_10nm->byte_clk_hw); +err_bit_clk_hw: + clk_hw_unregister_divider(pll_10nm->bit_clk_hw); +err_out_div_clk_hw: + clk_hw_unregister_divider(pll_10nm->out_div_clk_hw); +err_base_clk_hw: + clk_hw_unregister(&pll_10nm->base.clk_hw); + + return ret; } struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id) @@ -775,9 +818,6 @@ struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id) struct msm_dsi_pll *pll; int ret; - if (!pdev) - return ERR_PTR(-ENODEV); - pll_10nm = devm_kzalloc(&pdev->dev, sizeof(*pll_10nm), GFP_KERNEL); if (!pll_10nm) return ERR_PTR(-ENOMEM); |