1 // SPDX-License-Identifier: GPL-2.0+
8 #include <linux/media-bus-format.h>
9 #include <linux/mfd/syscon.h>
10 #include <linux/module.h>
12 #include <linux/of_device.h>
13 #include <linux/of_graph.h>
14 #include <linux/phy/phy.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm_runtime.h>
17 #include <linux/regmap.h>
19 #include <drm/drm_atomic_state_helper.h>
20 #include <drm/drm_bridge.h>
21 #include <drm/drm_connector.h>
22 #include <drm/drm_fourcc.h>
23 #include <drm/drm_of.h>
24 #include <drm/drm_print.h>
26 #include "imx-ldb-helper.h"
28 #define LDB_CH_SEL BIT(28)
31 #define CH_HSYNC_M(id) BIT(0 + ((id) * 2))
32 #define CH_VSYNC_M(id) BIT(1 + ((id) * 2))
33 #define CH_PHSYNC(id) BIT(0 + ((id) * 2))
34 #define CH_PVSYNC(id) BIT(1 + ((id) * 2))
36 #define DRIVER_NAME "imx8qxp-ldb"
38 struct imx8qxp_ldb_channel
{
39 struct ldb_channel base
;
47 struct imx8qxp_ldb_channel channel
[MAX_LDB_CHAN_NUM
];
48 struct clk
*clk_pixel
;
49 struct clk
*clk_bypass
;
50 struct drm_bridge
*companion
;
54 static inline struct imx8qxp_ldb_channel
*
55 base_to_imx8qxp_ldb_channel(struct ldb_channel
*base
)
57 return container_of(base
, struct imx8qxp_ldb_channel
, base
);
60 static inline struct imx8qxp_ldb
*base_to_imx8qxp_ldb(struct ldb
*base
)
62 return container_of(base
, struct imx8qxp_ldb
, base
);
65 static void imx8qxp_ldb_set_phy_cfg(struct imx8qxp_ldb
*imx8qxp_ldb
,
66 unsigned long di_clk
, bool is_split
,
67 struct phy_configure_opts_lvds
*phy_cfg
)
69 phy_cfg
->bits_per_lane_and_dclk_cycle
= 7;
73 phy_cfg
->differential_clk_rate
= di_clk
/ 2;
74 phy_cfg
->is_slave
= !imx8qxp_ldb
->companion
;
76 phy_cfg
->differential_clk_rate
= di_clk
;
77 phy_cfg
->is_slave
= false;
82 imx8qxp_ldb_bridge_atomic_check(struct drm_bridge
*bridge
,
83 struct drm_bridge_state
*bridge_state
,
84 struct drm_crtc_state
*crtc_state
,
85 struct drm_connector_state
*conn_state
)
87 struct ldb_channel
*ldb_ch
= bridge
->driver_private
;
88 struct ldb
*ldb
= ldb_ch
->ldb
;
89 struct imx8qxp_ldb_channel
*imx8qxp_ldb_ch
=
90 base_to_imx8qxp_ldb_channel(ldb_ch
);
91 struct imx8qxp_ldb
*imx8qxp_ldb
= base_to_imx8qxp_ldb(ldb
);
92 struct drm_bridge
*companion
= imx8qxp_ldb
->companion
;
93 struct drm_display_mode
*adj
= &crtc_state
->adjusted_mode
;
94 unsigned long di_clk
= adj
->clock
* 1000;
95 bool is_split
= ldb_channel_is_split_link(ldb_ch
);
96 union phy_configure_opts opts
= { };
97 struct phy_configure_opts_lvds
*phy_cfg
= &opts
.lvds
;
100 ret
= ldb_bridge_atomic_check_helper(bridge
, bridge_state
,
101 crtc_state
, conn_state
);
105 imx8qxp_ldb_set_phy_cfg(imx8qxp_ldb
, di_clk
, is_split
, phy_cfg
);
106 ret
= phy_validate(imx8qxp_ldb_ch
->phy
, PHY_MODE_LVDS
, 0, &opts
);
108 DRM_DEV_DEBUG_DRIVER(imx8qxp_ldb
->dev
,
109 "failed to validate PHY: %d\n", ret
);
113 if (is_split
&& companion
) {
114 ret
= companion
->funcs
->atomic_check(companion
,
115 bridge_state
, crtc_state
, conn_state
);
124 imx8qxp_ldb_bridge_mode_set(struct drm_bridge
*bridge
,
125 const struct drm_display_mode
*mode
,
126 const struct drm_display_mode
*adjusted_mode
)
128 struct ldb_channel
*ldb_ch
= bridge
->driver_private
;
129 struct ldb_channel
*companion_ldb_ch
;
130 struct ldb
*ldb
= ldb_ch
->ldb
;
131 struct imx8qxp_ldb_channel
*imx8qxp_ldb_ch
=
132 base_to_imx8qxp_ldb_channel(ldb_ch
);
133 struct imx8qxp_ldb
*imx8qxp_ldb
= base_to_imx8qxp_ldb(ldb
);
134 struct drm_bridge
*companion
= imx8qxp_ldb
->companion
;
135 struct device
*dev
= imx8qxp_ldb
->dev
;
136 unsigned long di_clk
= adjusted_mode
->clock
* 1000;
137 bool is_split
= ldb_channel_is_split_link(ldb_ch
);
138 union phy_configure_opts opts
= { };
139 struct phy_configure_opts_lvds
*phy_cfg
= &opts
.lvds
;
140 u32 chno
= ldb_ch
->chno
;
143 ret
= pm_runtime_get_sync(dev
);
145 DRM_DEV_ERROR(dev
, "failed to get runtime PM sync: %d\n", ret
);
147 ret
= phy_init(imx8qxp_ldb_ch
->phy
);
149 DRM_DEV_ERROR(dev
, "failed to initialize PHY: %d\n", ret
);
151 ret
= phy_set_mode(imx8qxp_ldb_ch
->phy
, PHY_MODE_LVDS
);
153 DRM_DEV_ERROR(dev
, "failed to set PHY mode: %d\n", ret
);
155 if (is_split
&& companion
) {
156 companion_ldb_ch
= bridge_to_ldb_ch(companion
);
158 companion_ldb_ch
->in_bus_format
= ldb_ch
->in_bus_format
;
159 companion_ldb_ch
->out_bus_format
= ldb_ch
->out_bus_format
;
162 clk_set_rate(imx8qxp_ldb
->clk_bypass
, di_clk
);
163 clk_set_rate(imx8qxp_ldb
->clk_pixel
, di_clk
);
165 imx8qxp_ldb_set_phy_cfg(imx8qxp_ldb
, di_clk
, is_split
, phy_cfg
);
166 ret
= phy_configure(imx8qxp_ldb_ch
->phy
, &opts
);
168 DRM_DEV_ERROR(dev
, "failed to configure PHY: %d\n", ret
);
171 ldb
->ldb_ctrl
&= ~LDB_CH_SEL
;
173 ldb
->ldb_ctrl
|= LDB_CH_SEL
;
175 /* input VSYNC signal from pixel link is active low */
176 if (imx8qxp_ldb_ch
->di_id
== 0)
177 ldb
->ldb_ctrl
|= LDB_DI0_VS_POL_ACT_LOW
;
179 ldb
->ldb_ctrl
|= LDB_DI1_VS_POL_ACT_LOW
;
182 * For split mode, settle input VSYNC signal polarity and
183 * channel selection down early.
186 regmap_write(ldb
->regmap
, ldb
->ctrl_reg
, ldb
->ldb_ctrl
);
188 ldb_bridge_mode_set_helper(bridge
, mode
, adjusted_mode
);
190 if (adjusted_mode
->flags
& DRM_MODE_FLAG_NVSYNC
)
191 regmap_update_bits(ldb
->regmap
, SS_CTRL
, CH_VSYNC_M(chno
), 0);
192 else if (adjusted_mode
->flags
& DRM_MODE_FLAG_PVSYNC
)
193 regmap_update_bits(ldb
->regmap
, SS_CTRL
,
194 CH_VSYNC_M(chno
), CH_PVSYNC(chno
));
196 if (adjusted_mode
->flags
& DRM_MODE_FLAG_NHSYNC
)
197 regmap_update_bits(ldb
->regmap
, SS_CTRL
, CH_HSYNC_M(chno
), 0);
198 else if (adjusted_mode
->flags
& DRM_MODE_FLAG_PHSYNC
)
199 regmap_update_bits(ldb
->regmap
, SS_CTRL
,
200 CH_HSYNC_M(chno
), CH_PHSYNC(chno
));
202 if (is_split
&& companion
)
203 companion
->funcs
->mode_set(companion
, mode
, adjusted_mode
);
207 imx8qxp_ldb_bridge_atomic_pre_enable(struct drm_bridge
*bridge
,
208 struct drm_bridge_state
*old_bridge_state
)
210 struct ldb_channel
*ldb_ch
= bridge
->driver_private
;
211 struct ldb
*ldb
= ldb_ch
->ldb
;
212 struct imx8qxp_ldb
*imx8qxp_ldb
= base_to_imx8qxp_ldb(ldb
);
213 struct drm_bridge
*companion
= imx8qxp_ldb
->companion
;
214 bool is_split
= ldb_channel_is_split_link(ldb_ch
);
216 clk_prepare_enable(imx8qxp_ldb
->clk_pixel
);
217 clk_prepare_enable(imx8qxp_ldb
->clk_bypass
);
219 if (is_split
&& companion
)
220 companion
->funcs
->atomic_pre_enable(companion
, old_bridge_state
);
224 imx8qxp_ldb_bridge_atomic_enable(struct drm_bridge
*bridge
,
225 struct drm_bridge_state
*old_bridge_state
)
227 struct ldb_channel
*ldb_ch
= bridge
->driver_private
;
228 struct ldb
*ldb
= ldb_ch
->ldb
;
229 struct imx8qxp_ldb_channel
*imx8qxp_ldb_ch
=
230 base_to_imx8qxp_ldb_channel(ldb_ch
);
231 struct imx8qxp_ldb
*imx8qxp_ldb
= base_to_imx8qxp_ldb(ldb
);
232 struct drm_bridge
*companion
= imx8qxp_ldb
->companion
;
233 struct device
*dev
= imx8qxp_ldb
->dev
;
234 bool is_split
= ldb_channel_is_split_link(ldb_ch
);
237 if (ldb_ch
->chno
== 0 || is_split
) {
238 ldb
->ldb_ctrl
&= ~LDB_CH0_MODE_EN_MASK
;
239 ldb
->ldb_ctrl
|= imx8qxp_ldb_ch
->di_id
== 0 ?
240 LDB_CH0_MODE_EN_TO_DI0
: LDB_CH0_MODE_EN_TO_DI1
;
242 if (ldb_ch
->chno
== 1 || is_split
) {
243 ldb
->ldb_ctrl
&= ~LDB_CH1_MODE_EN_MASK
;
244 ldb
->ldb_ctrl
|= imx8qxp_ldb_ch
->di_id
== 0 ?
245 LDB_CH1_MODE_EN_TO_DI0
: LDB_CH1_MODE_EN_TO_DI1
;
248 ldb_bridge_enable_helper(bridge
);
250 ret
= phy_power_on(imx8qxp_ldb_ch
->phy
);
252 DRM_DEV_ERROR(dev
, "failed to power on PHY: %d\n", ret
);
254 if (is_split
&& companion
)
255 companion
->funcs
->atomic_enable(companion
, old_bridge_state
);
259 imx8qxp_ldb_bridge_atomic_disable(struct drm_bridge
*bridge
,
260 struct drm_bridge_state
*old_bridge_state
)
262 struct ldb_channel
*ldb_ch
= bridge
->driver_private
;
263 struct ldb
*ldb
= ldb_ch
->ldb
;
264 struct imx8qxp_ldb_channel
*imx8qxp_ldb_ch
=
265 base_to_imx8qxp_ldb_channel(ldb_ch
);
266 struct imx8qxp_ldb
*imx8qxp_ldb
= base_to_imx8qxp_ldb(ldb
);
267 struct drm_bridge
*companion
= imx8qxp_ldb
->companion
;
268 struct device
*dev
= imx8qxp_ldb
->dev
;
269 bool is_split
= ldb_channel_is_split_link(ldb_ch
);
272 ret
= phy_power_off(imx8qxp_ldb_ch
->phy
);
274 DRM_DEV_ERROR(dev
, "failed to power off PHY: %d\n", ret
);
276 ret
= phy_exit(imx8qxp_ldb_ch
->phy
);
278 DRM_DEV_ERROR(dev
, "failed to teardown PHY: %d\n", ret
);
280 ldb_bridge_disable_helper(bridge
);
282 clk_disable_unprepare(imx8qxp_ldb
->clk_bypass
);
283 clk_disable_unprepare(imx8qxp_ldb
->clk_pixel
);
285 if (is_split
&& companion
)
286 companion
->funcs
->atomic_disable(companion
, old_bridge_state
);
288 ret
= pm_runtime_put(dev
);
290 DRM_DEV_ERROR(dev
, "failed to put runtime PM: %d\n", ret
);
293 static const u32 imx8qxp_ldb_bus_output_fmts
[] = {
294 MEDIA_BUS_FMT_RGB666_1X7X3_SPWG
,
295 MEDIA_BUS_FMT_RGB888_1X7X4_SPWG
,
296 MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA
,
300 static bool imx8qxp_ldb_bus_output_fmt_supported(u32 fmt
)
304 for (i
= 0; i
< ARRAY_SIZE(imx8qxp_ldb_bus_output_fmts
); i
++) {
305 if (imx8qxp_ldb_bus_output_fmts
[i
] == fmt
)
313 imx8qxp_ldb_bridge_atomic_get_input_bus_fmts(struct drm_bridge
*bridge
,
314 struct drm_bridge_state
*bridge_state
,
315 struct drm_crtc_state
*crtc_state
,
316 struct drm_connector_state
*conn_state
,
318 unsigned int *num_input_fmts
)
320 struct drm_display_info
*di
;
321 const struct drm_format_info
*finfo
;
324 if (!imx8qxp_ldb_bus_output_fmt_supported(output_fmt
))
329 input_fmts
= kmalloc(sizeof(*input_fmts
), GFP_KERNEL
);
333 switch (output_fmt
) {
334 case MEDIA_BUS_FMT_FIXED
:
335 di
= &conn_state
->connector
->display_info
;
338 * Look at the first bus format to determine input format.
339 * Default to MEDIA_BUS_FMT_RGB888_1X24, if no match.
341 if (di
->num_bus_formats
) {
342 finfo
= drm_format_info(di
->bus_formats
[0]);
344 input_fmts
[0] = finfo
->depth
== 18 ?
345 MEDIA_BUS_FMT_RGB666_1X24_CPADHI
:
346 MEDIA_BUS_FMT_RGB888_1X24
;
348 input_fmts
[0] = MEDIA_BUS_FMT_RGB888_1X24
;
351 case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG
:
352 input_fmts
[0] = MEDIA_BUS_FMT_RGB666_1X24_CPADHI
;
354 case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG
:
355 case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA
:
356 input_fmts
[0] = MEDIA_BUS_FMT_RGB888_1X24
;
368 imx8qxp_ldb_bridge_atomic_get_output_bus_fmts(struct drm_bridge
*bridge
,
369 struct drm_bridge_state
*bridge_state
,
370 struct drm_crtc_state
*crtc_state
,
371 struct drm_connector_state
*conn_state
,
372 unsigned int *num_output_fmts
)
374 *num_output_fmts
= ARRAY_SIZE(imx8qxp_ldb_bus_output_fmts
);
375 return kmemdup(imx8qxp_ldb_bus_output_fmts
,
376 sizeof(imx8qxp_ldb_bus_output_fmts
), GFP_KERNEL
);
379 static enum drm_mode_status
380 imx8qxp_ldb_bridge_mode_valid(struct drm_bridge
*bridge
,
381 const struct drm_display_info
*info
,
382 const struct drm_display_mode
*mode
)
384 struct ldb_channel
*ldb_ch
= bridge
->driver_private
;
385 bool is_single
= ldb_channel_is_single_link(ldb_ch
);
387 if (mode
->clock
> 170000)
388 return MODE_CLOCK_HIGH
;
390 if (mode
->clock
> 150000 && is_single
)
391 return MODE_CLOCK_HIGH
;
396 static const struct drm_bridge_funcs imx8qxp_ldb_bridge_funcs
= {
397 .atomic_duplicate_state
= drm_atomic_helper_bridge_duplicate_state
,
398 .atomic_destroy_state
= drm_atomic_helper_bridge_destroy_state
,
399 .atomic_reset
= drm_atomic_helper_bridge_reset
,
400 .mode_valid
= imx8qxp_ldb_bridge_mode_valid
,
401 .attach
= ldb_bridge_attach_helper
,
402 .atomic_check
= imx8qxp_ldb_bridge_atomic_check
,
403 .mode_set
= imx8qxp_ldb_bridge_mode_set
,
404 .atomic_pre_enable
= imx8qxp_ldb_bridge_atomic_pre_enable
,
405 .atomic_enable
= imx8qxp_ldb_bridge_atomic_enable
,
406 .atomic_disable
= imx8qxp_ldb_bridge_atomic_disable
,
407 .atomic_get_input_bus_fmts
=
408 imx8qxp_ldb_bridge_atomic_get_input_bus_fmts
,
409 .atomic_get_output_bus_fmts
=
410 imx8qxp_ldb_bridge_atomic_get_output_bus_fmts
,
413 static int imx8qxp_ldb_set_di_id(struct imx8qxp_ldb
*imx8qxp_ldb
)
415 struct imx8qxp_ldb_channel
*imx8qxp_ldb_ch
=
416 &imx8qxp_ldb
->channel
[imx8qxp_ldb
->active_chno
];
417 struct ldb_channel
*ldb_ch
= &imx8qxp_ldb_ch
->base
;
418 struct device_node
*ep
, *remote
;
419 struct device
*dev
= imx8qxp_ldb
->dev
;
420 struct of_endpoint endpoint
;
423 ep
= of_graph_get_endpoint_by_regs(ldb_ch
->np
, 0, -1);
425 DRM_DEV_ERROR(dev
, "failed to get port0 endpoint\n");
429 remote
= of_graph_get_remote_endpoint(ep
);
432 DRM_DEV_ERROR(dev
, "failed to get port0 remote endpoint\n");
436 ret
= of_graph_parse_endpoint(remote
, &endpoint
);
439 DRM_DEV_ERROR(dev
, "failed to parse port0 remote endpoint: %d\n",
444 imx8qxp_ldb_ch
->di_id
= endpoint
.id
;
450 imx8qxp_ldb_check_chno_and_dual_link(struct ldb_channel
*ldb_ch
, int link
)
452 if ((link
== DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS
&& ldb_ch
->chno
!= 0) ||
453 (link
== DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS
&& ldb_ch
->chno
!= 1))
459 static int imx8qxp_ldb_parse_dt_companion(struct imx8qxp_ldb
*imx8qxp_ldb
)
461 struct imx8qxp_ldb_channel
*imx8qxp_ldb_ch
=
462 &imx8qxp_ldb
->channel
[imx8qxp_ldb
->active_chno
];
463 struct ldb_channel
*ldb_ch
= &imx8qxp_ldb_ch
->base
;
464 struct ldb_channel
*companion_ldb_ch
;
465 struct device_node
*companion
;
466 struct device_node
*child
;
467 struct device_node
*companion_port
= NULL
;
468 struct device_node
*port1
, *port2
;
469 struct device
*dev
= imx8qxp_ldb
->dev
;
470 const struct of_device_id
*match
;
475 /* Locate the companion LDB for dual-link operation, if any. */
476 companion
= of_parse_phandle(dev
->of_node
, "fsl,companion-ldb", 0);
480 if (!of_device_is_available(companion
)) {
481 DRM_DEV_ERROR(dev
, "companion LDB is not available\n");
487 * Sanity check: the companion bridge must have the same compatible
490 match
= of_match_device(dev
->driver
->of_match_table
, dev
);
491 if (!of_device_is_compatible(companion
, match
->compatible
)) {
492 DRM_DEV_ERROR(dev
, "companion LDB is incompatible\n");
497 for_each_available_child_of_node(companion
, child
) {
498 ret
= of_property_read_u32(child
, "reg", &i
);
499 if (ret
|| i
> MAX_LDB_CHAN_NUM
- 1) {
501 "invalid channel node address: %u\n", i
);
508 * Channel numbers have to be different, because channel0
509 * transmits odd pixels and channel1 transmits even pixels.
511 if (i
== (ldb_ch
->chno
^ 0x1)) {
512 companion_port
= child
;
517 if (!companion_port
) {
519 "failed to find companion LDB channel port\n");
525 * We need to work out if the sink is expecting us to function in
526 * dual-link mode. We do this by looking at the DT port nodes we are
527 * connected to. If they are marked as expecting odd pixels and
528 * even pixels than we need to enable LDB split mode.
530 port1
= of_graph_get_port_by_id(ldb_ch
->np
, 1);
531 port2
= of_graph_get_port_by_id(companion_port
, 1);
532 dual_link
= drm_of_lvds_get_dual_link_pixel_order(port1
, port2
);
537 case DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS
:
538 ldb_ch
->link_type
= LDB_CH_DUAL_LINK_ODD_EVEN_PIXELS
;
540 case DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS
:
541 ldb_ch
->link_type
= LDB_CH_DUAL_LINK_EVEN_ODD_PIXELS
;
546 "failed to get dual link pixel order: %d\n", ret
);
550 ret
= imx8qxp_ldb_check_chno_and_dual_link(ldb_ch
, dual_link
);
553 "unmatched channel number(%u) vs dual link(%d)\n",
554 ldb_ch
->chno
, dual_link
);
558 imx8qxp_ldb
->companion
= of_drm_find_bridge(companion_port
);
559 if (!imx8qxp_ldb
->companion
) {
561 DRM_DEV_DEBUG_DRIVER(dev
,
562 "failed to find bridge for companion bridge: %d\n",
567 DRM_DEV_DEBUG_DRIVER(dev
,
568 "dual-link configuration detected (companion bridge %pOF)\n",
571 companion_ldb_ch
= bridge_to_ldb_ch(imx8qxp_ldb
->companion
);
572 companion_ldb_ch
->link_type
= ldb_ch
->link_type
;
574 of_node_put(companion_port
);
575 of_node_put(companion
);
579 static int imx8qxp_ldb_probe(struct platform_device
*pdev
)
581 struct device
*dev
= &pdev
->dev
;
582 struct imx8qxp_ldb
*imx8qxp_ldb
;
583 struct imx8qxp_ldb_channel
*imx8qxp_ldb_ch
;
585 struct ldb_channel
*ldb_ch
;
588 imx8qxp_ldb
= devm_kzalloc(dev
, sizeof(*imx8qxp_ldb
), GFP_KERNEL
);
592 imx8qxp_ldb
->clk_pixel
= devm_clk_get(dev
, "pixel");
593 if (IS_ERR(imx8qxp_ldb
->clk_pixel
)) {
594 ret
= PTR_ERR(imx8qxp_ldb
->clk_pixel
);
595 if (ret
!= -EPROBE_DEFER
)
597 "failed to get pixel clock: %d\n", ret
);
601 imx8qxp_ldb
->clk_bypass
= devm_clk_get(dev
, "bypass");
602 if (IS_ERR(imx8qxp_ldb
->clk_bypass
)) {
603 ret
= PTR_ERR(imx8qxp_ldb
->clk_bypass
);
604 if (ret
!= -EPROBE_DEFER
)
606 "failed to get bypass clock: %d\n", ret
);
610 imx8qxp_ldb
->dev
= dev
;
612 ldb
= &imx8qxp_ldb
->base
;
614 ldb
->ctrl_reg
= 0xe0;
616 for (i
= 0; i
< MAX_LDB_CHAN_NUM
; i
++)
617 ldb
->channel
[i
] = &imx8qxp_ldb
->channel
[i
].base
;
619 ret
= ldb_init_helper(ldb
);
623 if (ldb
->available_ch_cnt
== 0) {
624 DRM_DEV_DEBUG_DRIVER(dev
, "no available channel\n");
626 } else if (ldb
->available_ch_cnt
> 1) {
627 DRM_DEV_ERROR(dev
, "invalid available channel number(%u)\n",
628 ldb
->available_ch_cnt
);
632 for (i
= 0; i
< MAX_LDB_CHAN_NUM
; i
++) {
633 imx8qxp_ldb_ch
= &imx8qxp_ldb
->channel
[i
];
634 ldb_ch
= &imx8qxp_ldb_ch
->base
;
636 if (ldb_ch
->is_available
) {
637 imx8qxp_ldb
->active_chno
= ldb_ch
->chno
;
642 imx8qxp_ldb_ch
->phy
= devm_of_phy_get(dev
, ldb_ch
->np
, "lvds_phy");
643 if (IS_ERR(imx8qxp_ldb_ch
->phy
)) {
644 ret
= PTR_ERR(imx8qxp_ldb_ch
->phy
);
645 if (ret
!= -EPROBE_DEFER
)
646 DRM_DEV_ERROR(dev
, "failed to get channel%d PHY: %d\n",
647 imx8qxp_ldb
->active_chno
, ret
);
651 ret
= ldb_find_next_bridge_helper(ldb
);
655 ret
= imx8qxp_ldb_set_di_id(imx8qxp_ldb
);
659 ret
= imx8qxp_ldb_parse_dt_companion(imx8qxp_ldb
);
663 platform_set_drvdata(pdev
, imx8qxp_ldb
);
664 pm_runtime_enable(dev
);
666 ldb_add_bridge_helper(ldb
, &imx8qxp_ldb_bridge_funcs
);
671 static void imx8qxp_ldb_remove(struct platform_device
*pdev
)
673 struct imx8qxp_ldb
*imx8qxp_ldb
= platform_get_drvdata(pdev
);
674 struct ldb
*ldb
= &imx8qxp_ldb
->base
;
676 ldb_remove_bridge_helper(ldb
);
678 pm_runtime_disable(&pdev
->dev
);
681 static int imx8qxp_ldb_runtime_suspend(struct device
*dev
)
686 static int imx8qxp_ldb_runtime_resume(struct device
*dev
)
688 struct imx8qxp_ldb
*imx8qxp_ldb
= dev_get_drvdata(dev
);
689 struct ldb
*ldb
= &imx8qxp_ldb
->base
;
691 /* disable LDB by resetting the control register to POR default */
692 regmap_write(ldb
->regmap
, ldb
->ctrl_reg
, 0);
697 static const struct dev_pm_ops imx8qxp_ldb_pm_ops
= {
698 RUNTIME_PM_OPS(imx8qxp_ldb_runtime_suspend
, imx8qxp_ldb_runtime_resume
, NULL
)
701 static const struct of_device_id imx8qxp_ldb_dt_ids
[] = {
702 { .compatible
= "fsl,imx8qxp-ldb" },
705 MODULE_DEVICE_TABLE(of
, imx8qxp_ldb_dt_ids
);
707 static struct platform_driver imx8qxp_ldb_driver
= {
708 .probe
= imx8qxp_ldb_probe
,
709 .remove
= imx8qxp_ldb_remove
,
711 .pm
= pm_ptr(&imx8qxp_ldb_pm_ops
),
713 .of_match_table
= imx8qxp_ldb_dt_ids
,
716 module_platform_driver(imx8qxp_ldb_driver
);
718 MODULE_DESCRIPTION("i.MX8QXP LVDS Display Bridge(LDB)/Pixel Mapper bridge driver");
719 MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
720 MODULE_LICENSE("GPL v2");
721 MODULE_ALIAS("platform:" DRIVER_NAME
);