1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2013 Red Hat
4 * Author: Rob Clark <robdclark@gmail.com>
7 #include <linux/delay.h>
12 struct drm_bridge base
;
15 #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
17 void msm_hdmi_bridge_destroy(struct drm_bridge
*bridge
)
21 static void msm_hdmi_power_on(struct drm_bridge
*bridge
)
23 struct drm_device
*dev
= bridge
->dev
;
24 struct hdmi_bridge
*hdmi_bridge
= to_hdmi_bridge(bridge
);
25 struct hdmi
*hdmi
= hdmi_bridge
->hdmi
;
26 const struct hdmi_platform_config
*config
= hdmi
->config
;
29 pm_runtime_get_sync(&hdmi
->pdev
->dev
);
31 for (i
= 0; i
< config
->pwr_reg_cnt
; i
++) {
32 ret
= regulator_enable(hdmi
->pwr_regs
[i
]);
34 DRM_DEV_ERROR(dev
->dev
, "failed to enable pwr regulator: %s (%d)\n",
35 config
->pwr_reg_names
[i
], ret
);
39 if (config
->pwr_clk_cnt
> 0) {
40 DBG("pixclock: %lu", hdmi
->pixclock
);
41 ret
= clk_set_rate(hdmi
->pwr_clks
[0], hdmi
->pixclock
);
43 DRM_DEV_ERROR(dev
->dev
, "failed to set pixel clk: %s (%d)\n",
44 config
->pwr_clk_names
[0], ret
);
48 for (i
= 0; i
< config
->pwr_clk_cnt
; i
++) {
49 ret
= clk_prepare_enable(hdmi
->pwr_clks
[i
]);
51 DRM_DEV_ERROR(dev
->dev
, "failed to enable pwr clk: %s (%d)\n",
52 config
->pwr_clk_names
[i
], ret
);
57 static void power_off(struct drm_bridge
*bridge
)
59 struct drm_device
*dev
= bridge
->dev
;
60 struct hdmi_bridge
*hdmi_bridge
= to_hdmi_bridge(bridge
);
61 struct hdmi
*hdmi
= hdmi_bridge
->hdmi
;
62 const struct hdmi_platform_config
*config
= hdmi
->config
;
65 /* TODO do we need to wait for final vblank somewhere before
70 for (i
= 0; i
< config
->pwr_clk_cnt
; i
++)
71 clk_disable_unprepare(hdmi
->pwr_clks
[i
]);
73 for (i
= 0; i
< config
->pwr_reg_cnt
; i
++) {
74 ret
= regulator_disable(hdmi
->pwr_regs
[i
]);
76 DRM_DEV_ERROR(dev
->dev
, "failed to disable pwr regulator: %s (%d)\n",
77 config
->pwr_reg_names
[i
], ret
);
81 pm_runtime_put_autosuspend(&hdmi
->pdev
->dev
);
84 #define AVI_IFRAME_LINE_NUMBER 1
86 static void msm_hdmi_config_avi_infoframe(struct hdmi
*hdmi
)
88 struct drm_crtc
*crtc
= hdmi
->encoder
->crtc
;
89 const struct drm_display_mode
*mode
= &crtc
->state
->adjusted_mode
;
90 union hdmi_infoframe frame
;
91 u8 buffer
[HDMI_INFOFRAME_SIZE(AVI
)];
95 drm_hdmi_avi_infoframe_from_display_mode(&frame
.avi
,
96 hdmi
->connector
, mode
);
98 len
= hdmi_infoframe_pack(&frame
, buffer
, sizeof(buffer
));
100 DRM_DEV_ERROR(&hdmi
->pdev
->dev
,
101 "failed to configure avi infoframe\n");
106 * the AVI_INFOx registers don't map exactly to how the AVI infoframes
107 * are packed according to the spec. The checksum from the header is
108 * written to the LSB byte of AVI_INFO0 and the version is written to
109 * the third byte from the LSB of AVI_INFO3
111 hdmi_write(hdmi
, REG_HDMI_AVI_INFO(0),
117 hdmi_write(hdmi
, REG_HDMI_AVI_INFO(1),
123 hdmi_write(hdmi
, REG_HDMI_AVI_INFO(2),
129 hdmi_write(hdmi
, REG_HDMI_AVI_INFO(3),
134 hdmi_write(hdmi
, REG_HDMI_INFOFRAME_CTRL0
,
135 HDMI_INFOFRAME_CTRL0_AVI_SEND
|
136 HDMI_INFOFRAME_CTRL0_AVI_CONT
);
138 val
= hdmi_read(hdmi
, REG_HDMI_INFOFRAME_CTRL1
);
139 val
&= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK
;
140 val
|= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER
);
141 hdmi_write(hdmi
, REG_HDMI_INFOFRAME_CTRL1
, val
);
144 static void msm_hdmi_bridge_pre_enable(struct drm_bridge
*bridge
)
146 struct hdmi_bridge
*hdmi_bridge
= to_hdmi_bridge(bridge
);
147 struct hdmi
*hdmi
= hdmi_bridge
->hdmi
;
148 struct hdmi_phy
*phy
= hdmi
->phy
;
152 if (!hdmi
->power_on
) {
153 msm_hdmi_phy_resource_enable(phy
);
154 msm_hdmi_power_on(bridge
);
155 hdmi
->power_on
= true;
156 if (hdmi
->hdmi_mode
) {
157 msm_hdmi_config_avi_infoframe(hdmi
);
158 msm_hdmi_audio_update(hdmi
);
162 msm_hdmi_phy_powerup(phy
, hdmi
->pixclock
);
164 msm_hdmi_set_mode(hdmi
, true);
167 msm_hdmi_hdcp_on(hdmi
->hdcp_ctrl
);
170 static void msm_hdmi_bridge_enable(struct drm_bridge
*bridge
)
174 static void msm_hdmi_bridge_disable(struct drm_bridge
*bridge
)
178 static void msm_hdmi_bridge_post_disable(struct drm_bridge
*bridge
)
180 struct hdmi_bridge
*hdmi_bridge
= to_hdmi_bridge(bridge
);
181 struct hdmi
*hdmi
= hdmi_bridge
->hdmi
;
182 struct hdmi_phy
*phy
= hdmi
->phy
;
185 msm_hdmi_hdcp_off(hdmi
->hdcp_ctrl
);
188 msm_hdmi_set_mode(hdmi
, false);
190 msm_hdmi_phy_powerdown(phy
);
192 if (hdmi
->power_on
) {
194 hdmi
->power_on
= false;
196 msm_hdmi_audio_update(hdmi
);
197 msm_hdmi_phy_resource_disable(phy
);
201 static void msm_hdmi_bridge_mode_set(struct drm_bridge
*bridge
,
202 const struct drm_display_mode
*mode
,
203 const struct drm_display_mode
*adjusted_mode
)
205 struct hdmi_bridge
*hdmi_bridge
= to_hdmi_bridge(bridge
);
206 struct hdmi
*hdmi
= hdmi_bridge
->hdmi
;
207 int hstart
, hend
, vstart
, vend
;
210 mode
= adjusted_mode
;
212 hdmi
->pixclock
= mode
->clock
* 1000;
214 hstart
= mode
->htotal
- mode
->hsync_start
;
215 hend
= mode
->htotal
- mode
->hsync_start
+ mode
->hdisplay
;
217 vstart
= mode
->vtotal
- mode
->vsync_start
- 1;
218 vend
= mode
->vtotal
- mode
->vsync_start
+ mode
->vdisplay
- 1;
220 DBG("htotal=%d, vtotal=%d, hstart=%d, hend=%d, vstart=%d, vend=%d",
221 mode
->htotal
, mode
->vtotal
, hstart
, hend
, vstart
, vend
);
223 hdmi_write(hdmi
, REG_HDMI_TOTAL
,
224 HDMI_TOTAL_H_TOTAL(mode
->htotal
- 1) |
225 HDMI_TOTAL_V_TOTAL(mode
->vtotal
- 1));
227 hdmi_write(hdmi
, REG_HDMI_ACTIVE_HSYNC
,
228 HDMI_ACTIVE_HSYNC_START(hstart
) |
229 HDMI_ACTIVE_HSYNC_END(hend
));
230 hdmi_write(hdmi
, REG_HDMI_ACTIVE_VSYNC
,
231 HDMI_ACTIVE_VSYNC_START(vstart
) |
232 HDMI_ACTIVE_VSYNC_END(vend
));
234 if (mode
->flags
& DRM_MODE_FLAG_INTERLACE
) {
235 hdmi_write(hdmi
, REG_HDMI_VSYNC_TOTAL_F2
,
236 HDMI_VSYNC_TOTAL_F2_V_TOTAL(mode
->vtotal
));
237 hdmi_write(hdmi
, REG_HDMI_VSYNC_ACTIVE_F2
,
238 HDMI_VSYNC_ACTIVE_F2_START(vstart
+ 1) |
239 HDMI_VSYNC_ACTIVE_F2_END(vend
+ 1));
241 hdmi_write(hdmi
, REG_HDMI_VSYNC_TOTAL_F2
,
242 HDMI_VSYNC_TOTAL_F2_V_TOTAL(0));
243 hdmi_write(hdmi
, REG_HDMI_VSYNC_ACTIVE_F2
,
244 HDMI_VSYNC_ACTIVE_F2_START(0) |
245 HDMI_VSYNC_ACTIVE_F2_END(0));
249 if (mode
->flags
& DRM_MODE_FLAG_NHSYNC
)
250 frame_ctrl
|= HDMI_FRAME_CTRL_HSYNC_LOW
;
251 if (mode
->flags
& DRM_MODE_FLAG_NVSYNC
)
252 frame_ctrl
|= HDMI_FRAME_CTRL_VSYNC_LOW
;
253 if (mode
->flags
& DRM_MODE_FLAG_INTERLACE
)
254 frame_ctrl
|= HDMI_FRAME_CTRL_INTERLACED_EN
;
255 DBG("frame_ctrl=%08x", frame_ctrl
);
256 hdmi_write(hdmi
, REG_HDMI_FRAME_CTRL
, frame_ctrl
);
259 msm_hdmi_audio_update(hdmi
);
262 static const struct drm_bridge_funcs msm_hdmi_bridge_funcs
= {
263 .pre_enable
= msm_hdmi_bridge_pre_enable
,
264 .enable
= msm_hdmi_bridge_enable
,
265 .disable
= msm_hdmi_bridge_disable
,
266 .post_disable
= msm_hdmi_bridge_post_disable
,
267 .mode_set
= msm_hdmi_bridge_mode_set
,
271 /* initialize bridge */
272 struct drm_bridge
*msm_hdmi_bridge_init(struct hdmi
*hdmi
)
274 struct drm_bridge
*bridge
= NULL
;
275 struct hdmi_bridge
*hdmi_bridge
;
278 hdmi_bridge
= devm_kzalloc(hdmi
->dev
->dev
,
279 sizeof(*hdmi_bridge
), GFP_KERNEL
);
285 hdmi_bridge
->hdmi
= hdmi
;
287 bridge
= &hdmi_bridge
->base
;
288 bridge
->funcs
= &msm_hdmi_bridge_funcs
;
290 ret
= drm_bridge_attach(hdmi
->encoder
, bridge
, NULL
);
298 msm_hdmi_bridge_destroy(bridge
);