blob: beb26dfca2763d3f1eefded0766e437a840d6eea [file] [log] [blame]
Hai Lia6895542015-03-31 14:36:33 -04001/*
2 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include "dsi.h"
15
16struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
17{
18 if (!msm_dsi || !msm_dsi->panel)
19 return NULL;
20
21 return (msm_dsi->panel_flags & MIPI_DSI_MODE_VIDEO) ?
22 msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID] :
23 msm_dsi->encoders[MSM_DSI_CMD_ENCODER_ID];
24}
25
26static void dsi_destroy(struct msm_dsi *msm_dsi)
27{
28 if (!msm_dsi)
29 return;
30
31 msm_dsi_manager_unregister(msm_dsi);
Hai Li9d32c4982015-05-15 13:04:05 -040032
33 if (msm_dsi->phy) {
34 msm_dsi_phy_destroy(msm_dsi->phy);
35 msm_dsi->phy = NULL;
36 }
37
Hai Lia6895542015-03-31 14:36:33 -040038 if (msm_dsi->host) {
39 msm_dsi_host_destroy(msm_dsi->host);
40 msm_dsi->host = NULL;
41 }
42
43 platform_set_drvdata(msm_dsi->pdev, NULL);
44}
45
46static struct msm_dsi *dsi_init(struct platform_device *pdev)
47{
48 struct msm_dsi *msm_dsi = NULL;
49 int ret;
50
51 if (!pdev) {
52 dev_err(&pdev->dev, "no dsi device\n");
53 ret = -ENXIO;
54 goto fail;
55 }
56
57 msm_dsi = devm_kzalloc(&pdev->dev, sizeof(*msm_dsi), GFP_KERNEL);
58 if (!msm_dsi) {
59 ret = -ENOMEM;
60 goto fail;
61 }
62 DBG("dsi probed=%p", msm_dsi);
63
64 msm_dsi->pdev = pdev;
65 platform_set_drvdata(pdev, msm_dsi);
66
67 /* Init dsi host */
68 ret = msm_dsi_host_init(msm_dsi);
69 if (ret)
70 goto fail;
71
Hai Li9d32c4982015-05-15 13:04:05 -040072 /* Init dsi PHY */
73 msm_dsi->phy = msm_dsi_phy_init(pdev, msm_dsi->phy_type, msm_dsi->id);
74 if (!msm_dsi->phy) {
75 ret = -ENXIO;
76 pr_err("%s: phy init failed\n", __func__);
77 goto fail;
78 }
79
Hai Lia6895542015-03-31 14:36:33 -040080 /* Register to dsi manager */
81 ret = msm_dsi_manager_register(msm_dsi);
82 if (ret)
83 goto fail;
84
85 return msm_dsi;
86
87fail:
88 if (msm_dsi)
89 dsi_destroy(msm_dsi);
90
91 return ERR_PTR(ret);
92}
93
94static int dsi_bind(struct device *dev, struct device *master, void *data)
95{
96 struct drm_device *drm = dev_get_drvdata(master);
97 struct msm_drm_private *priv = drm->dev_private;
98 struct platform_device *pdev = to_platform_device(dev);
99 struct msm_dsi *msm_dsi;
100
101 DBG("");
102 msm_dsi = dsi_init(pdev);
103 if (IS_ERR(msm_dsi))
104 return PTR_ERR(msm_dsi);
105
106 priv->dsi[msm_dsi->id] = msm_dsi;
107
108 return 0;
109}
110
111static void dsi_unbind(struct device *dev, struct device *master,
112 void *data)
113{
114 struct drm_device *drm = dev_get_drvdata(master);
115 struct msm_drm_private *priv = drm->dev_private;
116 struct msm_dsi *msm_dsi = dev_get_drvdata(dev);
117 int id = msm_dsi->id;
118
119 if (priv->dsi[id]) {
120 dsi_destroy(msm_dsi);
121 priv->dsi[id] = NULL;
122 }
123}
124
125static const struct component_ops dsi_ops = {
126 .bind = dsi_bind,
127 .unbind = dsi_unbind,
128};
129
130static int dsi_dev_probe(struct platform_device *pdev)
131{
132 return component_add(&pdev->dev, &dsi_ops);
133}
134
135static int dsi_dev_remove(struct platform_device *pdev)
136{
137 DBG("");
138 component_del(&pdev->dev, &dsi_ops);
139 return 0;
140}
141
142static const struct of_device_id dt_match[] = {
143 { .compatible = "qcom,mdss-dsi-ctrl" },
144 {}
145};
146
147static struct platform_driver dsi_driver = {
148 .probe = dsi_dev_probe,
149 .remove = dsi_dev_remove,
150 .driver = {
151 .name = "msm_dsi",
152 .of_match_table = dt_match,
153 },
154};
155
156void __init msm_dsi_register(void)
157{
158 DBG("");
159 platform_driver_register(&dsi_driver);
160}
161
162void __exit msm_dsi_unregister(void)
163{
164 DBG("");
165 platform_driver_unregister(&dsi_driver);
166}
167
168int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
169 struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM])
170{
171 struct msm_drm_private *priv = dev->dev_private;
172 int ret, i;
173
174 if (WARN_ON(!encoders[MSM_DSI_VIDEO_ENCODER_ID] ||
175 !encoders[MSM_DSI_CMD_ENCODER_ID]))
176 return -EINVAL;
177
178 msm_dsi->dev = dev;
179
180 ret = msm_dsi_host_modeset_init(msm_dsi->host, dev);
181 if (ret) {
182 dev_err(dev->dev, "failed to modeset init host: %d\n", ret);
183 goto fail;
184 }
185
186 msm_dsi->bridge = msm_dsi_manager_bridge_init(msm_dsi->id);
187 if (IS_ERR(msm_dsi->bridge)) {
188 ret = PTR_ERR(msm_dsi->bridge);
189 dev_err(dev->dev, "failed to create dsi bridge: %d\n", ret);
190 msm_dsi->bridge = NULL;
191 goto fail;
192 }
193
Hai Li6f6b2872015-04-23 14:13:21 -0400194 for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) {
195 encoders[i]->bridge = msm_dsi->bridge;
196 msm_dsi->encoders[i] = encoders[i];
197 }
198
Hai Lia6895542015-03-31 14:36:33 -0400199 msm_dsi->connector = msm_dsi_manager_connector_init(msm_dsi->id);
200 if (IS_ERR(msm_dsi->connector)) {
201 ret = PTR_ERR(msm_dsi->connector);
202 dev_err(dev->dev, "failed to create dsi connector: %d\n", ret);
203 msm_dsi->connector = NULL;
204 goto fail;
205 }
206
Hai Lia6895542015-03-31 14:36:33 -0400207 priv->bridges[priv->num_bridges++] = msm_dsi->bridge;
208 priv->connectors[priv->num_connectors++] = msm_dsi->connector;
209
210 return 0;
211fail:
212 if (msm_dsi) {
213 /* bridge/connector are normally destroyed by drm: */
214 if (msm_dsi->bridge) {
215 msm_dsi_manager_bridge_destroy(msm_dsi->bridge);
216 msm_dsi->bridge = NULL;
217 }
218 if (msm_dsi->connector) {
219 msm_dsi->connector->funcs->destroy(msm_dsi->connector);
220 msm_dsi->connector = NULL;
221 }
222 }
223
224 return ret;
225}
226