Lines Matching +full:dual +full:- +full:link

1 // SPDX-License-Identifier: GPL-2.0+
8 #include <linux/media-bus-format.h>
26 #include "imx-ldb-helper.h"
36 #define DRIVER_NAME "imx8qxp-ldb"
69 phy_cfg->bits_per_lane_and_dclk_cycle = 7;
70 phy_cfg->lanes = 4;
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;
87 struct ldb_channel *ldb_ch = bridge->driver_private;
88 struct ldb *ldb = ldb_ch->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;
106 ret = phy_validate(imx8qxp_ldb_ch->phy, PHY_MODE_LVDS, 0, &opts);
108 DRM_DEV_DEBUG_DRIVER(imx8qxp_ldb->dev,
114 ret = companion->funcs->atomic_check(companion,
128 struct ldb_channel *ldb_ch = bridge->driver_private;
130 struct ldb *ldb = ldb_ch->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;
140 u32 chno = ldb_ch->chno;
147 ret = phy_init(imx8qxp_ldb_ch->phy);
151 ret = phy_set_mode(imx8qxp_ldb_ch->phy, PHY_MODE_LVDS);
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);
166 ret = phy_configure(imx8qxp_ldb_ch->phy, &opts);
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;
186 regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ldb_ctrl);
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,
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,
203 companion->funcs->mode_set(companion, mode, adjusted_mode);
209 struct ldb_channel *ldb_ch = bridge->driver_private;
210 struct ldb *ldb = ldb_ch->ldb;
212 struct drm_bridge *companion = imx8qxp_ldb->companion;
215 clk_prepare_enable(imx8qxp_ldb->clk_pixel);
216 clk_prepare_enable(imx8qxp_ldb->clk_bypass);
219 companion->funcs->atomic_pre_enable(companion, state);
225 struct ldb_channel *ldb_ch = bridge->driver_private;
226 struct ldb *ldb = ldb_ch->ldb;
230 struct drm_bridge *companion = imx8qxp_ldb->companion;
231 struct device *dev = imx8qxp_ldb->dev;
235 if (ldb_ch->chno == 0 || is_split) {
236 ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
237 ldb->ldb_ctrl |= imx8qxp_ldb_ch->di_id == 0 ?
240 if (ldb_ch->chno == 1 || is_split) {
241 ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
242 ldb->ldb_ctrl |= imx8qxp_ldb_ch->di_id == 0 ?
248 ret = phy_power_on(imx8qxp_ldb_ch->phy);
253 companion->funcs->atomic_enable(companion, state);
259 struct ldb_channel *ldb_ch = bridge->driver_private;
260 struct ldb *ldb = ldb_ch->ldb;
264 struct drm_bridge *companion = imx8qxp_ldb->companion;
265 struct device *dev = imx8qxp_ldb->dev;
269 ret = phy_power_off(imx8qxp_ldb_ch->phy);
273 ret = phy_exit(imx8qxp_ldb_ch->phy);
279 clk_disable_unprepare(imx8qxp_ldb->clk_bypass);
280 clk_disable_unprepare(imx8qxp_ldb->clk_pixel);
283 companion->funcs->atomic_disable(companion, state);
332 di = &conn_state->connector->display_info;
338 if (di->num_bus_formats) {
339 finfo = drm_format_info(di->bus_formats[0]);
341 input_fmts[0] = finfo->depth == 18 ?
381 struct ldb_channel *ldb_ch = bridge->driver_private;
384 if (mode->clock > 170000)
387 if (mode->clock > 150000 && is_single)
413 imx8qxp_ldb->channel[imx8qxp_ldb->active_chno];
414 struct ldb_channel *ldb_ch = &imx8qxp_ldb_ch->base;
416 struct device *dev = imx8qxp_ldb->dev;
420 ep = of_graph_get_endpoint_by_regs(ldb_ch->np, 0, -1);
423 return -EINVAL;
430 return -EINVAL;
441 imx8qxp_ldb_ch->di_id = endpoint.id;
447 imx8qxp_ldb_check_chno_and_dual_link(struct ldb_channel *ldb_ch, int link)
449 if ((link == DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS && ldb_ch->chno != 0) ||
450 (link == DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS && ldb_ch->chno != 1))
451 return -EINVAL;
459 imx8qxp_ldb->channel[imx8qxp_ldb->active_chno];
460 struct ldb_channel *ldb_ch = &imx8qxp_ldb_ch->base;
466 struct device *dev = imx8qxp_ldb->dev;
472 /* Locate the companion LDB for dual-link operation, if any. */
473 companion = of_parse_phandle(dev->of_node, "fsl,companion-ldb", 0);
479 ret = -ENODEV;
487 match = of_match_device(dev->driver->of_match_table, dev);
488 if (!of_device_is_compatible(companion, match->compatible)) {
490 ret = -ENXIO;
496 if (ret || i > MAX_LDB_CHAN_NUM - 1) {
499 ret = -EINVAL;
508 if (i == (ldb_ch->chno ^ 0x1)) {
517 ret = -EINVAL;
523 * dual-link mode. We do this by looking at the DT port nodes we are
527 port1 = of_graph_get_port_by_id(ldb_ch->np, 1);
535 ldb_ch->link_type = LDB_CH_DUAL_LINK_ODD_EVEN_PIXELS;
538 ldb_ch->link_type = LDB_CH_DUAL_LINK_EVEN_ODD_PIXELS;
543 "failed to get dual link pixel order: %d\n", ret);
550 "unmatched channel number(%u) vs dual link(%d)\n",
551 ldb_ch->chno, dual_link);
555 imx8qxp_ldb->companion = of_drm_find_bridge(companion_port);
556 if (!imx8qxp_ldb->companion) {
557 ret = -EPROBE_DEFER;
565 "dual-link configuration detected (companion bridge %pOF)\n",
568 companion_ldb_ch = bridge_to_ldb_ch(imx8qxp_ldb->companion);
569 companion_ldb_ch->link_type = ldb_ch->link_type;
578 struct device *dev = &pdev->dev;
587 return -ENOMEM;
590 imx8qxp_ldb->channel[i] =
593 if (IS_ERR(imx8qxp_ldb->channel[i]))
594 return PTR_ERR(imx8qxp_ldb->channel[i]);
597 imx8qxp_ldb->clk_pixel = devm_clk_get(dev, "pixel");
598 if (IS_ERR(imx8qxp_ldb->clk_pixel)) {
599 ret = PTR_ERR(imx8qxp_ldb->clk_pixel);
600 if (ret != -EPROBE_DEFER)
606 imx8qxp_ldb->clk_bypass = devm_clk_get(dev, "bypass");
607 if (IS_ERR(imx8qxp_ldb->clk_bypass)) {
608 ret = PTR_ERR(imx8qxp_ldb->clk_bypass);
609 if (ret != -EPROBE_DEFER)
615 imx8qxp_ldb->dev = dev;
617 ldb = &imx8qxp_ldb->base;
618 ldb->dev = dev;
619 ldb->ctrl_reg = 0xe0;
622 ldb->channel[i] = &imx8qxp_ldb->channel[i]->base;
628 if (ldb->available_ch_cnt == 0) {
631 } else if (ldb->available_ch_cnt > 1) {
633 ldb->available_ch_cnt);
634 return -EINVAL;
638 imx8qxp_ldb_ch = imx8qxp_ldb->channel[i];
639 ldb_ch = &imx8qxp_ldb_ch->base;
641 if (ldb_ch->is_available) {
642 imx8qxp_ldb->active_chno = ldb_ch->chno;
647 imx8qxp_ldb_ch->phy = devm_of_phy_get(dev, ldb_ch->np, "lvds_phy");
648 if (IS_ERR(imx8qxp_ldb_ch->phy)) {
649 ret = PTR_ERR(imx8qxp_ldb_ch->phy);
650 if (ret != -EPROBE_DEFER)
652 imx8qxp_ldb->active_chno, ret);
679 struct ldb *ldb = &imx8qxp_ldb->base;
683 pm_runtime_disable(&pdev->dev);
694 struct ldb *ldb = &imx8qxp_ldb->base;
697 regmap_write(ldb->regmap, ldb->ctrl_reg, 0);
707 { .compatible = "fsl,imx8qxp-ldb" },