xref: /linux/drivers/gpu/drm/msm/dsi/dsi.c (revision 9888495a14a80a0a229e13c293592da559c51e64)
1a689554bSHai Li /*
2a689554bSHai Li  * Copyright (c) 2015, The Linux Foundation. All rights reserved.
3a689554bSHai Li  *
4a689554bSHai Li  * This program is free software; you can redistribute it and/or modify
5a689554bSHai Li  * it under the terms of the GNU General Public License version 2 and
6a689554bSHai Li  * only version 2 as published by the Free Software Foundation.
7a689554bSHai Li  *
8a689554bSHai Li  * This program is distributed in the hope that it will be useful,
9a689554bSHai Li  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10a689554bSHai Li  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11a689554bSHai Li  * GNU General Public License for more details.
12a689554bSHai Li  */
13a689554bSHai Li 
14a689554bSHai Li #include "dsi.h"
15a689554bSHai Li 
16a689554bSHai Li struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
17a689554bSHai Li {
186f054ec5SArchit Taneja 	if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
19a689554bSHai Li 		return NULL;
20a689554bSHai Li 
2197e00119SArchit Taneja 	return msm_dsi->encoder;
22a689554bSHai Li }
23a689554bSHai Li 
24ec31abf6SHai Li static int dsi_get_phy(struct msm_dsi *msm_dsi)
25ec31abf6SHai Li {
26ec31abf6SHai Li 	struct platform_device *pdev = msm_dsi->pdev;
27ec31abf6SHai Li 	struct platform_device *phy_pdev;
28ec31abf6SHai Li 	struct device_node *phy_node;
29ec31abf6SHai Li 
3069696ea0SArchit Taneja 	phy_node = of_parse_phandle(pdev->dev.of_node, "phys", 0);
31ec31abf6SHai Li 	if (!phy_node) {
32ec31abf6SHai Li 		dev_err(&pdev->dev, "cannot find phy device\n");
33ec31abf6SHai Li 		return -ENXIO;
34ec31abf6SHai Li 	}
35ec31abf6SHai Li 
36ec31abf6SHai Li 	phy_pdev = of_find_device_by_node(phy_node);
37ec31abf6SHai Li 	if (phy_pdev)
38ec31abf6SHai Li 		msm_dsi->phy = platform_get_drvdata(phy_pdev);
39ec31abf6SHai Li 
40ec31abf6SHai Li 	of_node_put(phy_node);
41ec31abf6SHai Li 
42ec31abf6SHai Li 	if (!phy_pdev || !msm_dsi->phy) {
43ec31abf6SHai Li 		dev_err(&pdev->dev, "%s: phy driver is not ready\n", __func__);
44ec31abf6SHai Li 		return -EPROBE_DEFER;
45ec31abf6SHai Li 	}
46ec31abf6SHai Li 
47ec31abf6SHai Li 	msm_dsi->phy_dev = get_device(&phy_pdev->dev);
48ec31abf6SHai Li 
49ec31abf6SHai Li 	return 0;
50ec31abf6SHai Li }
51ec31abf6SHai Li 
52a689554bSHai Li static void dsi_destroy(struct msm_dsi *msm_dsi)
53a689554bSHai Li {
54a689554bSHai Li 	if (!msm_dsi)
55a689554bSHai Li 		return;
56a689554bSHai Li 
57a689554bSHai Li 	msm_dsi_manager_unregister(msm_dsi);
589d32c498SHai Li 
59ec31abf6SHai Li 	if (msm_dsi->phy_dev) {
60ec31abf6SHai Li 		put_device(msm_dsi->phy_dev);
619d32c498SHai Li 		msm_dsi->phy = NULL;
62ec31abf6SHai Li 		msm_dsi->phy_dev = NULL;
639d32c498SHai Li 	}
649d32c498SHai Li 
65a689554bSHai Li 	if (msm_dsi->host) {
66a689554bSHai Li 		msm_dsi_host_destroy(msm_dsi->host);
67a689554bSHai Li 		msm_dsi->host = NULL;
68a689554bSHai Li 	}
69a689554bSHai Li 
70a689554bSHai Li 	platform_set_drvdata(msm_dsi->pdev, NULL);
71a689554bSHai Li }
72a689554bSHai Li 
73a689554bSHai Li static struct msm_dsi *dsi_init(struct platform_device *pdev)
74a689554bSHai Li {
75da882cd1SMarkus Elfring 	struct msm_dsi *msm_dsi;
76a689554bSHai Li 	int ret;
77a689554bSHai Li 
78da882cd1SMarkus Elfring 	if (!pdev)
79da882cd1SMarkus Elfring 		return ERR_PTR(-ENXIO);
80a689554bSHai Li 
81a689554bSHai Li 	msm_dsi = devm_kzalloc(&pdev->dev, sizeof(*msm_dsi), GFP_KERNEL);
82da882cd1SMarkus Elfring 	if (!msm_dsi)
83da882cd1SMarkus Elfring 		return ERR_PTR(-ENOMEM);
84a689554bSHai Li 	DBG("dsi probed=%p", msm_dsi);
85a689554bSHai Li 
86aea24171SSean Paul 	msm_dsi->id = -1;
87a689554bSHai Li 	msm_dsi->pdev = pdev;
88a689554bSHai Li 	platform_set_drvdata(pdev, msm_dsi);
89a689554bSHai Li 
90a689554bSHai Li 	/* Init dsi host */
91a689554bSHai Li 	ret = msm_dsi_host_init(msm_dsi);
92a689554bSHai Li 	if (ret)
93da882cd1SMarkus Elfring 		goto destroy_dsi;
94a689554bSHai Li 
95ec31abf6SHai Li 	/* GET dsi PHY */
96ec31abf6SHai Li 	ret = dsi_get_phy(msm_dsi);
97ec31abf6SHai Li 	if (ret)
98da882cd1SMarkus Elfring 		goto destroy_dsi;
999d32c498SHai Li 
100a689554bSHai Li 	/* Register to dsi manager */
101a689554bSHai Li 	ret = msm_dsi_manager_register(msm_dsi);
102a689554bSHai Li 	if (ret)
103da882cd1SMarkus Elfring 		goto destroy_dsi;
104a689554bSHai Li 
105a689554bSHai Li 	return msm_dsi;
106a689554bSHai Li 
107da882cd1SMarkus Elfring destroy_dsi:
108a689554bSHai Li 	dsi_destroy(msm_dsi);
109a689554bSHai Li 	return ERR_PTR(ret);
110a689554bSHai Li }
111a689554bSHai Li 
112a689554bSHai Li static int dsi_bind(struct device *dev, struct device *master, void *data)
113a689554bSHai Li {
114a689554bSHai Li 	struct drm_device *drm = dev_get_drvdata(master);
115a689554bSHai Li 	struct msm_drm_private *priv = drm->dev_private;
116a689554bSHai Li 	struct platform_device *pdev = to_platform_device(dev);
117a689554bSHai Li 	struct msm_dsi *msm_dsi;
118a689554bSHai Li 
119a689554bSHai Li 	DBG("");
120a689554bSHai Li 	msm_dsi = dsi_init(pdev);
121*9888495aSSean Paul 	if (IS_ERR(msm_dsi)) {
122*9888495aSSean Paul 		/* Don't fail the bind if the dsi port is not connected */
123*9888495aSSean Paul 		if (PTR_ERR(msm_dsi) == -ENODEV)
124*9888495aSSean Paul 			return 0;
125*9888495aSSean Paul 		else
126a689554bSHai Li 			return PTR_ERR(msm_dsi);
127*9888495aSSean Paul 	}
128a689554bSHai Li 
129a689554bSHai Li 	priv->dsi[msm_dsi->id] = msm_dsi;
130a689554bSHai Li 
131a689554bSHai Li 	return 0;
132a689554bSHai Li }
133a689554bSHai Li 
134a689554bSHai Li static void dsi_unbind(struct device *dev, struct device *master,
135a689554bSHai Li 		void *data)
136a689554bSHai Li {
137a689554bSHai Li 	struct drm_device *drm = dev_get_drvdata(master);
138a689554bSHai Li 	struct msm_drm_private *priv = drm->dev_private;
139a689554bSHai Li 	struct msm_dsi *msm_dsi = dev_get_drvdata(dev);
140a689554bSHai Li 	int id = msm_dsi->id;
141a689554bSHai Li 
142a689554bSHai Li 	if (priv->dsi[id]) {
143a689554bSHai Li 		dsi_destroy(msm_dsi);
144a689554bSHai Li 		priv->dsi[id] = NULL;
145a689554bSHai Li 	}
146a689554bSHai Li }
147a689554bSHai Li 
148a689554bSHai Li static const struct component_ops dsi_ops = {
149a689554bSHai Li 	.bind   = dsi_bind,
150a689554bSHai Li 	.unbind = dsi_unbind,
151a689554bSHai Li };
152a689554bSHai Li 
153a689554bSHai Li static int dsi_dev_probe(struct platform_device *pdev)
154a689554bSHai Li {
155a689554bSHai Li 	return component_add(&pdev->dev, &dsi_ops);
156a689554bSHai Li }
157a689554bSHai Li 
158a689554bSHai Li static int dsi_dev_remove(struct platform_device *pdev)
159a689554bSHai Li {
160a689554bSHai Li 	DBG("");
161a689554bSHai Li 	component_del(&pdev->dev, &dsi_ops);
162a689554bSHai Li 	return 0;
163a689554bSHai Li }
164a689554bSHai Li 
165a689554bSHai Li static const struct of_device_id dt_match[] = {
166a689554bSHai Li 	{ .compatible = "qcom,mdss-dsi-ctrl" },
167a689554bSHai Li 	{}
168a689554bSHai Li };
169a689554bSHai Li 
170f54ca1a0SArchit Taneja static const struct dev_pm_ops dsi_pm_ops = {
171f54ca1a0SArchit Taneja 	SET_RUNTIME_PM_OPS(msm_dsi_runtime_suspend, msm_dsi_runtime_resume, NULL)
172f54ca1a0SArchit Taneja };
173f54ca1a0SArchit Taneja 
174a689554bSHai Li static struct platform_driver dsi_driver = {
175a689554bSHai Li 	.probe = dsi_dev_probe,
176a689554bSHai Li 	.remove = dsi_dev_remove,
177a689554bSHai Li 	.driver = {
178a689554bSHai Li 		.name = "msm_dsi",
179a689554bSHai Li 		.of_match_table = dt_match,
180f54ca1a0SArchit Taneja 		.pm = &dsi_pm_ops,
181a689554bSHai Li 	},
182a689554bSHai Li };
183a689554bSHai Li 
184a689554bSHai Li void __init msm_dsi_register(void)
185a689554bSHai Li {
186a689554bSHai Li 	DBG("");
187ec31abf6SHai Li 	msm_dsi_phy_driver_register();
188a689554bSHai Li 	platform_driver_register(&dsi_driver);
189a689554bSHai Li }
190a689554bSHai Li 
191a689554bSHai Li void __exit msm_dsi_unregister(void)
192a689554bSHai Li {
193a689554bSHai Li 	DBG("");
194ec31abf6SHai Li 	msm_dsi_phy_driver_unregister();
195a689554bSHai Li 	platform_driver_unregister(&dsi_driver);
196a689554bSHai Li }
197a689554bSHai Li 
198a689554bSHai Li int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
19997e00119SArchit Taneja 			 struct drm_encoder *encoder)
200a689554bSHai Li {
20152749d60SGustavo A. R. Silva 	struct msm_drm_private *priv;
202c118e290SArchit Taneja 	struct drm_bridge *ext_bridge;
20397e00119SArchit Taneja 	int ret;
204a689554bSHai Li 
2053f0689e6SLloyd Atkinson 	if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
206a689554bSHai Li 		return -EINVAL;
207a689554bSHai Li 
20852749d60SGustavo A. R. Silva 	priv = dev->dev_private;
209a689554bSHai Li 	msm_dsi->dev = dev;
210a689554bSHai Li 
211a689554bSHai Li 	ret = msm_dsi_host_modeset_init(msm_dsi->host, dev);
212a689554bSHai Li 	if (ret) {
213a689554bSHai Li 		dev_err(dev->dev, "failed to modeset init host: %d\n", ret);
214a689554bSHai Li 		goto fail;
215a689554bSHai Li 	}
216a689554bSHai Li 
2178b03ad30SChandan Uddaraju 	if (!msm_dsi_manager_validate_current_config(msm_dsi->id))
2188b03ad30SChandan Uddaraju 		goto fail;
2198b03ad30SChandan Uddaraju 
22097e00119SArchit Taneja 	msm_dsi->encoder = encoder;
2210bb70b82SArchit Taneja 
222a689554bSHai Li 	msm_dsi->bridge = msm_dsi_manager_bridge_init(msm_dsi->id);
223a689554bSHai Li 	if (IS_ERR(msm_dsi->bridge)) {
224a689554bSHai Li 		ret = PTR_ERR(msm_dsi->bridge);
225a689554bSHai Li 		dev_err(dev->dev, "failed to create dsi bridge: %d\n", ret);
226a689554bSHai Li 		msm_dsi->bridge = NULL;
227a689554bSHai Li 		goto fail;
228a689554bSHai Li 	}
229a689554bSHai Li 
230c118e290SArchit Taneja 	/*
231c118e290SArchit Taneja 	 * check if the dsi encoder output is connected to a panel or an
232c118e290SArchit Taneja 	 * external bridge. We create a connector only if we're connected to a
233c118e290SArchit Taneja 	 * drm_panel device. When we're connected to an external bridge, we
234c118e290SArchit Taneja 	 * assume that the drm_bridge driver will create the connector itself.
235c118e290SArchit Taneja 	 */
236c118e290SArchit Taneja 	ext_bridge = msm_dsi_host_get_bridge(msm_dsi->host);
237c118e290SArchit Taneja 
238c118e290SArchit Taneja 	if (ext_bridge)
239c118e290SArchit Taneja 		msm_dsi->connector =
240c118e290SArchit Taneja 			msm_dsi_manager_ext_bridge_init(msm_dsi->id);
241c118e290SArchit Taneja 	else
242c118e290SArchit Taneja 		msm_dsi->connector =
243c118e290SArchit Taneja 			msm_dsi_manager_connector_init(msm_dsi->id);
244c118e290SArchit Taneja 
245a689554bSHai Li 	if (IS_ERR(msm_dsi->connector)) {
246a689554bSHai Li 		ret = PTR_ERR(msm_dsi->connector);
247c118e290SArchit Taneja 		dev_err(dev->dev,
248c118e290SArchit Taneja 			"failed to create dsi connector: %d\n", ret);
249a689554bSHai Li 		msm_dsi->connector = NULL;
250a689554bSHai Li 		goto fail;
251a689554bSHai Li 	}
252a689554bSHai Li 
253a689554bSHai Li 	priv->bridges[priv->num_bridges++]       = msm_dsi->bridge;
254a689554bSHai Li 	priv->connectors[priv->num_connectors++] = msm_dsi->connector;
255a689554bSHai Li 
256a689554bSHai Li 	return 0;
257a689554bSHai Li fail:
258a689554bSHai Li 	/* bridge/connector are normally destroyed by drm: */
259a689554bSHai Li 	if (msm_dsi->bridge) {
260a689554bSHai Li 		msm_dsi_manager_bridge_destroy(msm_dsi->bridge);
261a689554bSHai Li 		msm_dsi->bridge = NULL;
262a689554bSHai Li 	}
263c118e290SArchit Taneja 
264c118e290SArchit Taneja 	/* don't destroy connector if we didn't make it */
265c118e290SArchit Taneja 	if (msm_dsi->connector && !msm_dsi->external_bridge)
266a689554bSHai Li 		msm_dsi->connector->funcs->destroy(msm_dsi->connector);
267c118e290SArchit Taneja 
268a689554bSHai Li 	msm_dsi->connector = NULL;
269a689554bSHai Li 
270a689554bSHai Li 	return ret;
271a689554bSHai Li }
272a689554bSHai Li 
273