diff options
Diffstat (limited to 'drivers/gpu/drm/msm/dp/dp_ctrl.c')
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_ctrl.c | 150 |
1 files changed, 134 insertions, 16 deletions
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index fb588fde298a..b501a06e3ec6 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -76,13 +76,16 @@ struct dp_ctrl_private { struct drm_dp_aux *aux; struct dp_panel *panel; struct dp_link *link; - struct dp_power *power; struct dp_parser *parser; struct dp_catalog *catalog; struct completion idle_comp; struct completion psr_op_comp; struct completion video_comp; + + bool core_clks_on; + bool link_clks_on; + bool stream_clks_on; }; static int dp_aux_link_configure(struct drm_dp_aux *aux, @@ -1333,6 +1336,83 @@ static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl, name, rate); } +int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl, + enum dp_pm_type pm_type, bool enable) +{ + struct dp_ctrl_private *ctrl; + struct dss_module_power *mp; + int ret = 0; + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + if (pm_type != DP_CORE_PM && + pm_type != DP_CTRL_PM && + pm_type != DP_STREAM_PM) { + DRM_ERROR("unsupported ctrl module: %s\n", + dp_parser_pm_name(pm_type)); + return -EINVAL; + } + + if (enable) { + if (pm_type == DP_CORE_PM && ctrl->core_clks_on) { + drm_dbg_dp(ctrl->drm_dev, + "core clks already enabled\n"); + return 0; + } + + if (pm_type == DP_CTRL_PM && ctrl->link_clks_on) { + drm_dbg_dp(ctrl->drm_dev, + "links clks already enabled\n"); + return 0; + } + + if (pm_type == DP_STREAM_PM && ctrl->stream_clks_on) { + drm_dbg_dp(ctrl->drm_dev, + "pixel clks already enabled\n"); + return 0; + } + + if ((pm_type == DP_CTRL_PM) && (!ctrl->core_clks_on)) { + drm_dbg_dp(ctrl->drm_dev, + "Enable core clks before link clks\n"); + mp = &ctrl->parser->mp[DP_CORE_PM]; + + ret = clk_bulk_prepare_enable(mp->num_clk, mp->clocks); + if (ret) + return ret; + + ctrl->core_clks_on = true; + } + } + + mp = &ctrl->parser->mp[pm_type]; + if (enable) { + ret = clk_bulk_prepare_enable(mp->num_clk, mp->clocks); + if (ret) + return ret; + } else { + clk_bulk_disable_unprepare(mp->num_clk, mp->clocks); + } + + if (pm_type == DP_CORE_PM) + ctrl->core_clks_on = enable; + else if (pm_type == DP_STREAM_PM) + ctrl->stream_clks_on = enable; + else + ctrl->link_clks_on = enable; + + drm_dbg_dp(ctrl->drm_dev, "%s clocks for %s\n", + enable ? "enable" : "disable", + dp_parser_pm_name(pm_type)); + drm_dbg_dp(ctrl->drm_dev, + "stream_clks:%s link_clks:%s core_clks:%s\n", + ctrl->stream_clks_on ? "on" : "off", + ctrl->link_clks_on ? "on" : "off", + ctrl->core_clks_on ? "on" : "off"); + + return 0; +} + static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl) { int ret = 0; @@ -1349,7 +1429,7 @@ static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl) phy_power_on(phy); dev_pm_opp_set_rate(ctrl->dev, ctrl->link->link_params.rate * 1000); - ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, true); + ret = dp_ctrl_clk_enable(&ctrl->dp_ctrl, DP_CTRL_PM, true); if (ret) DRM_ERROR("Unable to start link clocks. ret=%d\n", ret); @@ -1497,7 +1577,7 @@ static int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private *ctrl) * link maintenance. */ dev_pm_opp_set_rate(ctrl->dev, 0); - ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false); + ret = dp_ctrl_clk_enable(&ctrl->dp_ctrl, DP_CTRL_PM, false); if (ret) { DRM_ERROR("Failed to disable clocks. ret=%d\n", ret); return ret; @@ -1529,7 +1609,7 @@ static int dp_ctrl_deinitialize_mainlink(struct dp_ctrl_private *ctrl) dp_catalog_ctrl_reset(ctrl->catalog); dev_pm_opp_set_rate(ctrl->dev, 0); - ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false); + ret = dp_ctrl_clk_enable(&ctrl->dp_ctrl, DP_CTRL_PM, false); if (ret) { DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret); } @@ -1651,7 +1731,7 @@ static int dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl) pixel_rate = ctrl->panel->dp_mode.drm_mode.clock; dp_ctrl_set_clock_rate(ctrl, DP_STREAM_PM, "stream_pixel", pixel_rate * 1000); - ret = dp_power_clk_enable(ctrl->power, DP_STREAM_PM, true); + ret = dp_ctrl_clk_enable(&ctrl->dp_ctrl, DP_STREAM_PM, true); if (ret) { DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret); return ret; @@ -1747,7 +1827,7 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl) rate = ctrl->panel->link_info.rate; pixel_rate = ctrl->panel->dp_mode.drm_mode.clock; - dp_power_clk_enable(ctrl->power, DP_CORE_PM, true); + dp_ctrl_clk_enable(&ctrl->dp_ctrl, DP_CORE_PM, true); if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { drm_dbg_dp(ctrl->drm_dev, @@ -1880,7 +1960,11 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train) ctrl->link->link_params.rate, ctrl->link->link_params.num_lanes, pixel_rate); - if (!dp_power_clk_status(ctrl->power, DP_CTRL_PM)) { /* link clk is off */ + drm_dbg_dp(ctrl->drm_dev, + "core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n", + ctrl->core_clks_on, ctrl->link_clks_on, ctrl->stream_clks_on); + + if (!ctrl->link_clks_on) { /* link clk is off */ ret = dp_ctrl_enable_mainlink_clocks(ctrl); if (ret) { DRM_ERROR("Failed to start link clocks. ret=%d\n", ret); @@ -1890,7 +1974,7 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train) dp_ctrl_set_clock_rate(ctrl, DP_STREAM_PM, "stream_pixel", pixel_rate * 1000); - ret = dp_power_clk_enable(ctrl->power, DP_STREAM_PM, true); + ret = dp_ctrl_clk_enable(&ctrl->dp_ctrl, DP_STREAM_PM, true); if (ret) { DRM_ERROR("Unable to start pixel clocks. ret=%d\n", ret); goto end; @@ -1946,8 +2030,8 @@ int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl) dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); - if (dp_power_clk_status(ctrl->power, DP_STREAM_PM)) { - ret = dp_power_clk_enable(ctrl->power, DP_STREAM_PM, false); + if (ctrl->stream_clks_on) { + ret = dp_ctrl_clk_enable(&ctrl->dp_ctrl, DP_STREAM_PM, false); if (ret) { DRM_ERROR("Failed to disable pclk. ret=%d\n", ret); return ret; @@ -1955,7 +2039,7 @@ int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl) } dev_pm_opp_set_rate(ctrl->dev, 0); - ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false); + ret = dp_ctrl_clk_enable(&ctrl->dp_ctrl, DP_CTRL_PM, false); if (ret) { DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret); return ret; @@ -1985,7 +2069,7 @@ int dp_ctrl_off_link(struct dp_ctrl *dp_ctrl) dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); - ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false); + ret = dp_ctrl_clk_enable(&ctrl->dp_ctrl, DP_CTRL_PM, false); if (ret) { DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret); } @@ -2019,12 +2103,12 @@ int dp_ctrl_off(struct dp_ctrl *dp_ctrl) dp_catalog_ctrl_reset(ctrl->catalog); - ret = dp_power_clk_enable(ctrl->power, DP_STREAM_PM, false); + ret = dp_ctrl_clk_enable(&ctrl->dp_ctrl, DP_STREAM_PM, false); if (ret) DRM_ERROR("Failed to disable pixel clocks. ret=%d\n", ret); dev_pm_opp_set_rate(ctrl->dev, 0); - ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false); + ret = dp_ctrl_clk_enable(&ctrl->dp_ctrl, DP_CTRL_PM, false); if (ret) { DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret); } @@ -2081,9 +2165,38 @@ irqreturn_t dp_ctrl_isr(struct dp_ctrl *dp_ctrl) return ret; } +static int dp_ctrl_clk_init(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl_private; + int rc = 0; + struct dss_module_power *core, *ctrl, *stream; + struct device *dev; + + ctrl_private = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + dev = ctrl_private->dev; + + core = &ctrl_private->parser->mp[DP_CORE_PM]; + ctrl = &ctrl_private->parser->mp[DP_CTRL_PM]; + stream = &ctrl_private->parser->mp[DP_STREAM_PM]; + + rc = devm_clk_bulk_get(dev, core->num_clk, core->clocks); + if (rc) + return rc; + + rc = devm_clk_bulk_get(dev, ctrl->num_clk, ctrl->clocks); + if (rc) + return -ENODEV; + + rc = devm_clk_bulk_get(dev, stream->num_clk, stream->clocks); + if (rc) + return -ENODEV; + + return 0; +} + struct dp_ctrl *dp_ctrl_get(struct device *dev, struct dp_link *link, struct dp_panel *panel, struct drm_dp_aux *aux, - struct dp_power *power, struct dp_catalog *catalog, + struct dp_catalog *catalog, struct dp_parser *parser) { struct dp_ctrl_private *ctrl; @@ -2120,11 +2233,16 @@ struct dp_ctrl *dp_ctrl_get(struct device *dev, struct dp_link *link, /* in parameters */ ctrl->parser = parser; ctrl->panel = panel; - ctrl->power = power; ctrl->aux = aux; ctrl->link = link; ctrl->catalog = catalog; ctrl->dev = dev; + ret = dp_ctrl_clk_init(&ctrl->dp_ctrl); + if (ret) { + dev_err(dev, "failed to init clocks\n"); + return ERR_PTR(ret); + } + return &ctrl->dp_ctrl; } |