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