1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2013 Red Hat
4 * Author: Rob Clark <robdclark@gmail.com>
5 */
6
7 #include <linux/delay.h>
8 #include <drm/drm_bridge_connector.h>
9
10 #include "msm_kms.h"
11 #include "hdmi.h"
12
msm_hdmi_bridge_destroy(struct drm_bridge * bridge)13 void msm_hdmi_bridge_destroy(struct drm_bridge *bridge)
14 {
15 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
16
17 msm_hdmi_hpd_disable(hdmi_bridge);
18 }
19
msm_hdmi_power_on(struct drm_bridge * bridge)20 static void msm_hdmi_power_on(struct drm_bridge *bridge)
21 {
22 struct drm_device *dev = bridge->dev;
23 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
24 struct hdmi *hdmi = hdmi_bridge->hdmi;
25 const struct hdmi_platform_config *config = hdmi->config;
26 int i, ret;
27
28 pm_runtime_get_sync(&hdmi->pdev->dev);
29
30 for (i = 0; i < config->pwr_reg_cnt; i++) {
31 ret = regulator_enable(hdmi->pwr_regs[i]);
32 if (ret) {
33 DRM_DEV_ERROR(dev->dev, "failed to enable pwr regulator: %s (%d)\n",
34 config->pwr_reg_names[i], ret);
35 }
36 }
37
38 if (config->pwr_clk_cnt > 0) {
39 DBG("pixclock: %lu", hdmi->pixclock);
40 ret = clk_set_rate(hdmi->pwr_clks[0], hdmi->pixclock);
41 if (ret) {
42 DRM_DEV_ERROR(dev->dev, "failed to set pixel clk: %s (%d)\n",
43 config->pwr_clk_names[0], ret);
44 }
45 }
46
47 for (i = 0; i < config->pwr_clk_cnt; i++) {
48 ret = clk_prepare_enable(hdmi->pwr_clks[i]);
49 if (ret) {
50 DRM_DEV_ERROR(dev->dev, "failed to enable pwr clk: %s (%d)\n",
51 config->pwr_clk_names[i], ret);
52 }
53 }
54 }
55
power_off(struct drm_bridge * bridge)56 static void power_off(struct drm_bridge *bridge)
57 {
58 struct drm_device *dev = bridge->dev;
59 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
60 struct hdmi *hdmi = hdmi_bridge->hdmi;
61 const struct hdmi_platform_config *config = hdmi->config;
62 int i, ret;
63
64 /* TODO do we need to wait for final vblank somewhere before
65 * cutting the clocks?
66 */
67 mdelay(16 + 4);
68
69 for (i = 0; i < config->pwr_clk_cnt; i++)
70 clk_disable_unprepare(hdmi->pwr_clks[i]);
71
72 for (i = 0; i < config->pwr_reg_cnt; i++) {
73 ret = regulator_disable(hdmi->pwr_regs[i]);
74 if (ret) {
75 DRM_DEV_ERROR(dev->dev, "failed to disable pwr regulator: %s (%d)\n",
76 config->pwr_reg_names[i], ret);
77 }
78 }
79
80 pm_runtime_put_autosuspend(&hdmi->pdev->dev);
81 }
82
83 #define AVI_IFRAME_LINE_NUMBER 1
84
msm_hdmi_config_avi_infoframe(struct hdmi * hdmi)85 static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
86 {
87 struct drm_crtc *crtc = hdmi->encoder->crtc;
88 const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
89 union hdmi_infoframe frame;
90 u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
91 u32 val;
92 int len;
93
94 drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
95 hdmi->connector, mode);
96
97 len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer));
98 if (len < 0) {
99 DRM_DEV_ERROR(&hdmi->pdev->dev,
100 "failed to configure avi infoframe\n");
101 return;
102 }
103
104 /*
105 * the AVI_INFOx registers don't map exactly to how the AVI infoframes
106 * are packed according to the spec. The checksum from the header is
107 * written to the LSB byte of AVI_INFO0 and the version is written to
108 * the third byte from the LSB of AVI_INFO3
109 */
110 hdmi_write(hdmi, REG_HDMI_AVI_INFO(0),
111 buffer[3] |
112 buffer[4] << 8 |
113 buffer[5] << 16 |
114 buffer[6] << 24);
115
116 hdmi_write(hdmi, REG_HDMI_AVI_INFO(1),
117 buffer[7] |
118 buffer[8] << 8 |
119 buffer[9] << 16 |
120 buffer[10] << 24);
121
122 hdmi_write(hdmi, REG_HDMI_AVI_INFO(2),
123 buffer[11] |
124 buffer[12] << 8 |
125 buffer[13] << 16 |
126 buffer[14] << 24);
127
128 hdmi_write(hdmi, REG_HDMI_AVI_INFO(3),
129 buffer[15] |
130 buffer[16] << 8 |
131 buffer[1] << 24);
132
133 hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0,
134 HDMI_INFOFRAME_CTRL0_AVI_SEND |
135 HDMI_INFOFRAME_CTRL0_AVI_CONT);
136
137 val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
138 val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
139 val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
140 hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
141 }
142
msm_hdmi_bridge_pre_enable(struct drm_bridge * bridge)143 static void msm_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
144 {
145 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
146 struct hdmi *hdmi = hdmi_bridge->hdmi;
147 struct hdmi_phy *phy = hdmi->phy;
148
149 DBG("power up");
150
151 if (!hdmi->power_on) {
152 msm_hdmi_phy_resource_enable(phy);
153 msm_hdmi_power_on(bridge);
154 hdmi->power_on = true;
155 if (hdmi->hdmi_mode) {
156 msm_hdmi_config_avi_infoframe(hdmi);
157 msm_hdmi_audio_update(hdmi);
158 }
159 }
160
161 msm_hdmi_phy_powerup(phy, hdmi->pixclock);
162
163 msm_hdmi_set_mode(hdmi, true);
164
165 if (hdmi->hdcp_ctrl)
166 msm_hdmi_hdcp_on(hdmi->hdcp_ctrl);
167 }
168
msm_hdmi_bridge_enable(struct drm_bridge * bridge)169 static void msm_hdmi_bridge_enable(struct drm_bridge *bridge)
170 {
171 }
172
msm_hdmi_bridge_disable(struct drm_bridge * bridge)173 static void msm_hdmi_bridge_disable(struct drm_bridge *bridge)
174 {
175 }
176
msm_hdmi_bridge_post_disable(struct drm_bridge * bridge)177 static void msm_hdmi_bridge_post_disable(struct drm_bridge *bridge)
178 {
179 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
180 struct hdmi *hdmi = hdmi_bridge->hdmi;
181 struct hdmi_phy *phy = hdmi->phy;
182
183 if (hdmi->hdcp_ctrl)
184 msm_hdmi_hdcp_off(hdmi->hdcp_ctrl);
185
186 DBG("power down");
187 msm_hdmi_set_mode(hdmi, false);
188
189 msm_hdmi_phy_powerdown(phy);
190
191 if (hdmi->power_on) {
192 power_off(bridge);
193 hdmi->power_on = false;
194 if (hdmi->hdmi_mode)
195 msm_hdmi_audio_update(hdmi);
196 msm_hdmi_phy_resource_disable(phy);
197 }
198 }
199
msm_hdmi_bridge_mode_set(struct drm_bridge * bridge,const struct drm_display_mode * mode,const struct drm_display_mode * adjusted_mode)200 static void msm_hdmi_bridge_mode_set(struct drm_bridge *bridge,
201 const struct drm_display_mode *mode,
202 const struct drm_display_mode *adjusted_mode)
203 {
204 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
205 struct hdmi *hdmi = hdmi_bridge->hdmi;
206 int hstart, hend, vstart, vend;
207 uint32_t frame_ctrl;
208
209 mode = adjusted_mode;
210
211 hdmi->pixclock = mode->clock * 1000;
212
213 hstart = mode->htotal - mode->hsync_start;
214 hend = mode->htotal - mode->hsync_start + mode->hdisplay;
215
216 vstart = mode->vtotal - mode->vsync_start - 1;
217 vend = mode->vtotal - mode->vsync_start + mode->vdisplay - 1;
218
219 DBG("htotal=%d, vtotal=%d, hstart=%d, hend=%d, vstart=%d, vend=%d",
220 mode->htotal, mode->vtotal, hstart, hend, vstart, vend);
221
222 hdmi_write(hdmi, REG_HDMI_TOTAL,
223 HDMI_TOTAL_H_TOTAL(mode->htotal - 1) |
224 HDMI_TOTAL_V_TOTAL(mode->vtotal - 1));
225
226 hdmi_write(hdmi, REG_HDMI_ACTIVE_HSYNC,
227 HDMI_ACTIVE_HSYNC_START(hstart) |
228 HDMI_ACTIVE_HSYNC_END(hend));
229 hdmi_write(hdmi, REG_HDMI_ACTIVE_VSYNC,
230 HDMI_ACTIVE_VSYNC_START(vstart) |
231 HDMI_ACTIVE_VSYNC_END(vend));
232
233 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
234 hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
235 HDMI_VSYNC_TOTAL_F2_V_TOTAL(mode->vtotal));
236 hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
237 HDMI_VSYNC_ACTIVE_F2_START(vstart + 1) |
238 HDMI_VSYNC_ACTIVE_F2_END(vend + 1));
239 } else {
240 hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
241 HDMI_VSYNC_TOTAL_F2_V_TOTAL(0));
242 hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
243 HDMI_VSYNC_ACTIVE_F2_START(0) |
244 HDMI_VSYNC_ACTIVE_F2_END(0));
245 }
246
247 frame_ctrl = 0;
248 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
249 frame_ctrl |= HDMI_FRAME_CTRL_HSYNC_LOW;
250 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
251 frame_ctrl |= HDMI_FRAME_CTRL_VSYNC_LOW;
252 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
253 frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
254 DBG("frame_ctrl=%08x", frame_ctrl);
255 hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
256
257 if (hdmi->hdmi_mode)
258 msm_hdmi_audio_update(hdmi);
259 }
260
msm_hdmi_bridge_get_edid(struct drm_bridge * bridge,struct drm_connector * connector)261 static struct edid *msm_hdmi_bridge_get_edid(struct drm_bridge *bridge,
262 struct drm_connector *connector)
263 {
264 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
265 struct hdmi *hdmi = hdmi_bridge->hdmi;
266 struct edid *edid;
267 uint32_t hdmi_ctrl;
268
269 hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL);
270 hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE);
271
272 edid = drm_get_edid(connector, hdmi->i2c);
273
274 hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
275
276 hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid);
277
278 return edid;
279 }
280
msm_hdmi_bridge_mode_valid(struct drm_bridge * bridge,const struct drm_display_info * info,const struct drm_display_mode * mode)281 static enum drm_mode_status msm_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
282 const struct drm_display_info *info,
283 const struct drm_display_mode *mode)
284 {
285 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
286 struct hdmi *hdmi = hdmi_bridge->hdmi;
287 const struct hdmi_platform_config *config = hdmi->config;
288 struct msm_drm_private *priv = bridge->dev->dev_private;
289 struct msm_kms *kms = priv->kms;
290 long actual, requested;
291
292 requested = 1000 * mode->clock;
293 actual = kms->funcs->round_pixclk(kms,
294 requested, hdmi_bridge->hdmi->encoder);
295
296 /* for mdp5/apq8074, we manage our own pixel clk (as opposed to
297 * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder
298 * instead):
299 */
300 if (config->pwr_clk_cnt > 0)
301 actual = clk_round_rate(hdmi->pwr_clks[0], actual);
302
303 DBG("requested=%ld, actual=%ld", requested, actual);
304
305 if (actual != requested)
306 return MODE_CLOCK_RANGE;
307
308 return 0;
309 }
310
311 static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
312 .pre_enable = msm_hdmi_bridge_pre_enable,
313 .enable = msm_hdmi_bridge_enable,
314 .disable = msm_hdmi_bridge_disable,
315 .post_disable = msm_hdmi_bridge_post_disable,
316 .mode_set = msm_hdmi_bridge_mode_set,
317 .mode_valid = msm_hdmi_bridge_mode_valid,
318 .get_edid = msm_hdmi_bridge_get_edid,
319 .detect = msm_hdmi_bridge_detect,
320 };
321
322 static void
msm_hdmi_hotplug_work(struct work_struct * work)323 msm_hdmi_hotplug_work(struct work_struct *work)
324 {
325 struct hdmi_bridge *hdmi_bridge =
326 container_of(work, struct hdmi_bridge, hpd_work);
327 struct drm_bridge *bridge = &hdmi_bridge->base;
328
329 drm_bridge_hpd_notify(bridge, drm_bridge_detect(bridge));
330 }
331
332 /* initialize bridge */
msm_hdmi_bridge_init(struct hdmi * hdmi)333 struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi)
334 {
335 struct drm_bridge *bridge = NULL;
336 struct hdmi_bridge *hdmi_bridge;
337 int ret;
338
339 hdmi_bridge = devm_kzalloc(hdmi->dev->dev,
340 sizeof(*hdmi_bridge), GFP_KERNEL);
341 if (!hdmi_bridge) {
342 ret = -ENOMEM;
343 goto fail;
344 }
345
346 hdmi_bridge->hdmi = hdmi;
347 INIT_WORK(&hdmi_bridge->hpd_work, msm_hdmi_hotplug_work);
348
349 bridge = &hdmi_bridge->base;
350 bridge->funcs = &msm_hdmi_bridge_funcs;
351 bridge->ddc = hdmi->i2c;
352 bridge->type = DRM_MODE_CONNECTOR_HDMIA;
353 bridge->ops = DRM_BRIDGE_OP_HPD |
354 DRM_BRIDGE_OP_DETECT |
355 DRM_BRIDGE_OP_EDID;
356
357 ret = drm_bridge_attach(hdmi->encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
358 if (ret)
359 goto fail;
360
361 return bridge;
362
363 fail:
364 if (bridge)
365 msm_hdmi_bridge_destroy(bridge);
366
367 return ERR_PTR(ret);
368 }
369