Lines Matching +full:lvds +full:- +full:bridge

1 // SPDX-License-Identifier: GPL-2.0
3 * Lontium LT9211 bridge driver
6 * 2xDSI/2xLVDS/1xDPI -> 2xDSI/2xLVDS/1xDPI
8 * 1xDSI -> 1xLVDS
17 #include <linux/media-bus-format.h>
40 /* DSI lane count - 0 means 4 lanes ; 1, 2, 3 means 1, 2, 3 lanes. */
44 struct drm_bridge bridge; member
96 static struct lt9211 *bridge_to_lt9211(struct drm_bridge *bridge) in bridge_to_lt9211() argument
98 return container_of(bridge, struct lt9211, bridge); in bridge_to_lt9211()
101 static int lt9211_attach(struct drm_bridge *bridge, in lt9211_attach() argument
104 struct lt9211 *ctx = bridge_to_lt9211(bridge); in lt9211_attach()
106 return drm_bridge_attach(bridge->encoder, ctx->panel_bridge, in lt9211_attach()
107 &ctx->bridge, flags); in lt9211_attach()
116 ret = regmap_bulk_read(ctx->regmap, REG_CHIPID0, chipid, 3); in lt9211_read_chipid()
118 dev_err(ctx->dev, "Failed to read Chip ID: %d\n", ret); in lt9211_read_chipid()
125 dev_err(ctx->dev, "Unknown Chip ID: 0x%02x 0x%02x 0x%02x\n", in lt9211_read_chipid()
127 return -EINVAL; in lt9211_read_chipid()
148 return regmap_multi_reg_write(ctx->regmap, lt9211_system_init_seq, in lt9211_system_init()
173 /* 0x8588: BIT 6 set = MIPI-RX, BIT 4 unset = LVDS-TX */ in lt9211_configure_rx()
176 { REG_DSI_LANE, REG_DSI_LANE_COUNT(ctx->dsi->lanes) }, in lt9211_configure_rx()
192 ret = regmap_multi_reg_write(ctx->regmap, lt9211_rx_phy_seq, in lt9211_configure_rx()
197 ret = regmap_multi_reg_write(ctx->regmap, lt9211_rx_cal_reset_seq, in lt9211_configure_rx()
202 ret = regmap_multi_reg_write(ctx->regmap, lt9211_rx_dig_seq, in lt9211_configure_rx()
207 ret = regmap_multi_reg_write(ctx->regmap, lt9211_rx_div_reset_seq, in lt9211_configure_rx()
214 return regmap_multi_reg_write(ctx->regmap, lt9211_rx_div_clear_seq, in lt9211_configure_rx()
229 ret = regmap_write(ctx->regmap, 0x8600, 0x01); in lt9211_autodetect_rx()
237 ret = regmap_bulk_read(ctx->regmap, 0x8608, bc, sizeof(bc)); in lt9211_autodetect_rx()
244 /* Width/Height/Format Auto-detection */ in lt9211_autodetect_rx()
245 ret = regmap_bulk_read(ctx->regmap, 0xd082, buf, sizeof(buf)); in lt9211_autodetect_rx()
258 dev_err(ctx->dev, "Unsupported DSI pixel format 0x%01x\n", in lt9211_autodetect_rx()
260 return -EINVAL; in lt9211_autodetect_rx()
263 if (width != mode->hdisplay) { in lt9211_autodetect_rx()
264 dev_err(ctx->dev, in lt9211_autodetect_rx()
266 width, mode->hdisplay); in lt9211_autodetect_rx()
267 return -EINVAL; in lt9211_autodetect_rx()
270 if (height != mode->vdisplay) { in lt9211_autodetect_rx()
271 dev_err(ctx->dev, in lt9211_autodetect_rx()
273 height, mode->vdisplay); in lt9211_autodetect_rx()
274 return -EINVAL; in lt9211_autodetect_rx()
277 dev_dbg(ctx->dev, "RX: %dx%d format=0x%01x byteclock=%d kHz\n", in lt9211_autodetect_rx()
287 { 0xd00d, (mode->vtotal >> 8) & 0xff }, in lt9211_configure_timing()
288 { 0xd00e, mode->vtotal & 0xff }, in lt9211_configure_timing()
289 { 0xd00f, (mode->vdisplay >> 8) & 0xff }, in lt9211_configure_timing()
290 { 0xd010, mode->vdisplay & 0xff }, in lt9211_configure_timing()
291 { 0xd011, (mode->htotal >> 8) & 0xff }, in lt9211_configure_timing()
292 { 0xd012, mode->htotal & 0xff }, in lt9211_configure_timing()
293 { 0xd013, (mode->hdisplay >> 8) & 0xff }, in lt9211_configure_timing()
294 { 0xd014, mode->hdisplay & 0xff }, in lt9211_configure_timing()
295 { 0xd015, (mode->vsync_end - mode->vsync_start) & 0xff }, in lt9211_configure_timing()
296 { 0xd016, (mode->hsync_end - mode->hsync_start) & 0xff }, in lt9211_configure_timing()
297 { 0xd017, ((mode->vsync_start - mode->vdisplay) >> 8) & 0xff }, in lt9211_configure_timing()
298 { 0xd018, (mode->vsync_start - mode->vdisplay) & 0xff }, in lt9211_configure_timing()
299 { 0xd019, ((mode->hsync_start - mode->hdisplay) >> 8) & 0xff }, in lt9211_configure_timing()
300 { 0xd01a, (mode->hsync_start - mode->hdisplay) & 0xff }, in lt9211_configure_timing()
303 return regmap_multi_reg_write(ctx->regmap, lt9211_timing, in lt9211_configure_timing()
331 ret = regmap_write(ctx->regmap, 0x822d, 0x48); in lt9211_configure_plls()
335 if (mode->clock < 44000) { in lt9211_configure_plls()
336 ret = regmap_write(ctx->regmap, 0x8235, 0x83); in lt9211_configure_plls()
337 } else if (mode->clock < 88000) { in lt9211_configure_plls()
338 ret = regmap_write(ctx->regmap, 0x8235, 0x82); in lt9211_configure_plls()
339 } else if (mode->clock < 176000) { in lt9211_configure_plls()
340 ret = regmap_write(ctx->regmap, 0x8235, 0x81); in lt9211_configure_plls()
342 dev_err(ctx->dev, in lt9211_configure_plls()
344 mode->clock); in lt9211_configure_plls()
345 return -EINVAL; in lt9211_configure_plls()
354 ret = regmap_multi_reg_write(ctx->regmap, lt9211_pcr_seq, in lt9211_configure_plls()
360 ret = regmap_read_poll_timeout(ctx->regmap, 0xd087, pval, pval & 0x8, in lt9211_configure_plls()
363 dev_err(ctx->dev, "PCR unstable, ret=%i\n", ret); in lt9211_configure_plls()
374 /* BIT(7) is LVDS dual-port */ in lt9211_configure_tx()
375 { 0x823b, 0x38 | (ctx->lvds_dual_link ? BIT(7) : 0) }, in lt9211_configure_tx()
389 /* LVDS channel order, Odd:Even 0x10..A:B, 0x40..B:A */ in lt9211_configure_tx()
390 { 0x8646, ctx->lvds_dual_link_even_odd_swap ? 0x40 : 0x10 }, in lt9211_configure_tx()
400 { 0x855c, ctx->lvds_dual_link ? BIT(0) : 0 }, in lt9211_configure_tx()
413 { 0x8237, ctx->lvds_dual_link ? 0x2a : 0x29 }, in lt9211_configure_tx()
425 ret = regmap_multi_reg_write(ctx->regmap, system_lt9211_tx_phy_seq, in lt9211_configure_tx()
430 ret = regmap_multi_reg_write(ctx->regmap, system_lt9211_tx_dig_seq, in lt9211_configure_tx()
435 ret = regmap_multi_reg_write(ctx->regmap, system_lt9211_tx_pll_seq, in lt9211_configure_tx()
440 ret = regmap_read_poll_timeout(ctx->regmap, 0x871f, pval, pval & 0x80, in lt9211_configure_tx()
443 dev_err(ctx->dev, "TX PLL unstable, ret=%i\n", ret); in lt9211_configure_tx()
447 ret = regmap_read_poll_timeout(ctx->regmap, 0x8720, pval, pval & 0x80, in lt9211_configure_tx()
450 dev_err(ctx->dev, "TX PLL unstable, ret=%i\n", ret); in lt9211_configure_tx()
457 static void lt9211_atomic_enable(struct drm_bridge *bridge, in lt9211_atomic_enable() argument
460 struct lt9211 *ctx = bridge_to_lt9211(bridge); in lt9211_atomic_enable()
461 struct drm_atomic_state *state = old_bridge_state->base.state; in lt9211_atomic_enable()
472 ret = regulator_enable(ctx->vccio); in lt9211_atomic_enable()
474 dev_err(ctx->dev, "Failed to enable vccio: %d\n", ret); in lt9211_atomic_enable()
479 gpiod_set_value(ctx->reset_gpio, 1); in lt9211_atomic_enable()
480 usleep_range(20000, 21000); /* Very long post-reset delay. */ in lt9211_atomic_enable()
482 /* Get the LVDS format from the bridge state. */ in lt9211_atomic_enable()
483 bridge_state = drm_atomic_get_new_bridge_state(state, bridge); in lt9211_atomic_enable()
484 bus_flags = bridge_state->output_bus_cfg.flags; in lt9211_atomic_enable()
486 switch (bridge_state->output_bus_cfg.format) { in lt9211_atomic_enable()
502 * LVDS bus pixel format, use SPWG24 default in lt9211_atomic_enable()
507 dev_warn(ctx->dev, in lt9211_atomic_enable()
508 …"Unsupported LVDS bus format 0x%04x, please check output bridge driver. Falling back to SPWG24.\n", in lt9211_atomic_enable()
509 bridge_state->output_bus_cfg.format); in lt9211_atomic_enable()
515 * from the bridge to the encoder, to the connector and to the CRTC. in lt9211_atomic_enable()
518 bridge->encoder); in lt9211_atomic_enable()
519 crtc = drm_atomic_get_new_connector_state(state, connector)->crtc; in lt9211_atomic_enable()
521 mode = &crtc_state->adjusted_mode; in lt9211_atomic_enable()
552 dev_dbg(ctx->dev, "LT9211 enabled.\n"); in lt9211_atomic_enable()
555 static void lt9211_atomic_disable(struct drm_bridge *bridge, in lt9211_atomic_disable() argument
558 struct lt9211 *ctx = bridge_to_lt9211(bridge); in lt9211_atomic_disable()
565 gpiod_set_value(ctx->reset_gpio, 0); in lt9211_atomic_disable()
568 ret = regulator_disable(ctx->vccio); in lt9211_atomic_disable()
570 dev_err(ctx->dev, "Failed to disable vccio: %d\n", ret); in lt9211_atomic_disable()
572 regcache_mark_dirty(ctx->regmap); in lt9211_atomic_disable()
576 lt9211_mode_valid(struct drm_bridge *bridge, in lt9211_mode_valid() argument
580 /* LVDS output clock range 25..176 MHz */ in lt9211_mode_valid()
581 if (mode->clock < 25000) in lt9211_mode_valid()
583 if (mode->clock > 176000) in lt9211_mode_valid()
592 lt9211_atomic_get_input_bus_fmts(struct drm_bridge *bridge, in lt9211_atomic_get_input_bus_fmts() argument
608 /* This is the DSI-end bus format */ in lt9211_atomic_get_input_bus_fmts()
630 struct device *dev = ctx->dev; in lt9211_parse_dt()
635 ctx->vccio = devm_regulator_get(dev, "vccio"); in lt9211_parse_dt()
636 if (IS_ERR(ctx->vccio)) in lt9211_parse_dt()
637 return dev_err_probe(dev, PTR_ERR(ctx->vccio), in lt9211_parse_dt()
640 ctx->lvds_dual_link = false; in lt9211_parse_dt()
641 ctx->lvds_dual_link_even_odd_swap = false; in lt9211_parse_dt()
643 port2 = of_graph_get_port_by_id(dev->of_node, 2); in lt9211_parse_dt()
644 port3 = of_graph_get_port_by_id(dev->of_node, 3); in lt9211_parse_dt()
650 ctx->lvds_dual_link = true; in lt9211_parse_dt()
651 /* Odd pixels to LVDS Channel A, even pixels to B */ in lt9211_parse_dt()
652 ctx->lvds_dual_link_even_odd_swap = false; in lt9211_parse_dt()
654 ctx->lvds_dual_link = true; in lt9211_parse_dt()
655 /* Even pixels to LVDS Channel A, odd pixels to B */ in lt9211_parse_dt()
656 ctx->lvds_dual_link_even_odd_swap = true; in lt9211_parse_dt()
659 ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, &panel_bridge); in lt9211_parse_dt()
668 ctx->panel_bridge = panel_bridge; in lt9211_parse_dt()
680 struct device *dev = ctx->dev; in lt9211_host_attach()
688 endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1); in lt9211_host_attach()
696 return -EPROBE_DEFER; in lt9211_host_attach()
706 ctx->dsi = dsi; in lt9211_host_attach()
708 dsi->lanes = dsi_lanes; in lt9211_host_attach()
709 dsi->format = MIPI_DSI_FMT_RGB888; in lt9211_host_attach()
710 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | in lt9211_host_attach()
726 struct device *dev = &client->dev; in lt9211_probe()
732 return -ENOMEM; in lt9211_probe()
734 ctx->dev = dev; in lt9211_probe()
740 ctx->reset_gpio = devm_gpiod_get_optional(ctx->dev, "reset", in lt9211_probe()
742 if (IS_ERR(ctx->reset_gpio)) in lt9211_probe()
743 return PTR_ERR(ctx->reset_gpio); in lt9211_probe()
751 ctx->regmap = devm_regmap_init_i2c(client, &lt9211_regmap_config); in lt9211_probe()
752 if (IS_ERR(ctx->regmap)) in lt9211_probe()
753 return PTR_ERR(ctx->regmap); in lt9211_probe()
758 ctx->bridge.funcs = &lt9211_funcs; in lt9211_probe()
759 ctx->bridge.of_node = dev->of_node; in lt9211_probe()
760 drm_bridge_add(&ctx->bridge); in lt9211_probe()
764 drm_bridge_remove(&ctx->bridge); in lt9211_probe()
773 drm_bridge_remove(&ctx->bridge); in lt9211_remove()
800 MODULE_DESCRIPTION("Lontium LT9211 DSI/LVDS/DPI bridge driver");