Skip to content

Commit c86b412

Browse files
committed
drm/vc4: hdmi: Move the HSM clock enable to runtime_pm
In order to access the HDMI controller, we need to make sure the HSM clock is enabled. If we were to access it with the clock disabled, the CPU would completely hang, resulting in an hard crash. Since we have different code path that would require it, let's move that clock enable / disable to runtime_pm that will take care of the reference counting for us. Since we also want to change the HSM clock rate and it's only valid while the clock is disabled, we need to move the clk_set_min_rate() call on the HSM clock above pm_runtime_get_and_sync(). Fixes: 4f6e3d6 ("drm/vc4: Add runtime PM support to the HDMI encoder driver") Signed-off-by: Maxime Ripard <maxime@cerno.tech> Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com> Reviewed-by: Nicolas Saenz Julienne <nsaenz@kernel.org> Tested-by: Nicolas Saenz Julienne <nsaenz@kernel.org> Tested-by: Michael Stapelberg <michael@stapelberg.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20210922125419.4125779-5-maxime@cerno.tech Link: https://lore.kernel.org/linux-arm-kernel/20210924152334.1342630-1-maxime@cerno.tech/
1 parent 3e85b81 commit c86b412

File tree

1 file changed

+44
-26
lines changed

1 file changed

+44
-26
lines changed

drivers/gpu/drm/vc4/vc4_hdmi.c

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,6 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
628628
vc4_hdmi->variant->phy_disable(vc4_hdmi);
629629

630630
clk_disable_unprepare(vc4_hdmi->pixel_bvb_clock);
631-
clk_disable_unprepare(vc4_hdmi->hsm_clock);
632631
clk_disable_unprepare(vc4_hdmi->pixel_clock);
633632

634633
ret = pm_runtime_put(&vc4_hdmi->pdev->dev);
@@ -894,28 +893,10 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
894893
conn_state_to_vc4_hdmi_conn_state(conn_state);
895894
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
896895
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
897-
unsigned long bvb_rate, pixel_rate, hsm_rate;
896+
unsigned long pixel_rate = vc4_conn_state->pixel_rate;
897+
unsigned long bvb_rate, hsm_rate;
898898
int ret;
899899

900-
ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
901-
if (ret < 0) {
902-
DRM_ERROR("Failed to retain power domain: %d\n", ret);
903-
return;
904-
}
905-
906-
pixel_rate = vc4_conn_state->pixel_rate;
907-
ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate);
908-
if (ret) {
909-
DRM_ERROR("Failed to set pixel clock rate: %d\n", ret);
910-
return;
911-
}
912-
913-
ret = clk_prepare_enable(vc4_hdmi->pixel_clock);
914-
if (ret) {
915-
DRM_ERROR("Failed to turn on pixel clock: %d\n", ret);
916-
return;
917-
}
918-
919900
/*
920901
* As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
921902
* be faster than pixel clock, infinitesimally faster, tested in
@@ -939,10 +920,21 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
939920
return;
940921
}
941922

942-
ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
923+
ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
924+
if (ret < 0) {
925+
DRM_ERROR("Failed to retain power domain: %d\n", ret);
926+
return;
927+
}
928+
929+
ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate);
943930
if (ret) {
944-
DRM_ERROR("Failed to turn on HSM clock: %d\n", ret);
945-
clk_disable_unprepare(vc4_hdmi->pixel_clock);
931+
DRM_ERROR("Failed to set pixel clock rate: %d\n", ret);
932+
return;
933+
}
934+
935+
ret = clk_prepare_enable(vc4_hdmi->pixel_clock);
936+
if (ret) {
937+
DRM_ERROR("Failed to turn on pixel clock: %d\n", ret);
946938
return;
947939
}
948940

@@ -958,15 +950,13 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
958950
ret = clk_set_min_rate(vc4_hdmi->pixel_bvb_clock, bvb_rate);
959951
if (ret) {
960952
DRM_ERROR("Failed to set pixel bvb clock rate: %d\n", ret);
961-
clk_disable_unprepare(vc4_hdmi->hsm_clock);
962953
clk_disable_unprepare(vc4_hdmi->pixel_clock);
963954
return;
964955
}
965956

966957
ret = clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);
967958
if (ret) {
968959
DRM_ERROR("Failed to turn on pixel bvb clock: %d\n", ret);
969-
clk_disable_unprepare(vc4_hdmi->hsm_clock);
970960
clk_disable_unprepare(vc4_hdmi->pixel_clock);
971961
return;
972962
}
@@ -2108,6 +2098,27 @@ static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
21082098
return 0;
21092099
}
21102100

2101+
static int __maybe_unused vc4_hdmi_runtime_suspend(struct device *dev)
2102+
{
2103+
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
2104+
2105+
clk_disable_unprepare(vc4_hdmi->hsm_clock);
2106+
2107+
return 0;
2108+
}
2109+
2110+
static int vc4_hdmi_runtime_resume(struct device *dev)
2111+
{
2112+
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
2113+
int ret;
2114+
2115+
ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
2116+
if (ret)
2117+
return ret;
2118+
2119+
return 0;
2120+
}
2121+
21112122
static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
21122123
{
21132124
const struct vc4_hdmi_variant *variant = of_device_get_match_data(dev);
@@ -2375,11 +2386,18 @@ static const struct of_device_id vc4_hdmi_dt_match[] = {
23752386
{}
23762387
};
23772388

2389+
static const struct dev_pm_ops vc4_hdmi_pm_ops = {
2390+
SET_RUNTIME_PM_OPS(vc4_hdmi_runtime_suspend,
2391+
vc4_hdmi_runtime_resume,
2392+
NULL)
2393+
};
2394+
23782395
struct platform_driver vc4_hdmi_driver = {
23792396
.probe = vc4_hdmi_dev_probe,
23802397
.remove = vc4_hdmi_dev_remove,
23812398
.driver = {
23822399
.name = "vc4_hdmi",
23832400
.of_match_table = vc4_hdmi_dt_match,
2401+
.pm = &vc4_hdmi_pm_ops,
23842402
},
23852403
};

0 commit comments

Comments
 (0)