Commit 0af5e0b4 authored by Neil Armstrong's avatar Neil Armstrong

drm/meson: encoder_hdmi: switch to bridge DRM_BRIDGE_ATTACH_NO_CONNECTOR

This implements the necessary change to no more use the embedded
connector in dw-hdmi and use the dedicated bridge connector driver
by passing DRM_BRIDGE_ATTACH_NO_CONNECTOR to the bridge attach call.

The necessary connector properties are added to handle the same
functionalities as the embedded dw-hdmi connector, i.e. the HDR
metadata, the CEC notifier & other flags.

The dw-hdmi output_port is set to 1 in order to look for a connector
next bridge in order to get DRM_BRIDGE_ATTACH_NO_CONNECTOR working.
Signed-off-by: default avatarNeil Armstrong <narmstrong@baylibre.com>
Acked-by: default avatarSam Ravnborg <sam@ravnborg.org>
Acked-by: default avatarMartin Blumenstingl <martin.blumenstingl@googlemail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20211020123947.2585572-5-narmstrong@baylibre.com
parent e67f6037
...@@ -6,9 +6,11 @@ config DRM_MESON ...@@ -6,9 +6,11 @@ config DRM_MESON
select DRM_KMS_HELPER select DRM_KMS_HELPER
select DRM_KMS_CMA_HELPER select DRM_KMS_CMA_HELPER
select DRM_GEM_CMA_HELPER select DRM_GEM_CMA_HELPER
select DRM_DISPLAY_CONNECTOR
select VIDEOMODE_HELPERS select VIDEOMODE_HELPERS
select REGMAP_MMIO select REGMAP_MMIO
select MESON_CANVAS select MESON_CANVAS
select CEC_CORE if CEC_NOTIFIER
config DRM_MESON_DW_HDMI config DRM_MESON_DW_HDMI
tristate "HDMI Synopsys Controller support for Amlogic Meson Display" tristate "HDMI Synopsys Controller support for Amlogic Meson Display"
......
...@@ -803,6 +803,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, ...@@ -803,6 +803,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709; dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
dw_plat_data->ycbcr_420_allowed = true; dw_plat_data->ycbcr_420_allowed = true;
dw_plat_data->disable_cec = true; dw_plat_data->disable_cec = true;
dw_plat_data->output_port = 1;
if (dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || if (dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxm-dw-hdmi") || dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxm-dw-hdmi") ||
......
...@@ -14,8 +14,11 @@ ...@@ -14,8 +14,11 @@
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <media/cec-notifier.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h> #include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_device.h> #include <drm/drm_device.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
...@@ -34,8 +37,10 @@ struct meson_encoder_hdmi { ...@@ -34,8 +37,10 @@ struct meson_encoder_hdmi {
struct drm_encoder encoder; struct drm_encoder encoder;
struct drm_bridge bridge; struct drm_bridge bridge;
struct drm_bridge *next_bridge; struct drm_bridge *next_bridge;
struct drm_connector *connector;
struct meson_drm *priv; struct meson_drm *priv;
unsigned long output_bus_fmt; unsigned long output_bus_fmt;
struct cec_notifier *cec_notifier;
}; };
#define bridge_to_meson_encoder_hdmi(x) \ #define bridge_to_meson_encoder_hdmi(x) \
...@@ -50,6 +55,14 @@ static int meson_encoder_hdmi_attach(struct drm_bridge *bridge, ...@@ -50,6 +55,14 @@ static int meson_encoder_hdmi_attach(struct drm_bridge *bridge,
&encoder_hdmi->bridge, flags); &encoder_hdmi->bridge, flags);
} }
static void meson_encoder_hdmi_detach(struct drm_bridge *bridge)
{
struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge);
cec_notifier_conn_unregister(encoder_hdmi->cec_notifier);
encoder_hdmi->cec_notifier = NULL;
}
static void meson_encoder_hdmi_set_vclk(struct meson_encoder_hdmi *encoder_hdmi, static void meson_encoder_hdmi_set_vclk(struct meson_encoder_hdmi *encoder_hdmi,
const struct drm_display_mode *mode) const struct drm_display_mode *mode)
{ {
...@@ -298,9 +311,30 @@ static int meson_encoder_hdmi_atomic_check(struct drm_bridge *bridge, ...@@ -298,9 +311,30 @@ static int meson_encoder_hdmi_atomic_check(struct drm_bridge *bridge,
return 0; return 0;
} }
static void meson_encoder_hdmi_hpd_notify(struct drm_bridge *bridge,
enum drm_connector_status status)
{
struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge);
struct edid *edid;
if (!encoder_hdmi->cec_notifier)
return;
if (status == connector_status_connected) {
edid = drm_bridge_get_edid(encoder_hdmi->next_bridge, encoder_hdmi->connector);
if (!edid)
return;
cec_notifier_set_phys_addr_from_edid(encoder_hdmi->cec_notifier, edid);
} else
cec_notifier_phys_addr_invalidate(encoder_hdmi->cec_notifier);
}
static const struct drm_bridge_funcs meson_encoder_hdmi_bridge_funcs = { static const struct drm_bridge_funcs meson_encoder_hdmi_bridge_funcs = {
.attach = meson_encoder_hdmi_attach, .attach = meson_encoder_hdmi_attach,
.detach = meson_encoder_hdmi_detach,
.mode_valid = meson_encoder_hdmi_mode_valid, .mode_valid = meson_encoder_hdmi_mode_valid,
.hpd_notify = meson_encoder_hdmi_hpd_notify,
.atomic_enable = meson_encoder_hdmi_atomic_enable, .atomic_enable = meson_encoder_hdmi_atomic_enable,
.atomic_disable = meson_encoder_hdmi_atomic_disable, .atomic_disable = meson_encoder_hdmi_atomic_disable,
.atomic_get_input_bus_fmts = meson_encoder_hdmi_get_inp_bus_fmts, .atomic_get_input_bus_fmts = meson_encoder_hdmi_get_inp_bus_fmts,
...@@ -313,6 +347,7 @@ static const struct drm_bridge_funcs meson_encoder_hdmi_bridge_funcs = { ...@@ -313,6 +347,7 @@ static const struct drm_bridge_funcs meson_encoder_hdmi_bridge_funcs = {
int meson_encoder_hdmi_init(struct meson_drm *priv) int meson_encoder_hdmi_init(struct meson_drm *priv)
{ {
struct meson_encoder_hdmi *meson_encoder_hdmi; struct meson_encoder_hdmi *meson_encoder_hdmi;
struct platform_device *pdev;
struct device_node *remote; struct device_node *remote;
int ret; int ret;
...@@ -337,6 +372,7 @@ int meson_encoder_hdmi_init(struct meson_drm *priv) ...@@ -337,6 +372,7 @@ int meson_encoder_hdmi_init(struct meson_drm *priv)
meson_encoder_hdmi->bridge.funcs = &meson_encoder_hdmi_bridge_funcs; meson_encoder_hdmi->bridge.funcs = &meson_encoder_hdmi_bridge_funcs;
meson_encoder_hdmi->bridge.of_node = priv->dev->of_node; meson_encoder_hdmi->bridge.of_node = priv->dev->of_node;
meson_encoder_hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; meson_encoder_hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
meson_encoder_hdmi->bridge.interlace_allowed = true;
drm_bridge_add(&meson_encoder_hdmi->bridge); drm_bridge_add(&meson_encoder_hdmi->bridge);
...@@ -353,17 +389,58 @@ int meson_encoder_hdmi_init(struct meson_drm *priv) ...@@ -353,17 +389,58 @@ int meson_encoder_hdmi_init(struct meson_drm *priv)
meson_encoder_hdmi->encoder.possible_crtcs = BIT(0); meson_encoder_hdmi->encoder.possible_crtcs = BIT(0);
/* Attach HDMI Encoder Bridge to Encoder */ /* Attach HDMI Encoder Bridge to Encoder */
ret = drm_bridge_attach(&meson_encoder_hdmi->encoder, &meson_encoder_hdmi->bridge, NULL, 0); ret = drm_bridge_attach(&meson_encoder_hdmi->encoder, &meson_encoder_hdmi->bridge, NULL,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret) { if (ret) {
dev_err(priv->dev, "Failed to attach bridge: %d\n", ret); dev_err(priv->dev, "Failed to attach bridge: %d\n", ret);
return ret; return ret;
} }
/* Initialize & attach Bridge Connector */
meson_encoder_hdmi->connector = drm_bridge_connector_init(priv->drm,
&meson_encoder_hdmi->encoder);
if (IS_ERR(meson_encoder_hdmi->connector)) {
dev_err(priv->dev, "Unable to create HDMI bridge connector\n");
return PTR_ERR(meson_encoder_hdmi->connector);
}
drm_connector_attach_encoder(meson_encoder_hdmi->connector,
&meson_encoder_hdmi->encoder);
/* /*
* We should have now in place: * We should have now in place:
* encoder->[hdmi encoder bridge]->[dw-hdmi bridge]->[dw-hdmi connector] * encoder->[hdmi encoder bridge]->[dw-hdmi bridge]->[display connector bridge]->[display connector]
*/ */
/*
* drm_connector_attach_max_bpc_property() requires the
* connector to have a state.
*/
drm_atomic_helper_connector_reset(meson_encoder_hdmi->connector);
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL) ||
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
drm_connector_attach_hdr_output_metadata_property(meson_encoder_hdmi->connector);
drm_connector_attach_max_bpc_property(meson_encoder_hdmi->connector, 8, 8);
/* Handle this here until handled by drm_bridge_connector_init() */
meson_encoder_hdmi->connector->ycbcr_420_allowed = true;
pdev = of_find_device_by_node(remote);
if (pdev) {
struct cec_connector_info conn_info;
struct cec_notifier *notifier;
cec_fill_conn_info_from_drm(&conn_info, meson_encoder_hdmi->connector);
notifier = cec_notifier_conn_register(&pdev->dev, NULL, &conn_info);
if (!notifier)
return -ENOMEM;
meson_encoder_hdmi->cec_notifier = notifier;
}
dev_dbg(priv->dev, "HDMI encoder initialized\n"); dev_dbg(priv->dev, "HDMI encoder initialized\n");
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment