Lines Matching +full:hdmi +full:- +full:bridge

1 // SPDX-License-Identifier: GPL-2.0-or-later
19 #include <media/cec-notifier.h>
29 #include <linux/media-bus-format.h>
40 struct drm_bridge bridge; member
49 container_of(x, struct meson_encoder_hdmi, bridge)
51 static int meson_encoder_hdmi_attach(struct drm_bridge *bridge, in meson_encoder_hdmi_attach() argument
54 struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); in meson_encoder_hdmi_attach()
56 return drm_bridge_attach(bridge->encoder, encoder_hdmi->next_bridge, in meson_encoder_hdmi_attach()
57 &encoder_hdmi->bridge, flags); in meson_encoder_hdmi_attach()
60 static void meson_encoder_hdmi_detach(struct drm_bridge *bridge) in meson_encoder_hdmi_detach() argument
62 struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); in meson_encoder_hdmi_detach()
64 cec_notifier_conn_unregister(encoder_hdmi->cec_notifier); in meson_encoder_hdmi_detach()
65 encoder_hdmi->cec_notifier = NULL; in meson_encoder_hdmi_detach()
71 struct meson_drm *priv = encoder_hdmi->priv; in meson_encoder_hdmi_set_vclk()
78 vclk_freq = mode->clock; in meson_encoder_hdmi_set_vclk()
81 if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) in meson_encoder_hdmi_set_vclk()
94 if (mode->flags & DRM_MODE_FLAG_DBLCLK) in meson_encoder_hdmi_set_vclk()
102 encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) in meson_encoder_hdmi_set_vclk()
107 if (mode->flags & DRM_MODE_FLAG_DBLCLK) in meson_encoder_hdmi_set_vclk()
110 dev_dbg(priv->dev, "vclk:%d phy=%d venc=%d hdmi=%d enci=%d\n", in meson_encoder_hdmi_set_vclk()
112 priv->venc.hdmi_use_enci); in meson_encoder_hdmi_set_vclk()
115 venc_freq, hdmi_freq, priv->venc.hdmi_use_enci); in meson_encoder_hdmi_set_vclk()
118 static enum drm_mode_status meson_encoder_hdmi_mode_valid(struct drm_bridge *bridge, in meson_encoder_hdmi_mode_valid() argument
122 struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); in meson_encoder_hdmi_mode_valid()
123 struct meson_drm *priv = encoder_hdmi->priv; in meson_encoder_hdmi_mode_valid()
124 bool is_hdmi2_sink = display_info->hdmi.scdc.supported; in meson_encoder_hdmi_mode_valid()
132 dev_dbg(priv->dev, "Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); in meson_encoder_hdmi_mode_valid()
134 /* If sink does not support 540MHz, reject the non-420 HDMI2 modes */ in meson_encoder_hdmi_mode_valid()
135 if (display_info->max_tmds_clock && in meson_encoder_hdmi_mode_valid()
136 mode->clock > display_info->max_tmds_clock && in meson_encoder_hdmi_mode_valid()
141 /* Check against non-VIC supported modes */ in meson_encoder_hdmi_mode_valid()
147 return meson_vclk_dmt_supported_freq(priv, mode->clock); in meson_encoder_hdmi_mode_valid()
152 vclk_freq = mode->clock; in meson_encoder_hdmi_mode_valid()
164 if (mode->flags & DRM_MODE_FLAG_DBLCLK) in meson_encoder_hdmi_mode_valid()
179 if (mode->flags & DRM_MODE_FLAG_DBLCLK) in meson_encoder_hdmi_mode_valid()
182 dev_dbg(priv->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n", in meson_encoder_hdmi_mode_valid()
188 static void meson_encoder_hdmi_atomic_enable(struct drm_bridge *bridge, in meson_encoder_hdmi_atomic_enable() argument
191 struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); in meson_encoder_hdmi_atomic_enable()
192 struct drm_atomic_state *state = bridge_state->base.state; in meson_encoder_hdmi_atomic_enable()
194 struct meson_drm *priv = encoder_hdmi->priv; in meson_encoder_hdmi_atomic_enable()
202 connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); in meson_encoder_hdmi_atomic_enable()
210 crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); in meson_encoder_hdmi_atomic_enable()
214 mode = &crtc_state->adjusted_mode; in meson_encoder_hdmi_atomic_enable()
218 dev_dbg(priv->dev, "\"%s\" vic %d\n", mode->name, vic); in meson_encoder_hdmi_atomic_enable()
220 if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) { in meson_encoder_hdmi_atomic_enable()
223 } else if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYVY8_1X16) in meson_encoder_hdmi_atomic_enable()
226 /* VENC + VENC-DVI Mode setup */ in meson_encoder_hdmi_atomic_enable()
232 if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) in meson_encoder_hdmi_atomic_enable()
233 /* Setup YUV420 to HDMI-TX, no 10bit diphering */ in meson_encoder_hdmi_atomic_enable()
235 priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); in meson_encoder_hdmi_atomic_enable()
236 else if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYVY8_1X16) in meson_encoder_hdmi_atomic_enable()
237 /* Setup YUV422 to HDMI-TX, no 10bit diphering */ in meson_encoder_hdmi_atomic_enable()
239 priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); in meson_encoder_hdmi_atomic_enable()
241 /* Setup YUV444 to HDMI-TX, no 10bit diphering */ in meson_encoder_hdmi_atomic_enable()
242 writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); in meson_encoder_hdmi_atomic_enable()
244 dev_dbg(priv->dev, "%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP"); in meson_encoder_hdmi_atomic_enable()
246 if (priv->venc.hdmi_use_enci) in meson_encoder_hdmi_atomic_enable()
247 writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); in meson_encoder_hdmi_atomic_enable()
249 writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN)); in meson_encoder_hdmi_atomic_enable()
252 static void meson_encoder_hdmi_atomic_disable(struct drm_bridge *bridge, in meson_encoder_hdmi_atomic_disable() argument
255 struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); in meson_encoder_hdmi_atomic_disable()
256 struct meson_drm *priv = encoder_hdmi->priv; in meson_encoder_hdmi_atomic_disable()
259 priv->io_base + _REG(VPU_HDMI_SETTING)); in meson_encoder_hdmi_atomic_disable()
261 writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); in meson_encoder_hdmi_atomic_disable()
262 writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN)); in meson_encoder_hdmi_atomic_disable()
272 meson_encoder_hdmi_get_inp_bus_fmts(struct drm_bridge *bridge, in meson_encoder_hdmi_get_inp_bus_fmts() argument
302 static int meson_encoder_hdmi_atomic_check(struct drm_bridge *bridge, in meson_encoder_hdmi_atomic_check() argument
307 struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); in meson_encoder_hdmi_atomic_check()
309 drm_atomic_get_old_connector_state(conn_state->state, conn_state->connector); in meson_encoder_hdmi_atomic_check()
310 struct meson_drm *priv = encoder_hdmi->priv; in meson_encoder_hdmi_atomic_check()
312 encoder_hdmi->output_bus_fmt = bridge_state->output_bus_cfg.format; in meson_encoder_hdmi_atomic_check()
314 dev_dbg(priv->dev, "output_bus_fmt %lx\n", encoder_hdmi->output_bus_fmt); in meson_encoder_hdmi_atomic_check()
317 crtc_state->mode_changed = true; in meson_encoder_hdmi_atomic_check()
322 static void meson_encoder_hdmi_hpd_notify(struct drm_bridge *bridge, in meson_encoder_hdmi_hpd_notify() argument
325 struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); in meson_encoder_hdmi_hpd_notify()
327 if (!encoder_hdmi->cec_notifier) in meson_encoder_hdmi_hpd_notify()
334 drm_edid = drm_bridge_edid_read(encoder_hdmi->next_bridge, in meson_encoder_hdmi_hpd_notify()
335 encoder_hdmi->connector); in meson_encoder_hdmi_hpd_notify()
341 * cec_notifier_set_phys_addr(encoder_hdmi->cec_notifier, in meson_encoder_hdmi_hpd_notify()
342 * connector->display_info.source_physical_address) from a path in meson_encoder_hdmi_hpd_notify()
348 cec_notifier_set_phys_addr_from_edid(encoder_hdmi->cec_notifier, edid); in meson_encoder_hdmi_hpd_notify()
352 cec_notifier_phys_addr_invalidate(encoder_hdmi->cec_notifier); in meson_encoder_hdmi_hpd_notify()
376 meson_encoder_hdmi = devm_kzalloc(priv->dev, sizeof(*meson_encoder_hdmi), GFP_KERNEL); in meson_encoder_hdmi_probe()
378 return -ENOMEM; in meson_encoder_hdmi_probe()
380 /* HDMI Transceiver Bridge */ in meson_encoder_hdmi_probe()
381 remote = of_graph_get_remote_node(priv->dev->of_node, 1, 0); in meson_encoder_hdmi_probe()
383 dev_err(priv->dev, "HDMI transceiver device is disabled"); in meson_encoder_hdmi_probe()
387 meson_encoder_hdmi->next_bridge = of_drm_find_bridge(remote); in meson_encoder_hdmi_probe()
388 if (!meson_encoder_hdmi->next_bridge) { in meson_encoder_hdmi_probe()
389 ret = dev_err_probe(priv->dev, -EPROBE_DEFER, in meson_encoder_hdmi_probe()
390 "Failed to find HDMI transceiver bridge\n"); in meson_encoder_hdmi_probe()
394 /* HDMI Encoder Bridge */ in meson_encoder_hdmi_probe()
395 meson_encoder_hdmi->bridge.funcs = &meson_encoder_hdmi_bridge_funcs; in meson_encoder_hdmi_probe()
396 meson_encoder_hdmi->bridge.of_node = priv->dev->of_node; in meson_encoder_hdmi_probe()
397 meson_encoder_hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; in meson_encoder_hdmi_probe()
398 meson_encoder_hdmi->bridge.interlace_allowed = true; in meson_encoder_hdmi_probe()
400 drm_bridge_add(&meson_encoder_hdmi->bridge); in meson_encoder_hdmi_probe()
402 meson_encoder_hdmi->priv = priv; in meson_encoder_hdmi_probe()
405 ret = drm_simple_encoder_init(priv->drm, &meson_encoder_hdmi->encoder, in meson_encoder_hdmi_probe()
408 dev_err_probe(priv->dev, ret, "Failed to init HDMI encoder\n"); in meson_encoder_hdmi_probe()
412 meson_encoder_hdmi->encoder.possible_crtcs = BIT(0); in meson_encoder_hdmi_probe()
414 /* Attach HDMI Encoder Bridge to Encoder */ in meson_encoder_hdmi_probe()
415 ret = drm_bridge_attach(&meson_encoder_hdmi->encoder, &meson_encoder_hdmi->bridge, NULL, in meson_encoder_hdmi_probe()
418 dev_err_probe(priv->dev, ret, "Failed to attach bridge\n"); in meson_encoder_hdmi_probe()
422 /* Initialize & attach Bridge Connector */ in meson_encoder_hdmi_probe()
423 meson_encoder_hdmi->connector = drm_bridge_connector_init(priv->drm, in meson_encoder_hdmi_probe()
424 &meson_encoder_hdmi->encoder); in meson_encoder_hdmi_probe()
425 if (IS_ERR(meson_encoder_hdmi->connector)) { in meson_encoder_hdmi_probe()
426 ret = dev_err_probe(priv->dev, in meson_encoder_hdmi_probe()
427 PTR_ERR(meson_encoder_hdmi->connector), in meson_encoder_hdmi_probe()
428 "Unable to create HDMI bridge connector\n"); in meson_encoder_hdmi_probe()
431 drm_connector_attach_encoder(meson_encoder_hdmi->connector, in meson_encoder_hdmi_probe()
432 &meson_encoder_hdmi->encoder); in meson_encoder_hdmi_probe()
436 …* encoder->[hdmi encoder bridge]->[dw-hdmi bridge]->[display connector bridge]->[display connector] in meson_encoder_hdmi_probe()
443 drm_atomic_helper_connector_reset(meson_encoder_hdmi->connector); in meson_encoder_hdmi_probe()
448 drm_connector_attach_hdr_output_metadata_property(meson_encoder_hdmi->connector); in meson_encoder_hdmi_probe()
450 drm_connector_attach_max_bpc_property(meson_encoder_hdmi->connector, 8, 8); in meson_encoder_hdmi_probe()
453 meson_encoder_hdmi->connector->ycbcr_420_allowed = true; in meson_encoder_hdmi_probe()
461 cec_fill_conn_info_from_drm(&conn_info, meson_encoder_hdmi->connector); in meson_encoder_hdmi_probe()
463 notifier = cec_notifier_conn_register(&pdev->dev, NULL, &conn_info); in meson_encoder_hdmi_probe()
465 put_device(&pdev->dev); in meson_encoder_hdmi_probe()
466 return -ENOMEM; in meson_encoder_hdmi_probe()
469 meson_encoder_hdmi->cec_notifier = notifier; in meson_encoder_hdmi_probe()
472 priv->encoders[MESON_ENC_HDMI] = meson_encoder_hdmi; in meson_encoder_hdmi_probe()
474 dev_dbg(priv->dev, "HDMI encoder initialized\n"); in meson_encoder_hdmi_probe()
487 if (priv->encoders[MESON_ENC_HDMI]) { in meson_encoder_hdmi_remove()
488 meson_encoder_hdmi = priv->encoders[MESON_ENC_HDMI]; in meson_encoder_hdmi_remove()
489 drm_bridge_remove(&meson_encoder_hdmi->bridge); in meson_encoder_hdmi_remove()