Lines Matching +full:imx8qm +full:- +full:lvds +full:- +full:phy
1 // SPDX-License-Identifier: GPL-2.0+
8 #include <linux/media-bus-format.h>
13 #include <linux/phy/phy.h>
25 #include "imx-ldb-helper.h"
40 #define DRIVER_NAME "imx8qm-ldb"
44 struct phy *phy; member
72 phy_cfg->bits_per_lane_and_dclk_cycle = 7; in imx8qm_ldb_set_phy_cfg()
73 phy_cfg->lanes = 4; in imx8qm_ldb_set_phy_cfg()
74 phy_cfg->differential_clk_rate = is_split ? di_clk / 2 : di_clk; in imx8qm_ldb_set_phy_cfg()
75 phy_cfg->is_slave = is_slave; in imx8qm_ldb_set_phy_cfg()
83 struct ldb_channel *ldb_ch = bridge->driver_private; in imx8qm_ldb_bridge_atomic_check()
84 struct ldb *ldb = ldb_ch->ldb; in imx8qm_ldb_bridge_atomic_check()
88 struct drm_display_mode *adj = &crtc_state->adjusted_mode; in imx8qm_ldb_bridge_atomic_check()
89 unsigned long di_clk = adj->clock * 1000; in imx8qm_ldb_bridge_atomic_check()
92 struct phy_configure_opts_lvds *phy_cfg = &opts.lvds; in imx8qm_ldb_bridge_atomic_check()
101 ret = phy_validate(imx8qm_ldb_ch->phy, PHY_MODE_LVDS, 0, &opts); in imx8qm_ldb_bridge_atomic_check()
103 DRM_DEV_DEBUG_DRIVER(imx8qm_ldb->dev, in imx8qm_ldb_bridge_atomic_check()
104 "failed to validate PHY: %d\n", ret); in imx8qm_ldb_bridge_atomic_check()
110 &imx8qm_ldb->channel[imx8qm_ldb->active_chno ^ 1]; in imx8qm_ldb_bridge_atomic_check()
113 ret = phy_validate(imx8qm_ldb_ch->phy, PHY_MODE_LVDS, 0, &opts); in imx8qm_ldb_bridge_atomic_check()
115 DRM_DEV_DEBUG_DRIVER(imx8qm_ldb->dev, in imx8qm_ldb_bridge_atomic_check()
116 "failed to validate slave PHY: %d\n", in imx8qm_ldb_bridge_atomic_check()
130 struct ldb_channel *ldb_ch = bridge->driver_private; in imx8qm_ldb_bridge_mode_set()
131 struct ldb *ldb = ldb_ch->ldb; in imx8qm_ldb_bridge_mode_set()
135 struct device *dev = imx8qm_ldb->dev; in imx8qm_ldb_bridge_mode_set()
136 unsigned long di_clk = adjusted_mode->clock * 1000; in imx8qm_ldb_bridge_mode_set()
139 struct phy_configure_opts_lvds *phy_cfg = &opts.lvds; in imx8qm_ldb_bridge_mode_set()
140 u32 chno = ldb_ch->chno; in imx8qm_ldb_bridge_mode_set()
147 ret = phy_init(imx8qm_ldb_ch->phy); in imx8qm_ldb_bridge_mode_set()
149 DRM_DEV_ERROR(dev, "failed to initialize PHY: %d\n", ret); in imx8qm_ldb_bridge_mode_set()
151 clk_set_rate(imx8qm_ldb->clk_bypass, di_clk); in imx8qm_ldb_bridge_mode_set()
152 clk_set_rate(imx8qm_ldb->clk_pixel, di_clk); in imx8qm_ldb_bridge_mode_set()
155 ret = phy_configure(imx8qm_ldb_ch->phy, &opts); in imx8qm_ldb_bridge_mode_set()
157 DRM_DEV_ERROR(dev, "failed to configure PHY: %d\n", ret); in imx8qm_ldb_bridge_mode_set()
161 &imx8qm_ldb->channel[imx8qm_ldb->active_chno ^ 1]; in imx8qm_ldb_bridge_mode_set()
164 ret = phy_configure(imx8qm_ldb_ch->phy, &opts); in imx8qm_ldb_bridge_mode_set()
166 DRM_DEV_ERROR(dev, "failed to configure slave PHY: %d\n", in imx8qm_ldb_bridge_mode_set()
171 if (ldb_ch->chno == 0 || is_split) in imx8qm_ldb_bridge_mode_set()
172 ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW; in imx8qm_ldb_bridge_mode_set()
173 if (ldb_ch->chno == 1 || is_split) in imx8qm_ldb_bridge_mode_set()
174 ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW; in imx8qm_ldb_bridge_mode_set()
176 switch (ldb_ch->out_bus_format) { in imx8qm_ldb_bridge_mode_set()
181 if (ldb_ch->chno == 0 || is_split) in imx8qm_ldb_bridge_mode_set()
182 ldb->ldb_ctrl |= LDB_CH0_DATA_WIDTH_24BIT; in imx8qm_ldb_bridge_mode_set()
183 if (ldb_ch->chno == 1 || is_split) in imx8qm_ldb_bridge_mode_set()
184 ldb->ldb_ctrl |= LDB_CH1_DATA_WIDTH_24BIT; in imx8qm_ldb_bridge_mode_set()
190 if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) in imx8qm_ldb_bridge_mode_set()
191 regmap_update_bits(ldb->regmap, SS_CTRL, CH_VSYNC_M(chno), 0); in imx8qm_ldb_bridge_mode_set()
192 else if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) in imx8qm_ldb_bridge_mode_set()
193 regmap_update_bits(ldb->regmap, SS_CTRL, in imx8qm_ldb_bridge_mode_set()
196 if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) in imx8qm_ldb_bridge_mode_set()
197 regmap_update_bits(ldb->regmap, SS_CTRL, CH_HSYNC_M(chno), 0); in imx8qm_ldb_bridge_mode_set()
198 else if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) in imx8qm_ldb_bridge_mode_set()
199 regmap_update_bits(ldb->regmap, SS_CTRL, in imx8qm_ldb_bridge_mode_set()
207 struct ldb_channel *ldb_ch = bridge->driver_private; in imx8qm_ldb_bridge_atomic_enable()
208 struct ldb *ldb = ldb_ch->ldb; in imx8qm_ldb_bridge_atomic_enable()
212 struct device *dev = imx8qm_ldb->dev; in imx8qm_ldb_bridge_atomic_enable()
216 clk_prepare_enable(imx8qm_ldb->clk_pixel); in imx8qm_ldb_bridge_atomic_enable()
217 clk_prepare_enable(imx8qm_ldb->clk_bypass); in imx8qm_ldb_bridge_atomic_enable()
220 if (ldb_ch->chno == 0 || is_split) { in imx8qm_ldb_bridge_atomic_enable()
221 ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK; in imx8qm_ldb_bridge_atomic_enable()
222 ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI0; in imx8qm_ldb_bridge_atomic_enable()
224 if (ldb_ch->chno == 1 || is_split) { in imx8qm_ldb_bridge_atomic_enable()
225 ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK; in imx8qm_ldb_bridge_atomic_enable()
226 ldb->ldb_ctrl |= LDB_CH1_MODE_EN_TO_DI0; in imx8qm_ldb_bridge_atomic_enable()
230 ret = phy_power_on(imx8qm_ldb->channel[0].phy); in imx8qm_ldb_bridge_atomic_enable()
233 "failed to power on channel0 PHY: %d\n", in imx8qm_ldb_bridge_atomic_enable()
236 ret = phy_power_on(imx8qm_ldb->channel[1].phy); in imx8qm_ldb_bridge_atomic_enable()
239 "failed to power on channel1 PHY: %d\n", in imx8qm_ldb_bridge_atomic_enable()
242 ret = phy_power_on(imx8qm_ldb_ch->phy); in imx8qm_ldb_bridge_atomic_enable()
244 DRM_DEV_ERROR(dev, "failed to power on PHY: %d\n", ret); in imx8qm_ldb_bridge_atomic_enable()
254 struct ldb_channel *ldb_ch = bridge->driver_private; in imx8qm_ldb_bridge_atomic_disable()
255 struct ldb *ldb = ldb_ch->ldb; in imx8qm_ldb_bridge_atomic_disable()
259 struct device *dev = imx8qm_ldb->dev; in imx8qm_ldb_bridge_atomic_disable()
266 ret = phy_power_off(imx8qm_ldb->channel[0].phy); in imx8qm_ldb_bridge_atomic_disable()
269 "failed to power off channel0 PHY: %d\n", in imx8qm_ldb_bridge_atomic_disable()
271 ret = phy_power_off(imx8qm_ldb->channel[1].phy); in imx8qm_ldb_bridge_atomic_disable()
274 "failed to power off channel1 PHY: %d\n", in imx8qm_ldb_bridge_atomic_disable()
277 ret = phy_power_off(imx8qm_ldb_ch->phy); in imx8qm_ldb_bridge_atomic_disable()
279 DRM_DEV_ERROR(dev, "failed to power off PHY: %d\n", ret); in imx8qm_ldb_bridge_atomic_disable()
282 clk_disable_unprepare(imx8qm_ldb->clk_bypass); in imx8qm_ldb_bridge_atomic_disable()
283 clk_disable_unprepare(imx8qm_ldb->clk_pixel); in imx8qm_ldb_bridge_atomic_disable()
332 di = &conn_state->connector->display_info; in imx8qm_ldb_bridge_atomic_get_input_bus_fmts()
338 if (di->num_bus_formats) { in imx8qm_ldb_bridge_atomic_get_input_bus_fmts()
339 finfo = drm_format_info(di->bus_formats[0]); in imx8qm_ldb_bridge_atomic_get_input_bus_fmts()
341 input_fmts[0] = finfo->depth == 18 ? in imx8qm_ldb_bridge_atomic_get_input_bus_fmts()
381 struct ldb_channel *ldb_ch = bridge->driver_private; in imx8qm_ldb_bridge_mode_valid()
384 if (mode->clock > 300000) in imx8qm_ldb_bridge_mode_valid()
387 if (mode->clock > 150000 && is_single) in imx8qm_ldb_bridge_mode_valid()
413 struct device *dev = imx8qm_ldb->dev; in imx8qm_ldb_get_phy()
417 imx8qm_ldb_ch = &imx8qm_ldb->channel[i]; in imx8qm_ldb_get_phy()
418 ldb_ch = &imx8qm_ldb_ch->base; in imx8qm_ldb_get_phy()
420 if (!ldb_ch->is_available) in imx8qm_ldb_get_phy()
423 imx8qm_ldb_ch->phy = devm_of_phy_get(dev, ldb_ch->np, in imx8qm_ldb_get_phy()
425 if (IS_ERR(imx8qm_ldb_ch->phy)) { in imx8qm_ldb_get_phy()
426 ret = PTR_ERR(imx8qm_ldb_ch->phy); in imx8qm_ldb_get_phy()
427 if (ret != -EPROBE_DEFER) in imx8qm_ldb_get_phy()
429 "failed to get channel%d PHY: %d\n", in imx8qm_ldb_get_phy()
440 struct device *dev = &pdev->dev; in imx8qm_ldb_probe()
451 return -ENOMEM; in imx8qm_ldb_probe()
453 imx8qm_ldb->clk_pixel = devm_clk_get(dev, "pixel"); in imx8qm_ldb_probe()
454 if (IS_ERR(imx8qm_ldb->clk_pixel)) { in imx8qm_ldb_probe()
455 ret = PTR_ERR(imx8qm_ldb->clk_pixel); in imx8qm_ldb_probe()
456 if (ret != -EPROBE_DEFER) in imx8qm_ldb_probe()
462 imx8qm_ldb->clk_bypass = devm_clk_get(dev, "bypass"); in imx8qm_ldb_probe()
463 if (IS_ERR(imx8qm_ldb->clk_bypass)) { in imx8qm_ldb_probe()
464 ret = PTR_ERR(imx8qm_ldb->clk_bypass); in imx8qm_ldb_probe()
465 if (ret != -EPROBE_DEFER) in imx8qm_ldb_probe()
471 imx8qm_ldb->dev = dev; in imx8qm_ldb_probe()
473 ldb = &imx8qm_ldb->base; in imx8qm_ldb_probe()
474 ldb->dev = dev; in imx8qm_ldb_probe()
475 ldb->ctrl_reg = 0xe0; in imx8qm_ldb_probe()
478 ldb->channel[i] = &imx8qm_ldb->channel[i].base; in imx8qm_ldb_probe()
484 if (ldb->available_ch_cnt == 0) { in imx8qm_ldb_probe()
489 if (ldb->available_ch_cnt == 2) { in imx8qm_ldb_probe()
490 port1 = of_graph_get_port_by_id(ldb->channel[0]->np, 1); in imx8qm_ldb_probe()
491 port2 = of_graph_get_port_by_id(ldb->channel[1]->np, 1); in imx8qm_ldb_probe()
500 return -EINVAL; in imx8qm_ldb_probe()
503 imx8qm_ldb->active_chno = 0; in imx8qm_ldb_probe()
504 imx8qm_ldb_ch = &imx8qm_ldb->channel[0]; in imx8qm_ldb_probe()
505 ldb_ch = &imx8qm_ldb_ch->base; in imx8qm_ldb_probe()
506 ldb_ch->link_type = pixel_order; in imx8qm_ldb_probe()
509 imx8qm_ldb_ch = &imx8qm_ldb->channel[i]; in imx8qm_ldb_probe()
510 ldb_ch = &imx8qm_ldb_ch->base; in imx8qm_ldb_probe()
512 if (ldb_ch->is_available) { in imx8qm_ldb_probe()
513 imx8qm_ldb->active_chno = ldb_ch->chno; in imx8qm_ldb_probe()
538 struct ldb *ldb = &imx8qm_ldb->base; in imx8qm_ldb_remove()
542 pm_runtime_disable(&pdev->dev); in imx8qm_ldb_remove()
553 struct ldb *ldb = &imx8qm_ldb->base; in imx8qm_ldb_runtime_resume()
556 regmap_write(ldb->regmap, ldb->ctrl_reg, 0); in imx8qm_ldb_runtime_resume()
567 { .compatible = "fsl,imx8qm-ldb" },
583 MODULE_DESCRIPTION("i.MX8QM LVDS Display Bridge(LDB)/Pixel Mapper bridge driver");