1013413cdSMasahiro Yamada // SPDX-License-Identifier: GPL-2.0+
2013413cdSMasahiro Yamada
3013413cdSMasahiro Yamada /*
4013413cdSMasahiro Yamada * Copyright 2020 NXP
5013413cdSMasahiro Yamada */
6013413cdSMasahiro Yamada
7013413cdSMasahiro Yamada #include <linux/clk.h>
8013413cdSMasahiro Yamada #include <linux/media-bus-format.h>
9013413cdSMasahiro Yamada #include <linux/mfd/syscon.h>
10013413cdSMasahiro Yamada #include <linux/module.h>
11013413cdSMasahiro Yamada #include <linux/of.h>
12013413cdSMasahiro Yamada #include <linux/of_device.h>
13013413cdSMasahiro Yamada #include <linux/of_graph.h>
14013413cdSMasahiro Yamada #include <linux/phy/phy.h>
15*722d4f06SRob Herring #include <linux/platform_device.h>
16013413cdSMasahiro Yamada #include <linux/pm_runtime.h>
17013413cdSMasahiro Yamada #include <linux/regmap.h>
18013413cdSMasahiro Yamada
19013413cdSMasahiro Yamada #include <drm/drm_atomic_state_helper.h>
20013413cdSMasahiro Yamada #include <drm/drm_bridge.h>
21013413cdSMasahiro Yamada #include <drm/drm_connector.h>
22013413cdSMasahiro Yamada #include <drm/drm_fourcc.h>
23013413cdSMasahiro Yamada #include <drm/drm_of.h>
24013413cdSMasahiro Yamada #include <drm/drm_print.h>
25013413cdSMasahiro Yamada
26013413cdSMasahiro Yamada #include "imx-ldb-helper.h"
27013413cdSMasahiro Yamada
28013413cdSMasahiro Yamada #define LDB_CH_SEL BIT(28)
29013413cdSMasahiro Yamada
30013413cdSMasahiro Yamada #define SS_CTRL 0x20
31013413cdSMasahiro Yamada #define CH_HSYNC_M(id) BIT(0 + ((id) * 2))
32013413cdSMasahiro Yamada #define CH_VSYNC_M(id) BIT(1 + ((id) * 2))
33013413cdSMasahiro Yamada #define CH_PHSYNC(id) BIT(0 + ((id) * 2))
34013413cdSMasahiro Yamada #define CH_PVSYNC(id) BIT(1 + ((id) * 2))
35013413cdSMasahiro Yamada
36013413cdSMasahiro Yamada #define DRIVER_NAME "imx8qxp-ldb"
37013413cdSMasahiro Yamada
38013413cdSMasahiro Yamada struct imx8qxp_ldb_channel {
39013413cdSMasahiro Yamada struct ldb_channel base;
40013413cdSMasahiro Yamada struct phy *phy;
41013413cdSMasahiro Yamada unsigned int di_id;
42013413cdSMasahiro Yamada };
43013413cdSMasahiro Yamada
44013413cdSMasahiro Yamada struct imx8qxp_ldb {
45013413cdSMasahiro Yamada struct ldb base;
46013413cdSMasahiro Yamada struct device *dev;
47013413cdSMasahiro Yamada struct imx8qxp_ldb_channel channel[MAX_LDB_CHAN_NUM];
48013413cdSMasahiro Yamada struct clk *clk_pixel;
49013413cdSMasahiro Yamada struct clk *clk_bypass;
50013413cdSMasahiro Yamada struct drm_bridge *companion;
51013413cdSMasahiro Yamada int active_chno;
52013413cdSMasahiro Yamada };
53013413cdSMasahiro Yamada
54013413cdSMasahiro Yamada static inline struct imx8qxp_ldb_channel *
base_to_imx8qxp_ldb_channel(struct ldb_channel * base)55013413cdSMasahiro Yamada base_to_imx8qxp_ldb_channel(struct ldb_channel *base)
56013413cdSMasahiro Yamada {
57013413cdSMasahiro Yamada return container_of(base, struct imx8qxp_ldb_channel, base);
58013413cdSMasahiro Yamada }
59013413cdSMasahiro Yamada
base_to_imx8qxp_ldb(struct ldb * base)60013413cdSMasahiro Yamada static inline struct imx8qxp_ldb *base_to_imx8qxp_ldb(struct ldb *base)
61013413cdSMasahiro Yamada {
62013413cdSMasahiro Yamada return container_of(base, struct imx8qxp_ldb, base);
63013413cdSMasahiro Yamada }
64013413cdSMasahiro Yamada
imx8qxp_ldb_set_phy_cfg(struct imx8qxp_ldb * imx8qxp_ldb,unsigned long di_clk,bool is_split,struct phy_configure_opts_lvds * phy_cfg)65013413cdSMasahiro Yamada static void imx8qxp_ldb_set_phy_cfg(struct imx8qxp_ldb *imx8qxp_ldb,
66013413cdSMasahiro Yamada unsigned long di_clk, bool is_split,
67013413cdSMasahiro Yamada struct phy_configure_opts_lvds *phy_cfg)
68013413cdSMasahiro Yamada {
69013413cdSMasahiro Yamada phy_cfg->bits_per_lane_and_dclk_cycle = 7;
70013413cdSMasahiro Yamada phy_cfg->lanes = 4;
71013413cdSMasahiro Yamada
72013413cdSMasahiro Yamada if (is_split) {
73013413cdSMasahiro Yamada phy_cfg->differential_clk_rate = di_clk / 2;
74013413cdSMasahiro Yamada phy_cfg->is_slave = !imx8qxp_ldb->companion;
75013413cdSMasahiro Yamada } else {
76013413cdSMasahiro Yamada phy_cfg->differential_clk_rate = di_clk;
77013413cdSMasahiro Yamada phy_cfg->is_slave = false;
78013413cdSMasahiro Yamada }
79013413cdSMasahiro Yamada }
80013413cdSMasahiro Yamada
81013413cdSMasahiro Yamada static int
imx8qxp_ldb_bridge_atomic_check(struct drm_bridge * bridge,struct drm_bridge_state * bridge_state,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)82013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_check(struct drm_bridge *bridge,
83013413cdSMasahiro Yamada struct drm_bridge_state *bridge_state,
84013413cdSMasahiro Yamada struct drm_crtc_state *crtc_state,
85013413cdSMasahiro Yamada struct drm_connector_state *conn_state)
86013413cdSMasahiro Yamada {
87013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = bridge->driver_private;
88013413cdSMasahiro Yamada struct ldb *ldb = ldb_ch->ldb;
89013413cdSMasahiro Yamada struct imx8qxp_ldb_channel *imx8qxp_ldb_ch =
90013413cdSMasahiro Yamada base_to_imx8qxp_ldb_channel(ldb_ch);
91013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb = base_to_imx8qxp_ldb(ldb);
92013413cdSMasahiro Yamada struct drm_bridge *companion = imx8qxp_ldb->companion;
93013413cdSMasahiro Yamada struct drm_display_mode *adj = &crtc_state->adjusted_mode;
94013413cdSMasahiro Yamada unsigned long di_clk = adj->clock * 1000;
95013413cdSMasahiro Yamada bool is_split = ldb_channel_is_split_link(ldb_ch);
96013413cdSMasahiro Yamada union phy_configure_opts opts = { };
97013413cdSMasahiro Yamada struct phy_configure_opts_lvds *phy_cfg = &opts.lvds;
98013413cdSMasahiro Yamada int ret;
99013413cdSMasahiro Yamada
100013413cdSMasahiro Yamada ret = ldb_bridge_atomic_check_helper(bridge, bridge_state,
101013413cdSMasahiro Yamada crtc_state, conn_state);
102013413cdSMasahiro Yamada if (ret)
103013413cdSMasahiro Yamada return ret;
104013413cdSMasahiro Yamada
105013413cdSMasahiro Yamada imx8qxp_ldb_set_phy_cfg(imx8qxp_ldb, di_clk, is_split, phy_cfg);
106013413cdSMasahiro Yamada ret = phy_validate(imx8qxp_ldb_ch->phy, PHY_MODE_LVDS, 0, &opts);
107013413cdSMasahiro Yamada if (ret < 0) {
108013413cdSMasahiro Yamada DRM_DEV_DEBUG_DRIVER(imx8qxp_ldb->dev,
109013413cdSMasahiro Yamada "failed to validate PHY: %d\n", ret);
110013413cdSMasahiro Yamada return ret;
111013413cdSMasahiro Yamada }
112013413cdSMasahiro Yamada
113013413cdSMasahiro Yamada if (is_split && companion) {
114013413cdSMasahiro Yamada ret = companion->funcs->atomic_check(companion,
115013413cdSMasahiro Yamada bridge_state, crtc_state, conn_state);
116013413cdSMasahiro Yamada if (ret)
117013413cdSMasahiro Yamada return ret;
118013413cdSMasahiro Yamada }
119013413cdSMasahiro Yamada
120013413cdSMasahiro Yamada return ret;
121013413cdSMasahiro Yamada }
122013413cdSMasahiro Yamada
123013413cdSMasahiro Yamada static void
imx8qxp_ldb_bridge_mode_set(struct drm_bridge * bridge,const struct drm_display_mode * mode,const struct drm_display_mode * adjusted_mode)124013413cdSMasahiro Yamada imx8qxp_ldb_bridge_mode_set(struct drm_bridge *bridge,
125013413cdSMasahiro Yamada const struct drm_display_mode *mode,
126013413cdSMasahiro Yamada const struct drm_display_mode *adjusted_mode)
127013413cdSMasahiro Yamada {
128013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = bridge->driver_private;
129013413cdSMasahiro Yamada struct ldb_channel *companion_ldb_ch;
130013413cdSMasahiro Yamada struct ldb *ldb = ldb_ch->ldb;
131013413cdSMasahiro Yamada struct imx8qxp_ldb_channel *imx8qxp_ldb_ch =
132013413cdSMasahiro Yamada base_to_imx8qxp_ldb_channel(ldb_ch);
133013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb = base_to_imx8qxp_ldb(ldb);
134013413cdSMasahiro Yamada struct drm_bridge *companion = imx8qxp_ldb->companion;
135013413cdSMasahiro Yamada struct device *dev = imx8qxp_ldb->dev;
136013413cdSMasahiro Yamada unsigned long di_clk = adjusted_mode->clock * 1000;
137013413cdSMasahiro Yamada bool is_split = ldb_channel_is_split_link(ldb_ch);
138013413cdSMasahiro Yamada union phy_configure_opts opts = { };
139013413cdSMasahiro Yamada struct phy_configure_opts_lvds *phy_cfg = &opts.lvds;
140013413cdSMasahiro Yamada u32 chno = ldb_ch->chno;
141013413cdSMasahiro Yamada int ret;
142013413cdSMasahiro Yamada
143013413cdSMasahiro Yamada ret = pm_runtime_get_sync(dev);
144013413cdSMasahiro Yamada if (ret < 0)
145013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to get runtime PM sync: %d\n", ret);
146013413cdSMasahiro Yamada
147013413cdSMasahiro Yamada ret = phy_init(imx8qxp_ldb_ch->phy);
148013413cdSMasahiro Yamada if (ret < 0)
149013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to initialize PHY: %d\n", ret);
150013413cdSMasahiro Yamada
151013413cdSMasahiro Yamada ret = phy_set_mode(imx8qxp_ldb_ch->phy, PHY_MODE_LVDS);
152013413cdSMasahiro Yamada if (ret < 0)
153013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to set PHY mode: %d\n", ret);
154013413cdSMasahiro Yamada
155013413cdSMasahiro Yamada if (is_split && companion) {
156013413cdSMasahiro Yamada companion_ldb_ch = bridge_to_ldb_ch(companion);
157013413cdSMasahiro Yamada
158013413cdSMasahiro Yamada companion_ldb_ch->in_bus_format = ldb_ch->in_bus_format;
159013413cdSMasahiro Yamada companion_ldb_ch->out_bus_format = ldb_ch->out_bus_format;
160013413cdSMasahiro Yamada }
161013413cdSMasahiro Yamada
162013413cdSMasahiro Yamada clk_set_rate(imx8qxp_ldb->clk_bypass, di_clk);
163013413cdSMasahiro Yamada clk_set_rate(imx8qxp_ldb->clk_pixel, di_clk);
164013413cdSMasahiro Yamada
165013413cdSMasahiro Yamada imx8qxp_ldb_set_phy_cfg(imx8qxp_ldb, di_clk, is_split, phy_cfg);
166013413cdSMasahiro Yamada ret = phy_configure(imx8qxp_ldb_ch->phy, &opts);
167013413cdSMasahiro Yamada if (ret < 0)
168013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to configure PHY: %d\n", ret);
169013413cdSMasahiro Yamada
170013413cdSMasahiro Yamada if (chno == 0)
171013413cdSMasahiro Yamada ldb->ldb_ctrl &= ~LDB_CH_SEL;
172013413cdSMasahiro Yamada else
173013413cdSMasahiro Yamada ldb->ldb_ctrl |= LDB_CH_SEL;
174013413cdSMasahiro Yamada
175013413cdSMasahiro Yamada /* input VSYNC signal from pixel link is active low */
176013413cdSMasahiro Yamada if (imx8qxp_ldb_ch->di_id == 0)
177013413cdSMasahiro Yamada ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW;
178013413cdSMasahiro Yamada else
179013413cdSMasahiro Yamada ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW;
180013413cdSMasahiro Yamada
181013413cdSMasahiro Yamada /*
182013413cdSMasahiro Yamada * For split mode, settle input VSYNC signal polarity and
183013413cdSMasahiro Yamada * channel selection down early.
184013413cdSMasahiro Yamada */
185013413cdSMasahiro Yamada if (is_split)
186013413cdSMasahiro Yamada regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ldb_ctrl);
187013413cdSMasahiro Yamada
188013413cdSMasahiro Yamada ldb_bridge_mode_set_helper(bridge, mode, adjusted_mode);
189013413cdSMasahiro Yamada
190013413cdSMasahiro Yamada if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
191013413cdSMasahiro Yamada regmap_update_bits(ldb->regmap, SS_CTRL, CH_VSYNC_M(chno), 0);
192013413cdSMasahiro Yamada else if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
193013413cdSMasahiro Yamada regmap_update_bits(ldb->regmap, SS_CTRL,
194013413cdSMasahiro Yamada CH_VSYNC_M(chno), CH_PVSYNC(chno));
195013413cdSMasahiro Yamada
196013413cdSMasahiro Yamada if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
197013413cdSMasahiro Yamada regmap_update_bits(ldb->regmap, SS_CTRL, CH_HSYNC_M(chno), 0);
198013413cdSMasahiro Yamada else if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
199013413cdSMasahiro Yamada regmap_update_bits(ldb->regmap, SS_CTRL,
200013413cdSMasahiro Yamada CH_HSYNC_M(chno), CH_PHSYNC(chno));
201013413cdSMasahiro Yamada
202013413cdSMasahiro Yamada if (is_split && companion)
203013413cdSMasahiro Yamada companion->funcs->mode_set(companion, mode, adjusted_mode);
204013413cdSMasahiro Yamada }
205013413cdSMasahiro Yamada
206013413cdSMasahiro Yamada static void
imx8qxp_ldb_bridge_atomic_pre_enable(struct drm_bridge * bridge,struct drm_bridge_state * old_bridge_state)207013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_pre_enable(struct drm_bridge *bridge,
208013413cdSMasahiro Yamada struct drm_bridge_state *old_bridge_state)
209013413cdSMasahiro Yamada {
210013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = bridge->driver_private;
211013413cdSMasahiro Yamada struct ldb *ldb = ldb_ch->ldb;
212013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb = base_to_imx8qxp_ldb(ldb);
213013413cdSMasahiro Yamada struct drm_bridge *companion = imx8qxp_ldb->companion;
214013413cdSMasahiro Yamada bool is_split = ldb_channel_is_split_link(ldb_ch);
215013413cdSMasahiro Yamada
216013413cdSMasahiro Yamada clk_prepare_enable(imx8qxp_ldb->clk_pixel);
217013413cdSMasahiro Yamada clk_prepare_enable(imx8qxp_ldb->clk_bypass);
218013413cdSMasahiro Yamada
219013413cdSMasahiro Yamada if (is_split && companion)
220013413cdSMasahiro Yamada companion->funcs->atomic_pre_enable(companion, old_bridge_state);
221013413cdSMasahiro Yamada }
222013413cdSMasahiro Yamada
223013413cdSMasahiro Yamada static void
imx8qxp_ldb_bridge_atomic_enable(struct drm_bridge * bridge,struct drm_bridge_state * old_bridge_state)224013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_enable(struct drm_bridge *bridge,
225013413cdSMasahiro Yamada struct drm_bridge_state *old_bridge_state)
226013413cdSMasahiro Yamada {
227013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = bridge->driver_private;
228013413cdSMasahiro Yamada struct ldb *ldb = ldb_ch->ldb;
229013413cdSMasahiro Yamada struct imx8qxp_ldb_channel *imx8qxp_ldb_ch =
230013413cdSMasahiro Yamada base_to_imx8qxp_ldb_channel(ldb_ch);
231013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb = base_to_imx8qxp_ldb(ldb);
232013413cdSMasahiro Yamada struct drm_bridge *companion = imx8qxp_ldb->companion;
233013413cdSMasahiro Yamada struct device *dev = imx8qxp_ldb->dev;
234013413cdSMasahiro Yamada bool is_split = ldb_channel_is_split_link(ldb_ch);
235013413cdSMasahiro Yamada int ret;
236013413cdSMasahiro Yamada
237013413cdSMasahiro Yamada if (ldb_ch->chno == 0 || is_split) {
238013413cdSMasahiro Yamada ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
239013413cdSMasahiro Yamada ldb->ldb_ctrl |= imx8qxp_ldb_ch->di_id == 0 ?
240013413cdSMasahiro Yamada LDB_CH0_MODE_EN_TO_DI0 : LDB_CH0_MODE_EN_TO_DI1;
241013413cdSMasahiro Yamada }
242013413cdSMasahiro Yamada if (ldb_ch->chno == 1 || is_split) {
243013413cdSMasahiro Yamada ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
244013413cdSMasahiro Yamada ldb->ldb_ctrl |= imx8qxp_ldb_ch->di_id == 0 ?
245013413cdSMasahiro Yamada LDB_CH1_MODE_EN_TO_DI0 : LDB_CH1_MODE_EN_TO_DI1;
246013413cdSMasahiro Yamada }
247013413cdSMasahiro Yamada
248013413cdSMasahiro Yamada ldb_bridge_enable_helper(bridge);
249013413cdSMasahiro Yamada
250013413cdSMasahiro Yamada ret = phy_power_on(imx8qxp_ldb_ch->phy);
251013413cdSMasahiro Yamada if (ret)
252013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to power on PHY: %d\n", ret);
253013413cdSMasahiro Yamada
254013413cdSMasahiro Yamada if (is_split && companion)
255013413cdSMasahiro Yamada companion->funcs->atomic_enable(companion, old_bridge_state);
256013413cdSMasahiro Yamada }
257013413cdSMasahiro Yamada
258013413cdSMasahiro Yamada static void
imx8qxp_ldb_bridge_atomic_disable(struct drm_bridge * bridge,struct drm_bridge_state * old_bridge_state)259013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_disable(struct drm_bridge *bridge,
260013413cdSMasahiro Yamada struct drm_bridge_state *old_bridge_state)
261013413cdSMasahiro Yamada {
262013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = bridge->driver_private;
263013413cdSMasahiro Yamada struct ldb *ldb = ldb_ch->ldb;
264013413cdSMasahiro Yamada struct imx8qxp_ldb_channel *imx8qxp_ldb_ch =
265013413cdSMasahiro Yamada base_to_imx8qxp_ldb_channel(ldb_ch);
266013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb = base_to_imx8qxp_ldb(ldb);
267013413cdSMasahiro Yamada struct drm_bridge *companion = imx8qxp_ldb->companion;
268013413cdSMasahiro Yamada struct device *dev = imx8qxp_ldb->dev;
269013413cdSMasahiro Yamada bool is_split = ldb_channel_is_split_link(ldb_ch);
270013413cdSMasahiro Yamada int ret;
271013413cdSMasahiro Yamada
272013413cdSMasahiro Yamada ret = phy_power_off(imx8qxp_ldb_ch->phy);
273013413cdSMasahiro Yamada if (ret)
274013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to power off PHY: %d\n", ret);
275013413cdSMasahiro Yamada
276013413cdSMasahiro Yamada ret = phy_exit(imx8qxp_ldb_ch->phy);
277013413cdSMasahiro Yamada if (ret < 0)
278013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to teardown PHY: %d\n", ret);
279013413cdSMasahiro Yamada
280013413cdSMasahiro Yamada ldb_bridge_disable_helper(bridge);
281013413cdSMasahiro Yamada
282013413cdSMasahiro Yamada clk_disable_unprepare(imx8qxp_ldb->clk_bypass);
283013413cdSMasahiro Yamada clk_disable_unprepare(imx8qxp_ldb->clk_pixel);
284013413cdSMasahiro Yamada
285013413cdSMasahiro Yamada if (is_split && companion)
286013413cdSMasahiro Yamada companion->funcs->atomic_disable(companion, old_bridge_state);
287013413cdSMasahiro Yamada
288013413cdSMasahiro Yamada ret = pm_runtime_put(dev);
289013413cdSMasahiro Yamada if (ret < 0)
290013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to put runtime PM: %d\n", ret);
291013413cdSMasahiro Yamada }
292013413cdSMasahiro Yamada
293013413cdSMasahiro Yamada static const u32 imx8qxp_ldb_bus_output_fmts[] = {
294013413cdSMasahiro Yamada MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
295013413cdSMasahiro Yamada MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
296013413cdSMasahiro Yamada MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
297013413cdSMasahiro Yamada MEDIA_BUS_FMT_FIXED,
298013413cdSMasahiro Yamada };
299013413cdSMasahiro Yamada
imx8qxp_ldb_bus_output_fmt_supported(u32 fmt)300013413cdSMasahiro Yamada static bool imx8qxp_ldb_bus_output_fmt_supported(u32 fmt)
301013413cdSMasahiro Yamada {
302013413cdSMasahiro Yamada int i;
303013413cdSMasahiro Yamada
304013413cdSMasahiro Yamada for (i = 0; i < ARRAY_SIZE(imx8qxp_ldb_bus_output_fmts); i++) {
305013413cdSMasahiro Yamada if (imx8qxp_ldb_bus_output_fmts[i] == fmt)
306013413cdSMasahiro Yamada return true;
307013413cdSMasahiro Yamada }
308013413cdSMasahiro Yamada
309013413cdSMasahiro Yamada return false;
310013413cdSMasahiro Yamada }
311013413cdSMasahiro Yamada
312013413cdSMasahiro Yamada static u32 *
imx8qxp_ldb_bridge_atomic_get_input_bus_fmts(struct drm_bridge * bridge,struct drm_bridge_state * bridge_state,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state,u32 output_fmt,unsigned int * num_input_fmts)313013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
314013413cdSMasahiro Yamada struct drm_bridge_state *bridge_state,
315013413cdSMasahiro Yamada struct drm_crtc_state *crtc_state,
316013413cdSMasahiro Yamada struct drm_connector_state *conn_state,
317013413cdSMasahiro Yamada u32 output_fmt,
318013413cdSMasahiro Yamada unsigned int *num_input_fmts)
319013413cdSMasahiro Yamada {
320013413cdSMasahiro Yamada struct drm_display_info *di;
321013413cdSMasahiro Yamada const struct drm_format_info *finfo;
322013413cdSMasahiro Yamada u32 *input_fmts;
323013413cdSMasahiro Yamada
324013413cdSMasahiro Yamada if (!imx8qxp_ldb_bus_output_fmt_supported(output_fmt))
325013413cdSMasahiro Yamada return NULL;
326013413cdSMasahiro Yamada
327013413cdSMasahiro Yamada *num_input_fmts = 1;
328013413cdSMasahiro Yamada
329013413cdSMasahiro Yamada input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
330013413cdSMasahiro Yamada if (!input_fmts)
331013413cdSMasahiro Yamada return NULL;
332013413cdSMasahiro Yamada
333013413cdSMasahiro Yamada switch (output_fmt) {
334013413cdSMasahiro Yamada case MEDIA_BUS_FMT_FIXED:
335013413cdSMasahiro Yamada di = &conn_state->connector->display_info;
336013413cdSMasahiro Yamada
337013413cdSMasahiro Yamada /*
338013413cdSMasahiro Yamada * Look at the first bus format to determine input format.
339013413cdSMasahiro Yamada * Default to MEDIA_BUS_FMT_RGB888_1X24, if no match.
340013413cdSMasahiro Yamada */
341013413cdSMasahiro Yamada if (di->num_bus_formats) {
342013413cdSMasahiro Yamada finfo = drm_format_info(di->bus_formats[0]);
343013413cdSMasahiro Yamada
344013413cdSMasahiro Yamada input_fmts[0] = finfo->depth == 18 ?
345013413cdSMasahiro Yamada MEDIA_BUS_FMT_RGB666_1X24_CPADHI :
346013413cdSMasahiro Yamada MEDIA_BUS_FMT_RGB888_1X24;
347013413cdSMasahiro Yamada } else {
348013413cdSMasahiro Yamada input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
349013413cdSMasahiro Yamada }
350013413cdSMasahiro Yamada break;
351013413cdSMasahiro Yamada case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
352013413cdSMasahiro Yamada input_fmts[0] = MEDIA_BUS_FMT_RGB666_1X24_CPADHI;
353013413cdSMasahiro Yamada break;
354013413cdSMasahiro Yamada case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
355013413cdSMasahiro Yamada case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
356013413cdSMasahiro Yamada input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
357013413cdSMasahiro Yamada break;
358013413cdSMasahiro Yamada default:
359013413cdSMasahiro Yamada kfree(input_fmts);
360013413cdSMasahiro Yamada input_fmts = NULL;
361013413cdSMasahiro Yamada break;
362013413cdSMasahiro Yamada }
363013413cdSMasahiro Yamada
364013413cdSMasahiro Yamada return input_fmts;
365013413cdSMasahiro Yamada }
366013413cdSMasahiro Yamada
367013413cdSMasahiro Yamada static u32 *
imx8qxp_ldb_bridge_atomic_get_output_bus_fmts(struct drm_bridge * bridge,struct drm_bridge_state * bridge_state,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state,unsigned int * num_output_fmts)368013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
369013413cdSMasahiro Yamada struct drm_bridge_state *bridge_state,
370013413cdSMasahiro Yamada struct drm_crtc_state *crtc_state,
371013413cdSMasahiro Yamada struct drm_connector_state *conn_state,
372013413cdSMasahiro Yamada unsigned int *num_output_fmts)
373013413cdSMasahiro Yamada {
374013413cdSMasahiro Yamada *num_output_fmts = ARRAY_SIZE(imx8qxp_ldb_bus_output_fmts);
375013413cdSMasahiro Yamada return kmemdup(imx8qxp_ldb_bus_output_fmts,
376013413cdSMasahiro Yamada sizeof(imx8qxp_ldb_bus_output_fmts), GFP_KERNEL);
377013413cdSMasahiro Yamada }
378013413cdSMasahiro Yamada
379013413cdSMasahiro Yamada static enum drm_mode_status
imx8qxp_ldb_bridge_mode_valid(struct drm_bridge * bridge,const struct drm_display_info * info,const struct drm_display_mode * mode)380013413cdSMasahiro Yamada imx8qxp_ldb_bridge_mode_valid(struct drm_bridge *bridge,
381013413cdSMasahiro Yamada const struct drm_display_info *info,
382013413cdSMasahiro Yamada const struct drm_display_mode *mode)
383013413cdSMasahiro Yamada {
384013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = bridge->driver_private;
385013413cdSMasahiro Yamada bool is_single = ldb_channel_is_single_link(ldb_ch);
386013413cdSMasahiro Yamada
387013413cdSMasahiro Yamada if (mode->clock > 170000)
388013413cdSMasahiro Yamada return MODE_CLOCK_HIGH;
389013413cdSMasahiro Yamada
390013413cdSMasahiro Yamada if (mode->clock > 150000 && is_single)
391013413cdSMasahiro Yamada return MODE_CLOCK_HIGH;
392013413cdSMasahiro Yamada
393013413cdSMasahiro Yamada return MODE_OK;
394013413cdSMasahiro Yamada }
395013413cdSMasahiro Yamada
396013413cdSMasahiro Yamada static const struct drm_bridge_funcs imx8qxp_ldb_bridge_funcs = {
397013413cdSMasahiro Yamada .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
398013413cdSMasahiro Yamada .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
399013413cdSMasahiro Yamada .atomic_reset = drm_atomic_helper_bridge_reset,
400013413cdSMasahiro Yamada .mode_valid = imx8qxp_ldb_bridge_mode_valid,
401013413cdSMasahiro Yamada .attach = ldb_bridge_attach_helper,
402013413cdSMasahiro Yamada .atomic_check = imx8qxp_ldb_bridge_atomic_check,
403013413cdSMasahiro Yamada .mode_set = imx8qxp_ldb_bridge_mode_set,
404013413cdSMasahiro Yamada .atomic_pre_enable = imx8qxp_ldb_bridge_atomic_pre_enable,
405013413cdSMasahiro Yamada .atomic_enable = imx8qxp_ldb_bridge_atomic_enable,
406013413cdSMasahiro Yamada .atomic_disable = imx8qxp_ldb_bridge_atomic_disable,
407013413cdSMasahiro Yamada .atomic_get_input_bus_fmts =
408013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_get_input_bus_fmts,
409013413cdSMasahiro Yamada .atomic_get_output_bus_fmts =
410013413cdSMasahiro Yamada imx8qxp_ldb_bridge_atomic_get_output_bus_fmts,
411013413cdSMasahiro Yamada };
412013413cdSMasahiro Yamada
imx8qxp_ldb_set_di_id(struct imx8qxp_ldb * imx8qxp_ldb)413013413cdSMasahiro Yamada static int imx8qxp_ldb_set_di_id(struct imx8qxp_ldb *imx8qxp_ldb)
414013413cdSMasahiro Yamada {
415013413cdSMasahiro Yamada struct imx8qxp_ldb_channel *imx8qxp_ldb_ch =
416013413cdSMasahiro Yamada &imx8qxp_ldb->channel[imx8qxp_ldb->active_chno];
417013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = &imx8qxp_ldb_ch->base;
418013413cdSMasahiro Yamada struct device_node *ep, *remote;
419013413cdSMasahiro Yamada struct device *dev = imx8qxp_ldb->dev;
420013413cdSMasahiro Yamada struct of_endpoint endpoint;
421013413cdSMasahiro Yamada int ret;
422013413cdSMasahiro Yamada
423013413cdSMasahiro Yamada ep = of_graph_get_endpoint_by_regs(ldb_ch->np, 0, -1);
424013413cdSMasahiro Yamada if (!ep) {
425013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to get port0 endpoint\n");
426013413cdSMasahiro Yamada return -EINVAL;
427013413cdSMasahiro Yamada }
428013413cdSMasahiro Yamada
429013413cdSMasahiro Yamada remote = of_graph_get_remote_endpoint(ep);
430013413cdSMasahiro Yamada of_node_put(ep);
431013413cdSMasahiro Yamada if (!remote) {
432013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to get port0 remote endpoint\n");
433013413cdSMasahiro Yamada return -EINVAL;
434013413cdSMasahiro Yamada }
435013413cdSMasahiro Yamada
436013413cdSMasahiro Yamada ret = of_graph_parse_endpoint(remote, &endpoint);
437013413cdSMasahiro Yamada of_node_put(remote);
438013413cdSMasahiro Yamada if (ret) {
439013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to parse port0 remote endpoint: %d\n",
440013413cdSMasahiro Yamada ret);
441013413cdSMasahiro Yamada return ret;
442013413cdSMasahiro Yamada }
443013413cdSMasahiro Yamada
444013413cdSMasahiro Yamada imx8qxp_ldb_ch->di_id = endpoint.id;
445013413cdSMasahiro Yamada
446013413cdSMasahiro Yamada return 0;
447013413cdSMasahiro Yamada }
448013413cdSMasahiro Yamada
449013413cdSMasahiro Yamada static int
imx8qxp_ldb_check_chno_and_dual_link(struct ldb_channel * ldb_ch,int link)450013413cdSMasahiro Yamada imx8qxp_ldb_check_chno_and_dual_link(struct ldb_channel *ldb_ch, int link)
451013413cdSMasahiro Yamada {
452013413cdSMasahiro Yamada if ((link == DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS && ldb_ch->chno != 0) ||
453013413cdSMasahiro Yamada (link == DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS && ldb_ch->chno != 1))
454013413cdSMasahiro Yamada return -EINVAL;
455013413cdSMasahiro Yamada
456013413cdSMasahiro Yamada return 0;
457013413cdSMasahiro Yamada }
458013413cdSMasahiro Yamada
imx8qxp_ldb_parse_dt_companion(struct imx8qxp_ldb * imx8qxp_ldb)459013413cdSMasahiro Yamada static int imx8qxp_ldb_parse_dt_companion(struct imx8qxp_ldb *imx8qxp_ldb)
460013413cdSMasahiro Yamada {
461013413cdSMasahiro Yamada struct imx8qxp_ldb_channel *imx8qxp_ldb_ch =
462013413cdSMasahiro Yamada &imx8qxp_ldb->channel[imx8qxp_ldb->active_chno];
463013413cdSMasahiro Yamada struct ldb_channel *ldb_ch = &imx8qxp_ldb_ch->base;
464013413cdSMasahiro Yamada struct ldb_channel *companion_ldb_ch;
465013413cdSMasahiro Yamada struct device_node *companion;
466013413cdSMasahiro Yamada struct device_node *child;
467013413cdSMasahiro Yamada struct device_node *companion_port = NULL;
468013413cdSMasahiro Yamada struct device_node *port1, *port2;
469013413cdSMasahiro Yamada struct device *dev = imx8qxp_ldb->dev;
470013413cdSMasahiro Yamada const struct of_device_id *match;
471013413cdSMasahiro Yamada u32 i;
472013413cdSMasahiro Yamada int dual_link;
473013413cdSMasahiro Yamada int ret;
474013413cdSMasahiro Yamada
475013413cdSMasahiro Yamada /* Locate the companion LDB for dual-link operation, if any. */
476013413cdSMasahiro Yamada companion = of_parse_phandle(dev->of_node, "fsl,companion-ldb", 0);
477013413cdSMasahiro Yamada if (!companion)
478013413cdSMasahiro Yamada return 0;
479013413cdSMasahiro Yamada
480013413cdSMasahiro Yamada if (!of_device_is_available(companion)) {
481013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "companion LDB is not available\n");
482013413cdSMasahiro Yamada ret = -ENODEV;
483013413cdSMasahiro Yamada goto out;
484013413cdSMasahiro Yamada }
485013413cdSMasahiro Yamada
486013413cdSMasahiro Yamada /*
487013413cdSMasahiro Yamada * Sanity check: the companion bridge must have the same compatible
488013413cdSMasahiro Yamada * string.
489013413cdSMasahiro Yamada */
490013413cdSMasahiro Yamada match = of_match_device(dev->driver->of_match_table, dev);
491013413cdSMasahiro Yamada if (!of_device_is_compatible(companion, match->compatible)) {
492013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "companion LDB is incompatible\n");
493013413cdSMasahiro Yamada ret = -ENXIO;
494013413cdSMasahiro Yamada goto out;
495013413cdSMasahiro Yamada }
496013413cdSMasahiro Yamada
497013413cdSMasahiro Yamada for_each_available_child_of_node(companion, child) {
498013413cdSMasahiro Yamada ret = of_property_read_u32(child, "reg", &i);
499013413cdSMasahiro Yamada if (ret || i > MAX_LDB_CHAN_NUM - 1) {
500013413cdSMasahiro Yamada DRM_DEV_ERROR(dev,
501013413cdSMasahiro Yamada "invalid channel node address: %u\n", i);
502013413cdSMasahiro Yamada ret = -EINVAL;
503013413cdSMasahiro Yamada of_node_put(child);
504013413cdSMasahiro Yamada goto out;
505013413cdSMasahiro Yamada }
506013413cdSMasahiro Yamada
507013413cdSMasahiro Yamada /*
508013413cdSMasahiro Yamada * Channel numbers have to be different, because channel0
509013413cdSMasahiro Yamada * transmits odd pixels and channel1 transmits even pixels.
510013413cdSMasahiro Yamada */
511013413cdSMasahiro Yamada if (i == (ldb_ch->chno ^ 0x1)) {
512013413cdSMasahiro Yamada companion_port = child;
513013413cdSMasahiro Yamada break;
514013413cdSMasahiro Yamada }
515013413cdSMasahiro Yamada }
516013413cdSMasahiro Yamada
517013413cdSMasahiro Yamada if (!companion_port) {
518013413cdSMasahiro Yamada DRM_DEV_ERROR(dev,
519013413cdSMasahiro Yamada "failed to find companion LDB channel port\n");
520013413cdSMasahiro Yamada ret = -EINVAL;
521013413cdSMasahiro Yamada goto out;
522013413cdSMasahiro Yamada }
523013413cdSMasahiro Yamada
524013413cdSMasahiro Yamada /*
525013413cdSMasahiro Yamada * We need to work out if the sink is expecting us to function in
526013413cdSMasahiro Yamada * dual-link mode. We do this by looking at the DT port nodes we are
527013413cdSMasahiro Yamada * connected to. If they are marked as expecting odd pixels and
528013413cdSMasahiro Yamada * even pixels than we need to enable LDB split mode.
529013413cdSMasahiro Yamada */
530013413cdSMasahiro Yamada port1 = of_graph_get_port_by_id(ldb_ch->np, 1);
531013413cdSMasahiro Yamada port2 = of_graph_get_port_by_id(companion_port, 1);
532013413cdSMasahiro Yamada dual_link = drm_of_lvds_get_dual_link_pixel_order(port1, port2);
533013413cdSMasahiro Yamada of_node_put(port1);
534013413cdSMasahiro Yamada of_node_put(port2);
535013413cdSMasahiro Yamada
536013413cdSMasahiro Yamada switch (dual_link) {
537013413cdSMasahiro Yamada case DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS:
538013413cdSMasahiro Yamada ldb_ch->link_type = LDB_CH_DUAL_LINK_ODD_EVEN_PIXELS;
539013413cdSMasahiro Yamada break;
540013413cdSMasahiro Yamada case DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS:
541013413cdSMasahiro Yamada ldb_ch->link_type = LDB_CH_DUAL_LINK_EVEN_ODD_PIXELS;
542013413cdSMasahiro Yamada break;
543013413cdSMasahiro Yamada default:
544013413cdSMasahiro Yamada ret = dual_link;
545013413cdSMasahiro Yamada DRM_DEV_ERROR(dev,
546013413cdSMasahiro Yamada "failed to get dual link pixel order: %d\n", ret);
547013413cdSMasahiro Yamada goto out;
548013413cdSMasahiro Yamada }
549013413cdSMasahiro Yamada
550013413cdSMasahiro Yamada ret = imx8qxp_ldb_check_chno_and_dual_link(ldb_ch, dual_link);
551013413cdSMasahiro Yamada if (ret < 0) {
552013413cdSMasahiro Yamada DRM_DEV_ERROR(dev,
553013413cdSMasahiro Yamada "unmatched channel number(%u) vs dual link(%d)\n",
554013413cdSMasahiro Yamada ldb_ch->chno, dual_link);
555013413cdSMasahiro Yamada goto out;
556013413cdSMasahiro Yamada }
557013413cdSMasahiro Yamada
558013413cdSMasahiro Yamada imx8qxp_ldb->companion = of_drm_find_bridge(companion_port);
559013413cdSMasahiro Yamada if (!imx8qxp_ldb->companion) {
560013413cdSMasahiro Yamada ret = -EPROBE_DEFER;
561013413cdSMasahiro Yamada DRM_DEV_DEBUG_DRIVER(dev,
562013413cdSMasahiro Yamada "failed to find bridge for companion bridge: %d\n",
563013413cdSMasahiro Yamada ret);
564013413cdSMasahiro Yamada goto out;
565013413cdSMasahiro Yamada }
566013413cdSMasahiro Yamada
567013413cdSMasahiro Yamada DRM_DEV_DEBUG_DRIVER(dev,
568013413cdSMasahiro Yamada "dual-link configuration detected (companion bridge %pOF)\n",
569013413cdSMasahiro Yamada companion);
570013413cdSMasahiro Yamada
571013413cdSMasahiro Yamada companion_ldb_ch = bridge_to_ldb_ch(imx8qxp_ldb->companion);
572013413cdSMasahiro Yamada companion_ldb_ch->link_type = ldb_ch->link_type;
573013413cdSMasahiro Yamada out:
574013413cdSMasahiro Yamada of_node_put(companion_port);
575013413cdSMasahiro Yamada of_node_put(companion);
576013413cdSMasahiro Yamada return ret;
577013413cdSMasahiro Yamada }
578013413cdSMasahiro Yamada
imx8qxp_ldb_probe(struct platform_device * pdev)579013413cdSMasahiro Yamada static int imx8qxp_ldb_probe(struct platform_device *pdev)
580013413cdSMasahiro Yamada {
581013413cdSMasahiro Yamada struct device *dev = &pdev->dev;
582013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb;
583013413cdSMasahiro Yamada struct imx8qxp_ldb_channel *imx8qxp_ldb_ch;
584013413cdSMasahiro Yamada struct ldb *ldb;
585013413cdSMasahiro Yamada struct ldb_channel *ldb_ch;
586013413cdSMasahiro Yamada int ret, i;
587013413cdSMasahiro Yamada
588013413cdSMasahiro Yamada imx8qxp_ldb = devm_kzalloc(dev, sizeof(*imx8qxp_ldb), GFP_KERNEL);
589013413cdSMasahiro Yamada if (!imx8qxp_ldb)
590013413cdSMasahiro Yamada return -ENOMEM;
591013413cdSMasahiro Yamada
592013413cdSMasahiro Yamada imx8qxp_ldb->clk_pixel = devm_clk_get(dev, "pixel");
593013413cdSMasahiro Yamada if (IS_ERR(imx8qxp_ldb->clk_pixel)) {
594013413cdSMasahiro Yamada ret = PTR_ERR(imx8qxp_ldb->clk_pixel);
595013413cdSMasahiro Yamada if (ret != -EPROBE_DEFER)
596013413cdSMasahiro Yamada DRM_DEV_ERROR(dev,
597013413cdSMasahiro Yamada "failed to get pixel clock: %d\n", ret);
598013413cdSMasahiro Yamada return ret;
599013413cdSMasahiro Yamada }
600013413cdSMasahiro Yamada
601013413cdSMasahiro Yamada imx8qxp_ldb->clk_bypass = devm_clk_get(dev, "bypass");
602013413cdSMasahiro Yamada if (IS_ERR(imx8qxp_ldb->clk_bypass)) {
603013413cdSMasahiro Yamada ret = PTR_ERR(imx8qxp_ldb->clk_bypass);
604013413cdSMasahiro Yamada if (ret != -EPROBE_DEFER)
605013413cdSMasahiro Yamada DRM_DEV_ERROR(dev,
606013413cdSMasahiro Yamada "failed to get bypass clock: %d\n", ret);
607013413cdSMasahiro Yamada return ret;
608013413cdSMasahiro Yamada }
609013413cdSMasahiro Yamada
610013413cdSMasahiro Yamada imx8qxp_ldb->dev = dev;
611013413cdSMasahiro Yamada
612013413cdSMasahiro Yamada ldb = &imx8qxp_ldb->base;
613013413cdSMasahiro Yamada ldb->dev = dev;
614013413cdSMasahiro Yamada ldb->ctrl_reg = 0xe0;
615013413cdSMasahiro Yamada
616013413cdSMasahiro Yamada for (i = 0; i < MAX_LDB_CHAN_NUM; i++)
617013413cdSMasahiro Yamada ldb->channel[i] = &imx8qxp_ldb->channel[i].base;
618013413cdSMasahiro Yamada
619013413cdSMasahiro Yamada ret = ldb_init_helper(ldb);
620013413cdSMasahiro Yamada if (ret)
621013413cdSMasahiro Yamada return ret;
622013413cdSMasahiro Yamada
623013413cdSMasahiro Yamada if (ldb->available_ch_cnt == 0) {
624013413cdSMasahiro Yamada DRM_DEV_DEBUG_DRIVER(dev, "no available channel\n");
625013413cdSMasahiro Yamada return 0;
626013413cdSMasahiro Yamada } else if (ldb->available_ch_cnt > 1) {
627013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "invalid available channel number(%u)\n",
628013413cdSMasahiro Yamada ldb->available_ch_cnt);
629013413cdSMasahiro Yamada return -EINVAL;
630013413cdSMasahiro Yamada }
631013413cdSMasahiro Yamada
632013413cdSMasahiro Yamada for (i = 0; i < MAX_LDB_CHAN_NUM; i++) {
633013413cdSMasahiro Yamada imx8qxp_ldb_ch = &imx8qxp_ldb->channel[i];
634013413cdSMasahiro Yamada ldb_ch = &imx8qxp_ldb_ch->base;
635013413cdSMasahiro Yamada
636013413cdSMasahiro Yamada if (ldb_ch->is_available) {
637013413cdSMasahiro Yamada imx8qxp_ldb->active_chno = ldb_ch->chno;
638013413cdSMasahiro Yamada break;
639013413cdSMasahiro Yamada }
640013413cdSMasahiro Yamada }
641013413cdSMasahiro Yamada
642013413cdSMasahiro Yamada imx8qxp_ldb_ch->phy = devm_of_phy_get(dev, ldb_ch->np, "lvds_phy");
643013413cdSMasahiro Yamada if (IS_ERR(imx8qxp_ldb_ch->phy)) {
644013413cdSMasahiro Yamada ret = PTR_ERR(imx8qxp_ldb_ch->phy);
645013413cdSMasahiro Yamada if (ret != -EPROBE_DEFER)
646013413cdSMasahiro Yamada DRM_DEV_ERROR(dev, "failed to get channel%d PHY: %d\n",
647013413cdSMasahiro Yamada imx8qxp_ldb->active_chno, ret);
648013413cdSMasahiro Yamada return ret;
649013413cdSMasahiro Yamada }
650013413cdSMasahiro Yamada
651013413cdSMasahiro Yamada ret = ldb_find_next_bridge_helper(ldb);
652013413cdSMasahiro Yamada if (ret)
653013413cdSMasahiro Yamada return ret;
654013413cdSMasahiro Yamada
655013413cdSMasahiro Yamada ret = imx8qxp_ldb_set_di_id(imx8qxp_ldb);
656013413cdSMasahiro Yamada if (ret)
657013413cdSMasahiro Yamada return ret;
658013413cdSMasahiro Yamada
659013413cdSMasahiro Yamada ret = imx8qxp_ldb_parse_dt_companion(imx8qxp_ldb);
660013413cdSMasahiro Yamada if (ret)
661013413cdSMasahiro Yamada return ret;
662013413cdSMasahiro Yamada
663013413cdSMasahiro Yamada platform_set_drvdata(pdev, imx8qxp_ldb);
664013413cdSMasahiro Yamada pm_runtime_enable(dev);
665013413cdSMasahiro Yamada
666013413cdSMasahiro Yamada ldb_add_bridge_helper(ldb, &imx8qxp_ldb_bridge_funcs);
667013413cdSMasahiro Yamada
668013413cdSMasahiro Yamada return ret;
669013413cdSMasahiro Yamada }
670013413cdSMasahiro Yamada
imx8qxp_ldb_remove(struct platform_device * pdev)671013413cdSMasahiro Yamada static void imx8qxp_ldb_remove(struct platform_device *pdev)
672013413cdSMasahiro Yamada {
673013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb = platform_get_drvdata(pdev);
674013413cdSMasahiro Yamada struct ldb *ldb = &imx8qxp_ldb->base;
675013413cdSMasahiro Yamada
676013413cdSMasahiro Yamada ldb_remove_bridge_helper(ldb);
677013413cdSMasahiro Yamada
678013413cdSMasahiro Yamada pm_runtime_disable(&pdev->dev);
679013413cdSMasahiro Yamada }
680013413cdSMasahiro Yamada
imx8qxp_ldb_runtime_suspend(struct device * dev)681013413cdSMasahiro Yamada static int __maybe_unused imx8qxp_ldb_runtime_suspend(struct device *dev)
682013413cdSMasahiro Yamada {
683013413cdSMasahiro Yamada return 0;
684013413cdSMasahiro Yamada }
685013413cdSMasahiro Yamada
imx8qxp_ldb_runtime_resume(struct device * dev)686013413cdSMasahiro Yamada static int __maybe_unused imx8qxp_ldb_runtime_resume(struct device *dev)
687013413cdSMasahiro Yamada {
688013413cdSMasahiro Yamada struct imx8qxp_ldb *imx8qxp_ldb = dev_get_drvdata(dev);
689013413cdSMasahiro Yamada struct ldb *ldb = &imx8qxp_ldb->base;
690013413cdSMasahiro Yamada
691013413cdSMasahiro Yamada /* disable LDB by resetting the control register to POR default */
692013413cdSMasahiro Yamada regmap_write(ldb->regmap, ldb->ctrl_reg, 0);
693013413cdSMasahiro Yamada
694013413cdSMasahiro Yamada return 0;
695013413cdSMasahiro Yamada }
696013413cdSMasahiro Yamada
697013413cdSMasahiro Yamada static const struct dev_pm_ops imx8qxp_ldb_pm_ops = {
698013413cdSMasahiro Yamada SET_RUNTIME_PM_OPS(imx8qxp_ldb_runtime_suspend,
699013413cdSMasahiro Yamada imx8qxp_ldb_runtime_resume, NULL)
700013413cdSMasahiro Yamada };
701013413cdSMasahiro Yamada
702013413cdSMasahiro Yamada static const struct of_device_id imx8qxp_ldb_dt_ids[] = {
703013413cdSMasahiro Yamada { .compatible = "fsl,imx8qxp-ldb" },
704013413cdSMasahiro Yamada { /* sentinel */ }
705013413cdSMasahiro Yamada };
706013413cdSMasahiro Yamada MODULE_DEVICE_TABLE(of, imx8qxp_ldb_dt_ids);
707013413cdSMasahiro Yamada
708013413cdSMasahiro Yamada static struct platform_driver imx8qxp_ldb_driver = {
709013413cdSMasahiro Yamada .probe = imx8qxp_ldb_probe,
710013413cdSMasahiro Yamada .remove_new = imx8qxp_ldb_remove,
711013413cdSMasahiro Yamada .driver = {
712013413cdSMasahiro Yamada .pm = &imx8qxp_ldb_pm_ops,
713013413cdSMasahiro Yamada .name = DRIVER_NAME,
714013413cdSMasahiro Yamada .of_match_table = imx8qxp_ldb_dt_ids,
715013413cdSMasahiro Yamada },
716013413cdSMasahiro Yamada };
717013413cdSMasahiro Yamada module_platform_driver(imx8qxp_ldb_driver);
718013413cdSMasahiro Yamada
719013413cdSMasahiro Yamada MODULE_DESCRIPTION("i.MX8QXP LVDS Display Bridge(LDB)/Pixel Mapper bridge driver");
720013413cdSMasahiro Yamada MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
721013413cdSMasahiro Yamada MODULE_LICENSE("GPL v2");
722013413cdSMasahiro Yamada MODULE_ALIAS("platform:" DRIVER_NAME);
723