Skip to content

Commit 0c5ec81

Browse files
committed
drm/msm/hdmi: implement proper runtime PM handling
It is completely not obvious, but the so-called 'hpd' clocks and regulators are required for the HDMI host to function properly. Merge pwr and hpd regulators. Use regulators, clocks and pinctrl to implement proper runtime PM callbacks. Reviewed-by: Jessica Zhang <[email protected]> Signed-off-by: Dmitry Baryshkov <[email protected]> Patchwork: https://patchwork.freedesktop.org/patch/651715/ Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Dmitry Baryshkov <[email protected]>
1 parent 531b4e2 commit 0c5ec81

File tree

4 files changed

+47
-74
lines changed

4 files changed

+47
-74
lines changed

drivers/gpu/drm/msm/hdmi/hdmi.c

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/gpio/consumer.h>
99
#include <linux/of_irq.h>
1010
#include <linux/of_platform.h>
11+
#include <linux/pinctrl/consumer.h>
1112
#include <linux/platform_device.h>
1213

1314
#include <drm/drm_bridge_connector.h>
@@ -224,11 +225,11 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
224225
.item ## _names = item ##_names_ ## entry, \
225226
.item ## _cnt = ARRAY_SIZE(item ## _names_ ## entry)
226227

227-
static const char * const hpd_reg_names_8960[] = {"core-vdda"};
228+
static const char * const pwr_reg_names_8960[] = {"core-vdda"};
228229
static const char * const hpd_clk_names_8960[] = {"core", "master_iface", "slave_iface"};
229230

230231
static const struct hdmi_platform_config hdmi_tx_8960_config = {
231-
HDMI_CFG(hpd_reg, 8960),
232+
HDMI_CFG(pwr_reg, 8960),
232233
HDMI_CFG(hpd_clk, 8960),
233234
};
234235

@@ -318,20 +319,6 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev)
318319
if (hdmi->irq < 0)
319320
return hdmi->irq;
320321

321-
hdmi->hpd_regs = devm_kcalloc(&pdev->dev,
322-
config->hpd_reg_cnt,
323-
sizeof(hdmi->hpd_regs[0]),
324-
GFP_KERNEL);
325-
if (!hdmi->hpd_regs)
326-
return -ENOMEM;
327-
328-
for (i = 0; i < config->hpd_reg_cnt; i++)
329-
hdmi->hpd_regs[i].supply = config->hpd_reg_names[i];
330-
331-
ret = devm_regulator_bulk_get(&pdev->dev, config->hpd_reg_cnt, hdmi->hpd_regs);
332-
if (ret)
333-
return dev_err_probe(dev, ret, "failed to get hpd regulators\n");
334-
335322
hdmi->pwr_regs = devm_kcalloc(&pdev->dev,
336323
config->pwr_reg_cnt,
337324
sizeof(hdmi->pwr_regs[0]),
@@ -409,6 +396,48 @@ static void msm_hdmi_dev_remove(struct platform_device *pdev)
409396
msm_hdmi_put_phy(hdmi);
410397
}
411398

399+
static int msm_hdmi_runtime_suspend(struct device *dev)
400+
{
401+
struct hdmi *hdmi = dev_get_drvdata(dev);
402+
const struct hdmi_platform_config *config = hdmi->config;
403+
404+
clk_bulk_disable_unprepare(config->hpd_clk_cnt, hdmi->hpd_clks);
405+
406+
pinctrl_pm_select_sleep_state(dev);
407+
408+
regulator_bulk_disable(config->pwr_reg_cnt, hdmi->pwr_regs);
409+
410+
return 0;
411+
}
412+
413+
static int msm_hdmi_runtime_resume(struct device *dev)
414+
{
415+
struct hdmi *hdmi = dev_get_drvdata(dev);
416+
const struct hdmi_platform_config *config = hdmi->config;
417+
int ret;
418+
419+
ret = regulator_bulk_enable(config->pwr_reg_cnt, hdmi->pwr_regs);
420+
if (ret)
421+
return ret;
422+
423+
ret = pinctrl_pm_select_default_state(dev);
424+
if (ret)
425+
goto fail;
426+
427+
ret = clk_bulk_prepare_enable(config->hpd_clk_cnt, hdmi->hpd_clks);
428+
if (ret)
429+
goto fail;
430+
431+
return 0;
432+
433+
fail:
434+
pinctrl_pm_select_sleep_state(dev);
435+
436+
return ret;
437+
}
438+
439+
DEFINE_RUNTIME_DEV_PM_OPS(msm_hdmi_pm_ops, msm_hdmi_runtime_suspend, msm_hdmi_runtime_resume, NULL);
440+
412441
static const struct of_device_id msm_hdmi_dt_match[] = {
413442
{ .compatible = "qcom,hdmi-tx-8998", .data = &hdmi_tx_8974_config },
414443
{ .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8974_config },
@@ -426,6 +455,7 @@ static struct platform_driver msm_hdmi_driver = {
426455
.driver = {
427456
.name = "hdmi_msm",
428457
.of_match_table = msm_hdmi_dt_match,
458+
.pm = &msm_hdmi_pm_ops,
429459
},
430460
};
431461

drivers/gpu/drm/msm/hdmi/hdmi.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ struct hdmi {
4747
void __iomem *qfprom_mmio;
4848
phys_addr_t mmio_phy_addr;
4949

50-
struct regulator_bulk_data *hpd_regs;
5150
struct regulator_bulk_data *pwr_regs;
5251
struct clk_bulk_data *hpd_clks;
5352
struct clk *extp_clk;
@@ -83,10 +82,6 @@ struct hdmi {
8382

8483
/* platform config data (ie. from DT, or pdata) */
8584
struct hdmi_platform_config {
86-
/* regulators that need to be on for hpd: */
87-
const char * const *hpd_reg_names;
88-
int hpd_reg_cnt;
89-
9085
/* regulators that need to be on for screen pwr: */
9186
const char * const *pwr_reg_names;
9287
int pwr_reg_cnt;

drivers/gpu/drm/msm/hdmi/hdmi_bridge.c

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,10 @@ static void msm_hdmi_power_on(struct drm_bridge *bridge)
1818
struct drm_device *dev = bridge->dev;
1919
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
2020
struct hdmi *hdmi = hdmi_bridge->hdmi;
21-
const struct hdmi_platform_config *config = hdmi->config;
2221
int ret;
2322

2423
pm_runtime_resume_and_get(&hdmi->pdev->dev);
2524

26-
ret = regulator_bulk_enable(config->pwr_reg_cnt, hdmi->pwr_regs);
27-
if (ret)
28-
DRM_DEV_ERROR(dev->dev, "failed to enable pwr regulator: %d\n", ret);
29-
3025
if (hdmi->extp_clk) {
3126
DBG("pixclock: %lu", hdmi->pixclock);
3227
ret = clk_set_rate(hdmi->extp_clk, hdmi->pixclock);
@@ -41,11 +36,8 @@ static void msm_hdmi_power_on(struct drm_bridge *bridge)
4136

4237
static void power_off(struct drm_bridge *bridge)
4338
{
44-
struct drm_device *dev = bridge->dev;
4539
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
4640
struct hdmi *hdmi = hdmi_bridge->hdmi;
47-
const struct hdmi_platform_config *config = hdmi->config;
48-
int ret;
4941

5042
/* TODO do we need to wait for final vblank somewhere before
5143
* cutting the clocks?
@@ -55,10 +47,6 @@ static void power_off(struct drm_bridge *bridge)
5547
if (hdmi->extp_clk)
5648
clk_disable_unprepare(hdmi->extp_clk);
5749

58-
ret = regulator_bulk_disable(config->pwr_reg_cnt, hdmi->pwr_regs);
59-
if (ret)
60-
DRM_DEV_ERROR(dev->dev, "failed to disable pwr regulator: %d\n", ret);
61-
6250
pm_runtime_put(&hdmi->pdev->dev);
6351
}
6452

drivers/gpu/drm/msm/hdmi/hdmi_hpd.c

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -64,36 +64,17 @@ int msm_hdmi_hpd_enable(struct drm_bridge *bridge)
6464
{
6565
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
6666
struct hdmi *hdmi = hdmi_bridge->hdmi;
67-
const struct hdmi_platform_config *config = hdmi->config;
6867
struct device *dev = &hdmi->pdev->dev;
6968
uint32_t hpd_ctrl;
7069
int ret;
7170
unsigned long flags;
7271

73-
ret = regulator_bulk_enable(config->hpd_reg_cnt, hdmi->hpd_regs);
74-
if (ret) {
75-
DRM_DEV_ERROR(dev, "failed to enable hpd regulators: %d\n", ret);
76-
goto fail;
77-
}
78-
79-
ret = pinctrl_pm_select_default_state(dev);
80-
if (ret) {
81-
DRM_DEV_ERROR(dev, "pinctrl state chg failed: %d\n", ret);
82-
goto fail;
83-
}
84-
8572
if (hdmi->hpd_gpiod)
8673
gpiod_set_value_cansleep(hdmi->hpd_gpiod, 1);
8774

8875
ret = pm_runtime_resume_and_get(dev);
89-
if (ret) {
90-
DRM_DEV_ERROR(dev, "runtime resume failed: %d\n", ret);
91-
goto fail;
92-
}
93-
94-
ret = clk_bulk_prepare_enable(config->hpd_clk_cnt, hdmi->hpd_clks);
9576
if (ret)
96-
goto fail;
77+
return ret;
9778

9879
msm_hdmi_set_mode(hdmi, false);
9980
msm_hdmi_phy_reset(hdmi);
@@ -119,32 +100,18 @@ int msm_hdmi_hpd_enable(struct drm_bridge *bridge)
119100
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
120101

121102
return 0;
122-
123-
fail:
124-
return ret;
125103
}
126104

127105
void msm_hdmi_hpd_disable(struct hdmi *hdmi)
128106
{
129-
const struct hdmi_platform_config *config = hdmi->config;
130107
struct device *dev = &hdmi->pdev->dev;
131-
int ret;
132108

133109
/* Disable HPD interrupt */
134110
hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0);
135111

136112
msm_hdmi_set_mode(hdmi, false);
137113

138-
clk_bulk_disable_unprepare(config->hpd_clk_cnt, hdmi->hpd_clks);
139114
pm_runtime_put(dev);
140-
141-
ret = pinctrl_pm_select_sleep_state(dev);
142-
if (ret)
143-
dev_warn(dev, "pinctrl state chg failed: %d\n", ret);
144-
145-
ret = regulator_bulk_disable(config->hpd_reg_cnt, hdmi->hpd_regs);
146-
if (ret)
147-
dev_warn(dev, "failed to disable hpd regulator: %d\n", ret);
148115
}
149116

150117
void msm_hdmi_hpd_irq(struct drm_bridge *bridge)
@@ -179,22 +146,15 @@ void msm_hdmi_hpd_irq(struct drm_bridge *bridge)
179146

180147
static enum drm_connector_status detect_reg(struct hdmi *hdmi)
181148
{
182-
const struct hdmi_platform_config *config = hdmi->config;
183149
u32 hpd_int_status = 0;
184150
int ret;
185151

186152
ret = pm_runtime_resume_and_get(&hdmi->pdev->dev);
187153
if (ret)
188154
goto out;
189155

190-
ret = clk_bulk_prepare_enable(config->hpd_clk_cnt, hdmi->hpd_clks);
191-
if (ret)
192-
goto out;
193-
194156
hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
195157

196-
clk_bulk_disable_unprepare(config->hpd_clk_cnt, hdmi->hpd_clks);
197-
198158
out:
199159
pm_runtime_put(&hdmi->pdev->dev);
200160

0 commit comments

Comments
 (0)