xref: /linux/drivers/gpu/drm/msm/hdmi/hdmi.c (revision c06b6cde2a1c3bcbb561bd57bb6f34eae9030921)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2014 The Linux Foundation. All rights reserved.
4  * Copyright (C) 2013 Red Hat
5  * Author: Rob Clark <robdclark@gmail.com>
6  */
7 
8 #include <linux/gpio/consumer.h>
9 #include <linux/of_irq.h>
10 #include <linux/of_platform.h>
11 #include <linux/pinctrl/consumer.h>
12 #include <linux/platform_device.h>
13 
14 #include <drm/drm_bridge_connector.h>
15 #include <drm/drm_of.h>
16 #include <drm/display/drm_hdmi_state_helper.h>
17 
18 #include "msm_kms.h"
19 #include "hdmi.h"
20 
21 void msm_hdmi_set_mode(struct hdmi *hdmi, bool power_on)
22 {
23 	u32 ctrl = 0;
24 	unsigned long flags;
25 
26 	spin_lock_irqsave(&hdmi->reg_lock, flags);
27 	if (power_on) {
28 		ctrl |= HDMI_CTRL_ENABLE;
29 		if (!hdmi->connector->display_info.is_hdmi) {
30 			ctrl |= HDMI_CTRL_HDMI;
31 			hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);
32 			ctrl &= ~HDMI_CTRL_HDMI;
33 		} else {
34 			ctrl |= HDMI_CTRL_HDMI;
35 		}
36 	} else {
37 		ctrl = HDMI_CTRL_HDMI;
38 	}
39 
40 	hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);
41 	spin_unlock_irqrestore(&hdmi->reg_lock, flags);
42 	DBG("HDMI Core: %s, HDMI_CTRL=0x%08x",
43 			power_on ? "Enable" : "Disable", ctrl);
44 }
45 
46 static irqreturn_t msm_hdmi_irq(int irq, void *dev_id)
47 {
48 	struct hdmi *hdmi = dev_id;
49 
50 	/* Process HPD: */
51 	msm_hdmi_hpd_irq(hdmi->bridge);
52 
53 	/* Process DDC: */
54 	msm_hdmi_i2c_irq(hdmi->i2c);
55 
56 	/* Process HDCP: */
57 	if (hdmi->hdcp_ctrl)
58 		msm_hdmi_hdcp_irq(hdmi->hdcp_ctrl);
59 
60 	/* TODO audio.. */
61 
62 	return IRQ_HANDLED;
63 }
64 
65 static void msm_hdmi_destroy(struct hdmi *hdmi)
66 {
67 	/*
68 	 * at this point, hpd has been disabled,
69 	 * after flush workq, it's safe to deinit hdcp
70 	 */
71 	if (hdmi->workq)
72 		destroy_workqueue(hdmi->workq);
73 	msm_hdmi_hdcp_destroy(hdmi);
74 
75 	if (hdmi->i2c)
76 		msm_hdmi_i2c_destroy(hdmi->i2c);
77 }
78 
79 static void msm_hdmi_put_phy(struct hdmi *hdmi)
80 {
81 	if (hdmi->phy_dev) {
82 		put_device(hdmi->phy_dev);
83 		hdmi->phy = NULL;
84 		hdmi->phy_dev = NULL;
85 	}
86 }
87 
88 static int msm_hdmi_get_phy(struct hdmi *hdmi)
89 {
90 	struct platform_device *pdev = hdmi->pdev;
91 	struct platform_device *phy_pdev;
92 	struct device_node *phy_node;
93 
94 	phy_node = of_parse_phandle(dev_of_node(&pdev->dev), "phys", 0);
95 	if (!phy_node) {
96 		DRM_DEV_ERROR(&pdev->dev, "cannot find phy device\n");
97 		return -ENXIO;
98 	}
99 
100 	phy_pdev = of_find_device_by_node(phy_node);
101 	of_node_put(phy_node);
102 
103 	if (!phy_pdev)
104 		return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "phy driver is not ready\n");
105 
106 	hdmi->phy = platform_get_drvdata(phy_pdev);
107 	if (!hdmi->phy) {
108 		put_device(&phy_pdev->dev);
109 		return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "phy driver is not ready\n");
110 	}
111 
112 	hdmi->phy_dev = &phy_pdev->dev;
113 
114 	return 0;
115 }
116 
117 /* construct hdmi at bind/probe time, grab all the resources.  If
118  * we are to EPROBE_DEFER we want to do it here, rather than later
119  * at modeset_init() time
120  */
121 static int msm_hdmi_init(struct hdmi *hdmi)
122 {
123 	struct platform_device *pdev = hdmi->pdev;
124 	int ret;
125 
126 	hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0);
127 	if (!hdmi->workq) {
128 		ret = -ENOMEM;
129 		goto fail;
130 	}
131 
132 	hdmi->i2c = msm_hdmi_i2c_init(hdmi);
133 	if (IS_ERR(hdmi->i2c)) {
134 		ret = PTR_ERR(hdmi->i2c);
135 		DRM_DEV_ERROR(&pdev->dev, "failed to get i2c: %d\n", ret);
136 		hdmi->i2c = NULL;
137 		goto fail;
138 	}
139 
140 	hdmi->hdcp_ctrl = msm_hdmi_hdcp_init(hdmi);
141 	if (IS_ERR(hdmi->hdcp_ctrl)) {
142 		dev_warn(&pdev->dev, "failed to init hdcp: disabled\n");
143 		hdmi->hdcp_ctrl = NULL;
144 	}
145 
146 	return 0;
147 
148 fail:
149 	msm_hdmi_destroy(hdmi);
150 
151 	return ret;
152 }
153 
154 /* Second part of initialization, the drm/kms level modeset_init,
155  * constructs/initializes mode objects, etc, is called from master
156  * driver (not hdmi sub-device's probe/bind!)
157  *
158  * Any resource (regulator/clk/etc) which could be missing at boot
159  * should be handled in msm_hdmi_init() so that failure happens from
160  * hdmi sub-device's probe.
161  */
162 int msm_hdmi_modeset_init(struct hdmi *hdmi,
163 		struct drm_device *dev, struct drm_encoder *encoder)
164 {
165 	int ret;
166 
167 	hdmi->dev = dev;
168 	hdmi->encoder = encoder;
169 
170 	ret = msm_hdmi_bridge_init(hdmi);
171 	if (ret) {
172 		DRM_DEV_ERROR(dev->dev, "failed to create HDMI bridge: %d\n", ret);
173 		goto fail;
174 	}
175 
176 	if (hdmi->next_bridge) {
177 		ret = drm_bridge_attach(hdmi->encoder, hdmi->next_bridge, hdmi->bridge,
178 					DRM_BRIDGE_ATTACH_NO_CONNECTOR);
179 		if (ret) {
180 			DRM_DEV_ERROR(dev->dev, "failed to attach next HDMI bridge: %d\n", ret);
181 			goto fail;
182 		}
183 	}
184 
185 	hdmi->connector = drm_bridge_connector_init(hdmi->dev, encoder);
186 	if (IS_ERR(hdmi->connector)) {
187 		ret = PTR_ERR(hdmi->connector);
188 		DRM_DEV_ERROR(dev->dev, "failed to create HDMI connector: %d\n", ret);
189 		hdmi->connector = NULL;
190 		goto fail;
191 	}
192 
193 	ret = devm_request_irq(dev->dev, hdmi->irq,
194 			msm_hdmi_irq, IRQF_TRIGGER_HIGH,
195 			"hdmi_isr", hdmi);
196 	if (ret < 0) {
197 		DRM_DEV_ERROR(dev->dev, "failed to request IRQ%u: %d\n",
198 				hdmi->irq, ret);
199 		goto fail;
200 	}
201 
202 	return 0;
203 
204 fail:
205 	if (hdmi->connector) {
206 		hdmi->connector->funcs->destroy(hdmi->connector);
207 		hdmi->connector = NULL;
208 	}
209 
210 	return ret;
211 }
212 
213 /*
214  * The hdmi device:
215  */
216 
217 static const char * const pwr_reg_names_8960[] = {"core-vdda"};
218 static const char * const pwr_clk_names_8960[] = {"core", "master_iface", "slave_iface"};
219 
220 static const struct hdmi_platform_config hdmi_tx_8960_config = {
221 	.pwr_reg_names = pwr_reg_names_8960,
222 	.pwr_reg_cnt = ARRAY_SIZE(pwr_reg_names_8960),
223 	.pwr_clk_names = pwr_clk_names_8960,
224 	.pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names_8960),
225 };
226 
227 static const char * const pwr_reg_names_8x74[] = {"core-vdda", "core-vcc"};
228 static const char * const pwr_clk_names_8x74[] = {"iface", "core", "mdp_core", "alt_iface"};
229 
230 static const struct hdmi_platform_config hdmi_tx_8974_config = {
231 	.pwr_reg_names = pwr_reg_names_8x74,
232 	.pwr_reg_cnt = ARRAY_SIZE(pwr_reg_names_8x74),
233 	.pwr_clk_names = pwr_clk_names_8x74,
234 	.pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names_8x74),
235 };
236 
237 static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
238 {
239 	struct msm_drm_private *priv = dev_get_drvdata(master);
240 	struct hdmi *hdmi = dev_get_drvdata(dev);
241 	int err;
242 
243 	err = msm_hdmi_init(hdmi);
244 	if (err)
245 		return err;
246 	priv->kms->hdmi = hdmi;
247 
248 	return 0;
249 }
250 
251 static void msm_hdmi_unbind(struct device *dev, struct device *master,
252 		void *data)
253 {
254 	struct msm_drm_private *priv = dev_get_drvdata(master);
255 
256 	if (priv->kms->hdmi) {
257 		msm_hdmi_destroy(priv->kms->hdmi);
258 		priv->kms->hdmi = NULL;
259 	}
260 }
261 
262 static const struct component_ops msm_hdmi_ops = {
263 		.bind   = msm_hdmi_bind,
264 		.unbind = msm_hdmi_unbind,
265 };
266 
267 static int msm_hdmi_dev_probe(struct platform_device *pdev)
268 {
269 	const struct hdmi_platform_config *config;
270 	struct device *dev = &pdev->dev;
271 	struct hdmi *hdmi;
272 	struct resource *res;
273 	int i, ret;
274 
275 	config = of_device_get_match_data(dev);
276 	if (!config)
277 		return -EINVAL;
278 
279 	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
280 	if (!hdmi)
281 		return -ENOMEM;
282 
283 	hdmi->pdev = pdev;
284 	hdmi->config = config;
285 	spin_lock_init(&hdmi->reg_lock);
286 	mutex_init(&hdmi->state_mutex);
287 
288 	ret = drm_of_find_panel_or_bridge(dev_of_node(dev), 1, 0, NULL, &hdmi->next_bridge);
289 	if (ret && ret != -ENODEV)
290 		return ret;
291 
292 	hdmi->mmio = msm_ioremap(pdev, "core_physical");
293 	if (IS_ERR(hdmi->mmio))
294 		return PTR_ERR(hdmi->mmio);
295 
296 	/* HDCP needs physical address of hdmi register */
297 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
298 		"core_physical");
299 	if (!res)
300 		return -EINVAL;
301 	hdmi->mmio_phy_addr = res->start;
302 
303 	hdmi->qfprom_mmio = msm_ioremap(pdev, "qfprom_physical");
304 	if (IS_ERR(hdmi->qfprom_mmio)) {
305 		DRM_DEV_INFO(dev, "can't find qfprom resource\n");
306 		hdmi->qfprom_mmio = NULL;
307 	}
308 
309 	hdmi->irq = platform_get_irq(pdev, 0);
310 	if (hdmi->irq < 0)
311 		return hdmi->irq;
312 
313 	hdmi->pwr_regs = devm_kcalloc(dev, config->pwr_reg_cnt,
314 				      sizeof(hdmi->pwr_regs[0]),
315 				      GFP_KERNEL);
316 	if (!hdmi->pwr_regs)
317 		return -ENOMEM;
318 
319 	for (i = 0; i < config->pwr_reg_cnt; i++)
320 		hdmi->pwr_regs[i].supply = config->pwr_reg_names[i];
321 
322 	ret = devm_regulator_bulk_get(dev, config->pwr_reg_cnt, hdmi->pwr_regs);
323 	if (ret)
324 		return dev_err_probe(dev, ret, "failed to get pwr regulators\n");
325 
326 	hdmi->pwr_clks = devm_kcalloc(dev, config->pwr_clk_cnt,
327 				      sizeof(hdmi->pwr_clks[0]),
328 				      GFP_KERNEL);
329 	if (!hdmi->pwr_clks)
330 		return -ENOMEM;
331 
332 	for (i = 0; i < config->pwr_clk_cnt; i++)
333 		hdmi->pwr_clks[i].id = config->pwr_clk_names[i];
334 
335 	ret = devm_clk_bulk_get(dev, config->pwr_clk_cnt, hdmi->pwr_clks);
336 	if (ret)
337 		return ret;
338 
339 	hdmi->extp_clk = devm_clk_get_optional(dev, "extp");
340 	if (IS_ERR(hdmi->extp_clk))
341 		return dev_err_probe(dev, PTR_ERR(hdmi->extp_clk),
342 				     "failed to get extp clock\n");
343 
344 	hdmi->hpd_gpiod = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN);
345 	/* This will catch e.g. -EPROBE_DEFER */
346 	if (IS_ERR(hdmi->hpd_gpiod))
347 		return dev_err_probe(dev, PTR_ERR(hdmi->hpd_gpiod),
348 				     "failed to get hpd gpio\n");
349 
350 	if (!hdmi->hpd_gpiod)
351 		DBG("failed to get HPD gpio");
352 
353 	if (hdmi->hpd_gpiod)
354 		gpiod_set_consumer_name(hdmi->hpd_gpiod, "HDMI_HPD");
355 
356 	ret = msm_hdmi_get_phy(hdmi);
357 	if (ret)
358 		return ret;
359 
360 	ret = devm_pm_runtime_enable(dev);
361 	if (ret)
362 		goto err_put_phy;
363 
364 	platform_set_drvdata(pdev, hdmi);
365 
366 	ret = component_add(dev, &msm_hdmi_ops);
367 	if (ret)
368 		goto err_put_phy;
369 
370 	return 0;
371 
372 err_put_phy:
373 	msm_hdmi_put_phy(hdmi);
374 	return ret;
375 }
376 
377 static void msm_hdmi_dev_remove(struct platform_device *pdev)
378 {
379 	struct hdmi *hdmi = dev_get_drvdata(&pdev->dev);
380 
381 	component_del(&pdev->dev, &msm_hdmi_ops);
382 
383 	msm_hdmi_put_phy(hdmi);
384 }
385 
386 static int msm_hdmi_runtime_suspend(struct device *dev)
387 {
388 	struct hdmi *hdmi = dev_get_drvdata(dev);
389 	const struct hdmi_platform_config *config = hdmi->config;
390 
391 	clk_bulk_disable_unprepare(config->pwr_clk_cnt, hdmi->pwr_clks);
392 
393 	pinctrl_pm_select_sleep_state(dev);
394 
395 	regulator_bulk_disable(config->pwr_reg_cnt, hdmi->pwr_regs);
396 
397 	return 0;
398 }
399 
400 static int msm_hdmi_runtime_resume(struct device *dev)
401 {
402 	struct hdmi *hdmi = dev_get_drvdata(dev);
403 	const struct hdmi_platform_config *config = hdmi->config;
404 	int ret;
405 
406 	ret = regulator_bulk_enable(config->pwr_reg_cnt, hdmi->pwr_regs);
407 	if (ret)
408 		return ret;
409 
410 	ret = pinctrl_pm_select_default_state(dev);
411 	if (ret)
412 		goto fail;
413 
414 	ret = clk_bulk_prepare_enable(config->pwr_clk_cnt, hdmi->pwr_clks);
415 	if (ret)
416 		goto fail;
417 
418 	return 0;
419 
420 fail:
421 	pinctrl_pm_select_sleep_state(dev);
422 
423 	return ret;
424 }
425 
426 static DEFINE_RUNTIME_DEV_PM_OPS(msm_hdmi_pm_ops, msm_hdmi_runtime_suspend, msm_hdmi_runtime_resume, NULL);
427 
428 static const struct of_device_id msm_hdmi_dt_match[] = {
429 	{ .compatible = "qcom,hdmi-tx-8998", .data = &hdmi_tx_8974_config },
430 	{ .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8974_config },
431 	{ .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8974_config },
432 	{ .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8974_config },
433 	{ .compatible = "qcom,hdmi-tx-8974", .data = &hdmi_tx_8974_config },
434 	{ .compatible = "qcom,hdmi-tx-8960", .data = &hdmi_tx_8960_config },
435 	{ .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8960_config },
436 	{}
437 };
438 MODULE_DEVICE_TABLE(of, msm_hdmi_dt_match);
439 
440 static struct platform_driver msm_hdmi_driver = {
441 	.probe = msm_hdmi_dev_probe,
442 	.remove = msm_hdmi_dev_remove,
443 	.driver = {
444 		.name = "hdmi_msm",
445 		.of_match_table = msm_hdmi_dt_match,
446 		.pm = &msm_hdmi_pm_ops,
447 	},
448 };
449 
450 void __init msm_hdmi_register(void)
451 {
452 	msm_hdmi_phy_driver_register();
453 	platform_driver_register(&msm_hdmi_driver);
454 }
455 
456 void __exit msm_hdmi_unregister(void)
457 {
458 	platform_driver_unregister(&msm_hdmi_driver);
459 	msm_hdmi_phy_driver_unregister();
460 }
461