xref: /openbmc/linux/drivers/gpu/drm/msm/dsi/dsi_manager.c (revision 99b7e93c)
1 /*
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 "msm_kms.h"
15 #include "dsi.h"
16 
17 struct msm_dsi_manager {
18 	struct msm_dsi *dsi[DSI_MAX];
19 
20 	bool is_dual_panel;
21 	bool is_sync_needed;
22 	int master_panel_id;
23 };
24 
25 static struct msm_dsi_manager msm_dsim_glb;
26 
27 #define IS_DUAL_PANEL()		(msm_dsim_glb.is_dual_panel)
28 #define IS_SYNC_NEEDED()	(msm_dsim_glb.is_sync_needed)
29 #define IS_MASTER_PANEL(id)	(msm_dsim_glb.master_panel_id == id)
30 
31 static inline struct msm_dsi *dsi_mgr_get_dsi(int id)
32 {
33 	return msm_dsim_glb.dsi[id];
34 }
35 
36 static inline struct msm_dsi *dsi_mgr_get_other_dsi(int id)
37 {
38 	return msm_dsim_glb.dsi[(id + 1) % DSI_MAX];
39 }
40 
41 static int dsi_mgr_parse_dual_panel(struct device_node *np, int id)
42 {
43 	struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
44 
45 	/* We assume 2 dsi nodes have the same information of dual-panel and
46 	 * sync-mode, and only one node specifies master in case of dual mode.
47 	 */
48 	if (!msm_dsim->is_dual_panel)
49 		msm_dsim->is_dual_panel = of_property_read_bool(
50 						np, "qcom,dual-panel-mode");
51 
52 	if (msm_dsim->is_dual_panel) {
53 		if (of_property_read_bool(np, "qcom,master-panel"))
54 			msm_dsim->master_panel_id = id;
55 		if (!msm_dsim->is_sync_needed)
56 			msm_dsim->is_sync_needed = of_property_read_bool(
57 					np, "qcom,sync-dual-panel");
58 	}
59 
60 	return 0;
61 }
62 
63 struct dsi_connector {
64 	struct drm_connector base;
65 	int id;
66 };
67 
68 struct dsi_bridge {
69 	struct drm_bridge base;
70 	int id;
71 };
72 
73 #define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
74 #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
75 
76 static inline int dsi_mgr_connector_get_id(struct drm_connector *connector)
77 {
78 	struct dsi_connector *dsi_connector = to_dsi_connector(connector);
79 	return dsi_connector->id;
80 }
81 
82 static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
83 {
84 	struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
85 	return dsi_bridge->id;
86 }
87 
88 static enum drm_connector_status dsi_mgr_connector_detect(
89 		struct drm_connector *connector, bool force)
90 {
91 	int id = dsi_mgr_connector_get_id(connector);
92 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
93 	struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
94 	struct msm_drm_private *priv = connector->dev->dev_private;
95 	struct msm_kms *kms = priv->kms;
96 
97 	DBG("id=%d", id);
98 	if (!msm_dsi->panel) {
99 		msm_dsi->panel = msm_dsi_host_get_panel(msm_dsi->host,
100 						&msm_dsi->panel_flags);
101 
102 		/* There is only 1 panel in the global panel list
103 		 * for dual panel mode. Therefore slave dsi should get
104 		 * the drm_panel instance from master dsi, and
105 		 * keep using the panel flags got from the current DSI link.
106 		 */
107 		if (!msm_dsi->panel && IS_DUAL_PANEL() &&
108 			!IS_MASTER_PANEL(id) && other_dsi)
109 			msm_dsi->panel = msm_dsi_host_get_panel(
110 					other_dsi->host, NULL);
111 
112 		if (msm_dsi->panel && IS_DUAL_PANEL())
113 			drm_object_attach_property(&connector->base,
114 				connector->dev->mode_config.tile_property, 0);
115 
116 		/* Set split display info to kms once dual panel is connected
117 		 * to both hosts
118 		 */
119 		if (msm_dsi->panel && IS_DUAL_PANEL() &&
120 			other_dsi && other_dsi->panel) {
121 			bool cmd_mode = !(msm_dsi->panel_flags &
122 						MIPI_DSI_MODE_VIDEO);
123 			struct drm_encoder *encoder = msm_dsi_get_encoder(
124 					dsi_mgr_get_dsi(DSI_ENCODER_MASTER));
125 			struct drm_encoder *slave_enc = msm_dsi_get_encoder(
126 					dsi_mgr_get_dsi(DSI_ENCODER_SLAVE));
127 
128 			if (kms->funcs->set_split_display)
129 				kms->funcs->set_split_display(kms, encoder,
130 							slave_enc, cmd_mode);
131 			else
132 				pr_err("mdp does not support dual panel\n");
133 		}
134 	}
135 
136 	return msm_dsi->panel ? connector_status_connected :
137 		connector_status_disconnected;
138 }
139 
140 static void dsi_mgr_connector_destroy(struct drm_connector *connector)
141 {
142 	DBG("");
143 	drm_connector_unregister(connector);
144 	drm_connector_cleanup(connector);
145 }
146 
147 static void dsi_dual_connector_fix_modes(struct drm_connector *connector)
148 {
149 	struct drm_display_mode *mode, *m;
150 
151 	/* Only support left-right mode */
152 	list_for_each_entry_safe(mode, m, &connector->probed_modes, head) {
153 		mode->clock >>= 1;
154 		mode->hdisplay >>= 1;
155 		mode->hsync_start >>= 1;
156 		mode->hsync_end >>= 1;
157 		mode->htotal >>= 1;
158 		drm_mode_set_name(mode);
159 	}
160 }
161 
162 static int dsi_dual_connector_tile_init(
163 			struct drm_connector *connector, int id)
164 {
165 	struct drm_display_mode *mode;
166 	/* Fake topology id */
167 	char topo_id[8] = {'M', 'S', 'M', 'D', 'U', 'D', 'S', 'I'};
168 
169 	if (connector->tile_group) {
170 		DBG("Tile property has been initialized");
171 		return 0;
172 	}
173 
174 	/* Use the first mode only for now */
175 	mode = list_first_entry(&connector->probed_modes,
176 				struct drm_display_mode,
177 				head);
178 	if (!mode)
179 		return -EINVAL;
180 
181 	connector->tile_group = drm_mode_get_tile_group(
182 					connector->dev, topo_id);
183 	if (!connector->tile_group)
184 		connector->tile_group = drm_mode_create_tile_group(
185 					connector->dev, topo_id);
186 	if (!connector->tile_group) {
187 		pr_err("%s: failed to create tile group\n", __func__);
188 		return -ENOMEM;
189 	}
190 
191 	connector->has_tile = true;
192 	connector->tile_is_single_monitor = true;
193 
194 	/* mode has been fixed */
195 	connector->tile_h_size = mode->hdisplay;
196 	connector->tile_v_size = mode->vdisplay;
197 
198 	/* Only support left-right mode */
199 	connector->num_h_tile = 2;
200 	connector->num_v_tile = 1;
201 
202 	connector->tile_v_loc = 0;
203 	connector->tile_h_loc = (id == DSI_RIGHT) ? 1 : 0;
204 
205 	return 0;
206 }
207 
208 static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
209 {
210 	int id = dsi_mgr_connector_get_id(connector);
211 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
212 	struct drm_panel *panel = msm_dsi->panel;
213 	int ret, num;
214 
215 	if (!panel)
216 		return 0;
217 
218 	/* Since we have 2 connectors, but only 1 drm_panel in dual DSI mode,
219 	 * panel should not attach to any connector.
220 	 * Only temporarily attach panel to the current connector here,
221 	 * to let panel set mode to this connector.
222 	 */
223 	drm_panel_attach(panel, connector);
224 	num = drm_panel_get_modes(panel);
225 	drm_panel_detach(panel);
226 	if (!num)
227 		return 0;
228 
229 	if (IS_DUAL_PANEL()) {
230 		/* report half resolution to user */
231 		dsi_dual_connector_fix_modes(connector);
232 		ret = dsi_dual_connector_tile_init(connector, id);
233 		if (ret)
234 			return ret;
235 		ret = drm_mode_connector_set_tile_property(connector);
236 		if (ret) {
237 			pr_err("%s: set tile property failed, %d\n",
238 					__func__, ret);
239 			return ret;
240 		}
241 	}
242 
243 	return num;
244 }
245 
246 static int dsi_mgr_connector_mode_valid(struct drm_connector *connector,
247 				struct drm_display_mode *mode)
248 {
249 	int id = dsi_mgr_connector_get_id(connector);
250 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
251 	struct drm_encoder *encoder = msm_dsi_get_encoder(msm_dsi);
252 	struct msm_drm_private *priv = connector->dev->dev_private;
253 	struct msm_kms *kms = priv->kms;
254 	long actual, requested;
255 
256 	DBG("");
257 	requested = 1000 * mode->clock;
258 	actual = kms->funcs->round_pixclk(kms, requested, encoder);
259 
260 	DBG("requested=%ld, actual=%ld", requested, actual);
261 	if (actual != requested)
262 		return MODE_CLOCK_RANGE;
263 
264 	return MODE_OK;
265 }
266 
267 static struct drm_encoder *
268 dsi_mgr_connector_best_encoder(struct drm_connector *connector)
269 {
270 	int id = dsi_mgr_connector_get_id(connector);
271 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
272 
273 	DBG("");
274 	return msm_dsi_get_encoder(msm_dsi);
275 }
276 
277 static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
278 {
279 	int id = dsi_mgr_bridge_get_id(bridge);
280 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
281 	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
282 	struct mipi_dsi_host *host = msm_dsi->host;
283 	struct drm_panel *panel = msm_dsi->panel;
284 	bool is_dual_panel = IS_DUAL_PANEL();
285 	int ret;
286 
287 	DBG("id=%d", id);
288 	if (!panel || (is_dual_panel && (DSI_1 == id)))
289 		return;
290 
291 	ret = msm_dsi_host_power_on(host);
292 	if (ret) {
293 		pr_err("%s: power on host %d failed, %d\n", __func__, id, ret);
294 		goto host_on_fail;
295 	}
296 
297 	if (is_dual_panel && msm_dsi1) {
298 		ret = msm_dsi_host_power_on(msm_dsi1->host);
299 		if (ret) {
300 			pr_err("%s: power on host1 failed, %d\n",
301 							__func__, ret);
302 			goto host1_on_fail;
303 		}
304 	}
305 
306 	/* Always call panel functions once, because even for dual panels,
307 	 * there is only one drm_panel instance.
308 	 */
309 	ret = drm_panel_prepare(panel);
310 	if (ret) {
311 		pr_err("%s: prepare panel %d failed, %d\n", __func__, id, ret);
312 		goto panel_prep_fail;
313 	}
314 
315 	ret = msm_dsi_host_enable(host);
316 	if (ret) {
317 		pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
318 		goto host_en_fail;
319 	}
320 
321 	if (is_dual_panel && msm_dsi1) {
322 		ret = msm_dsi_host_enable(msm_dsi1->host);
323 		if (ret) {
324 			pr_err("%s: enable host1 failed, %d\n", __func__, ret);
325 			goto host1_en_fail;
326 		}
327 	}
328 
329 	ret = drm_panel_enable(panel);
330 	if (ret) {
331 		pr_err("%s: enable panel %d failed, %d\n", __func__, id, ret);
332 		goto panel_en_fail;
333 	}
334 
335 	return;
336 
337 panel_en_fail:
338 	if (is_dual_panel && msm_dsi1)
339 		msm_dsi_host_disable(msm_dsi1->host);
340 host1_en_fail:
341 	msm_dsi_host_disable(host);
342 host_en_fail:
343 	drm_panel_unprepare(panel);
344 panel_prep_fail:
345 	if (is_dual_panel && msm_dsi1)
346 		msm_dsi_host_power_off(msm_dsi1->host);
347 host1_on_fail:
348 	msm_dsi_host_power_off(host);
349 host_on_fail:
350 	return;
351 }
352 
353 static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
354 {
355 	DBG("");
356 }
357 
358 static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
359 {
360 	DBG("");
361 }
362 
363 static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
364 {
365 	int id = dsi_mgr_bridge_get_id(bridge);
366 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
367 	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
368 	struct mipi_dsi_host *host = msm_dsi->host;
369 	struct drm_panel *panel = msm_dsi->panel;
370 	bool is_dual_panel = IS_DUAL_PANEL();
371 	int ret;
372 
373 	DBG("id=%d", id);
374 
375 	if (!panel || (is_dual_panel && (DSI_1 == id)))
376 		return;
377 
378 	ret = drm_panel_disable(panel);
379 	if (ret)
380 		pr_err("%s: Panel %d OFF failed, %d\n", __func__, id, ret);
381 
382 	ret = msm_dsi_host_disable(host);
383 	if (ret)
384 		pr_err("%s: host %d disable failed, %d\n", __func__, id, ret);
385 
386 	if (is_dual_panel && msm_dsi1) {
387 		ret = msm_dsi_host_disable(msm_dsi1->host);
388 		if (ret)
389 			pr_err("%s: host1 disable failed, %d\n", __func__, ret);
390 	}
391 
392 	ret = drm_panel_unprepare(panel);
393 	if (ret)
394 		pr_err("%s: Panel %d unprepare failed,%d\n", __func__, id, ret);
395 
396 	ret = msm_dsi_host_power_off(host);
397 	if (ret)
398 		pr_err("%s: host %d power off failed,%d\n", __func__, id, ret);
399 
400 	if (is_dual_panel && msm_dsi1) {
401 		ret = msm_dsi_host_power_off(msm_dsi1->host);
402 		if (ret)
403 			pr_err("%s: host1 power off failed, %d\n",
404 								__func__, ret);
405 	}
406 }
407 
408 static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge,
409 		struct drm_display_mode *mode,
410 		struct drm_display_mode *adjusted_mode)
411 {
412 	int id = dsi_mgr_bridge_get_id(bridge);
413 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
414 	struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
415 	struct mipi_dsi_host *host = msm_dsi->host;
416 	bool is_dual_panel = IS_DUAL_PANEL();
417 
418 	DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
419 			mode->base.id, mode->name,
420 			mode->vrefresh, mode->clock,
421 			mode->hdisplay, mode->hsync_start,
422 			mode->hsync_end, mode->htotal,
423 			mode->vdisplay, mode->vsync_start,
424 			mode->vsync_end, mode->vtotal,
425 			mode->type, mode->flags);
426 
427 	if (is_dual_panel && (DSI_1 == id))
428 		return;
429 
430 	msm_dsi_host_set_display_mode(host, adjusted_mode);
431 	if (is_dual_panel && other_dsi)
432 		msm_dsi_host_set_display_mode(other_dsi->host, adjusted_mode);
433 }
434 
435 static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
436 	.dpms = drm_atomic_helper_connector_dpms,
437 	.detect = dsi_mgr_connector_detect,
438 	.fill_modes = drm_helper_probe_single_connector_modes,
439 	.destroy = dsi_mgr_connector_destroy,
440 	.reset = drm_atomic_helper_connector_reset,
441 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
442 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
443 };
444 
445 static const struct drm_connector_helper_funcs dsi_mgr_conn_helper_funcs = {
446 	.get_modes = dsi_mgr_connector_get_modes,
447 	.mode_valid = dsi_mgr_connector_mode_valid,
448 	.best_encoder = dsi_mgr_connector_best_encoder,
449 };
450 
451 static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
452 	.pre_enable = dsi_mgr_bridge_pre_enable,
453 	.enable = dsi_mgr_bridge_enable,
454 	.disable = dsi_mgr_bridge_disable,
455 	.post_disable = dsi_mgr_bridge_post_disable,
456 	.mode_set = dsi_mgr_bridge_mode_set,
457 };
458 
459 /* initialize connector */
460 struct drm_connector *msm_dsi_manager_connector_init(u8 id)
461 {
462 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
463 	struct drm_connector *connector = NULL;
464 	struct dsi_connector *dsi_connector;
465 	int ret;
466 
467 	dsi_connector = devm_kzalloc(msm_dsi->dev->dev,
468 				sizeof(*dsi_connector), GFP_KERNEL);
469 	if (!dsi_connector) {
470 		ret = -ENOMEM;
471 		goto fail;
472 	}
473 
474 	dsi_connector->id = id;
475 
476 	connector = &dsi_connector->base;
477 
478 	ret = drm_connector_init(msm_dsi->dev, connector,
479 			&dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
480 	if (ret)
481 		goto fail;
482 
483 	drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
484 
485 	/* Enable HPD to let hpd event is handled
486 	 * when panel is attached to the host.
487 	 */
488 	connector->polled = DRM_CONNECTOR_POLL_HPD;
489 
490 	/* Display driver doesn't support interlace now. */
491 	connector->interlace_allowed = 0;
492 	connector->doublescan_allowed = 0;
493 
494 	ret = drm_connector_register(connector);
495 	if (ret)
496 		goto fail;
497 
498 	return connector;
499 
500 fail:
501 	if (connector)
502 		dsi_mgr_connector_destroy(connector);
503 
504 	return ERR_PTR(ret);
505 }
506 
507 /* initialize bridge */
508 struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
509 {
510 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
511 	struct drm_bridge *bridge = NULL;
512 	struct dsi_bridge *dsi_bridge;
513 	int ret;
514 
515 	dsi_bridge = devm_kzalloc(msm_dsi->dev->dev,
516 				sizeof(*dsi_bridge), GFP_KERNEL);
517 	if (!dsi_bridge) {
518 		ret = -ENOMEM;
519 		goto fail;
520 	}
521 
522 	dsi_bridge->id = id;
523 
524 	bridge = &dsi_bridge->base;
525 	bridge->funcs = &dsi_mgr_bridge_funcs;
526 
527 	ret = drm_bridge_attach(msm_dsi->dev, bridge);
528 	if (ret)
529 		goto fail;
530 
531 	return bridge;
532 
533 fail:
534 	if (bridge)
535 		msm_dsi_manager_bridge_destroy(bridge);
536 
537 	return ERR_PTR(ret);
538 }
539 
540 void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
541 {
542 }
543 
544 int msm_dsi_manager_phy_enable(int id,
545 		const unsigned long bit_rate, const unsigned long esc_rate,
546 		u32 *clk_pre, u32 *clk_post)
547 {
548 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
549 	struct msm_dsi_phy *phy = msm_dsi->phy;
550 	int ret;
551 
552 	ret = msm_dsi_phy_enable(phy, IS_DUAL_PANEL(), bit_rate, esc_rate);
553 	if (ret)
554 		return ret;
555 
556 	msm_dsi->phy_enabled = true;
557 	msm_dsi_phy_get_clk_pre_post(phy, clk_pre, clk_post);
558 
559 	return 0;
560 }
561 
562 void msm_dsi_manager_phy_disable(int id)
563 {
564 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
565 	struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
566 	struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
567 	struct msm_dsi_phy *phy = msm_dsi->phy;
568 
569 	/* disable DSI phy
570 	 * In dual-dsi configuration, the phy should be disabled for the
571 	 * first controller only when the second controller is disabled.
572 	 */
573 	msm_dsi->phy_enabled = false;
574 	if (IS_DUAL_PANEL() && mdsi && sdsi) {
575 		if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
576 			msm_dsi_phy_disable(sdsi->phy);
577 			msm_dsi_phy_disable(mdsi->phy);
578 		}
579 	} else {
580 		msm_dsi_phy_disable(phy);
581 	}
582 }
583 
584 int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg)
585 {
586 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
587 	struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0);
588 	struct mipi_dsi_host *host = msm_dsi->host;
589 	bool is_read = (msg->rx_buf && msg->rx_len);
590 	bool need_sync = (IS_SYNC_NEEDED() && !is_read);
591 	int ret;
592 
593 	if (!msg->tx_buf || !msg->tx_len)
594 		return 0;
595 
596 	/* In dual master case, panel requires the same commands sent to
597 	 * both DSI links. Host issues the command trigger to both links
598 	 * when DSI_1 calls the cmd transfer function, no matter it happens
599 	 * before or after DSI_0 cmd transfer.
600 	 */
601 	if (need_sync && (id == DSI_0))
602 		return is_read ? msg->rx_len : msg->tx_len;
603 
604 	if (need_sync && msm_dsi0) {
605 		ret = msm_dsi_host_xfer_prepare(msm_dsi0->host, msg);
606 		if (ret) {
607 			pr_err("%s: failed to prepare non-trigger host, %d\n",
608 				__func__, ret);
609 			return ret;
610 		}
611 	}
612 	ret = msm_dsi_host_xfer_prepare(host, msg);
613 	if (ret) {
614 		pr_err("%s: failed to prepare host, %d\n", __func__, ret);
615 		goto restore_host0;
616 	}
617 
618 	ret = is_read ? msm_dsi_host_cmd_rx(host, msg) :
619 			msm_dsi_host_cmd_tx(host, msg);
620 
621 	msm_dsi_host_xfer_restore(host, msg);
622 
623 restore_host0:
624 	if (need_sync && msm_dsi0)
625 		msm_dsi_host_xfer_restore(msm_dsi0->host, msg);
626 
627 	return ret;
628 }
629 
630 bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len)
631 {
632 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
633 	struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0);
634 	struct mipi_dsi_host *host = msm_dsi->host;
635 
636 	if (IS_SYNC_NEEDED() && (id == DSI_0))
637 		return false;
638 
639 	if (IS_SYNC_NEEDED() && msm_dsi0)
640 		msm_dsi_host_cmd_xfer_commit(msm_dsi0->host, iova, len);
641 
642 	msm_dsi_host_cmd_xfer_commit(host, iova, len);
643 
644 	return true;
645 }
646 
647 int msm_dsi_manager_register(struct msm_dsi *msm_dsi)
648 {
649 	struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
650 	int id = msm_dsi->id;
651 	struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
652 	int ret;
653 
654 	if (id > DSI_MAX) {
655 		pr_err("%s: invalid id %d\n", __func__, id);
656 		return -EINVAL;
657 	}
658 
659 	if (msm_dsim->dsi[id]) {
660 		pr_err("%s: dsi%d already registered\n", __func__, id);
661 		return -EBUSY;
662 	}
663 
664 	msm_dsim->dsi[id] = msm_dsi;
665 
666 	ret = dsi_mgr_parse_dual_panel(msm_dsi->pdev->dev.of_node, id);
667 	if (ret) {
668 		pr_err("%s: failed to parse dual panel info\n", __func__);
669 		return ret;
670 	}
671 
672 	if (!IS_DUAL_PANEL()) {
673 		ret = msm_dsi_host_register(msm_dsi->host, true);
674 	} else if (!other_dsi) {
675 		return 0;
676 	} else {
677 		struct msm_dsi *mdsi = IS_MASTER_PANEL(id) ?
678 					msm_dsi : other_dsi;
679 		struct msm_dsi *sdsi = IS_MASTER_PANEL(id) ?
680 					other_dsi : msm_dsi;
681 		/* Register slave host first, so that slave DSI device
682 		 * has a chance to probe, and do not block the master
683 		 * DSI device's probe.
684 		 * Also, do not check defer for the slave host,
685 		 * because only master DSI device adds the panel to global
686 		 * panel list. The panel's device is the master DSI device.
687 		 */
688 		ret = msm_dsi_host_register(sdsi->host, false);
689 		if (ret)
690 			return ret;
691 		ret = msm_dsi_host_register(mdsi->host, true);
692 	}
693 
694 	return ret;
695 }
696 
697 void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi)
698 {
699 	struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
700 
701 	if (msm_dsi->host)
702 		msm_dsi_host_unregister(msm_dsi->host);
703 	msm_dsim->dsi[msm_dsi->id] = NULL;
704 }
705 
706