1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * DesignWare MIPI DSI Host Controller v1.02 driver
4 *
5 * Copyright (c) 2016 Linaro Limited.
6 * Copyright (c) 2014-2016 Hisilicon Limited.
7 *
8 * Author:
9 * <shizongxuan@huawei.com>
10 * <zhangxiubin@huawei.com>
11 * <lvda3@hisilicon.com>
12 */
13 #include <linux/clk.h>
14 #include <linux/component.h>
15 #include <linux/delay.h>
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
18
19 #include <drm/drm_atomic_helper.h>
20 #include <drm/drm_device.h>
21 #include <drm/drm_encoder_slave.h>
22 #include <drm/drm_mipi_dsi.h>
23 #include <drm/drm_of.h>
24 #include <drm/drm_print.h>
25 #include <drm/drm_probe_helper.h>
26 #include <drm/drm_sysfs.h>
27
28 #include "kirin_drm_dsi.h"
29 #include "dw_dsi_reg.h"
30
31 static struct kirin_dsi_ops *hisi_dsi_ops;
32
dsi_set_output_client(struct drm_device * dev)33 void dsi_set_output_client(struct drm_device *dev)
34 {
35 enum dsi_output_client client;
36 struct drm_connector *connector;
37 struct drm_encoder *encoder;
38 struct drm_connector_list_iter conn_iter;
39 struct dw_dsi *dsi;
40
41 mutex_lock(&dev->mode_config.mutex);
42
43 /* find dsi encoder */
44 drm_for_each_encoder(encoder, dev)
45 if (encoder->encoder_type == DRM_MODE_ENCODER_DSI)
46 break;
47 dsi = encoder_to_dsi(encoder);
48
49 /* find HDMI connector */
50 drm_connector_list_iter_begin(dev, &conn_iter);
51 drm_for_each_connector_iter(connector, &conn_iter)
52 if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)
53 break;
54 drm_connector_list_iter_end(&conn_iter);
55
56 /*
57 * set the proper dsi output client
58 */
59 client = connector->status == connector_status_connected ? OUT_HDMI :
60 OUT_PANEL;
61 if (client != dsi->cur_client) {
62 /*
63 * set the switch ic to select the HDMI or MIPI_DSI
64 */
65 if (hisi_dsi_ops->version == KIRIN960_DSI)
66 gpiod_set_value_cansleep(dsi->gpio_mux, client);
67
68 dsi->cur_client = client;
69 /* let the userspace know panel connector status has changed */
70 drm_sysfs_hotplug_event(dev);
71 DRM_INFO("client change to %s\n",
72 client == OUT_HDMI ? "HDMI" : "panel");
73 }
74
75 mutex_unlock(&dev->mode_config.mutex);
76 }
77 EXPORT_SYMBOL_GPL(dsi_set_output_client);
78 /************************for the panel attach to dsi*****************************/
dsi_connector_get_modes(struct drm_connector * connector)79 static int dsi_connector_get_modes(struct drm_connector *connector)
80 {
81 struct dw_dsi *dsi = connector_to_dsi(connector);
82
83 return drm_panel_get_modes(dsi->panel, connector);
84 }
85
86 static enum drm_mode_status
dsi_connector_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)87 dsi_connector_mode_valid(struct drm_connector *connector,
88 struct drm_display_mode *mode)
89 {
90 enum drm_mode_status mode_status = MODE_OK;
91
92 return mode_status;
93 }
94
95 static struct drm_encoder *
dsi_connector_best_encoder(struct drm_connector * connector)96 dsi_connector_best_encoder(struct drm_connector *connector)
97 {
98 struct dw_dsi *dsi = connector_to_dsi(connector);
99
100 return &dsi->encoder;
101 }
102
103 static struct drm_connector_helper_funcs dsi_connector_helper_funcs = {
104 .get_modes = dsi_connector_get_modes,
105 .mode_valid = dsi_connector_mode_valid,
106 .best_encoder = dsi_connector_best_encoder,
107 };
108
109 static enum drm_connector_status
dsi_connector_detect(struct drm_connector * connector,bool force)110 dsi_connector_detect(struct drm_connector *connector, bool force)
111 {
112 struct dw_dsi *dsi = connector_to_dsi(connector);
113 enum drm_connector_status status;
114
115 status = dsi->cur_client == OUT_PANEL ? connector_status_connected :
116 connector_status_disconnected;
117
118 return status;
119 }
120
dsi_connector_destroy(struct drm_connector * connector)121 static void dsi_connector_destroy(struct drm_connector *connector)
122 {
123 drm_connector_unregister(connector);
124 drm_connector_cleanup(connector);
125 }
126
127 static struct drm_connector_funcs dsi_atomic_connector_funcs = {
128 .fill_modes = drm_helper_probe_single_connector_modes,
129 .detect = dsi_connector_detect,
130 .destroy = dsi_connector_destroy,
131 .reset = drm_atomic_helper_connector_reset,
132 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
133 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
134 };
135
dsi_connector_init(struct drm_device * dev,struct dw_dsi * dsi)136 static int dsi_connector_init(struct drm_device *dev, struct dw_dsi *dsi)
137 {
138 struct drm_encoder *encoder = &dsi->encoder;
139 struct drm_connector *connector = &dsi->connector;
140 int ret;
141
142 connector->polled = DRM_CONNECTOR_POLL_HPD;
143 drm_connector_helper_add(connector, &dsi_connector_helper_funcs);
144
145 ret = drm_connector_init(dev, &dsi->connector,
146 &dsi_atomic_connector_funcs,
147 DRM_MODE_CONNECTOR_DSI);
148 if (ret)
149 return ret;
150
151 ret = drm_connector_attach_encoder(connector, encoder);
152 if (ret)
153 return ret;
154
155 DRM_INFO("connector init\n");
156 return 0;
157 }
158
159 /****************************************************************************/
160
161 /***************************for the encoder_helper_funcs****************************************/
162 static const struct drm_encoder_funcs dw_encoder_funcs = {
163 .destroy = drm_encoder_cleanup,
164 };
165
dsi_encoder_atomic_check(struct drm_encoder * encoder,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)166 static int dsi_encoder_atomic_check(struct drm_encoder *encoder,
167 struct drm_crtc_state *crtc_state,
168 struct drm_connector_state *conn_state)
169 {
170 /* do nothing */
171 return 0;
172 }
173
174 static enum drm_mode_status
dsi_encoder_mode_valid(struct drm_encoder * encoder,const struct drm_display_mode * mode)175 dsi_encoder_mode_valid(struct drm_encoder *encoder,
176 const struct drm_display_mode *mode)
177
178 {
179 return hisi_dsi_ops->encoder_valid(encoder, mode);
180 }
181
dsi_encoder_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adj_mode)182 static void dsi_encoder_mode_set(struct drm_encoder *encoder,
183 struct drm_display_mode *mode,
184 struct drm_display_mode *adj_mode)
185 {
186 struct dw_dsi *dsi = encoder_to_dsi(encoder);
187
188 drm_mode_copy(&dsi->cur_mode, adj_mode);
189 }
190
dsi_encoder_enable(struct drm_encoder * encoder)191 static void dsi_encoder_enable(struct drm_encoder *encoder)
192 {
193 struct dw_dsi *dsi = encoder_to_dsi(encoder);
194
195 if (dsi->enable)
196 return;
197
198 hisi_dsi_ops->encoder_enable(encoder);
199
200 if (hisi_dsi_ops->version == KIRIN960_DSI) {
201 /* turn on panel */
202 if (dsi->panel && drm_panel_prepare(dsi->panel))
203 DRM_ERROR("failed to prepare panel\n");
204
205 /*dw_dsi_set_mode(dsi, DSI_VIDEO_MODE);*/
206
207 /* turn on panel's back light */
208 if (dsi->panel && drm_panel_enable(dsi->panel))
209 DRM_ERROR("failed to enable panel\n");
210 }
211
212 dsi->enable = true;
213 }
214
dw_dsi_set_mode(struct dw_dsi * dsi,enum dsi_work_mode mode)215 static void dw_dsi_set_mode(struct dw_dsi *dsi, enum dsi_work_mode mode)
216 {
217 struct dsi_hw_ctx *ctx = dsi->ctx;
218 void __iomem *base = ctx->base;
219
220 writel(RESET, base + PWR_UP);
221 writel(mode, base + MODE_CFG);
222 writel(POWERUP, base + PWR_UP);
223 }
224
dsi_encoder_disable(struct drm_encoder * encoder)225 static void dsi_encoder_disable(struct drm_encoder *encoder)
226 {
227 struct dw_dsi *dsi = encoder_to_dsi(encoder);
228 struct dsi_hw_ctx *ctx = dsi->ctx;
229
230 if (!dsi->enable)
231 return;
232
233 dw_dsi_set_mode(dsi, DSI_COMMAND_MODE);
234
235 if (hisi_dsi_ops->version == KIRIN960_DSI) {
236 /* turn off panel's backlight */
237 if (dsi->panel && drm_panel_disable(dsi->panel))
238 DRM_ERROR("failed to disable panel\n");
239
240 /* turn off panel */
241 if (dsi->panel && drm_panel_unprepare(dsi->panel))
242 DRM_ERROR("failed to unprepare panel\n");
243
244 clk_disable_unprepare(ctx->dss_dphy0_ref_clk);
245 clk_disable_unprepare(ctx->dss_dphy0_cfg_clk);
246 clk_disable_unprepare(ctx->dss_pclk_dsi0_clk);
247 }
248
249 dsi->enable = false;
250 }
251
252 static const struct drm_encoder_helper_funcs dw_encoder_helper_funcs = {
253 .atomic_check = dsi_encoder_atomic_check,
254 .mode_valid = dsi_encoder_mode_valid,
255 .mode_set = dsi_encoder_mode_set,
256 .enable = dsi_encoder_enable,
257 .disable = dsi_encoder_disable
258 };
259
260 /****************************************************************************/
dsi_bridge_init(struct drm_device * dev,struct dw_dsi * dsi)261 static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi)
262 {
263 struct drm_encoder *encoder = &dsi->encoder;
264 struct drm_bridge *bridge = dsi->bridge;
265 int ret;
266
267 /* associate the bridge to dsi encoder */
268 ret = drm_bridge_attach(encoder, bridge, NULL, 0);
269
270 if (ret) {
271 DRM_ERROR("failed to attach external bridge\n");
272 return ret;
273 }
274
275 return 0;
276 }
277
dw_drm_encoder_init(struct device * dev,struct drm_device * drm_dev,struct drm_encoder * encoder)278 static int dw_drm_encoder_init(struct device *dev, struct drm_device *drm_dev,
279 struct drm_encoder *encoder)
280 {
281 int ret;
282 u32 crtc_mask = drm_of_find_possible_crtcs(drm_dev, dev->of_node);
283
284 if (!crtc_mask) {
285 DRM_ERROR("failed to find crtc mask\n");
286 return -EINVAL;
287 }
288
289 encoder->possible_crtcs = crtc_mask;
290 ret = drm_encoder_init(drm_dev, encoder, &dw_encoder_funcs,
291 DRM_MODE_ENCODER_DSI, NULL);
292 if (ret) {
293 DRM_ERROR("failed to init dsi encoder\n");
294 return ret;
295 }
296
297 drm_encoder_helper_add(encoder, &dw_encoder_helper_funcs);
298
299 return 0;
300 }
301
dsi_bind(struct device * dev,struct device * master,void * data)302 static int dsi_bind(struct device *dev, struct device *master, void *data)
303 {
304 struct dsi_data *ddata = dev_get_drvdata(dev);
305 struct dw_dsi *dsi = &ddata->dsi;
306 struct drm_device *drm_dev = data;
307 int ret;
308
309 DRM_INFO("+.\n");
310 ret = dw_drm_encoder_init(dev, drm_dev, &dsi->encoder);
311 if (ret)
312 return ret;
313
314 if (dsi->bridge) {
315 ret = dsi_bridge_init(drm_dev, dsi);
316 if (ret)
317 return ret;
318 }
319
320 if (hisi_dsi_ops->version == KIRIN960_DSI) {
321 if (dsi->panel) {
322 ret = dsi_connector_init(drm_dev, dsi);
323 if (ret)
324 return ret;
325 }
326 } else if (hisi_dsi_ops->version == KIRIN620_DSI) {
327 /*the panel for the kirin620 drm have not support*/
328 }
329
330 DRM_INFO("-.\n");
331 return 0;
332 }
333
dsi_unbind(struct device * dev,struct device * master,void * data)334 static void dsi_unbind(struct device *dev, struct device *master, void *data)
335 {
336 /* do nothing */
337 }
338
339 static const struct component_ops dsi_ops = {
340 .bind = dsi_bind,
341 .unbind = dsi_unbind,
342 };
343
dsi_probe(struct platform_device * pdev)344 static int dsi_probe(struct platform_device *pdev)
345 {
346 struct device *dev = &pdev->dev;
347 struct dsi_data *data;
348 struct dw_dsi *dsi;
349 struct dsi_hw_ctx *ctx;
350 int ret;
351
352 hisi_dsi_ops = (struct kirin_dsi_ops *)of_device_get_match_data(dev);
353
354 DRM_INFO("+.\n");
355 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
356 if (!data) {
357 DRM_ERROR("failed to allocate dsi data.\n");
358 return -ENOMEM;
359 }
360 dsi = &data->dsi;
361 ctx = &data->ctx;
362 dsi->ctx = ctx;
363
364 if (hisi_dsi_ops == NULL)
365 DRM_ERROR("hisi_dsi_ops is not bind\n");
366 ret = hisi_dsi_ops->host_init(dev, dsi);
367 if (ret)
368 return ret;
369
370 ret = hisi_dsi_ops->parse_dt(pdev, dsi);
371 if (ret)
372 goto err_host_unregister;
373
374 platform_set_drvdata(pdev, data);
375
376 ret = component_add(dev, &dsi_ops);
377 if (ret)
378 goto err_host_unregister;
379
380 DRM_INFO("-.\n");
381 return 0;
382
383 err_host_unregister:
384 mipi_dsi_host_unregister(&dsi->host);
385 return ret;
386 }
387
dsi_remove(struct platform_device * pdev)388 static int dsi_remove(struct platform_device *pdev)
389 {
390 component_del(&pdev->dev, &dsi_ops);
391
392 return 0;
393 }
394
395 static const struct of_device_id dsi_of_match[] = {
396 #ifdef CONFIG_DRM_HISI_KIRIN960
397 {
398 .compatible = "hisilicon,hi3660-dsi",
399 .data = &kirin_dsi_960,
400 },
401 #endif
402 #ifdef CONFIG_DRM_HISI_KIRIN620
403 {
404 .compatible = "hisilicon,hi6220-dsi",
405 .data = &kirin_dsi_620,
406 },
407 #endif
408 { /* end node */ }
409 };
410 MODULE_DEVICE_TABLE(of, dsi_of_match);
411
412 static struct platform_driver dsi_driver = {
413 .probe = dsi_probe,
414 .remove = dsi_remove,
415 .driver = {
416 .name = "dw-dsi",
417 .of_match_table = dsi_of_match,
418 },
419 };
420
421 module_platform_driver(dsi_driver);
422
423 MODULE_DESCRIPTION("DesignWare MIPI DSI Host Controller v1.02 driver");
424 MODULE_LICENSE("GPL v2");
425