Loading drivers/video/fbdev/msm/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ mdss-dsi-objs += mdss_dsi_panel.o mdss-dsi-objs += msm_mdss_io_8974.o mdss-dsi-objs += mdss_dsi_phy.o mdss-dsi-objs += mdss_dsi_phy_v3.o mdss-dsi-objs += mdss_dsi_phy_12nm.o mdss-dsi-objs += mdss_dsi_clk.o obj-$(CONFIG_FB_MSM_MDSS) += mdss-dsi.o obj-$(CONFIG_FB_MSM_MDSS) += mdss_panel.o Loading drivers/video/fbdev/msm/mdss_dsi.c +13 −13 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. */ /* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ #include <linux/module.h> #include <linux/interrupt.h> Loading Loading @@ -3317,10 +3317,10 @@ static int mdss_dsi_ctrl_clock_init(struct platform_device *ctrl_pdev, info.core_clks.mmss_misc_ahb_clk = ctrl_pdata->shared_data->mmss_misc_ahb_clk; info.link_clks.esc_clk = ctrl_pdata->esc_clk; info.link_clks.byte_clk = ctrl_pdata->byte_clk; info.link_clks.pixel_clk = ctrl_pdata->pixel_clk; info.link_clks.byte_intf_clk = ctrl_pdata->byte_intf_clk; info.link_lp_clks.esc_clk = ctrl_pdata->esc_clk; info.link_hs_clks.byte_clk = ctrl_pdata->byte_clk; info.link_hs_clks.pixel_clk = ctrl_pdata->pixel_clk; info.link_hs_clks.byte_intf_clk = ctrl_pdata->byte_intf_clk; info.pre_clkoff_cb = mdss_dsi_pre_clkoff_cb; info.post_clkon_cb = mdss_dsi_post_clkon_cb; Loading Loading @@ -4394,11 +4394,11 @@ static int mdss_dsi_parse_ctrl_params(struct platform_device *ctrl_pdev, if (!data) { pr_err("%s:%d, Unable to read Phy Strength ctrl settings\n", __func__, __LINE__); return -EINVAL; } } else { pinfo->mipi.dsi_phy_db.strength_len = len; for (i = 0; i < len; i++) pinfo->mipi.dsi_phy_db.strength[i] = data[i]; } pinfo->mipi.dsi_phy_db.reg_ldo_mode = of_property_read_bool( ctrl_pdev->dev.of_node, "qcom,regulator-ldo-mode"); Loading Loading @@ -4429,11 +4429,11 @@ static int mdss_dsi_parse_ctrl_params(struct platform_device *ctrl_pdev, if (!data) { pr_err("%s:%d, Unable to read Phy lane configure settings\n", __func__, __LINE__); return -EINVAL; } } else { pinfo->mipi.dsi_phy_db.lanecfg_len = len; for (i = 0; i < len; i++) pinfo->mipi.dsi_phy_db.lanecfg[i] = data[i]; } ctrl_pdata->timing_db_mode = of_property_read_bool( ctrl_pdev->dev.of_node, "qcom,timing-db-mode"); Loading drivers/video/fbdev/msm/mdss_dsi.h +6 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. */ /* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ #ifndef MDSS_DSI_H #define MDSS_DSI_H Loading Loading @@ -350,6 +350,7 @@ struct dsi_panel_timing { struct mdss_panel_timing timing; uint32_t phy_timing[12]; uint32_t phy_timing_8996[40]; uint32_t phy_timing_12nm[8]; /* DSI_CLKOUT_TIMING_CTRL */ char t_clk_post; char t_clk_pre; Loading Loading @@ -646,15 +647,19 @@ void mdss_dsi_shadow_clk_deinit(struct device *dev, struct mdss_dsi_ctrl_pdata *ctrl_pdata); int mdss_dsi_pre_clkoff_cb(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state new_state); int mdss_dsi_post_clkoff_cb(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state curr_state); int mdss_dsi_post_clkon_cb(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state curr_state); int mdss_dsi_pre_clkon_cb(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state new_state); int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable); void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl); Loading drivers/video/fbdev/msm/mdss_dsi_clk.c +255 −121 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2015-2016, 2018-2020, The Linux Foundation. All rights reserved. */ /* Copyright (c) 2015-2016, 2018-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "mdss-dsi-clk:[%s] " fmt, __func__ #include <linux/clk.h> Loading @@ -17,11 +17,9 @@ struct dsi_core_clks { }; struct dsi_link_clks { struct mdss_dsi_link_clk_info clks; struct mdss_dsi_link_hs_clk_info hs_clks; struct mdss_dsi_link_lp_clk_info lp_clks; u32 current_clk_state; u32 byte_clk_rate; u32 pix_clk_rate; u32 esc_clk_rate; }; struct mdss_dsi_clk_mngr { Loading Loading @@ -63,8 +61,7 @@ static int dsi_core_clk_start(struct dsi_core_clks *c_clks) rc = clk_prepare_enable(c_clks->clks.mdp_core_clk); if (rc) { pr_err("%s: failed to enable mdp_core_clock. rc=%d\n", __func__, rc); pr_err("failed to enable mdp_core_clock. rc=%d\n", rc); goto error; } Loading @@ -84,15 +81,15 @@ static int dsi_core_clk_start(struct dsi_core_clks *c_clks) rc = clk_prepare_enable(c_clks->clks.axi_clk); if (rc) { pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc); pr_err("failed to enable ahb clock. rc=%d\n", rc); goto disable_ahb_clk; } if (c_clks->clks.mmss_misc_ahb_clk) { rc = clk_prepare_enable(c_clks->clks.mmss_misc_ahb_clk); if (rc) { pr_err("%s: failed to enable mmss misc ahb clk.rc=%d\n", __func__, rc); pr_err("failed to enable mmss misc ahb clk.rc=%d\n", rc); goto disable_axi_clk; } } Loading Loading @@ -142,12 +139,15 @@ static int dsi_core_clk_stop(struct dsi_core_clks *c_clks) return 0; } static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks) static int dsi_link_hs_clk_set_rate( struct mdss_dsi_link_hs_clk_info *link_hs_clks) { int rc = 0; struct mdss_dsi_clk_mngr *mngr; struct dsi_link_clks *l_clks; struct mdss_dsi_ctrl_pdata *ctrl; l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks); mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks); /* Loading @@ -162,19 +162,13 @@ static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks) if (ctrl->panel_data.panel_info.cont_splash_enabled) return 0; rc = clk_set_rate(l_clks->clks.esc_clk, l_clks->esc_clk_rate); if (rc) { pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc); goto error; } rc = clk_set_rate(l_clks->clks.byte_clk, l_clks->byte_clk_rate); rc = clk_set_rate(link_hs_clks->byte_clk, link_hs_clks->byte_clk_rate); if (rc) { pr_err("clk_set_rate failed for byte_clk rc = %d\n", rc); goto error; } rc = clk_set_rate(l_clks->clks.pixel_clk, l_clks->pix_clk_rate); rc = clk_set_rate(link_hs_clks->pixel_clk, link_hs_clks->pix_clk_rate); if (rc) { pr_err("clk_set_rate failed for pixel_clk rc = %d\n", rc); goto error; Loading @@ -186,9 +180,9 @@ static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks) * byte_intf_clk_rate = byte_clk_rate / 2 * todo: this needs to be revisited when support for CPHY is added */ if (l_clks->clks.byte_intf_clk) { rc = clk_set_rate(l_clks->clks.byte_intf_clk, l_clks->byte_clk_rate / 2); if (link_hs_clks->byte_intf_clk) { rc = clk_set_rate(link_hs_clks->byte_intf_clk, link_hs_clks->byte_clk_rate / 2); if (rc) { pr_err("set rate failed for byte intf clk rc=%d\n", rc); goto error; Loading @@ -199,30 +193,25 @@ static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks) return rc; } static int dsi_link_clk_prepare(struct dsi_link_clks *l_clks) static int dsi_link_hs_clk_prepare( struct mdss_dsi_link_hs_clk_info *link_hs_clks) { int rc = 0; rc = clk_prepare(l_clks->clks.esc_clk); rc = clk_prepare(link_hs_clks->byte_clk); if (rc) { pr_err("%s: Failed to prepare dsi esc clk\n", __func__); goto esc_clk_err; } rc = clk_prepare(l_clks->clks.byte_clk); if (rc) { pr_err("%s: Failed to prepare dsi byte clk\n", __func__); pr_err("Failed to prepare dsi byte clk\n"); goto byte_clk_err; } rc = clk_prepare(l_clks->clks.pixel_clk); rc = clk_prepare(link_hs_clks->pixel_clk); if (rc) { pr_err("%s: Failed to prepare dsi pixel clk\n", __func__); pr_err("Failed to prepare dsi pixel_clk\n"); goto pixel_clk_err; } if (l_clks->clks.byte_intf_clk) { rc = clk_prepare(l_clks->clks.byte_intf_clk); if (link_hs_clks->byte_intf_clk) { rc = clk_prepare(link_hs_clks->byte_intf_clk); if (rc) { pr_err("%s: Failed to prepare dsi byte_intf clk\n", __func__); Loading @@ -233,50 +222,43 @@ static int dsi_link_clk_prepare(struct dsi_link_clks *l_clks) return rc; byte_intf_clk_err: clk_unprepare(l_clks->clks.pixel_clk); clk_unprepare(link_hs_clks->pixel_clk); pixel_clk_err: clk_unprepare(l_clks->clks.byte_clk); clk_unprepare(link_hs_clks->byte_clk); byte_clk_err: clk_unprepare(l_clks->clks.esc_clk); esc_clk_err: return rc; } static int dsi_link_clk_unprepare(struct dsi_link_clks *l_clks) static int dsi_link_hs_clk_unprepare( struct mdss_dsi_link_hs_clk_info *link_hs_clks) { if (l_clks->clks.byte_intf_clk) clk_unprepare(l_clks->clks.byte_intf_clk); clk_unprepare(l_clks->clks.pixel_clk); clk_unprepare(l_clks->clks.byte_clk); clk_unprepare(l_clks->clks.esc_clk); if (link_hs_clks->byte_intf_clk) clk_unprepare(link_hs_clks->byte_intf_clk); clk_unprepare(link_hs_clks->pixel_clk); clk_unprepare(link_hs_clks->byte_clk); return 0; } static int dsi_link_clk_enable(struct dsi_link_clks *l_clks) static int dsi_link_hs_clk_enable( struct mdss_dsi_link_hs_clk_info *link_hs_clks) { int rc = 0; rc = clk_enable(l_clks->clks.esc_clk); rc = clk_enable(link_hs_clks->byte_clk); if (rc) { pr_err("%s: Failed to enable dsi esc clk\n", __func__); goto esc_clk_err; } rc = clk_enable(l_clks->clks.byte_clk); if (rc) { pr_err("%s: Failed to enable dsi byte clk\n", __func__); pr_err("Failed to enable dsi byte clk\n"); goto byte_clk_err; } rc = clk_enable(l_clks->clks.pixel_clk); rc = clk_enable(link_hs_clks->pixel_clk); if (rc) { pr_err("%s: Failed to enable dsi pixel clk\n", __func__); pr_err("Failed to enable dsi pixel_clk\n"); goto pixel_clk_err; } if (l_clks->clks.byte_intf_clk) { rc = clk_enable(l_clks->clks.byte_intf_clk); if (link_hs_clks->byte_intf_clk) { rc = clk_enable(link_hs_clks->byte_intf_clk); if (rc) { pr_err("%s: Failed to enable dsi byte_intf clk\n", __func__); Loading @@ -287,74 +269,148 @@ static int dsi_link_clk_enable(struct dsi_link_clks *l_clks) return rc; byte_intf_clk_err: clk_disable(l_clks->clks.pixel_clk); clk_disable(link_hs_clks->pixel_clk); pixel_clk_err: clk_disable(l_clks->clks.byte_clk); clk_disable(link_hs_clks->byte_clk); byte_clk_err: clk_disable(l_clks->clks.esc_clk); esc_clk_err: return rc; } static int dsi_link_clk_disable(struct dsi_link_clks *l_clks) static int dsi_link_hs_clk_disable( struct mdss_dsi_link_hs_clk_info *link_hs_clks) { if (l_clks->clks.byte_intf_clk) clk_disable(l_clks->clks.byte_intf_clk); clk_disable(l_clks->clks.esc_clk); clk_disable(l_clks->clks.pixel_clk); clk_disable(l_clks->clks.byte_clk); if (link_hs_clks->byte_intf_clk) clk_disable(link_hs_clks->byte_intf_clk); clk_disable(link_hs_clks->pixel_clk); clk_disable(link_hs_clks->byte_clk); return 0; } static int dsi_link_clk_start(struct dsi_link_clks *l_clks) static int dsi_link_hs_clk_start( struct mdss_dsi_link_hs_clk_info *link_hs_clks, enum mdss_dsi_link_clk_op_type op_type) { int rc = 0; struct dsi_link_clks *l_clks; struct mdss_dsi_clk_mngr *mngr; l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks); mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks); rc = dsi_link_clk_set_rate(l_clks); if (op_type & MDSS_DSI_LINK_CLK_SET_RATE) { rc = dsi_link_hs_clk_set_rate(link_hs_clks); if (rc) { pr_err("failed to set clk rates, rc = %d\n", rc); pr_err("failed to set HS clk rates, rc = %d\n", rc); goto error; } } rc = dsi_link_clk_prepare(l_clks); if (op_type & MDSS_DSI_LINK_CLK_PREPARE) { rc = dsi_link_hs_clk_prepare(link_hs_clks); if (rc) { pr_err("failed to prepare link clks, rc = %d\n", rc); pr_err("failed to prepare link HS clks, rc = %d\n", rc); goto error; } } rc = dsi_link_clk_enable(l_clks); if (op_type & MDSS_DSI_LINK_CLK_ENABLE) { rc = dsi_link_hs_clk_enable(link_hs_clks); if (rc) { pr_err("failed to enable link clks, rc = %d\n", rc); pr_err("failed to enable link HS clks, rc = %d\n", rc); goto error_unprepare; } } pr_debug("%s: LINK CLOCK IS ON\n", mngr->name); pr_debug("%s: LINK HS CLOCK IS ON\n", mngr->name); return rc; error_unprepare: dsi_link_clk_unprepare(l_clks); dsi_link_hs_clk_unprepare(link_hs_clks); error: return rc; } static int dsi_link_lp_clk_start( struct mdss_dsi_link_lp_clk_info *link_lp_clks) { int rc = 0; struct mdss_dsi_clk_mngr *mngr; struct dsi_link_clks *l_clks; struct mdss_dsi_ctrl_pdata *ctrl; l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks); mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks); /* * In an ideal world, cont_splash_enabled should not be required inside * the clock manager. But, in the current driver cont_splash_enabled * flag is set inside mdp driver and there is no interface event * associated with this flag setting. Also, set rate for clock need not * be called for every enable call. It should be done only once when * coming out of suspend. */ ctrl = mngr->priv_data; if (ctrl->panel_data.panel_info.cont_splash_enabled) goto prepare; rc = clk_set_rate(link_lp_clks->esc_clk, link_lp_clks->esc_clk_rate); if (rc) { pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc); goto error; } prepare: rc = clk_prepare(link_lp_clks->esc_clk); if (rc) { pr_err("Failed to prepare dsi esc clk\n"); goto error; } rc = clk_enable(link_lp_clks->esc_clk); if (rc) { pr_err("Failed to enable dsi esc clk\n"); clk_unprepare(l_clks->lp_clks.esc_clk); goto error; } error: pr_debug("%s: LINK LP CLOCK IS ON\n", mngr->name); return rc; } static int dsi_link_clk_stop(struct dsi_link_clks *l_clks) static int dsi_link_hs_clk_stop( struct mdss_dsi_link_hs_clk_info *link_hs_clks) { struct dsi_link_clks *l_clks; struct mdss_dsi_clk_mngr *mngr; l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks); mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks); (void)dsi_link_clk_disable(l_clks); (void)dsi_link_hs_clk_disable(link_hs_clks); (void)dsi_link_clk_unprepare(l_clks); pr_debug("%s: LINK CLOCK IS OFF\n", mngr->name); (void)dsi_link_hs_clk_unprepare(link_hs_clks); pr_debug("%s: LINK HS CLOCK IS OFF\n", mngr->name); return 0; } static int dsi_link_lp_clk_stop( struct mdss_dsi_link_lp_clk_info *link_lp_clks) { struct dsi_link_clks *l_clks; struct mdss_dsi_clk_mngr *mngr; l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks); mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks); clk_disable(l_clks->lp_clks.esc_clk); clk_unprepare(l_clks->lp_clks.esc_clk); pr_debug("%s: LINK LP CLOCK IS OFF\n", mngr->name); return 0; } static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, struct dsi_link_clks *l_clks, u32 l_state) { Loading Loading @@ -385,7 +441,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (c_clks && (c_state == MDSS_DSI_CLK_ON)) { if (c_clks->current_clk_state == MDSS_DSI_CLK_OFF) { rc = mngr->pre_clkon_cb(mngr->priv_data, MDSS_DSI_CORE_CLK, MDSS_DSI_CORE_CLK, MDSS_DSI_LINK_NONE, MDSS_DSI_CLK_ON); if (rc) { pr_err("failed to turn on MDP FS rc= %d\n", rc); Loading @@ -400,7 +456,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (mngr->post_clkon_cb) { rc = mngr->post_clkon_cb(mngr->priv_data, MDSS_DSI_CORE_CLK, MDSS_DSI_CORE_CLK, MDSS_DSI_LINK_NONE, MDSS_DSI_CLK_ON); if (rc) pr_err("post clk on cb failed, rc = %d\n", rc); Loading @@ -413,21 +469,50 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (l_state == MDSS_DSI_CLK_ON) { if (mngr->pre_clkon_cb) { rc = mngr->pre_clkon_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, l_state); MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_LP_CLK, l_state); if (rc) pr_err("pre link clk on cb failed\n"); pr_err("pre link LP clk on cb failed\n"); } rc = dsi_link_clk_start(l_clks); rc = dsi_link_lp_clk_start(&l_clks->lp_clks); if (rc) { pr_err("failed to start link clk rc= %d\n", rc); pr_err("failed to start LP link clk clk\n"); goto error; } if (mngr->post_clkon_cb) { rc = mngr->post_clkon_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_LP_CLK, l_state); if (rc) pr_err("post LP clk on cb failed\n"); } if (mngr->pre_clkon_cb) { rc = mngr->pre_clkon_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_HS_CLK, l_state); if (rc) pr_err("post link clk on cb failed\n"); pr_err("pre HS clk on cb failed\n"); } rc = dsi_link_hs_clk_start(&l_clks->hs_clks, (MDSS_DSI_LINK_CLK_SET_RATE | MDSS_DSI_LINK_CLK_PREPARE)); if (rc) { pr_err("failed to prepare HS clk rc= %d\n", rc); goto error; } if (mngr->post_clkon_cb) { rc = mngr->post_clkon_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_HS_CLK, l_state); if (rc) pr_err("post HS clk on cb failed\n"); } rc = dsi_link_hs_clk_start(&l_clks->hs_clks, MDSS_DSI_LINK_CLK_ENABLE); if (rc) { pr_err("failed to enable HS clk rc= %d\n", rc); goto error; } } else { /* Loading Loading @@ -456,9 +541,16 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, goto error; } rc = dsi_link_clk_start(l_clks); rc = dsi_link_lp_clk_start(&l_clks->lp_clks); if (rc) { pr_err("LP Link clks did not start\n"); goto error; } rc = dsi_link_hs_clk_start(&l_clks->hs_clks, MDSS_DSI_LINK_CLK_START); if (rc) { pr_err("Link clks did not start\n"); pr_err("HS Link clks did not start\n"); goto error; } l_c_on = true; Loading @@ -467,24 +559,50 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (mngr->pre_clkoff_cb) { rc = mngr->pre_clkoff_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, l_state); MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_HS_CLK, l_state); if (rc) pr_err("pre HS clk off cb failed\n"); } rc = dsi_link_hs_clk_stop(&l_clks->hs_clks); if (rc) { pr_err("failed to stop HS clk, rc = %d\n", rc); goto error; } if (mngr->post_clkoff_cb) { rc = mngr->post_clkoff_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_HS_CLK, l_state); if (rc) pr_err("post HS clk off cb failed\n"); } if (mngr->pre_clkoff_cb) { rc = mngr->pre_clkoff_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_LP_CLK, l_state); if (rc) pr_err("pre link clk off cb failed\n"); pr_err("pre LP clk off cb failed\n"); } rc = dsi_link_clk_stop(l_clks); rc = dsi_link_lp_clk_stop(&l_clks->lp_clks); if (rc) { pr_err("failed to stop link clk, rc = %d\n", pr_err("failed to stop LP link clk, rc = %d\n", rc); goto error; } if (mngr->post_clkoff_cb) { rc = mngr->post_clkoff_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, l_state); MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_LP_CLK, l_state); if (rc) pr_err("post link clk off cb failed\n"); pr_err("post LP clk off cb failed\n"); } /* * This check is to save unnecessary clock state * change when going from EARLY_GATE to OFF. In the Loading Loading @@ -540,7 +658,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (mngr->pre_clkoff_cb) { rc = mngr->pre_clkoff_cb(mngr->priv_data, MDSS_DSI_CORE_CLK, MDSS_DSI_CORE_CLK, MDSS_DSI_LINK_NONE, c_state); if (rc) pr_err("pre core clk off cb failed\n"); Loading @@ -555,7 +673,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (c_state == MDSS_DSI_CLK_OFF) { if (mngr->post_clkoff_cb) { rc = mngr->post_clkoff_cb(mngr->priv_data, MDSS_DSI_CORE_CLK, MDSS_DSI_CORE_CLK, MDSS_DSI_LINK_NONE, MDSS_DSI_CLK_OFF); if (rc) pr_err("post clkoff cb fail, rc = %d\n", Loading Loading @@ -648,18 +766,20 @@ static int dsi_set_clk_rate(struct mdss_dsi_clk_mngr *mngr, int clk, u32 rate, MDSS_XLOG(clk, rate, flags); switch (clk) { case MDSS_DSI_LINK_ESC_CLK: mngr->link_clks.esc_clk_rate = rate; mngr->link_clks.lp_clks.esc_clk_rate = rate; if (!flags) { rc = clk_set_rate(mngr->link_clks.clks.esc_clk, rate); rc = clk_set_rate(mngr->link_clks.lp_clks.esc_clk, rate); if (rc) pr_err("set rate failed for esc clk rc=%d\n", rc); } break; case MDSS_DSI_LINK_BYTE_CLK: mngr->link_clks.byte_clk_rate = rate; mngr->link_clks.hs_clks.byte_clk_rate = rate; if (!flags) { rc = clk_set_rate(mngr->link_clks.clks.byte_clk, rate); rc = clk_set_rate(mngr->link_clks.hs_clks.byte_clk, rate); if (rc) { pr_err("set rate failed for byte clk rc=%d\n", rc); Loading @@ -673,9 +793,9 @@ static int dsi_set_clk_rate(struct mdss_dsi_clk_mngr *mngr, int clk, u32 rate, * todo: this needs to be revisited when support for * CPHY is added. */ if (mngr->link_clks.clks.byte_intf_clk) { if (mngr->link_clks.hs_clks.byte_intf_clk) { rc = clk_set_rate( mngr->link_clks.clks.byte_intf_clk, mngr->link_clks.hs_clks.byte_intf_clk, rate / 2); if (rc) pr_err("set rate failed for byte intf clk rc=%d\n", Loading @@ -684,9 +804,10 @@ static int dsi_set_clk_rate(struct mdss_dsi_clk_mngr *mngr, int clk, u32 rate, } break; case MDSS_DSI_LINK_PIX_CLK: mngr->link_clks.pix_clk_rate = rate; mngr->link_clks.hs_clks.pix_clk_rate = rate; if (!flags) { rc = clk_set_rate(mngr->link_clks.clks.pixel_clk, rate); rc = clk_set_rate(mngr->link_clks.hs_clks.pixel_clk, rate); if (rc) pr_err("failed to set rate for pix clk rc=%d\n", rc); Loading Loading @@ -945,8 +1066,10 @@ void *mdss_dsi_clk_init(struct mdss_dsi_clk_info *info) mutex_init(&mngr->clk_mutex); memcpy(&mngr->core_clks.clks, &info->core_clks, sizeof(struct mdss_dsi_core_clk_info)); memcpy(&mngr->link_clks.clks, &info->link_clks, sizeof(struct mdss_dsi_link_clk_info)); memcpy(&mngr->link_clks.hs_clks, &info->link_hs_clks, sizeof(struct mdss_dsi_link_hs_clk_info)); memcpy(&mngr->link_clks.lp_clks, &info->link_lp_clks, sizeof(struct mdss_dsi_link_lp_clk_info)); INIT_LIST_HEAD(&mngr->client_list); mngr->pre_clkon_cb = info->pre_clkon_cb; Loading Loading @@ -1038,15 +1161,26 @@ int mdss_dsi_clk_force_toggle(void *client, u32 clk) if ((clk & MDSS_DSI_LINK_CLK) && (mngr->link_clks.current_clk_state == MDSS_DSI_CLK_ON)) { rc = dsi_link_clk_stop(&mngr->link_clks); rc = dsi_link_hs_clk_stop(&mngr->link_clks.hs_clks); if (rc) { pr_err("failed to stop link clks\n"); pr_err("failed to stop HS link clks\n"); goto error; } rc = dsi_link_clk_start(&mngr->link_clks); rc = dsi_link_lp_clk_stop(&mngr->link_clks.lp_clks); if (rc) { pr_err("failed to stop LP link clks\n"); goto error; } rc = dsi_link_lp_clk_start(&mngr->link_clks.lp_clks); if (rc) pr_err("failed to start LP link clks\n"); rc = dsi_link_hs_clk_start(&mngr->link_clks.hs_clks, MDSS_DSI_LINK_CLK_START); if (rc) pr_err("failed to start link clks\n"); pr_err("failed to start HS link clks\n"); } else if (clk & MDSS_DSI_LINK_CLK) { pr_err("cannot reset, link clock is off\n"); Loading drivers/video/fbdev/msm/mdss_dsi_clk.h +38 −10 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2015-2016, 2018, 2020, The Linux Foundation. All rights reserved. */ /* Copyright (c) 2015-2016, 2018, 2020-2021, The Linux Foundation. All rights reserved. */ #ifndef _MDSS_DSI_CLK_H_ #define _MDSS_DSI_CLK_H_ Loading Loading @@ -30,6 +30,13 @@ enum mdss_dsi_link_clk_type { MDSS_DSI_LINK_CLK_MAX, }; enum mdss_dsi_link_clk_op_type { MDSS_DSI_LINK_CLK_SET_RATE = BIT(0), MDSS_DSI_LINK_CLK_PREPARE = BIT(1), MDSS_DSI_LINK_CLK_ENABLE = BIT(2), MDSS_DSI_LINK_CLK_START = BIT(0) | BIT(1) | BIT(2), }; enum mdss_dsi_clk_type { MDSS_DSI_CORE_CLK = BIT(0), MDSS_DSI_LINK_CLK = BIT(1), Loading @@ -37,52 +44,66 @@ enum mdss_dsi_clk_type { MDSS_DSI_CLKS_MAX = BIT(2), }; enum mdss_dsi_lclk_type { MDSS_DSI_LINK_NONE = 0, MDSS_DSI_LINK_LP_CLK = BIT(0), MDSS_DSI_LINK_HS_CLK = BIT(1), }; /** * typedef *pre_clockoff_cb() - Callback before clock is turned off * @priv: private data pointer. * @clk_type: clock which is being turned off. * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. * @new_state: next state for the clock. * * @return: error code. */ typedef int (*pre_clockoff_cb)(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state new_state); /** * typedef *post_clockoff_cb() - Callback after clock is turned off * @priv: private data pointer. * @clk_type: clock which was turned off. * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. * @curr_state: current state for the clock. * * @return: error code. */ typedef int (*post_clockoff_cb)(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state curr_state); /** * typedef *post_clockon_cb() - Callback after clock is turned on * @priv: private data pointer. * @clk_type: clock which was turned on. * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. * @curr_state: current state for the clock. * * @return: error code. */ typedef int (*post_clockon_cb)(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state curr_state); /** * typedef *pre_clockon_cb() - Callback before clock is turned on * @priv: private data pointer. * @clk_type: clock which is being turned on. * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. * @new_state: next state for the clock. * * @return: error code. */ typedef int (*pre_clockon_cb)(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state new_state); struct mdss_dsi_core_clk_info { Loading @@ -93,11 +114,17 @@ struct mdss_dsi_core_clk_info { struct clk *mmss_misc_ahb_clk; }; struct mdss_dsi_link_clk_info { struct clk *esc_clk; struct mdss_dsi_link_hs_clk_info { struct clk *byte_clk; struct clk *pixel_clk; struct clk *byte_intf_clk; u32 byte_clk_rate; u32 pix_clk_rate; }; struct mdss_dsi_link_lp_clk_info { struct clk *esc_clk; u32 esc_clk_rate; }; struct dsi_panel_clk_ctrl { Loading @@ -119,7 +146,8 @@ struct dsi_panel_clk_ctrl { struct mdss_dsi_clk_info { char name[DSI_CLK_NAME_LEN]; struct mdss_dsi_core_clk_info core_clks; struct mdss_dsi_link_clk_info link_clks; struct mdss_dsi_link_hs_clk_info link_hs_clks; struct mdss_dsi_link_lp_clk_info link_lp_clks; pre_clockoff_cb pre_clkoff_cb; post_clockoff_cb post_clkoff_cb; post_clockon_cb post_clkon_cb; Loading Loading
drivers/video/fbdev/msm/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ mdss-dsi-objs += mdss_dsi_panel.o mdss-dsi-objs += msm_mdss_io_8974.o mdss-dsi-objs += mdss_dsi_phy.o mdss-dsi-objs += mdss_dsi_phy_v3.o mdss-dsi-objs += mdss_dsi_phy_12nm.o mdss-dsi-objs += mdss_dsi_clk.o obj-$(CONFIG_FB_MSM_MDSS) += mdss-dsi.o obj-$(CONFIG_FB_MSM_MDSS) += mdss_panel.o Loading
drivers/video/fbdev/msm/mdss_dsi.c +13 −13 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. */ /* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ #include <linux/module.h> #include <linux/interrupt.h> Loading Loading @@ -3317,10 +3317,10 @@ static int mdss_dsi_ctrl_clock_init(struct platform_device *ctrl_pdev, info.core_clks.mmss_misc_ahb_clk = ctrl_pdata->shared_data->mmss_misc_ahb_clk; info.link_clks.esc_clk = ctrl_pdata->esc_clk; info.link_clks.byte_clk = ctrl_pdata->byte_clk; info.link_clks.pixel_clk = ctrl_pdata->pixel_clk; info.link_clks.byte_intf_clk = ctrl_pdata->byte_intf_clk; info.link_lp_clks.esc_clk = ctrl_pdata->esc_clk; info.link_hs_clks.byte_clk = ctrl_pdata->byte_clk; info.link_hs_clks.pixel_clk = ctrl_pdata->pixel_clk; info.link_hs_clks.byte_intf_clk = ctrl_pdata->byte_intf_clk; info.pre_clkoff_cb = mdss_dsi_pre_clkoff_cb; info.post_clkon_cb = mdss_dsi_post_clkon_cb; Loading Loading @@ -4394,11 +4394,11 @@ static int mdss_dsi_parse_ctrl_params(struct platform_device *ctrl_pdev, if (!data) { pr_err("%s:%d, Unable to read Phy Strength ctrl settings\n", __func__, __LINE__); return -EINVAL; } } else { pinfo->mipi.dsi_phy_db.strength_len = len; for (i = 0; i < len; i++) pinfo->mipi.dsi_phy_db.strength[i] = data[i]; } pinfo->mipi.dsi_phy_db.reg_ldo_mode = of_property_read_bool( ctrl_pdev->dev.of_node, "qcom,regulator-ldo-mode"); Loading Loading @@ -4429,11 +4429,11 @@ static int mdss_dsi_parse_ctrl_params(struct platform_device *ctrl_pdev, if (!data) { pr_err("%s:%d, Unable to read Phy lane configure settings\n", __func__, __LINE__); return -EINVAL; } } else { pinfo->mipi.dsi_phy_db.lanecfg_len = len; for (i = 0; i < len; i++) pinfo->mipi.dsi_phy_db.lanecfg[i] = data[i]; } ctrl_pdata->timing_db_mode = of_property_read_bool( ctrl_pdev->dev.of_node, "qcom,timing-db-mode"); Loading
drivers/video/fbdev/msm/mdss_dsi.h +6 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. */ /* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ #ifndef MDSS_DSI_H #define MDSS_DSI_H Loading Loading @@ -350,6 +350,7 @@ struct dsi_panel_timing { struct mdss_panel_timing timing; uint32_t phy_timing[12]; uint32_t phy_timing_8996[40]; uint32_t phy_timing_12nm[8]; /* DSI_CLKOUT_TIMING_CTRL */ char t_clk_post; char t_clk_pre; Loading Loading @@ -646,15 +647,19 @@ void mdss_dsi_shadow_clk_deinit(struct device *dev, struct mdss_dsi_ctrl_pdata *ctrl_pdata); int mdss_dsi_pre_clkoff_cb(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state new_state); int mdss_dsi_post_clkoff_cb(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state curr_state); int mdss_dsi_post_clkon_cb(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state curr_state); int mdss_dsi_pre_clkon_cb(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state new_state); int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable); void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl); Loading
drivers/video/fbdev/msm/mdss_dsi_clk.c +255 −121 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2015-2016, 2018-2020, The Linux Foundation. All rights reserved. */ /* Copyright (c) 2015-2016, 2018-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "mdss-dsi-clk:[%s] " fmt, __func__ #include <linux/clk.h> Loading @@ -17,11 +17,9 @@ struct dsi_core_clks { }; struct dsi_link_clks { struct mdss_dsi_link_clk_info clks; struct mdss_dsi_link_hs_clk_info hs_clks; struct mdss_dsi_link_lp_clk_info lp_clks; u32 current_clk_state; u32 byte_clk_rate; u32 pix_clk_rate; u32 esc_clk_rate; }; struct mdss_dsi_clk_mngr { Loading Loading @@ -63,8 +61,7 @@ static int dsi_core_clk_start(struct dsi_core_clks *c_clks) rc = clk_prepare_enable(c_clks->clks.mdp_core_clk); if (rc) { pr_err("%s: failed to enable mdp_core_clock. rc=%d\n", __func__, rc); pr_err("failed to enable mdp_core_clock. rc=%d\n", rc); goto error; } Loading @@ -84,15 +81,15 @@ static int dsi_core_clk_start(struct dsi_core_clks *c_clks) rc = clk_prepare_enable(c_clks->clks.axi_clk); if (rc) { pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc); pr_err("failed to enable ahb clock. rc=%d\n", rc); goto disable_ahb_clk; } if (c_clks->clks.mmss_misc_ahb_clk) { rc = clk_prepare_enable(c_clks->clks.mmss_misc_ahb_clk); if (rc) { pr_err("%s: failed to enable mmss misc ahb clk.rc=%d\n", __func__, rc); pr_err("failed to enable mmss misc ahb clk.rc=%d\n", rc); goto disable_axi_clk; } } Loading Loading @@ -142,12 +139,15 @@ static int dsi_core_clk_stop(struct dsi_core_clks *c_clks) return 0; } static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks) static int dsi_link_hs_clk_set_rate( struct mdss_dsi_link_hs_clk_info *link_hs_clks) { int rc = 0; struct mdss_dsi_clk_mngr *mngr; struct dsi_link_clks *l_clks; struct mdss_dsi_ctrl_pdata *ctrl; l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks); mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks); /* Loading @@ -162,19 +162,13 @@ static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks) if (ctrl->panel_data.panel_info.cont_splash_enabled) return 0; rc = clk_set_rate(l_clks->clks.esc_clk, l_clks->esc_clk_rate); if (rc) { pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc); goto error; } rc = clk_set_rate(l_clks->clks.byte_clk, l_clks->byte_clk_rate); rc = clk_set_rate(link_hs_clks->byte_clk, link_hs_clks->byte_clk_rate); if (rc) { pr_err("clk_set_rate failed for byte_clk rc = %d\n", rc); goto error; } rc = clk_set_rate(l_clks->clks.pixel_clk, l_clks->pix_clk_rate); rc = clk_set_rate(link_hs_clks->pixel_clk, link_hs_clks->pix_clk_rate); if (rc) { pr_err("clk_set_rate failed for pixel_clk rc = %d\n", rc); goto error; Loading @@ -186,9 +180,9 @@ static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks) * byte_intf_clk_rate = byte_clk_rate / 2 * todo: this needs to be revisited when support for CPHY is added */ if (l_clks->clks.byte_intf_clk) { rc = clk_set_rate(l_clks->clks.byte_intf_clk, l_clks->byte_clk_rate / 2); if (link_hs_clks->byte_intf_clk) { rc = clk_set_rate(link_hs_clks->byte_intf_clk, link_hs_clks->byte_clk_rate / 2); if (rc) { pr_err("set rate failed for byte intf clk rc=%d\n", rc); goto error; Loading @@ -199,30 +193,25 @@ static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks) return rc; } static int dsi_link_clk_prepare(struct dsi_link_clks *l_clks) static int dsi_link_hs_clk_prepare( struct mdss_dsi_link_hs_clk_info *link_hs_clks) { int rc = 0; rc = clk_prepare(l_clks->clks.esc_clk); rc = clk_prepare(link_hs_clks->byte_clk); if (rc) { pr_err("%s: Failed to prepare dsi esc clk\n", __func__); goto esc_clk_err; } rc = clk_prepare(l_clks->clks.byte_clk); if (rc) { pr_err("%s: Failed to prepare dsi byte clk\n", __func__); pr_err("Failed to prepare dsi byte clk\n"); goto byte_clk_err; } rc = clk_prepare(l_clks->clks.pixel_clk); rc = clk_prepare(link_hs_clks->pixel_clk); if (rc) { pr_err("%s: Failed to prepare dsi pixel clk\n", __func__); pr_err("Failed to prepare dsi pixel_clk\n"); goto pixel_clk_err; } if (l_clks->clks.byte_intf_clk) { rc = clk_prepare(l_clks->clks.byte_intf_clk); if (link_hs_clks->byte_intf_clk) { rc = clk_prepare(link_hs_clks->byte_intf_clk); if (rc) { pr_err("%s: Failed to prepare dsi byte_intf clk\n", __func__); Loading @@ -233,50 +222,43 @@ static int dsi_link_clk_prepare(struct dsi_link_clks *l_clks) return rc; byte_intf_clk_err: clk_unprepare(l_clks->clks.pixel_clk); clk_unprepare(link_hs_clks->pixel_clk); pixel_clk_err: clk_unprepare(l_clks->clks.byte_clk); clk_unprepare(link_hs_clks->byte_clk); byte_clk_err: clk_unprepare(l_clks->clks.esc_clk); esc_clk_err: return rc; } static int dsi_link_clk_unprepare(struct dsi_link_clks *l_clks) static int dsi_link_hs_clk_unprepare( struct mdss_dsi_link_hs_clk_info *link_hs_clks) { if (l_clks->clks.byte_intf_clk) clk_unprepare(l_clks->clks.byte_intf_clk); clk_unprepare(l_clks->clks.pixel_clk); clk_unprepare(l_clks->clks.byte_clk); clk_unprepare(l_clks->clks.esc_clk); if (link_hs_clks->byte_intf_clk) clk_unprepare(link_hs_clks->byte_intf_clk); clk_unprepare(link_hs_clks->pixel_clk); clk_unprepare(link_hs_clks->byte_clk); return 0; } static int dsi_link_clk_enable(struct dsi_link_clks *l_clks) static int dsi_link_hs_clk_enable( struct mdss_dsi_link_hs_clk_info *link_hs_clks) { int rc = 0; rc = clk_enable(l_clks->clks.esc_clk); rc = clk_enable(link_hs_clks->byte_clk); if (rc) { pr_err("%s: Failed to enable dsi esc clk\n", __func__); goto esc_clk_err; } rc = clk_enable(l_clks->clks.byte_clk); if (rc) { pr_err("%s: Failed to enable dsi byte clk\n", __func__); pr_err("Failed to enable dsi byte clk\n"); goto byte_clk_err; } rc = clk_enable(l_clks->clks.pixel_clk); rc = clk_enable(link_hs_clks->pixel_clk); if (rc) { pr_err("%s: Failed to enable dsi pixel clk\n", __func__); pr_err("Failed to enable dsi pixel_clk\n"); goto pixel_clk_err; } if (l_clks->clks.byte_intf_clk) { rc = clk_enable(l_clks->clks.byte_intf_clk); if (link_hs_clks->byte_intf_clk) { rc = clk_enable(link_hs_clks->byte_intf_clk); if (rc) { pr_err("%s: Failed to enable dsi byte_intf clk\n", __func__); Loading @@ -287,74 +269,148 @@ static int dsi_link_clk_enable(struct dsi_link_clks *l_clks) return rc; byte_intf_clk_err: clk_disable(l_clks->clks.pixel_clk); clk_disable(link_hs_clks->pixel_clk); pixel_clk_err: clk_disable(l_clks->clks.byte_clk); clk_disable(link_hs_clks->byte_clk); byte_clk_err: clk_disable(l_clks->clks.esc_clk); esc_clk_err: return rc; } static int dsi_link_clk_disable(struct dsi_link_clks *l_clks) static int dsi_link_hs_clk_disable( struct mdss_dsi_link_hs_clk_info *link_hs_clks) { if (l_clks->clks.byte_intf_clk) clk_disable(l_clks->clks.byte_intf_clk); clk_disable(l_clks->clks.esc_clk); clk_disable(l_clks->clks.pixel_clk); clk_disable(l_clks->clks.byte_clk); if (link_hs_clks->byte_intf_clk) clk_disable(link_hs_clks->byte_intf_clk); clk_disable(link_hs_clks->pixel_clk); clk_disable(link_hs_clks->byte_clk); return 0; } static int dsi_link_clk_start(struct dsi_link_clks *l_clks) static int dsi_link_hs_clk_start( struct mdss_dsi_link_hs_clk_info *link_hs_clks, enum mdss_dsi_link_clk_op_type op_type) { int rc = 0; struct dsi_link_clks *l_clks; struct mdss_dsi_clk_mngr *mngr; l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks); mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks); rc = dsi_link_clk_set_rate(l_clks); if (op_type & MDSS_DSI_LINK_CLK_SET_RATE) { rc = dsi_link_hs_clk_set_rate(link_hs_clks); if (rc) { pr_err("failed to set clk rates, rc = %d\n", rc); pr_err("failed to set HS clk rates, rc = %d\n", rc); goto error; } } rc = dsi_link_clk_prepare(l_clks); if (op_type & MDSS_DSI_LINK_CLK_PREPARE) { rc = dsi_link_hs_clk_prepare(link_hs_clks); if (rc) { pr_err("failed to prepare link clks, rc = %d\n", rc); pr_err("failed to prepare link HS clks, rc = %d\n", rc); goto error; } } rc = dsi_link_clk_enable(l_clks); if (op_type & MDSS_DSI_LINK_CLK_ENABLE) { rc = dsi_link_hs_clk_enable(link_hs_clks); if (rc) { pr_err("failed to enable link clks, rc = %d\n", rc); pr_err("failed to enable link HS clks, rc = %d\n", rc); goto error_unprepare; } } pr_debug("%s: LINK CLOCK IS ON\n", mngr->name); pr_debug("%s: LINK HS CLOCK IS ON\n", mngr->name); return rc; error_unprepare: dsi_link_clk_unprepare(l_clks); dsi_link_hs_clk_unprepare(link_hs_clks); error: return rc; } static int dsi_link_lp_clk_start( struct mdss_dsi_link_lp_clk_info *link_lp_clks) { int rc = 0; struct mdss_dsi_clk_mngr *mngr; struct dsi_link_clks *l_clks; struct mdss_dsi_ctrl_pdata *ctrl; l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks); mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks); /* * In an ideal world, cont_splash_enabled should not be required inside * the clock manager. But, in the current driver cont_splash_enabled * flag is set inside mdp driver and there is no interface event * associated with this flag setting. Also, set rate for clock need not * be called for every enable call. It should be done only once when * coming out of suspend. */ ctrl = mngr->priv_data; if (ctrl->panel_data.panel_info.cont_splash_enabled) goto prepare; rc = clk_set_rate(link_lp_clks->esc_clk, link_lp_clks->esc_clk_rate); if (rc) { pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc); goto error; } prepare: rc = clk_prepare(link_lp_clks->esc_clk); if (rc) { pr_err("Failed to prepare dsi esc clk\n"); goto error; } rc = clk_enable(link_lp_clks->esc_clk); if (rc) { pr_err("Failed to enable dsi esc clk\n"); clk_unprepare(l_clks->lp_clks.esc_clk); goto error; } error: pr_debug("%s: LINK LP CLOCK IS ON\n", mngr->name); return rc; } static int dsi_link_clk_stop(struct dsi_link_clks *l_clks) static int dsi_link_hs_clk_stop( struct mdss_dsi_link_hs_clk_info *link_hs_clks) { struct dsi_link_clks *l_clks; struct mdss_dsi_clk_mngr *mngr; l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks); mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks); (void)dsi_link_clk_disable(l_clks); (void)dsi_link_hs_clk_disable(link_hs_clks); (void)dsi_link_clk_unprepare(l_clks); pr_debug("%s: LINK CLOCK IS OFF\n", mngr->name); (void)dsi_link_hs_clk_unprepare(link_hs_clks); pr_debug("%s: LINK HS CLOCK IS OFF\n", mngr->name); return 0; } static int dsi_link_lp_clk_stop( struct mdss_dsi_link_lp_clk_info *link_lp_clks) { struct dsi_link_clks *l_clks; struct mdss_dsi_clk_mngr *mngr; l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks); mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks); clk_disable(l_clks->lp_clks.esc_clk); clk_unprepare(l_clks->lp_clks.esc_clk); pr_debug("%s: LINK LP CLOCK IS OFF\n", mngr->name); return 0; } static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, struct dsi_link_clks *l_clks, u32 l_state) { Loading Loading @@ -385,7 +441,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (c_clks && (c_state == MDSS_DSI_CLK_ON)) { if (c_clks->current_clk_state == MDSS_DSI_CLK_OFF) { rc = mngr->pre_clkon_cb(mngr->priv_data, MDSS_DSI_CORE_CLK, MDSS_DSI_CORE_CLK, MDSS_DSI_LINK_NONE, MDSS_DSI_CLK_ON); if (rc) { pr_err("failed to turn on MDP FS rc= %d\n", rc); Loading @@ -400,7 +456,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (mngr->post_clkon_cb) { rc = mngr->post_clkon_cb(mngr->priv_data, MDSS_DSI_CORE_CLK, MDSS_DSI_CORE_CLK, MDSS_DSI_LINK_NONE, MDSS_DSI_CLK_ON); if (rc) pr_err("post clk on cb failed, rc = %d\n", rc); Loading @@ -413,21 +469,50 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (l_state == MDSS_DSI_CLK_ON) { if (mngr->pre_clkon_cb) { rc = mngr->pre_clkon_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, l_state); MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_LP_CLK, l_state); if (rc) pr_err("pre link clk on cb failed\n"); pr_err("pre link LP clk on cb failed\n"); } rc = dsi_link_clk_start(l_clks); rc = dsi_link_lp_clk_start(&l_clks->lp_clks); if (rc) { pr_err("failed to start link clk rc= %d\n", rc); pr_err("failed to start LP link clk clk\n"); goto error; } if (mngr->post_clkon_cb) { rc = mngr->post_clkon_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_LP_CLK, l_state); if (rc) pr_err("post LP clk on cb failed\n"); } if (mngr->pre_clkon_cb) { rc = mngr->pre_clkon_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_HS_CLK, l_state); if (rc) pr_err("post link clk on cb failed\n"); pr_err("pre HS clk on cb failed\n"); } rc = dsi_link_hs_clk_start(&l_clks->hs_clks, (MDSS_DSI_LINK_CLK_SET_RATE | MDSS_DSI_LINK_CLK_PREPARE)); if (rc) { pr_err("failed to prepare HS clk rc= %d\n", rc); goto error; } if (mngr->post_clkon_cb) { rc = mngr->post_clkon_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_HS_CLK, l_state); if (rc) pr_err("post HS clk on cb failed\n"); } rc = dsi_link_hs_clk_start(&l_clks->hs_clks, MDSS_DSI_LINK_CLK_ENABLE); if (rc) { pr_err("failed to enable HS clk rc= %d\n", rc); goto error; } } else { /* Loading Loading @@ -456,9 +541,16 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, goto error; } rc = dsi_link_clk_start(l_clks); rc = dsi_link_lp_clk_start(&l_clks->lp_clks); if (rc) { pr_err("LP Link clks did not start\n"); goto error; } rc = dsi_link_hs_clk_start(&l_clks->hs_clks, MDSS_DSI_LINK_CLK_START); if (rc) { pr_err("Link clks did not start\n"); pr_err("HS Link clks did not start\n"); goto error; } l_c_on = true; Loading @@ -467,24 +559,50 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (mngr->pre_clkoff_cb) { rc = mngr->pre_clkoff_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, l_state); MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_HS_CLK, l_state); if (rc) pr_err("pre HS clk off cb failed\n"); } rc = dsi_link_hs_clk_stop(&l_clks->hs_clks); if (rc) { pr_err("failed to stop HS clk, rc = %d\n", rc); goto error; } if (mngr->post_clkoff_cb) { rc = mngr->post_clkoff_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_HS_CLK, l_state); if (rc) pr_err("post HS clk off cb failed\n"); } if (mngr->pre_clkoff_cb) { rc = mngr->pre_clkoff_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_LP_CLK, l_state); if (rc) pr_err("pre link clk off cb failed\n"); pr_err("pre LP clk off cb failed\n"); } rc = dsi_link_clk_stop(l_clks); rc = dsi_link_lp_clk_stop(&l_clks->lp_clks); if (rc) { pr_err("failed to stop link clk, rc = %d\n", pr_err("failed to stop LP link clk, rc = %d\n", rc); goto error; } if (mngr->post_clkoff_cb) { rc = mngr->post_clkoff_cb(mngr->priv_data, MDSS_DSI_LINK_CLK, l_state); MDSS_DSI_LINK_CLK, MDSS_DSI_LINK_LP_CLK, l_state); if (rc) pr_err("post link clk off cb failed\n"); pr_err("post LP clk off cb failed\n"); } /* * This check is to save unnecessary clock state * change when going from EARLY_GATE to OFF. In the Loading Loading @@ -540,7 +658,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (mngr->pre_clkoff_cb) { rc = mngr->pre_clkoff_cb(mngr->priv_data, MDSS_DSI_CORE_CLK, MDSS_DSI_CORE_CLK, MDSS_DSI_LINK_NONE, c_state); if (rc) pr_err("pre core clk off cb failed\n"); Loading @@ -555,7 +673,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (c_state == MDSS_DSI_CLK_OFF) { if (mngr->post_clkoff_cb) { rc = mngr->post_clkoff_cb(mngr->priv_data, MDSS_DSI_CORE_CLK, MDSS_DSI_CORE_CLK, MDSS_DSI_LINK_NONE, MDSS_DSI_CLK_OFF); if (rc) pr_err("post clkoff cb fail, rc = %d\n", Loading Loading @@ -648,18 +766,20 @@ static int dsi_set_clk_rate(struct mdss_dsi_clk_mngr *mngr, int clk, u32 rate, MDSS_XLOG(clk, rate, flags); switch (clk) { case MDSS_DSI_LINK_ESC_CLK: mngr->link_clks.esc_clk_rate = rate; mngr->link_clks.lp_clks.esc_clk_rate = rate; if (!flags) { rc = clk_set_rate(mngr->link_clks.clks.esc_clk, rate); rc = clk_set_rate(mngr->link_clks.lp_clks.esc_clk, rate); if (rc) pr_err("set rate failed for esc clk rc=%d\n", rc); } break; case MDSS_DSI_LINK_BYTE_CLK: mngr->link_clks.byte_clk_rate = rate; mngr->link_clks.hs_clks.byte_clk_rate = rate; if (!flags) { rc = clk_set_rate(mngr->link_clks.clks.byte_clk, rate); rc = clk_set_rate(mngr->link_clks.hs_clks.byte_clk, rate); if (rc) { pr_err("set rate failed for byte clk rc=%d\n", rc); Loading @@ -673,9 +793,9 @@ static int dsi_set_clk_rate(struct mdss_dsi_clk_mngr *mngr, int clk, u32 rate, * todo: this needs to be revisited when support for * CPHY is added. */ if (mngr->link_clks.clks.byte_intf_clk) { if (mngr->link_clks.hs_clks.byte_intf_clk) { rc = clk_set_rate( mngr->link_clks.clks.byte_intf_clk, mngr->link_clks.hs_clks.byte_intf_clk, rate / 2); if (rc) pr_err("set rate failed for byte intf clk rc=%d\n", Loading @@ -684,9 +804,10 @@ static int dsi_set_clk_rate(struct mdss_dsi_clk_mngr *mngr, int clk, u32 rate, } break; case MDSS_DSI_LINK_PIX_CLK: mngr->link_clks.pix_clk_rate = rate; mngr->link_clks.hs_clks.pix_clk_rate = rate; if (!flags) { rc = clk_set_rate(mngr->link_clks.clks.pixel_clk, rate); rc = clk_set_rate(mngr->link_clks.hs_clks.pixel_clk, rate); if (rc) pr_err("failed to set rate for pix clk rc=%d\n", rc); Loading Loading @@ -945,8 +1066,10 @@ void *mdss_dsi_clk_init(struct mdss_dsi_clk_info *info) mutex_init(&mngr->clk_mutex); memcpy(&mngr->core_clks.clks, &info->core_clks, sizeof(struct mdss_dsi_core_clk_info)); memcpy(&mngr->link_clks.clks, &info->link_clks, sizeof(struct mdss_dsi_link_clk_info)); memcpy(&mngr->link_clks.hs_clks, &info->link_hs_clks, sizeof(struct mdss_dsi_link_hs_clk_info)); memcpy(&mngr->link_clks.lp_clks, &info->link_lp_clks, sizeof(struct mdss_dsi_link_lp_clk_info)); INIT_LIST_HEAD(&mngr->client_list); mngr->pre_clkon_cb = info->pre_clkon_cb; Loading Loading @@ -1038,15 +1161,26 @@ int mdss_dsi_clk_force_toggle(void *client, u32 clk) if ((clk & MDSS_DSI_LINK_CLK) && (mngr->link_clks.current_clk_state == MDSS_DSI_CLK_ON)) { rc = dsi_link_clk_stop(&mngr->link_clks); rc = dsi_link_hs_clk_stop(&mngr->link_clks.hs_clks); if (rc) { pr_err("failed to stop link clks\n"); pr_err("failed to stop HS link clks\n"); goto error; } rc = dsi_link_clk_start(&mngr->link_clks); rc = dsi_link_lp_clk_stop(&mngr->link_clks.lp_clks); if (rc) { pr_err("failed to stop LP link clks\n"); goto error; } rc = dsi_link_lp_clk_start(&mngr->link_clks.lp_clks); if (rc) pr_err("failed to start LP link clks\n"); rc = dsi_link_hs_clk_start(&mngr->link_clks.hs_clks, MDSS_DSI_LINK_CLK_START); if (rc) pr_err("failed to start link clks\n"); pr_err("failed to start HS link clks\n"); } else if (clk & MDSS_DSI_LINK_CLK) { pr_err("cannot reset, link clock is off\n"); Loading
drivers/video/fbdev/msm/mdss_dsi_clk.h +38 −10 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2015-2016, 2018, 2020, The Linux Foundation. All rights reserved. */ /* Copyright (c) 2015-2016, 2018, 2020-2021, The Linux Foundation. All rights reserved. */ #ifndef _MDSS_DSI_CLK_H_ #define _MDSS_DSI_CLK_H_ Loading Loading @@ -30,6 +30,13 @@ enum mdss_dsi_link_clk_type { MDSS_DSI_LINK_CLK_MAX, }; enum mdss_dsi_link_clk_op_type { MDSS_DSI_LINK_CLK_SET_RATE = BIT(0), MDSS_DSI_LINK_CLK_PREPARE = BIT(1), MDSS_DSI_LINK_CLK_ENABLE = BIT(2), MDSS_DSI_LINK_CLK_START = BIT(0) | BIT(1) | BIT(2), }; enum mdss_dsi_clk_type { MDSS_DSI_CORE_CLK = BIT(0), MDSS_DSI_LINK_CLK = BIT(1), Loading @@ -37,52 +44,66 @@ enum mdss_dsi_clk_type { MDSS_DSI_CLKS_MAX = BIT(2), }; enum mdss_dsi_lclk_type { MDSS_DSI_LINK_NONE = 0, MDSS_DSI_LINK_LP_CLK = BIT(0), MDSS_DSI_LINK_HS_CLK = BIT(1), }; /** * typedef *pre_clockoff_cb() - Callback before clock is turned off * @priv: private data pointer. * @clk_type: clock which is being turned off. * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. * @new_state: next state for the clock. * * @return: error code. */ typedef int (*pre_clockoff_cb)(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state new_state); /** * typedef *post_clockoff_cb() - Callback after clock is turned off * @priv: private data pointer. * @clk_type: clock which was turned off. * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. * @curr_state: current state for the clock. * * @return: error code. */ typedef int (*post_clockoff_cb)(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state curr_state); /** * typedef *post_clockon_cb() - Callback after clock is turned on * @priv: private data pointer. * @clk_type: clock which was turned on. * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. * @curr_state: current state for the clock. * * @return: error code. */ typedef int (*post_clockon_cb)(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state curr_state); /** * typedef *pre_clockon_cb() - Callback before clock is turned on * @priv: private data pointer. * @clk_type: clock which is being turned on. * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. * @new_state: next state for the clock. * * @return: error code. */ typedef int (*pre_clockon_cb)(void *priv, enum mdss_dsi_clk_type clk_type, enum mdss_dsi_lclk_type l_type, enum mdss_dsi_clk_state new_state); struct mdss_dsi_core_clk_info { Loading @@ -93,11 +114,17 @@ struct mdss_dsi_core_clk_info { struct clk *mmss_misc_ahb_clk; }; struct mdss_dsi_link_clk_info { struct clk *esc_clk; struct mdss_dsi_link_hs_clk_info { struct clk *byte_clk; struct clk *pixel_clk; struct clk *byte_intf_clk; u32 byte_clk_rate; u32 pix_clk_rate; }; struct mdss_dsi_link_lp_clk_info { struct clk *esc_clk; u32 esc_clk_rate; }; struct dsi_panel_clk_ctrl { Loading @@ -119,7 +146,8 @@ struct dsi_panel_clk_ctrl { struct mdss_dsi_clk_info { char name[DSI_CLK_NAME_LEN]; struct mdss_dsi_core_clk_info core_clks; struct mdss_dsi_link_clk_info link_clks; struct mdss_dsi_link_hs_clk_info link_hs_clks; struct mdss_dsi_link_lp_clk_info link_lp_clks; pre_clockoff_cb pre_clkoff_cb; post_clockoff_cb post_clkoff_cb; post_clockon_cb post_clkon_cb; Loading