2023-09-16 03:55:07

by Kuogee Hsieh

[permalink] [raw]
Subject: [PATCH v2 0/7] incorporate pm runtime framework and eDP clean up

Incorporate pm runtime framework into DP driver and clean up eDP
by moving of_dp_aux_populate_bus() to probe()

Kuogee Hsieh (7):
drm/msm/dp: tie dp_display_irq_handler() with dp driver
drm/msm/dp: replace is_connected with link_ready
drm/msm/dp: use drm_bridge_hpd_notify() to report HPD status changes
drm/msm/dp: incorporate pm_runtime framework into DP driver
drm/msm/dp: delete EV_HPD_INIT_SETUP
drm/msm/dp: add pm_runtime_force_suspend()/resume()
drm/msm/dp: move of_dp_aux_populate_bus() to eDP probe()

drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 4 -
drivers/gpu/drm/msm/dp/dp_aux.c | 30 +++
drivers/gpu/drm/msm/dp/dp_display.c | 348 ++++++++++++++------------------
drivers/gpu/drm/msm/dp/dp_display.h | 3 +-
drivers/gpu/drm/msm/dp/dp_drm.c | 14 +-
drivers/gpu/drm/msm/dp/dp_power.c | 9 -
drivers/gpu/drm/msm/msm_drv.h | 5 -
7 files changed, 185 insertions(+), 228 deletions(-)

--
2.7.4


2023-09-16 04:51:36

by Kuogee Hsieh

[permalink] [raw]
Subject: [PATCH v2 1/7] drm/msm/dp: tie dp_display_irq_handler() with dp driver

Currently the dp_display_irq_handler() is executed at msm_dp_modeset_init()
which ties irq registration to the DPU device's life cycle, while depending on
resources that are released as the DP device is torn down. Move register DP
driver irq handler at dp_display_probe() to have dp_display_irq_handler()
is tied with DP device.

Signed-off-by: Kuogee Hsieh <[email protected]>
---
drivers/gpu/drm/msm/dp/dp_display.c | 35 +++++++++++++----------------------
drivers/gpu/drm/msm/dp/dp_display.h | 1 -
2 files changed, 13 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 76f1395..c217430 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1193,30 +1193,23 @@ static irqreturn_t dp_display_irq_handler(int irq, void *dev_id)
return ret;
}

-int dp_display_request_irq(struct msm_dp *dp_display)
+static int dp_display_request_irq(struct dp_display_private *dp)
{
int rc = 0;
- struct dp_display_private *dp;
-
- if (!dp_display) {
- DRM_ERROR("invalid input\n");
- return -EINVAL;
- }
-
- dp = container_of(dp_display, struct dp_display_private, dp_display);
+ struct device *dev = &dp->pdev->dev;

- dp->irq = irq_of_parse_and_map(dp->pdev->dev.of_node, 0);
if (!dp->irq) {
- DRM_ERROR("failed to get irq\n");
- return -EINVAL;
+ dp->irq = platform_get_irq(dp->pdev, 0);
+ if (!dp->irq) {
+ DRM_ERROR("failed to get irq\n");
+ return -EINVAL;
+ }
}

- rc = devm_request_irq(dp_display->drm_dev->dev, dp->irq,
- dp_display_irq_handler,
+ rc = devm_request_irq(dev, dp->irq, dp_display_irq_handler,
IRQF_TRIGGER_HIGH, "dp_display_isr", dp);
if (rc < 0) {
- DRM_ERROR("failed to request IRQ%u: %d\n",
- dp->irq, rc);
+ DRM_ERROR("failed to request IRQ%u: %d\n", dp->irq, rc);
return rc;
}

@@ -1287,6 +1280,10 @@ static int dp_display_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, &dp->dp_display);

+ rc = dp_display_request_irq(dp);
+ if (rc)
+ return rc;
+
rc = component_add(&pdev->dev, &dp_display_comp_ops);
if (rc) {
DRM_ERROR("component add failed, rc=%d\n", rc);
@@ -1549,12 +1546,6 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,

dp_priv = container_of(dp_display, struct dp_display_private, dp_display);

- ret = dp_display_request_irq(dp_display);
- if (ret) {
- DRM_ERROR("request_irq failed, ret=%d\n", ret);
- return ret;
- }
-
ret = dp_display_get_next_bridge(dp_display);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index 1e9415a..b3c08de 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -35,7 +35,6 @@ struct msm_dp {
int dp_display_set_plugged_cb(struct msm_dp *dp_display,
hdmi_codec_plugged_cb fn, struct device *codec_dev);
int dp_display_get_modes(struct msm_dp *dp_display);
-int dp_display_request_irq(struct msm_dp *dp_display);
bool dp_display_check_video_test(struct msm_dp *dp_display);
int dp_display_get_test_bpp(struct msm_dp *dp_display);
void dp_display_signal_audio_start(struct msm_dp *dp_display);
--
2.7.4

2023-09-16 06:48:23

by Kuogee Hsieh

[permalink] [raw]
Subject: [PATCH v2 4/7] drm/msm/dp: incorporate pm_runtime framework into DP driver

Currently DP driver is executed independent of PM runtime framework.
This lead DP driver incompatible with others. Incorporating pm runtime
framework into DP driver so that both power and clocks to enable/disable
host controller fits with PM runtime mechanism. Once pm runtime framework
is incorporated into DP driver, wake up device from power up path is not
necessary. Hence remove it. Both EV_POWER_PM_GET and EV_POWER_PM_PUT events
are introduced to perform pm runtime control for the HPD GPIO routing to a
display-connector case.

Signed-off-by: Kuogee Hsieh <[email protected]>
---
drivers/gpu/drm/msm/dp/dp_aux.c | 5 ++
drivers/gpu/drm/msm/dp/dp_display.c | 114 +++++++++++++++++++++++++++---------
drivers/gpu/drm/msm/dp/dp_power.c | 9 ---
3 files changed, 90 insertions(+), 38 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index 8e3b677..8fa93c5 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -291,6 +291,9 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux,
return -EINVAL;
}

+ if (pm_runtime_resume_and_get(dp_aux->dev))
+ return -EINVAL;
+
mutex_lock(&aux->mutex);
if (!aux->initted) {
ret = -EIO;
@@ -364,6 +367,8 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux,

exit:
mutex_unlock(&aux->mutex);
+ pm_runtime_mark_last_busy(dp_aux->dev);
+ pm_runtime_put_autosuspend(dp_aux->dev);

return ret;
}
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 59f9d85..e7af7f7 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -60,6 +60,8 @@ enum {
EV_IRQ_HPD_INT,
EV_HPD_UNPLUG_INT,
EV_USER_NOTIFICATION,
+ EV_POWER_PM_GET,
+ EV_POWER_PM_PUT,
};

#define EVENT_TIMEOUT (HZ/10) /* 100ms */
@@ -276,13 +278,6 @@ static int dp_display_bind(struct device *dev, struct device *master,
dp->dp_display.drm_dev = drm;
priv->dp[dp->id] = &dp->dp_display;

- rc = dp->parser->parse(dp->parser);
- if (rc) {
- DRM_ERROR("device tree parsing failed\n");
- goto end;
- }
-
-
dp->drm_dev = drm;
dp->aux->drm_dev = drm;
rc = dp_aux_register(dp->aux);
@@ -291,12 +286,6 @@ static int dp_display_bind(struct device *dev, struct device *master,
goto end;
}

- rc = dp_power_client_init(dp->power);
- if (rc) {
- DRM_ERROR("Power client create failed\n");
- goto end;
- }
-
rc = dp_register_audio_driver(dev, dp->audio);
if (rc) {
DRM_ERROR("Audio registration Dp failed\n");
@@ -320,10 +309,6 @@ static void dp_display_unbind(struct device *dev, struct device *master,
struct dp_display_private *dp = dev_get_dp_display_private(dev);
struct msm_drm_private *priv = dev_get_drvdata(master);

- /* disable all HPD interrupts */
- if (dp->core_initialized)
- dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_INT_MASK, false);
-
kthread_stop(dp->ev_tsk);

of_dp_aux_depopulate_bus(dp->aux);
@@ -467,6 +452,18 @@ static void dp_display_host_deinit(struct dp_display_private *dp)
dp->core_initialized = false;
}

+static void dp_display_pm_get(struct dp_display_private *dp)
+{
+ if (pm_runtime_resume_and_get(&dp->pdev->dev))
+ DRM_ERROR("failed to start power\n");
+}
+
+static void dp_display_pm_put(struct dp_display_private *dp)
+{
+ pm_runtime_mark_last_busy(&dp->pdev->dev);
+ pm_runtime_put_autosuspend(&dp->pdev->dev);
+}
+
static int dp_display_usbpd_configure_cb(struct device *dev)
{
struct dp_display_private *dp = dev_get_dp_display_private(dev);
@@ -1096,7 +1093,6 @@ static int hpd_event_thread(void *data)

switch (todo->event_id) {
case EV_HPD_INIT_SETUP:
- dp_display_host_init(dp_priv);
break;
case EV_HPD_PLUG_INT:
dp_hpd_plug_handle(dp_priv, todo->data);
@@ -1111,6 +1107,12 @@ static int hpd_event_thread(void *data)
dp_display_send_hpd_notification(dp_priv,
todo->data);
break;
+ case EV_POWER_PM_GET:
+ dp_display_pm_get(dp_priv);
+ break;
+ case EV_POWER_PM_PUT:
+ dp_display_pm_put(dp_priv);
+ break;
default:
break;
}
@@ -1251,6 +1253,18 @@ static int dp_display_probe(struct platform_device *pdev)
return -EPROBE_DEFER;
}

+ rc = dp->parser->parse(dp->parser);
+ if (rc) {
+ DRM_ERROR("device tree parsing failed\n");
+ return -EPROBE_DEFER;
+ }
+
+ rc = dp_power_client_init(dp->power);
+ if (rc) {
+ DRM_ERROR("Power client create failed\n");
+ return -EPROBE_DEFER;
+ }
+
/* setup event q */
mutex_init(&dp->event_mutex);
init_waitqueue_head(&dp->event_q);
@@ -1263,6 +1277,10 @@ static int dp_display_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, &dp->dp_display);

+ devm_pm_runtime_enable(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
+ pm_runtime_use_autosuspend(&pdev->dev);
+
rc = dp_display_request_irq(dp);
if (rc)
return rc;
@@ -1285,6 +1303,36 @@ static int dp_display_remove(struct platform_device *pdev)

platform_set_drvdata(pdev, NULL);

+ pm_runtime_put_sync_suspend(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static int dp_pm_runtime_suspend(struct device *dev)
+{
+ struct dp_display_private *dp = dev_get_dp_display_private(dev);
+
+ if (dp->dp_display.is_edp) {
+ dp_display_host_phy_exit(dp);
+ dp_catalog_ctrl_hpd_disable(dp->catalog);
+ }
+ dp_display_host_deinit(dp);
+
+ return 0;
+}
+
+static int dp_pm_runtime_resume(struct device *dev)
+{
+ struct dp_display_private *dp = dev_get_dp_display_private(dev);
+
+ dp_display_host_init(dp);
+ if (dp->dp_display.is_edp) {
+ dp_catalog_ctrl_hpd_enable(dp->catalog);
+ dp_display_host_phy_init(dp);
+ }
+
return 0;
}

@@ -1389,6 +1437,7 @@ static int dp_pm_suspend(struct device *dev)
}

static const struct dev_pm_ops dp_pm_ops = {
+ SET_RUNTIME_PM_OPS(dp_pm_runtime_suspend, dp_pm_runtime_resume, NULL)
.suspend = dp_pm_suspend,
.resume = dp_pm_resume,
};
@@ -1473,10 +1522,6 @@ static int dp_display_get_next_bridge(struct msm_dp *dp)
aux_bus = of_get_child_by_name(dev->of_node, "aux-bus");

if (aux_bus && dp->is_edp) {
- dp_display_host_init(dp_priv);
- dp_catalog_ctrl_hpd_enable(dp_priv->catalog);
- dp_display_host_phy_init(dp_priv);
-
/*
* The code below assumes that the panel will finish probing
* by the time devm_of_dp_aux_populate_ep_devices() returns.
@@ -1578,6 +1623,11 @@ void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
dp_hpd_plug_handle(dp_display, 0);

mutex_lock(&dp_display->event_mutex);
+ if (pm_runtime_resume_and_get(&dp_display->pdev->dev)) {
+ DRM_ERROR("failed to start power\n");
+ mutex_unlock(&dp_display->event_mutex);
+ return;
+ }

state = dp_display->hpd_state;
if (state != ST_DISPLAY_OFF && state != ST_MAINLINK_READY) {
@@ -1658,6 +1708,8 @@ void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
}

drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type);
+
+ pm_runtime_put_sync(&dp_display->pdev->dev);
mutex_unlock(&dp_display->event_mutex);
}

@@ -1697,6 +1749,9 @@ void dp_bridge_hpd_enable(struct drm_bridge *bridge)
struct dp_display_private *dp = container_of(dp_display, struct dp_display_private, dp_display);

mutex_lock(&dp->event_mutex);
+ if (pm_runtime_resume_and_get(&dp->pdev->dev))
+ DRM_ERROR("failed to start power\n");
+
dp_catalog_ctrl_hpd_enable(dp->catalog);

/* enable HDP interrupts */
@@ -1718,6 +1773,9 @@ void dp_bridge_hpd_disable(struct drm_bridge *bridge)
dp_catalog_ctrl_hpd_disable(dp->catalog);

dp_display->internal_hpd = false;
+
+ pm_runtime_mark_last_busy(&dp->pdev->dev);
+ pm_runtime_put_autosuspend(&dp->pdev->dev);
mutex_unlock(&dp->event_mutex);
}

@@ -1732,13 +1790,11 @@ void dp_bridge_hpd_notify(struct drm_bridge *bridge,
if (dp_display->internal_hpd)
return;

- if (!dp->core_initialized) {
- drm_dbg_dp(dp->drm_dev, "not initialized\n");
- return;
- }
-
- if (!dp_display->link_ready && status == connector_status_connected)
+ if (!dp_display->link_ready && status == connector_status_connected) {
+ dp_add_event(dp, EV_POWER_PM_GET, 0, 0);
dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0);
- else if (dp_display->link_ready && status == connector_status_disconnected)
+ } else if (dp_display->link_ready && status == connector_status_disconnected) {
dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0);
+ dp_add_event(dp, EV_POWER_PM_PUT, 0, 0);
+ }
}
diff --git a/drivers/gpu/drm/msm/dp/dp_power.c b/drivers/gpu/drm/msm/dp/dp_power.c
index 5cb84ca..ed2f62a 100644
--- a/drivers/gpu/drm/msm/dp/dp_power.c
+++ b/drivers/gpu/drm/msm/dp/dp_power.c
@@ -152,8 +152,6 @@ int dp_power_client_init(struct dp_power *dp_power)

power = container_of(dp_power, struct dp_power_private, dp_power);

- pm_runtime_enable(power->dev);
-
return dp_power_clk_init(power);
}

@@ -162,8 +160,6 @@ void dp_power_client_deinit(struct dp_power *dp_power)
struct dp_power_private *power;

power = container_of(dp_power, struct dp_power_private, dp_power);
-
- pm_runtime_disable(power->dev);
}

int dp_power_init(struct dp_power *dp_power)
@@ -173,11 +169,7 @@ int dp_power_init(struct dp_power *dp_power)

power = container_of(dp_power, struct dp_power_private, dp_power);

- pm_runtime_get_sync(power->dev);
-
rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true);
- if (rc)
- pm_runtime_put_sync(power->dev);

return rc;
}
@@ -189,7 +181,6 @@ int dp_power_deinit(struct dp_power *dp_power)
power = container_of(dp_power, struct dp_power_private, dp_power);

dp_power_clk_enable(dp_power, DP_CORE_PM, false);
- pm_runtime_put_sync(power->dev);
return 0;
}

--
2.7.4