xref: /linux/drivers/gpu/drm/msm/dsi/dsi.c (revision 52749d601a6055da3352842575408fcba6f1da46)
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 
86a689554bSHai Li 	msm_dsi->pdev = pdev;
87a689554bSHai Li 	platform_set_drvdata(pdev, msm_dsi);
88a689554bSHai Li 
89a689554bSHai Li 	/* Init dsi host */
90a689554bSHai Li 	ret = msm_dsi_host_init(msm_dsi);
91a689554bSHai Li 	if (ret)
92da882cd1SMarkus Elfring 		goto destroy_dsi;
93a689554bSHai Li 
94ec31abf6SHai Li 	/* GET dsi PHY */
95ec31abf6SHai Li 	ret = dsi_get_phy(msm_dsi);
96ec31abf6SHai Li 	if (ret)
97da882cd1SMarkus Elfring 		goto destroy_dsi;
989d32c498SHai Li 
99a689554bSHai Li 	/* Register to dsi manager */
100a689554bSHai Li 	ret = msm_dsi_manager_register(msm_dsi);
101a689554bSHai Li 	if (ret)
102da882cd1SMarkus Elfring 		goto destroy_dsi;
103a689554bSHai Li 
104a689554bSHai Li 	return msm_dsi;
105a689554bSHai Li 
106da882cd1SMarkus Elfring destroy_dsi:
107a689554bSHai Li 	dsi_destroy(msm_dsi);
108a689554bSHai Li 	return ERR_PTR(ret);
109a689554bSHai Li }
110a689554bSHai Li 
111a689554bSHai Li static int dsi_bind(struct device *dev, struct device *master, void *data)
112a689554bSHai Li {
113a689554bSHai Li 	struct drm_device *drm = dev_get_drvdata(master);
114a689554bSHai Li 	struct msm_drm_private *priv = drm->dev_private;
115a689554bSHai Li 	struct platform_device *pdev = to_platform_device(dev);
116a689554bSHai Li 	struct msm_dsi *msm_dsi;
117a689554bSHai Li 
118a689554bSHai Li 	DBG("");
119a689554bSHai Li 	msm_dsi = dsi_init(pdev);
120a689554bSHai Li 	if (IS_ERR(msm_dsi))
121a689554bSHai Li 		return PTR_ERR(msm_dsi);
122a689554bSHai Li 
123a689554bSHai Li 	priv->dsi[msm_dsi->id] = msm_dsi;
124a689554bSHai Li 
125a689554bSHai Li 	return 0;
126a689554bSHai Li }
127a689554bSHai Li 
128a689554bSHai Li static void dsi_unbind(struct device *dev, struct device *master,
129a689554bSHai Li 		void *data)
130a689554bSHai Li {
131a689554bSHai Li 	struct drm_device *drm = dev_get_drvdata(master);
132a689554bSHai Li 	struct msm_drm_private *priv = drm->dev_private;
133a689554bSHai Li 	struct msm_dsi *msm_dsi = dev_get_drvdata(dev);
134a689554bSHai Li 	int id = msm_dsi->id;
135a689554bSHai Li 
136a689554bSHai Li 	if (priv->dsi[id]) {
137a689554bSHai Li 		dsi_destroy(msm_dsi);
138a689554bSHai Li 		priv->dsi[id] = NULL;
139a689554bSHai Li 	}
140a689554bSHai Li }
141a689554bSHai Li 
142a689554bSHai Li static const struct component_ops dsi_ops = {
143a689554bSHai Li 	.bind   = dsi_bind,
144a689554bSHai Li 	.unbind = dsi_unbind,
145a689554bSHai Li };
146a689554bSHai Li 
147a689554bSHai Li static int dsi_dev_probe(struct platform_device *pdev)
148a689554bSHai Li {
149a689554bSHai Li 	return component_add(&pdev->dev, &dsi_ops);
150a689554bSHai Li }
151a689554bSHai Li 
152a689554bSHai Li static int dsi_dev_remove(struct platform_device *pdev)
153a689554bSHai Li {
154a689554bSHai Li 	DBG("");
155a689554bSHai Li 	component_del(&pdev->dev, &dsi_ops);
156a689554bSHai Li 	return 0;
157a689554bSHai Li }
158a689554bSHai Li 
159a689554bSHai Li static const struct of_device_id dt_match[] = {
160a689554bSHai Li 	{ .compatible = "qcom,mdss-dsi-ctrl" },
161a689554bSHai Li 	{}
162a689554bSHai Li };
163a689554bSHai Li 
164f54ca1a0SArchit Taneja static const struct dev_pm_ops dsi_pm_ops = {
165f54ca1a0SArchit Taneja 	SET_RUNTIME_PM_OPS(msm_dsi_runtime_suspend, msm_dsi_runtime_resume, NULL)
166f54ca1a0SArchit Taneja };
167f54ca1a0SArchit Taneja 
168a689554bSHai Li static struct platform_driver dsi_driver = {
169a689554bSHai Li 	.probe = dsi_dev_probe,
170a689554bSHai Li 	.remove = dsi_dev_remove,
171a689554bSHai Li 	.driver = {
172a689554bSHai Li 		.name = "msm_dsi",
173a689554bSHai Li 		.of_match_table = dt_match,
174f54ca1a0SArchit Taneja 		.pm = &dsi_pm_ops,
175a689554bSHai Li 	},
176a689554bSHai Li };
177a689554bSHai Li 
178a689554bSHai Li void __init msm_dsi_register(void)
179a689554bSHai Li {
180a689554bSHai Li 	DBG("");
181ec31abf6SHai Li 	msm_dsi_phy_driver_register();
182a689554bSHai Li 	platform_driver_register(&dsi_driver);
183a689554bSHai Li }
184a689554bSHai Li 
185a689554bSHai Li void __exit msm_dsi_unregister(void)
186a689554bSHai Li {
187a689554bSHai Li 	DBG("");
188ec31abf6SHai Li 	msm_dsi_phy_driver_unregister();
189a689554bSHai Li 	platform_driver_unregister(&dsi_driver);
190a689554bSHai Li }
191a689554bSHai Li 
192a689554bSHai Li int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
19397e00119SArchit Taneja 			 struct drm_encoder *encoder)
194a689554bSHai Li {
195*52749d60SGustavo A. R. Silva 	struct msm_drm_private *priv;
196c118e290SArchit Taneja 	struct drm_bridge *ext_bridge;
19797e00119SArchit Taneja 	int ret;
198a689554bSHai Li 
1993f0689e6SLloyd Atkinson 	if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
200a689554bSHai Li 		return -EINVAL;
201a689554bSHai Li 
202*52749d60SGustavo A. R. Silva 	priv = dev->dev_private;
203a689554bSHai Li 	msm_dsi->dev = dev;
204a689554bSHai Li 
205a689554bSHai Li 	ret = msm_dsi_host_modeset_init(msm_dsi->host, dev);
206a689554bSHai Li 	if (ret) {
207a689554bSHai Li 		dev_err(dev->dev, "failed to modeset init host: %d\n", ret);
208a689554bSHai Li 		goto fail;
209a689554bSHai Li 	}
210a689554bSHai Li 
21197e00119SArchit Taneja 	msm_dsi->encoder = encoder;
2120bb70b82SArchit Taneja 
213a689554bSHai Li 	msm_dsi->bridge = msm_dsi_manager_bridge_init(msm_dsi->id);
214a689554bSHai Li 	if (IS_ERR(msm_dsi->bridge)) {
215a689554bSHai Li 		ret = PTR_ERR(msm_dsi->bridge);
216a689554bSHai Li 		dev_err(dev->dev, "failed to create dsi bridge: %d\n", ret);
217a689554bSHai Li 		msm_dsi->bridge = NULL;
218a689554bSHai Li 		goto fail;
219a689554bSHai Li 	}
220a689554bSHai Li 
221c118e290SArchit Taneja 	/*
222c118e290SArchit Taneja 	 * check if the dsi encoder output is connected to a panel or an
223c118e290SArchit Taneja 	 * external bridge. We create a connector only if we're connected to a
224c118e290SArchit Taneja 	 * drm_panel device. When we're connected to an external bridge, we
225c118e290SArchit Taneja 	 * assume that the drm_bridge driver will create the connector itself.
226c118e290SArchit Taneja 	 */
227c118e290SArchit Taneja 	ext_bridge = msm_dsi_host_get_bridge(msm_dsi->host);
228c118e290SArchit Taneja 
229c118e290SArchit Taneja 	if (ext_bridge)
230c118e290SArchit Taneja 		msm_dsi->connector =
231c118e290SArchit Taneja 			msm_dsi_manager_ext_bridge_init(msm_dsi->id);
232c118e290SArchit Taneja 	else
233c118e290SArchit Taneja 		msm_dsi->connector =
234c118e290SArchit Taneja 			msm_dsi_manager_connector_init(msm_dsi->id);
235c118e290SArchit Taneja 
236a689554bSHai Li 	if (IS_ERR(msm_dsi->connector)) {
237a689554bSHai Li 		ret = PTR_ERR(msm_dsi->connector);
238c118e290SArchit Taneja 		dev_err(dev->dev,
239c118e290SArchit Taneja 			"failed to create dsi connector: %d\n", ret);
240a689554bSHai Li 		msm_dsi->connector = NULL;
241a689554bSHai Li 		goto fail;
242a689554bSHai Li 	}
243a689554bSHai Li 
244a689554bSHai Li 	priv->bridges[priv->num_bridges++]       = msm_dsi->bridge;
245a689554bSHai Li 	priv->connectors[priv->num_connectors++] = msm_dsi->connector;
246a689554bSHai Li 
247a689554bSHai Li 	return 0;
248a689554bSHai Li fail:
249a689554bSHai Li 	/* bridge/connector are normally destroyed by drm: */
250a689554bSHai Li 	if (msm_dsi->bridge) {
251a689554bSHai Li 		msm_dsi_manager_bridge_destroy(msm_dsi->bridge);
252a689554bSHai Li 		msm_dsi->bridge = NULL;
253a689554bSHai Li 	}
254c118e290SArchit Taneja 
255c118e290SArchit Taneja 	/* don't destroy connector if we didn't make it */
256c118e290SArchit Taneja 	if (msm_dsi->connector && !msm_dsi->external_bridge)
257a689554bSHai Li 		msm_dsi->connector->funcs->destroy(msm_dsi->connector);
258c118e290SArchit Taneja 
259a689554bSHai Li 	msm_dsi->connector = NULL;
260a689554bSHai Li 
261a689554bSHai Li 	return ret;
262a689554bSHai Li }
263a689554bSHai Li 
264