File Index
Files and directories
Sign in
FILE

dsi_manager.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/msm/dsi/dsi_manager.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
  4 */
  5
  6#include "drm/drm_bridge_connector.h"
  7
  8#include "msm_kms.h"
  9#include "dsi.h"
 10
 11#define DSI_CLOCK_MASTER	DSI_0
 12#define DSI_CLOCK_SLAVE		DSI_1
 13
 14#define DSI_LEFT		DSI_0
 15#define DSI_RIGHT		DSI_1
 16
 17/* According to the current drm framework sequence, take the encoder of
 18 * DSI_1 as master encoder
 19 */
 20#define DSI_ENCODER_MASTER	DSI_1
 21#define DSI_ENCODER_SLAVE	DSI_0
 22
 23struct msm_dsi_manager {
 24	struct msm_dsi *dsi[DSI_MAX];
 25
 26	bool is_bonded_dsi;
 27	bool is_sync_needed;
 28	int master_dsi_link_id;
 29};
 30
 31static struct msm_dsi_manager msm_dsim_glb;
 32
 33#define IS_BONDED_DSI()		(msm_dsim_glb.is_bonded_dsi)
 34#define IS_SYNC_NEEDED()	(msm_dsim_glb.is_sync_needed)
 35#define IS_MASTER_DSI_LINK(id)	(msm_dsim_glb.master_dsi_link_id == id)
 36
 37static inline struct msm_dsi *dsi_mgr_get_dsi(int id)
 38{
 39	return msm_dsim_glb.dsi[id];
 40}
 41
 42static inline struct msm_dsi *dsi_mgr_get_other_dsi(int id)
 43{
 44	return msm_dsim_glb.dsi[(id + 1) % DSI_MAX];
 45}
 46
 47static int dsi_mgr_parse_of(struct device_node *np, int id)
 48{
 49	struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
 50
 51	/* We assume 2 dsi nodes have the same information of bonded dsi and
 52	 * sync-mode, and only one node specifies master in case of bonded mode.
 53	 */
 54	if (!msm_dsim->is_bonded_dsi)
 55		msm_dsim->is_bonded_dsi = of_property_read_bool(np, "qcom,dual-dsi-mode");
 56
 57	if (msm_dsim->is_bonded_dsi) {
 58		if (of_property_read_bool(np, "qcom,master-dsi"))
 59			msm_dsim->master_dsi_link_id = id;
 60		if (!msm_dsim->is_sync_needed)
 61			msm_dsim->is_sync_needed = of_property_read_bool(
 62					np, "qcom,sync-dual-dsi");
 63	}
 64
 65	return 0;
 66}
 67
 68static int dsi_mgr_setup_components(int id)
 69{
 70	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
 71	struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
 72	struct msm_dsi *clk_master_dsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
 73	struct msm_dsi *clk_slave_dsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
 74	int ret;
 75
 76	if (!IS_BONDED_DSI()) {
 77		/*
 78		 * Set the usecase before calling msm_dsi_host_register(), which would
 79		 * already program the PLL source mux based on a default usecase.
 80		 */
 81		msm_dsi_phy_set_usecase(msm_dsi->phy, MSM_DSI_PHY_STANDALONE);
 82		msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy);
 83
 84		ret = msm_dsi_host_register(msm_dsi->host);
 85		if (ret)
 86			return ret;
 87	} else if (other_dsi) {
 88		struct msm_dsi *master_link_dsi = IS_MASTER_DSI_LINK(id) ?
 89							msm_dsi : other_dsi;
 90		struct msm_dsi *slave_link_dsi = IS_MASTER_DSI_LINK(id) ?
 91							other_dsi : msm_dsi;
 92
 93		/*
 94		 * PLL0 is to drive both DSI link clocks in bonded DSI mode.
 95		 *
 96		 * Set the usecase before calling msm_dsi_host_register(), which would
 97		 * already program the PLL source mux based on a default usecase.
 98		 */
 99		msm_dsi_phy_set_usecase(clk_master_dsi->phy,
100					MSM_DSI_PHY_MASTER);
101		msm_dsi_phy_set_usecase(clk_slave_dsi->phy,
102					MSM_DSI_PHY_SLAVE);
103		msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy);
104		msm_dsi_host_set_phy_mode(other_dsi->host, other_dsi->phy);
105
106		/* Register slave host first, so that slave DSI device
107		 * has a chance to probe, and do not block the master
108		 * DSI device's probe.
109		 * Also, do not check defer for the slave host,
110		 * because only master DSI device adds the panel to global
111		 * panel list. The panel's device is the master DSI device.
112		 */
113		ret = msm_dsi_host_register(slave_link_dsi->host);
114		if (ret)
115			return ret;
116		ret = msm_dsi_host_register(master_link_dsi->host);
117		if (ret)
118			return ret;
119	}
120
121	return 0;
122}
123
124static int enable_phy(struct msm_dsi *msm_dsi,
125		      struct msm_dsi_phy_shared_timings *shared_timings)
126{
127	struct msm_dsi_phy_clk_request clk_req;
128	bool is_bonded_dsi = IS_BONDED_DSI();
129
130	msm_dsi_host_get_phy_clk_req(msm_dsi->host, &clk_req, is_bonded_dsi);
131
132	return msm_dsi_phy_enable(msm_dsi->phy, &clk_req, shared_timings);
133}
134
135static int
136dsi_mgr_phy_enable(int id,
137		   struct msm_dsi_phy_shared_timings shared_timings[DSI_MAX])
138{
139	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
140	struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
141	struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
142	int ret;
143
144	/* In case of bonded DSI, some registers in PHY1 have been programmed
145	 * during PLL0 clock's set_rate. The PHY1 reset called by host1 here
146	 * will silently reset those PHY1 registers. Therefore we need to reset
147	 * and enable both PHYs before any PLL clock operation.
148	 */
149	if (IS_BONDED_DSI() && mdsi && sdsi) {
150		if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
151			msm_dsi_host_reset_phy(mdsi->host);
152			msm_dsi_host_reset_phy(sdsi->host);
153
154			ret = enable_phy(mdsi,
155					 &shared_timings[DSI_CLOCK_MASTER]);
156			if (ret)
157				return ret;
158			ret = enable_phy(sdsi,
159					 &shared_timings[DSI_CLOCK_SLAVE]);
160			if (ret) {
161				msm_dsi_phy_disable(mdsi->phy);
162				return ret;
163			}
164		}
165	} else {
166		msm_dsi_host_reset_phy(msm_dsi->host);
167		ret = enable_phy(msm_dsi, &shared_timings[id]);
168		if (ret)
169			return ret;
170	}
171
172	msm_dsi->phy_enabled = true;
173
174	return 0;
175}
176
177static void dsi_mgr_phy_disable(int id)
178{
179	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
180	struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
181	struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
182
183	/* disable DSI phy
184	 * In bonded dsi configuration, the phy should be disabled for the
185	 * first controller only when the second controller is disabled.
186	 */
187	msm_dsi->phy_enabled = false;
188	if (IS_BONDED_DSI() && mdsi && sdsi) {
189		if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
190			msm_dsi_phy_disable(sdsi->phy);
191			msm_dsi_phy_disable(mdsi->phy);
192		}
193	} else {
194		msm_dsi_phy_disable(msm_dsi->phy);
195	}
196}
197
198struct dsi_bridge {
199	struct drm_bridge base;
200	int id;
201};
202
203#define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
204
205static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
206{
207	struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
208	return dsi_bridge->id;
209}
210
211static int dsi_mgr_bridge_power_on(struct drm_bridge *bridge)
212{
213	int id = dsi_mgr_bridge_get_id(bridge);
214	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
215	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
216	struct mipi_dsi_host *host = msm_dsi->host;
217	struct msm_dsi_phy_shared_timings phy_shared_timings[DSI_MAX];
218	bool is_bonded_dsi = IS_BONDED_DSI();
219	int ret;
220
221	DBG("id=%d", id);
222
223	ret = dsi_mgr_phy_enable(id, phy_shared_timings);
224	if (ret)
225		goto phy_en_fail;
226
227	ret = msm_dsi_host_power_on(host, &phy_shared_timings[id], is_bonded_dsi, msm_dsi->phy);
228	if (ret) {
229		pr_err("%s: power on host %d failed, %d\n", __func__, id, ret);
230		goto host_on_fail;
231	}
232
233	if (is_bonded_dsi && msm_dsi1) {
234		ret = msm_dsi_host_power_on(msm_dsi1->host,
235				&phy_shared_timings[DSI_1], is_bonded_dsi, msm_dsi1->phy);
236		if (ret) {
237			pr_err("%s: power on host1 failed, %d\n",
238							__func__, ret);
239			goto host1_on_fail;
240		}
241	}
242
243	/*
244	 * Enable before preparing the panel, disable after unpreparing, so
245	 * that the panel can communicate over the DSI link.
246	 */
247	msm_dsi_host_enable_irq(host);
248	if (is_bonded_dsi && msm_dsi1)
249		msm_dsi_host_enable_irq(msm_dsi1->host);
250
251	return 0;
252
253host1_on_fail:
254	msm_dsi_host_power_off(host);
255host_on_fail:
256	dsi_mgr_phy_disable(id);
257phy_en_fail:
258	return ret;
259}
260
261static void dsi_mgr_bridge_power_off(struct drm_bridge *bridge)
262{
263	int id = dsi_mgr_bridge_get_id(bridge);
264	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
265	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
266	struct mipi_dsi_host *host = msm_dsi->host;
267	bool is_bonded_dsi = IS_BONDED_DSI();
268
269	msm_dsi_host_disable_irq(host);
270	if (is_bonded_dsi && msm_dsi1) {
271		msm_dsi_host_disable_irq(msm_dsi1->host);
272		msm_dsi_host_power_off(msm_dsi1->host);
273	}
274	msm_dsi_host_power_off(host);
275	dsi_mgr_phy_disable(id);
276}
277
278static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
279{
280	int id = dsi_mgr_bridge_get_id(bridge);
281	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
282	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
283	struct mipi_dsi_host *host = msm_dsi->host;
284	bool is_bonded_dsi = IS_BONDED_DSI();
285	int ret;
286
287	DBG("id=%d", id);
288
289	/* Do nothing with the host if it is slave-DSI in case of bonded DSI */
290	if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
291		return;
292
293	ret = dsi_mgr_bridge_power_on(bridge);
294	if (ret) {
295		dev_err(&msm_dsi->pdev->dev, "Power on failed: %d\n", ret);
296		return;
297	}
298
299	ret = msm_dsi_host_enable(host);
300	if (ret) {
301		pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
302		goto host_en_fail;
303	}
304
305	if (is_bonded_dsi && msm_dsi1) {
306		ret = msm_dsi_host_enable(msm_dsi1->host);
307		if (ret) {
308			pr_err("%s: enable host1 failed, %d\n", __func__, ret);
309			goto host1_en_fail;
310		}
311	}
312
313	return;
314
315host1_en_fail:
316	msm_dsi_host_disable(host);
317host_en_fail:
318	dsi_mgr_bridge_power_off(bridge);
319}
320
321void msm_dsi_manager_tpg_enable(void)
322{
323	struct msm_dsi *m_dsi = dsi_mgr_get_dsi(DSI_0);
324	struct msm_dsi *s_dsi = dsi_mgr_get_dsi(DSI_1);
325
326	/* if dual dsi, trigger tpg on master first then slave */
327	if (m_dsi) {
328		msm_dsi_host_test_pattern_en(m_dsi->host);
329		if (IS_BONDED_DSI() && s_dsi)
330			msm_dsi_host_test_pattern_en(s_dsi->host);
331	}
332}
333
334static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
335{
336	int id = dsi_mgr_bridge_get_id(bridge);
337	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
338	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
339	struct mipi_dsi_host *host = msm_dsi->host;
340	bool is_bonded_dsi = IS_BONDED_DSI();
341	int ret;
342
343	DBG("id=%d", id);
344
345	/*
346	 * Do nothing with the host if it is slave-DSI in case of bonded DSI.
347	 * It is safe to call dsi_mgr_phy_disable() here because a single PHY
348	 * won't be diabled until both PHYs request disable.
349	 */
350	if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
351		goto disable_phy;
352
353	ret = msm_dsi_host_disable(host);
354	if (ret)
355		pr_err("%s: host %d disable failed, %d\n", __func__, id, ret);
356
357	if (is_bonded_dsi && msm_dsi1) {
358		ret = msm_dsi_host_disable(msm_dsi1->host);
359		if (ret)
360			pr_err("%s: host1 disable failed, %d\n", __func__, ret);
361	}
362
363	msm_dsi_host_disable_irq(host);
364	if (is_bonded_dsi && msm_dsi1)
365		msm_dsi_host_disable_irq(msm_dsi1->host);
366
367	/* Save PHY status if it is a clock source */
368	msm_dsi_phy_pll_save_state(msm_dsi->phy);
369
370	ret = msm_dsi_host_power_off(host);
371	if (ret)
372		pr_err("%s: host %d power off failed,%d\n", __func__, id, ret);
373
374	if (is_bonded_dsi && msm_dsi1) {
375		ret = msm_dsi_host_power_off(msm_dsi1->host);
376		if (ret)
377			pr_err("%s: host1 power off failed, %d\n",
378								__func__, ret);
379	}
380
381disable_phy:
382	dsi_mgr_phy_disable(id);
383}
384
385static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge,
386		const struct drm_display_mode *mode,
387		const struct drm_display_mode *adjusted_mode)
388{
389	int id = dsi_mgr_bridge_get_id(bridge);
390	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
391	struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
392	struct mipi_dsi_host *host = msm_dsi->host;
393	bool is_bonded_dsi = IS_BONDED_DSI();
394
395	DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode));
396
397	if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
398		return;
399
400	msm_dsi_host_set_display_mode(host, adjusted_mode);
401	if (is_bonded_dsi && other_dsi)
402		msm_dsi_host_set_display_mode(other_dsi->host, adjusted_mode);
403}
404
405static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
406						      const struct drm_display_info *info,
407						      const struct drm_display_mode *mode)
408{
409	int id = dsi_mgr_bridge_get_id(bridge);
410	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
411	struct mipi_dsi_host *host = msm_dsi->host;
412	struct platform_device *pdev = msm_dsi->pdev;
413	struct dev_pm_opp *opp;
414	unsigned long byte_clk_rate;
415
416	byte_clk_rate = dsi_byte_clk_get_rate(host, IS_BONDED_DSI(), mode);
417
418	opp = dev_pm_opp_find_freq_ceil(&pdev->dev, &byte_clk_rate);
419	if (!IS_ERR(opp)) {
420		dev_pm_opp_put(opp);
421	} else if (PTR_ERR(opp) == -ERANGE) {
422		/*
423		 * An empty table is created by devm_pm_opp_set_clkname() even
424		 * if there is none. Thus find_freq_ceil will still return
425		 * -ERANGE in such case.
426		 */
427		if (dev_pm_opp_get_opp_count(&pdev->dev) != 0)
428			return MODE_CLOCK_RANGE;
429	} else {
430			return MODE_ERROR;
431	}
432
433	return msm_dsi_host_check_dsc(host, mode);
434}
435
436static int dsi_mgr_bridge_attach(struct drm_bridge *bridge,
437				 struct drm_encoder *encoder,
438				 enum drm_bridge_attach_flags flags)
439{
440	int id = dsi_mgr_bridge_get_id(bridge);
441	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
442
443	return drm_bridge_attach(encoder, msm_dsi->next_bridge,
444				 bridge, flags);
445}
446
447static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
448	.attach = dsi_mgr_bridge_attach,
449	.pre_enable = dsi_mgr_bridge_pre_enable,
450	.post_disable = dsi_mgr_bridge_post_disable,
451	.mode_set = dsi_mgr_bridge_mode_set,
452	.mode_valid = dsi_mgr_bridge_mode_valid,
453};
454
455/* initialize bridge */
456int msm_dsi_manager_connector_init(struct msm_dsi *msm_dsi,
457				   struct drm_encoder *encoder)
458{
459	struct drm_device *dev = msm_dsi->dev;
460	struct drm_bridge *bridge;
461	struct dsi_bridge *dsi_bridge;
462	struct drm_connector *connector;
463	int ret;
464
465	dsi_bridge = devm_drm_bridge_alloc(msm_dsi->dev->dev, struct dsi_bridge, base,
466					   &dsi_mgr_bridge_funcs);
467	if (IS_ERR(dsi_bridge))
468		return PTR_ERR(dsi_bridge);
469
470	dsi_bridge->id = msm_dsi->id;
471
472	bridge = &dsi_bridge->base;
473
474	ret = devm_drm_bridge_add(msm_dsi->dev->dev, bridge);
475	if (ret)
476		return ret;
477
478	ret = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
479	if (ret)
480		return ret;
481
482	connector = drm_bridge_connector_init(dev, encoder);
483	if (IS_ERR(connector)) {
484		DRM_ERROR("Unable to create bridge connector\n");
485		return PTR_ERR(connector);
486	}
487
488	ret = drm_connector_attach_encoder(connector, encoder);
489	if (ret < 0)
490		return ret;
491
492	return 0;
493}
494
495int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg)
496{
497	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
498	struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0);
499	struct mipi_dsi_host *host = msm_dsi->host;
500	bool is_read = (msg->rx_buf && msg->rx_len);
501	bool need_sync = (IS_SYNC_NEEDED() && !is_read);
502	int ret;
503
504	if (!msg->tx_buf || !msg->tx_len)
505		return 0;
506
507	/* In bonded master case, panel requires the same commands sent to
508	 * both DSI links. Host issues the command trigger to both links
509	 * when DSI_1 calls the cmd transfer function, no matter it happens
510	 * before or after DSI_0 cmd transfer.
511	 */
512	if (need_sync && (id == DSI_0))
513		return is_read ? msg->rx_len : msg->tx_len;
514
515	if (need_sync && msm_dsi0) {
516		ret = msm_dsi_host_xfer_prepare(msm_dsi0->host, msg);
517		if (ret) {
518			pr_err("%s: failed to prepare non-trigger host, %d\n",
519				__func__, ret);
520			return ret;
521		}
522	}
523	ret = msm_dsi_host_xfer_prepare(host, msg);
524	if (ret) {
525		pr_err("%s: failed to prepare host, %d\n", __func__, ret);
526		goto restore_host0;
527	}
528
529	ret = is_read ? msm_dsi_host_cmd_rx(host, msg) :
530			msm_dsi_host_cmd_tx(host, msg);
531
532	msm_dsi_host_xfer_restore(host, msg);
533
534restore_host0:
535	if (need_sync && msm_dsi0)
536		msm_dsi_host_xfer_restore(msm_dsi0->host, msg);
537
538	return ret;
539}
540
541bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len)
542{
543	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
544	struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0);
545	struct mipi_dsi_host *host = msm_dsi->host;
546
547	if (IS_SYNC_NEEDED() && (id == DSI_0))
548		return false;
549
550	if (IS_SYNC_NEEDED() && msm_dsi0)
551		msm_dsi_host_cmd_xfer_commit(msm_dsi0->host, dma_base, len);
552
553	msm_dsi_host_cmd_xfer_commit(host, dma_base, len);
554
555	return true;
556}
557
558int msm_dsi_manager_register(struct msm_dsi *msm_dsi)
559{
560	struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
561	int id = msm_dsi->id;
562	int ret;
563
564	if (id >= DSI_MAX) {
565		pr_err("%s: invalid id %d\n", __func__, id);
566		return -EINVAL;
567	}
568
569	if (msm_dsim->dsi[id]) {
570		pr_err("%s: dsi%d already registered\n", __func__, id);
571		return -EBUSY;
572	}
573
574	msm_dsim->dsi[id] = msm_dsi;
575
576	ret = dsi_mgr_parse_of(msm_dsi->pdev->dev.of_node, id);
577	if (ret) {
578		pr_err("%s: failed to parse OF DSI info\n", __func__);
579		goto fail;
580	}
581
582	ret = dsi_mgr_setup_components(id);
583	if (ret) {
584		pr_err("%s: failed to register mipi dsi host for DSI %d: %d\n",
585			__func__, id, ret);
586		goto fail;
587	}
588
589	return 0;
590
591fail:
592	msm_dsim->dsi[id] = NULL;
593	return ret;
594}
595
596void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi)
597{
598	struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
599
600	if (msm_dsi->host)
601		msm_dsi_host_unregister(msm_dsi->host);
602
603	if (msm_dsi->id >= 0)
604		msm_dsim->dsi[msm_dsi->id] = NULL;
605}
606
607bool msm_dsi_is_bonded_dsi(struct msm_dsi *msm_dsi)
608{
609	return IS_BONDED_DSI();
610}
611
612bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi)
613{
614	return IS_MASTER_DSI_LINK(msm_dsi->id);
615}
616
617const char *msm_dsi_get_te_source(struct msm_dsi *msm_dsi)
618{
619	return msm_dsi->te_source;
620}
~/ Read-only file preview.