Path: blob/master/drivers/gpu/drm/display/drm_bridge_connector.c
29281 views
// SPDX-License-Identifier: GPL-2.0+1/*2* Copyright (C) 2019 Laurent Pinchart <[email protected]>3*/45#include <linux/export.h>6#include <linux/kernel.h>7#include <linux/module.h>8#include <linux/of.h>9#include <linux/property.h>10#include <linux/slab.h>1112#include <drm/drm_atomic_state_helper.h>13#include <drm/drm_bridge.h>14#include <drm/drm_bridge_connector.h>15#include <drm/drm_connector.h>16#include <drm/drm_device.h>17#include <drm/drm_edid.h>18#include <drm/drm_managed.h>19#include <drm/drm_modeset_helper_vtables.h>20#include <drm/drm_print.h>21#include <drm/drm_probe_helper.h>22#include <drm/display/drm_hdcp_helper.h>23#include <drm/display/drm_hdmi_audio_helper.h>24#include <drm/display/drm_hdmi_cec_helper.h>25#include <drm/display/drm_hdmi_helper.h>26#include <drm/display/drm_hdmi_state_helper.h>2728/**29* DOC: overview30*31* The DRM bridge connector helper object provides a DRM connector32* implementation that wraps a chain of &struct drm_bridge. The connector33* operations are fully implemented based on the operations of the bridges in34* the chain, and don't require any intervention from the display controller35* driver at runtime.36*37* To use the helper, display controller drivers create a bridge connector with38* a call to drm_bridge_connector_init(). This associates the newly created39* connector with the chain of bridges passed to the function and registers it40* with the DRM device. At that point the connector becomes fully usable, no41* further operation is needed.42*43* The DRM bridge connector operations are implemented based on the operations44* provided by the bridges in the chain. Each connector operation is delegated45* to the bridge closest to the connector (at the end of the chain) that46* provides the relevant functionality.47*48* To make use of this helper, all bridges in the chain shall report bridge49* operation flags (&drm_bridge->ops) and bridge output type50* (&drm_bridge->type), as well as the DRM_BRIDGE_ATTACH_NO_CONNECTOR attach51* flag (none of the bridges shall create a DRM connector directly).52*/5354/**55* struct drm_bridge_connector - A connector backed by a chain of bridges56*/57struct drm_bridge_connector {58/**59* @base: The base DRM connector60*/61struct drm_connector base;62/**63* @encoder:64*65* The encoder at the start of the bridges chain.66*/67struct drm_encoder *encoder;68/**69* @bridge_edid:70*71* The last bridge in the chain (closest to the connector) that provides72* EDID read support, if any (see &DRM_BRIDGE_OP_EDID).73*/74struct drm_bridge *bridge_edid;75/**76* @bridge_hpd:77*78* The last bridge in the chain (closest to the connector) that provides79* hot-plug detection notification, if any (see &DRM_BRIDGE_OP_HPD).80*/81struct drm_bridge *bridge_hpd;82/**83* @bridge_detect:84*85* The last bridge in the chain (closest to the connector) that provides86* connector detection, if any (see &DRM_BRIDGE_OP_DETECT).87*/88struct drm_bridge *bridge_detect;89/**90* @bridge_modes:91*92* The last bridge in the chain (closest to the connector) that provides93* connector modes detection, if any (see &DRM_BRIDGE_OP_MODES).94*/95struct drm_bridge *bridge_modes;96/**97* @bridge_hdmi:98*99* The bridge in the chain that implements necessary support for the100* HDMI connector infrastructure, if any (see &DRM_BRIDGE_OP_HDMI).101*/102struct drm_bridge *bridge_hdmi;103/**104* @bridge_hdmi_audio:105*106* The bridge in the chain that implements necessary support for the107* HDMI Audio infrastructure, if any (see &DRM_BRIDGE_OP_HDMI_AUDIO).108*/109struct drm_bridge *bridge_hdmi_audio;110/**111* @bridge_dp_audio:112*113* The bridge in the chain that implements necessary support for the114* DisplayPort Audio infrastructure, if any (see115* &DRM_BRIDGE_OP_DP_AUDIO).116*/117struct drm_bridge *bridge_dp_audio;118/**119* @bridge_hdmi_cec:120*121* The bridge in the chain that implements CEC support, if any (see122* DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER).123*/124struct drm_bridge *bridge_hdmi_cec;125};126127#define to_drm_bridge_connector(x) \128container_of(x, struct drm_bridge_connector, base)129130/* -----------------------------------------------------------------------------131* Bridge Connector Hot-Plug Handling132*/133134static void drm_bridge_connector_hpd_notify(struct drm_connector *connector,135enum drm_connector_status status)136{137struct drm_bridge_connector *bridge_connector =138to_drm_bridge_connector(connector);139struct drm_bridge *bridge;140141/* Notify all bridges in the pipeline of hotplug events. */142drm_for_each_bridge_in_chain(bridge_connector->encoder, bridge) {143if (bridge->funcs->hpd_notify)144bridge->funcs->hpd_notify(bridge, status);145}146}147148static void drm_bridge_connector_handle_hpd(struct drm_bridge_connector *drm_bridge_connector,149enum drm_connector_status status)150{151struct drm_connector *connector = &drm_bridge_connector->base;152struct drm_device *dev = connector->dev;153154mutex_lock(&dev->mode_config.mutex);155connector->status = status;156mutex_unlock(&dev->mode_config.mutex);157158drm_bridge_connector_hpd_notify(connector, status);159160drm_kms_helper_connector_hotplug_event(connector);161}162163static void drm_bridge_connector_hpd_cb(void *cb_data,164enum drm_connector_status status)165{166drm_bridge_connector_handle_hpd(cb_data, status);167}168169static void drm_bridge_connector_oob_hotplug_event(struct drm_connector *connector,170enum drm_connector_status status)171{172struct drm_bridge_connector *bridge_connector =173to_drm_bridge_connector(connector);174175drm_bridge_connector_handle_hpd(bridge_connector, status);176}177178static void drm_bridge_connector_enable_hpd(struct drm_connector *connector)179{180struct drm_bridge_connector *bridge_connector =181to_drm_bridge_connector(connector);182struct drm_bridge *hpd = bridge_connector->bridge_hpd;183184if (hpd)185drm_bridge_hpd_enable(hpd, drm_bridge_connector_hpd_cb,186bridge_connector);187}188189static void drm_bridge_connector_disable_hpd(struct drm_connector *connector)190{191struct drm_bridge_connector *bridge_connector =192to_drm_bridge_connector(connector);193struct drm_bridge *hpd = bridge_connector->bridge_hpd;194195if (hpd)196drm_bridge_hpd_disable(hpd);197}198199/* -----------------------------------------------------------------------------200* Bridge Connector Functions201*/202203static enum drm_connector_status204drm_bridge_connector_detect(struct drm_connector *connector, bool force)205{206struct drm_bridge_connector *bridge_connector =207to_drm_bridge_connector(connector);208struct drm_bridge *detect = bridge_connector->bridge_detect;209struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;210enum drm_connector_status status;211212if (detect) {213status = detect->funcs->detect(detect, connector);214215if (hdmi)216drm_atomic_helper_connector_hdmi_hotplug(connector, status);217218drm_bridge_connector_hpd_notify(connector, status);219} else {220switch (connector->connector_type) {221case DRM_MODE_CONNECTOR_DPI:222case DRM_MODE_CONNECTOR_LVDS:223case DRM_MODE_CONNECTOR_DSI:224case DRM_MODE_CONNECTOR_eDP:225status = connector_status_connected;226break;227default:228status = connector_status_unknown;229break;230}231}232233return status;234}235236static void drm_bridge_connector_force(struct drm_connector *connector)237{238struct drm_bridge_connector *bridge_connector =239to_drm_bridge_connector(connector);240struct drm_bridge *hdmi = bridge_connector->bridge_hdmi;241242if (hdmi)243drm_atomic_helper_connector_hdmi_force(connector);244}245246static void drm_bridge_connector_debugfs_init(struct drm_connector *connector,247struct dentry *root)248{249struct drm_bridge_connector *bridge_connector =250to_drm_bridge_connector(connector);251struct drm_encoder *encoder = bridge_connector->encoder;252struct drm_bridge *bridge;253254list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {255if (bridge->funcs->debugfs_init)256bridge->funcs->debugfs_init(bridge, root);257}258}259260static void drm_bridge_connector_reset(struct drm_connector *connector)261{262struct drm_bridge_connector *bridge_connector =263to_drm_bridge_connector(connector);264265drm_atomic_helper_connector_reset(connector);266if (bridge_connector->bridge_hdmi)267__drm_atomic_helper_connector_hdmi_reset(connector,268connector->state);269}270271static const struct drm_connector_funcs drm_bridge_connector_funcs = {272.reset = drm_bridge_connector_reset,273.detect = drm_bridge_connector_detect,274.force = drm_bridge_connector_force,275.fill_modes = drm_helper_probe_single_connector_modes,276.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,277.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,278.debugfs_init = drm_bridge_connector_debugfs_init,279.oob_hotplug_event = drm_bridge_connector_oob_hotplug_event,280};281282/* -----------------------------------------------------------------------------283* Bridge Connector Helper Functions284*/285286static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,287struct drm_bridge *bridge)288{289enum drm_connector_status status;290const struct drm_edid *drm_edid;291int n;292293status = drm_bridge_connector_detect(connector, false);294if (status != connector_status_connected)295goto no_edid;296297drm_edid = drm_bridge_edid_read(bridge, connector);298if (!drm_edid_valid(drm_edid)) {299drm_edid_free(drm_edid);300goto no_edid;301}302303drm_edid_connector_update(connector, drm_edid);304n = drm_edid_connector_add_modes(connector);305306drm_edid_free(drm_edid);307return n;308309no_edid:310drm_edid_connector_update(connector, NULL);311return 0;312}313314static int drm_bridge_connector_get_modes(struct drm_connector *connector)315{316struct drm_bridge_connector *bridge_connector =317to_drm_bridge_connector(connector);318struct drm_bridge *bridge;319320/*321* If there is a HDMI bridge, EDID has been updated as a part of322* the .detect(). Just update the modes here.323*/324bridge = bridge_connector->bridge_hdmi;325if (bridge)326return drm_edid_connector_add_modes(connector);327328/*329* If display exposes EDID, then we parse that in the normal way to330* build table of supported modes.331*/332bridge = bridge_connector->bridge_edid;333if (bridge)334return drm_bridge_connector_get_modes_edid(connector, bridge);335336/*337* Otherwise if the display pipeline reports modes (e.g. with a fixed338* resolution panel or an analog TV output), query it.339*/340bridge = bridge_connector->bridge_modes;341if (bridge)342return bridge->funcs->get_modes(bridge, connector);343344/*345* We can't retrieve modes, which can happen for instance for a DVI or346* VGA output with the DDC bus unconnected. The KMS core will add the347* default modes.348*/349return 0;350}351352static enum drm_mode_status353drm_bridge_connector_mode_valid(struct drm_connector *connector,354const struct drm_display_mode *mode)355{356struct drm_bridge_connector *bridge_connector =357to_drm_bridge_connector(connector);358359if (bridge_connector->bridge_hdmi)360return drm_hdmi_connector_mode_valid(connector, mode);361362return MODE_OK;363}364365static int drm_bridge_connector_atomic_check(struct drm_connector *connector,366struct drm_atomic_state *state)367{368struct drm_bridge_connector *bridge_connector =369to_drm_bridge_connector(connector);370371if (bridge_connector->bridge_hdmi)372return drm_atomic_helper_connector_hdmi_check(connector, state);373374return 0;375}376377static const struct drm_connector_helper_funcs drm_bridge_connector_helper_funcs = {378.get_modes = drm_bridge_connector_get_modes,379.mode_valid = drm_bridge_connector_mode_valid,380.enable_hpd = drm_bridge_connector_enable_hpd,381.disable_hpd = drm_bridge_connector_disable_hpd,382.atomic_check = drm_bridge_connector_atomic_check,383};384385static enum drm_mode_status386drm_bridge_connector_tmds_char_rate_valid(const struct drm_connector *connector,387const struct drm_display_mode *mode,388unsigned long long tmds_rate)389{390struct drm_bridge_connector *bridge_connector =391to_drm_bridge_connector(connector);392struct drm_bridge *bridge;393394bridge = bridge_connector->bridge_hdmi;395if (!bridge)396return MODE_ERROR;397398if (bridge->funcs->hdmi_tmds_char_rate_valid)399return bridge->funcs->hdmi_tmds_char_rate_valid(bridge, mode, tmds_rate);400else401return MODE_OK;402}403404static int drm_bridge_connector_clear_infoframe(struct drm_connector *connector,405enum hdmi_infoframe_type type)406{407struct drm_bridge_connector *bridge_connector =408to_drm_bridge_connector(connector);409struct drm_bridge *bridge;410411bridge = bridge_connector->bridge_hdmi;412if (!bridge)413return -EINVAL;414415return bridge->funcs->hdmi_clear_infoframe(bridge, type);416}417418static int drm_bridge_connector_write_infoframe(struct drm_connector *connector,419enum hdmi_infoframe_type type,420const u8 *buffer, size_t len)421{422struct drm_bridge_connector *bridge_connector =423to_drm_bridge_connector(connector);424struct drm_bridge *bridge;425426bridge = bridge_connector->bridge_hdmi;427if (!bridge)428return -EINVAL;429430return bridge->funcs->hdmi_write_infoframe(bridge, type, buffer, len);431}432433static const struct drm_edid *434drm_bridge_connector_read_edid(struct drm_connector *connector)435{436struct drm_bridge_connector *bridge_connector =437to_drm_bridge_connector(connector);438struct drm_bridge *bridge;439440bridge = bridge_connector->bridge_edid;441if (!bridge)442return NULL;443444return drm_bridge_edid_read(bridge, connector);445}446447static const struct drm_connector_hdmi_funcs drm_bridge_connector_hdmi_funcs = {448.tmds_char_rate_valid = drm_bridge_connector_tmds_char_rate_valid,449.clear_infoframe = drm_bridge_connector_clear_infoframe,450.write_infoframe = drm_bridge_connector_write_infoframe,451.read_edid = drm_bridge_connector_read_edid,452};453454static int drm_bridge_connector_audio_startup(struct drm_connector *connector)455{456struct drm_bridge_connector *bridge_connector =457to_drm_bridge_connector(connector);458struct drm_bridge *bridge;459460if (bridge_connector->bridge_hdmi_audio) {461bridge = bridge_connector->bridge_hdmi_audio;462463if (!bridge->funcs->hdmi_audio_startup)464return 0;465466return bridge->funcs->hdmi_audio_startup(bridge, connector);467}468469if (bridge_connector->bridge_dp_audio) {470bridge = bridge_connector->bridge_dp_audio;471472if (!bridge->funcs->dp_audio_startup)473return 0;474475return bridge->funcs->dp_audio_startup(bridge, connector);476}477478return -EINVAL;479}480481static int drm_bridge_connector_audio_prepare(struct drm_connector *connector,482struct hdmi_codec_daifmt *fmt,483struct hdmi_codec_params *hparms)484{485struct drm_bridge_connector *bridge_connector =486to_drm_bridge_connector(connector);487struct drm_bridge *bridge;488489if (bridge_connector->bridge_hdmi_audio) {490bridge = bridge_connector->bridge_hdmi_audio;491492return bridge->funcs->hdmi_audio_prepare(bridge, connector, fmt, hparms);493}494495if (bridge_connector->bridge_dp_audio) {496bridge = bridge_connector->bridge_dp_audio;497498return bridge->funcs->dp_audio_prepare(bridge, connector, fmt, hparms);499}500501return -EINVAL;502}503504static void drm_bridge_connector_audio_shutdown(struct drm_connector *connector)505{506struct drm_bridge_connector *bridge_connector =507to_drm_bridge_connector(connector);508struct drm_bridge *bridge;509510if (bridge_connector->bridge_hdmi_audio) {511bridge = bridge_connector->bridge_hdmi_audio;512bridge->funcs->hdmi_audio_shutdown(bridge, connector);513}514515if (bridge_connector->bridge_dp_audio) {516bridge = bridge_connector->bridge_dp_audio;517bridge->funcs->dp_audio_shutdown(bridge, connector);518}519}520521static int drm_bridge_connector_audio_mute_stream(struct drm_connector *connector,522bool enable, int direction)523{524struct drm_bridge_connector *bridge_connector =525to_drm_bridge_connector(connector);526struct drm_bridge *bridge;527528if (bridge_connector->bridge_hdmi_audio) {529bridge = bridge_connector->bridge_hdmi_audio;530531if (!bridge->funcs->hdmi_audio_mute_stream)532return -ENOTSUPP;533534return bridge->funcs->hdmi_audio_mute_stream(bridge, connector,535enable, direction);536}537538if (bridge_connector->bridge_dp_audio) {539bridge = bridge_connector->bridge_dp_audio;540541if (!bridge->funcs->dp_audio_mute_stream)542return -ENOTSUPP;543544return bridge->funcs->dp_audio_mute_stream(bridge, connector,545enable, direction);546}547548return -EINVAL;549}550551static const struct drm_connector_hdmi_audio_funcs drm_bridge_connector_hdmi_audio_funcs = {552.startup = drm_bridge_connector_audio_startup,553.prepare = drm_bridge_connector_audio_prepare,554.shutdown = drm_bridge_connector_audio_shutdown,555.mute_stream = drm_bridge_connector_audio_mute_stream,556};557558static int drm_bridge_connector_hdmi_cec_enable(struct drm_connector *connector, bool enable)559{560struct drm_bridge_connector *bridge_connector =561to_drm_bridge_connector(connector);562struct drm_bridge *bridge;563564bridge = bridge_connector->bridge_hdmi_cec;565566return bridge->funcs->hdmi_cec_enable(bridge, enable);567}568569static int drm_bridge_connector_hdmi_cec_log_addr(struct drm_connector *connector, u8 logical_addr)570{571struct drm_bridge_connector *bridge_connector =572to_drm_bridge_connector(connector);573struct drm_bridge *bridge;574575bridge = bridge_connector->bridge_hdmi_cec;576577return bridge->funcs->hdmi_cec_log_addr(bridge, logical_addr);578}579580static int drm_bridge_connector_hdmi_cec_transmit(struct drm_connector *connector,581u8 attempts,582u32 signal_free_time,583struct cec_msg *msg)584{585struct drm_bridge_connector *bridge_connector =586to_drm_bridge_connector(connector);587struct drm_bridge *bridge;588589bridge = bridge_connector->bridge_hdmi_cec;590591return bridge->funcs->hdmi_cec_transmit(bridge, attempts,592signal_free_time,593msg);594}595596static int drm_bridge_connector_hdmi_cec_init(struct drm_connector *connector)597{598struct drm_bridge_connector *bridge_connector =599to_drm_bridge_connector(connector);600struct drm_bridge *bridge;601602bridge = bridge_connector->bridge_hdmi_cec;603604if (!bridge->funcs->hdmi_cec_init)605return 0;606607return bridge->funcs->hdmi_cec_init(bridge, connector);608}609610static const struct drm_connector_hdmi_cec_funcs drm_bridge_connector_hdmi_cec_funcs = {611.init = drm_bridge_connector_hdmi_cec_init,612.enable = drm_bridge_connector_hdmi_cec_enable,613.log_addr = drm_bridge_connector_hdmi_cec_log_addr,614.transmit = drm_bridge_connector_hdmi_cec_transmit,615};616617/* -----------------------------------------------------------------------------618* Bridge Connector Initialisation619*/620621/**622* drm_bridge_connector_init - Initialise a connector for a chain of bridges623* @drm: the DRM device624* @encoder: the encoder where the bridge chain starts625*626* Allocate, initialise and register a &drm_bridge_connector with the @drm627* device. The connector is associated with a chain of bridges that starts at628* the @encoder. All bridges in the chain shall report bridge operation flags629* (&drm_bridge->ops) and bridge output type (&drm_bridge->type), and none of630* them may create a DRM connector directly.631*632* Returns a pointer to the new connector on success, or a negative error633* pointer otherwise.634*/635struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,636struct drm_encoder *encoder)637{638struct drm_bridge_connector *bridge_connector;639struct drm_connector *connector;640struct i2c_adapter *ddc = NULL;641struct drm_bridge *bridge, *panel_bridge = NULL;642unsigned int supported_formats = BIT(HDMI_COLORSPACE_RGB);643unsigned int max_bpc = 8;644bool support_hdcp = false;645int connector_type;646int ret;647648bridge_connector = drmm_kzalloc(drm, sizeof(*bridge_connector), GFP_KERNEL);649if (!bridge_connector)650return ERR_PTR(-ENOMEM);651652bridge_connector->encoder = encoder;653654/*655* TODO: Handle doublescan_allowed and stereo_allowed.656*/657connector = &bridge_connector->base;658connector->interlace_allowed = true;659connector->ycbcr_420_allowed = true;660661/*662* Initialise connector status handling. First locate the furthest663* bridges in the pipeline that support HPD and output detection. Then664* initialise the connector polling mode, using HPD if available and665* falling back to polling if supported. If neither HPD nor output666* detection are available, we don't support hotplug detection at all.667*/668connector_type = DRM_MODE_CONNECTOR_Unknown;669drm_for_each_bridge_in_chain(encoder, bridge) {670if (!bridge->interlace_allowed)671connector->interlace_allowed = false;672if (!bridge->ycbcr_420_allowed)673connector->ycbcr_420_allowed = false;674675if (bridge->ops & DRM_BRIDGE_OP_EDID)676bridge_connector->bridge_edid = bridge;677if (bridge->ops & DRM_BRIDGE_OP_HPD)678bridge_connector->bridge_hpd = bridge;679if (bridge->ops & DRM_BRIDGE_OP_DETECT)680bridge_connector->bridge_detect = bridge;681if (bridge->ops & DRM_BRIDGE_OP_MODES)682bridge_connector->bridge_modes = bridge;683if (bridge->ops & DRM_BRIDGE_OP_HDMI) {684if (bridge_connector->bridge_hdmi)685return ERR_PTR(-EBUSY);686if (!bridge->funcs->hdmi_write_infoframe ||687!bridge->funcs->hdmi_clear_infoframe)688return ERR_PTR(-EINVAL);689690bridge_connector->bridge_hdmi = bridge;691692if (bridge->supported_formats)693supported_formats = bridge->supported_formats;694if (bridge->max_bpc)695max_bpc = bridge->max_bpc;696}697698if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO) {699if (bridge_connector->bridge_hdmi_audio)700return ERR_PTR(-EBUSY);701702if (bridge_connector->bridge_dp_audio)703return ERR_PTR(-EBUSY);704705if (!bridge->hdmi_audio_max_i2s_playback_channels &&706!bridge->hdmi_audio_spdif_playback)707return ERR_PTR(-EINVAL);708709if (!bridge->funcs->hdmi_audio_prepare ||710!bridge->funcs->hdmi_audio_shutdown)711return ERR_PTR(-EINVAL);712713bridge_connector->bridge_hdmi_audio = bridge;714}715716if (bridge->ops & DRM_BRIDGE_OP_DP_AUDIO) {717if (bridge_connector->bridge_dp_audio)718return ERR_PTR(-EBUSY);719720if (bridge_connector->bridge_hdmi_audio)721return ERR_PTR(-EBUSY);722723if (!bridge->hdmi_audio_max_i2s_playback_channels &&724!bridge->hdmi_audio_spdif_playback)725return ERR_PTR(-EINVAL);726727if (!bridge->funcs->dp_audio_prepare ||728!bridge->funcs->dp_audio_shutdown)729return ERR_PTR(-EINVAL);730731bridge_connector->bridge_dp_audio = bridge;732}733734if (bridge->ops & DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER) {735if (bridge_connector->bridge_hdmi_cec)736return ERR_PTR(-EBUSY);737738bridge_connector->bridge_hdmi_cec = bridge;739}740741if (bridge->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) {742if (bridge_connector->bridge_hdmi_cec)743return ERR_PTR(-EBUSY);744745bridge_connector->bridge_hdmi_cec = bridge;746747if (!bridge->funcs->hdmi_cec_enable ||748!bridge->funcs->hdmi_cec_log_addr ||749!bridge->funcs->hdmi_cec_transmit)750return ERR_PTR(-EINVAL);751}752753if (drm_bridge_is_last(bridge))754connector_type = bridge->type;755756#ifdef CONFIG_OF757if (drm_bridge_is_last(bridge) && bridge->of_node)758connector->fwnode = fwnode_handle_get(of_fwnode_handle(bridge->of_node));759#endif760761if (bridge->ddc)762ddc = bridge->ddc;763764if (drm_bridge_is_panel(bridge))765panel_bridge = bridge;766767if (bridge->support_hdcp)768support_hdcp = true;769}770771if (connector_type == DRM_MODE_CONNECTOR_Unknown)772return ERR_PTR(-EINVAL);773774if (bridge_connector->bridge_hdmi) {775if (!connector->ycbcr_420_allowed)776supported_formats &= ~BIT(HDMI_COLORSPACE_YUV420);777778ret = drmm_connector_hdmi_init(drm, connector,779bridge_connector->bridge_hdmi->vendor,780bridge_connector->bridge_hdmi->product,781&drm_bridge_connector_funcs,782&drm_bridge_connector_hdmi_funcs,783connector_type, ddc,784supported_formats,785max_bpc);786if (ret)787return ERR_PTR(ret);788} else {789ret = drmm_connector_init(drm, connector,790&drm_bridge_connector_funcs,791connector_type, ddc);792if (ret)793return ERR_PTR(ret);794}795796if (bridge_connector->bridge_hdmi_audio ||797bridge_connector->bridge_dp_audio) {798struct device *dev;799struct drm_bridge *bridge;800801if (bridge_connector->bridge_hdmi_audio)802bridge = bridge_connector->bridge_hdmi_audio;803else804bridge = bridge_connector->bridge_dp_audio;805806dev = bridge->hdmi_audio_dev;807808ret = drm_connector_hdmi_audio_init(connector, dev,809&drm_bridge_connector_hdmi_audio_funcs,810bridge->hdmi_audio_max_i2s_playback_channels,811bridge->hdmi_audio_i2s_formats,812bridge->hdmi_audio_spdif_playback,813bridge->hdmi_audio_dai_port);814if (ret)815return ERR_PTR(ret);816}817818if (bridge_connector->bridge_hdmi_cec &&819bridge_connector->bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER) {820bridge = bridge_connector->bridge_hdmi_cec;821822ret = drmm_connector_hdmi_cec_notifier_register(connector,823NULL,824bridge->hdmi_cec_dev);825if (ret)826return ERR_PTR(ret);827}828829if (bridge_connector->bridge_hdmi_cec &&830bridge_connector->bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) {831bridge = bridge_connector->bridge_hdmi_cec;832833ret = drmm_connector_hdmi_cec_register(connector,834&drm_bridge_connector_hdmi_cec_funcs,835bridge->hdmi_cec_adapter_name,836bridge->hdmi_cec_available_las,837bridge->hdmi_cec_dev);838if (ret)839return ERR_PTR(ret);840}841842drm_connector_helper_add(connector, &drm_bridge_connector_helper_funcs);843844if (bridge_connector->bridge_hpd)845connector->polled = DRM_CONNECTOR_POLL_HPD;846else if (bridge_connector->bridge_detect)847connector->polled = DRM_CONNECTOR_POLL_CONNECT848| DRM_CONNECTOR_POLL_DISCONNECT;849850if (panel_bridge)851drm_panel_bridge_set_orientation(connector, panel_bridge);852853if (support_hdcp && IS_REACHABLE(CONFIG_DRM_DISPLAY_HELPER) &&854IS_ENABLED(CONFIG_DRM_DISPLAY_HDCP_HELPER))855drm_connector_attach_content_protection_property(connector, true);856857return connector;858}859EXPORT_SYMBOL_GPL(drm_bridge_connector_init);860861862