summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/msm/dp/dp_ctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/dp/dp_ctrl.c')
-rw-r--r--drivers/gpu/drm/msm/dp/dp_ctrl.c150
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;
}