• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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