| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758 |
- // SPDX-License-Identifier: MIT
- #include <drm/drm_atomic.h>
- #include <drm/drm_connector.h>
- #include <drm/drm_edid.h>
- #include <drm/drm_print.h>
- #include <drm/display/drm_hdmi_helper.h>
- #include <drm/display/drm_hdmi_state_helper.h>
- /**
- * __drm_atomic_helper_connector_hdmi_reset() - Initializes all HDMI @drm_connector_state resources
- * @connector: DRM connector
- * @new_conn_state: connector state to reset
- *
- * Initializes all HDMI resources from a @drm_connector_state without
- * actually allocating it. This is useful for HDMI drivers, in
- * combination with __drm_atomic_helper_connector_reset() or
- * drm_atomic_helper_connector_reset().
- */
- void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector *connector,
- struct drm_connector_state *new_conn_state)
- {
- unsigned int max_bpc = connector->max_bpc;
- new_conn_state->max_bpc = max_bpc;
- new_conn_state->max_requested_bpc = max_bpc;
- new_conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_AUTO;
- }
- EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset);
- static const struct drm_display_mode *
- connector_state_get_mode(const struct drm_connector_state *conn_state)
- {
- struct drm_atomic_state *state;
- struct drm_crtc_state *crtc_state;
- struct drm_crtc *crtc;
- state = conn_state->state;
- if (!state)
- return NULL;
- crtc = conn_state->crtc;
- if (!crtc)
- return NULL;
- crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
- if (!crtc_state)
- return NULL;
- return &crtc_state->mode;
- }
- static bool hdmi_is_limited_range(const struct drm_connector *connector,
- const struct drm_connector_state *conn_state)
- {
- const struct drm_display_info *info = &connector->display_info;
- const struct drm_display_mode *mode =
- connector_state_get_mode(conn_state);
- /*
- * The Broadcast RGB property only applies to RGB format, and
- * i915 just assumes limited range for YCbCr output, so let's
- * just do the same.
- */
- if (conn_state->hdmi.output_format != HDMI_COLORSPACE_RGB)
- return true;
- if (conn_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_FULL)
- return false;
- if (conn_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_LIMITED)
- return true;
- if (!info->is_hdmi)
- return false;
- return drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED;
- }
- static bool
- sink_supports_format_bpc(const struct drm_connector *connector,
- const struct drm_display_info *info,
- const struct drm_display_mode *mode,
- unsigned int format, unsigned int bpc)
- {
- struct drm_device *dev = connector->dev;
- u8 vic = drm_match_cea_mode(mode);
- /*
- * CTA-861-F, section 5.4 - Color Coding & Quantization states
- * that the bpc must be 8, 10, 12 or 16 except for the default
- * 640x480 VIC1 where the value must be 8.
- *
- * The definition of default here is ambiguous but the spec
- * refers to VIC1 being the default timing in several occasions
- * so our understanding is that for the default timing (ie,
- * VIC1), the bpc must be 8.
- */
- if (vic == 1 && bpc != 8) {
- drm_dbg_kms(dev, "VIC1 requires a bpc of 8, got %u\n", bpc);
- return false;
- }
- if (!info->is_hdmi &&
- (format != HDMI_COLORSPACE_RGB || bpc != 8)) {
- drm_dbg_kms(dev, "DVI Monitors require an RGB output at 8 bpc\n");
- return false;
- }
- if (!(connector->hdmi.supported_formats & BIT(format))) {
- drm_dbg_kms(dev, "%s format unsupported by the connector.\n",
- drm_hdmi_connector_get_output_format_name(format));
- return false;
- }
- switch (format) {
- case HDMI_COLORSPACE_RGB:
- drm_dbg_kms(dev, "RGB Format, checking the constraints.\n");
- /*
- * In some cases, like when the EDID readout fails, or
- * is not an HDMI compliant EDID for some reason, the
- * color_formats field will be blank and not report any
- * format supported. In such a case, assume that RGB is
- * supported so we can keep things going and light up
- * the display.
- */
- if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444))
- drm_warn(dev, "HDMI Sink doesn't support RGB, something's wrong.\n");
- if (bpc == 10 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30)) {
- drm_dbg_kms(dev, "10 BPC but sink doesn't support Deep Color 30.\n");
- return false;
- }
- if (bpc == 12 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36)) {
- drm_dbg_kms(dev, "12 BPC but sink doesn't support Deep Color 36.\n");
- return false;
- }
- drm_dbg_kms(dev, "RGB format supported in that configuration.\n");
- return true;
- case HDMI_COLORSPACE_YUV420:
- /* TODO: YUV420 is unsupported at the moment. */
- drm_dbg_kms(dev, "YUV420 format isn't supported yet.\n");
- return false;
- case HDMI_COLORSPACE_YUV422:
- drm_dbg_kms(dev, "YUV422 format, checking the constraints.\n");
- if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR422)) {
- drm_dbg_kms(dev, "Sink doesn't support YUV422.\n");
- return false;
- }
- if (bpc > 12) {
- drm_dbg_kms(dev, "YUV422 only supports 12 bpc or lower.\n");
- return false;
- }
- /*
- * HDMI Spec 1.3 - Section 6.5 Pixel Encodings and Color Depth
- * states that Deep Color is not relevant for YUV422 so we
- * don't need to check the Deep Color bits in the EDIDs here.
- */
- drm_dbg_kms(dev, "YUV422 format supported in that configuration.\n");
- return true;
- case HDMI_COLORSPACE_YUV444:
- drm_dbg_kms(dev, "YUV444 format, checking the constraints.\n");
- if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR444)) {
- drm_dbg_kms(dev, "Sink doesn't support YUV444.\n");
- return false;
- }
- if (bpc == 10 && !(info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_30)) {
- drm_dbg_kms(dev, "10 BPC but sink doesn't support Deep Color 30.\n");
- return false;
- }
- if (bpc == 12 && !(info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_36)) {
- drm_dbg_kms(dev, "12 BPC but sink doesn't support Deep Color 36.\n");
- return false;
- }
- drm_dbg_kms(dev, "YUV444 format supported in that configuration.\n");
- return true;
- }
- drm_dbg_kms(dev, "Unsupported pixel format.\n");
- return false;
- }
- static enum drm_mode_status
- hdmi_clock_valid(const struct drm_connector *connector,
- const struct drm_display_mode *mode,
- unsigned long long clock)
- {
- const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
- const struct drm_display_info *info = &connector->display_info;
- if (info->max_tmds_clock && clock > info->max_tmds_clock * 1000)
- return MODE_CLOCK_HIGH;
- if (funcs && funcs->tmds_char_rate_valid) {
- enum drm_mode_status status;
- status = funcs->tmds_char_rate_valid(connector, mode, clock);
- if (status != MODE_OK)
- return status;
- }
- return MODE_OK;
- }
- static int
- hdmi_compute_clock(const struct drm_connector *connector,
- struct drm_connector_state *conn_state,
- const struct drm_display_mode *mode,
- unsigned int bpc, enum hdmi_colorspace fmt)
- {
- enum drm_mode_status status;
- unsigned long long clock;
- clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
- if (!clock)
- return -EINVAL;
- status = hdmi_clock_valid(connector, mode, clock);
- if (status != MODE_OK)
- return -EINVAL;
- conn_state->hdmi.tmds_char_rate = clock;
- return 0;
- }
- static bool
- hdmi_try_format_bpc(const struct drm_connector *connector,
- struct drm_connector_state *conn_state,
- const struct drm_display_mode *mode,
- unsigned int bpc, enum hdmi_colorspace fmt)
- {
- const struct drm_display_info *info = &connector->display_info;
- struct drm_device *dev = connector->dev;
- int ret;
- drm_dbg_kms(dev, "Trying %s output format\n",
- drm_hdmi_connector_get_output_format_name(fmt));
- if (!sink_supports_format_bpc(connector, info, mode, fmt, bpc)) {
- drm_dbg_kms(dev, "%s output format not supported with %u bpc\n",
- drm_hdmi_connector_get_output_format_name(fmt),
- bpc);
- return false;
- }
- ret = hdmi_compute_clock(connector, conn_state, mode, bpc, fmt);
- if (ret) {
- drm_dbg_kms(dev, "Couldn't compute clock for %s output format and %u bpc\n",
- drm_hdmi_connector_get_output_format_name(fmt),
- bpc);
- return false;
- }
- drm_dbg_kms(dev, "%s output format supported with %u (TMDS char rate: %llu Hz)\n",
- drm_hdmi_connector_get_output_format_name(fmt),
- bpc, conn_state->hdmi.tmds_char_rate);
- return true;
- }
- static int
- hdmi_compute_format(const struct drm_connector *connector,
- struct drm_connector_state *conn_state,
- const struct drm_display_mode *mode,
- unsigned int bpc)
- {
- struct drm_device *dev = connector->dev;
- /*
- * TODO: Add support for YCbCr420 output for HDMI 2.0 capable
- * devices, for modes that only support YCbCr420.
- */
- if (hdmi_try_format_bpc(connector, conn_state, mode, bpc, HDMI_COLORSPACE_RGB)) {
- conn_state->hdmi.output_format = HDMI_COLORSPACE_RGB;
- return 0;
- }
- drm_dbg_kms(dev, "Failed. No Format Supported for that bpc count.\n");
- return -EINVAL;
- }
- static int
- hdmi_compute_config(const struct drm_connector *connector,
- struct drm_connector_state *conn_state,
- const struct drm_display_mode *mode)
- {
- struct drm_device *dev = connector->dev;
- unsigned int max_bpc = clamp_t(unsigned int,
- conn_state->max_bpc,
- 8, connector->max_bpc);
- unsigned int bpc;
- int ret;
- for (bpc = max_bpc; bpc >= 8; bpc -= 2) {
- drm_dbg_kms(dev, "Trying with a %d bpc output\n", bpc);
- ret = hdmi_compute_format(connector, conn_state, mode, bpc);
- if (ret)
- continue;
- conn_state->hdmi.output_bpc = bpc;
- drm_dbg_kms(dev,
- "Mode %ux%u @ %uHz: Found configuration: bpc: %u, fmt: %s, clock: %llu\n",
- mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode),
- conn_state->hdmi.output_bpc,
- drm_hdmi_connector_get_output_format_name(conn_state->hdmi.output_format),
- conn_state->hdmi.tmds_char_rate);
- return 0;
- }
- return -EINVAL;
- }
- static int hdmi_generate_avi_infoframe(const struct drm_connector *connector,
- struct drm_connector_state *conn_state)
- {
- const struct drm_display_mode *mode =
- connector_state_get_mode(conn_state);
- struct drm_connector_hdmi_infoframe *infoframe =
- &conn_state->hdmi.infoframes.avi;
- struct hdmi_avi_infoframe *frame =
- &infoframe->data.avi;
- bool is_limited_range = conn_state->hdmi.is_limited_range;
- enum hdmi_quantization_range rgb_quant_range =
- is_limited_range ? HDMI_QUANTIZATION_RANGE_LIMITED : HDMI_QUANTIZATION_RANGE_FULL;
- int ret;
- infoframe->set = false;
- ret = drm_hdmi_avi_infoframe_from_display_mode(frame, connector, mode);
- if (ret)
- return ret;
- frame->colorspace = conn_state->hdmi.output_format;
- /*
- * FIXME: drm_hdmi_avi_infoframe_quant_range() doesn't handle
- * YUV formats at all at the moment, so if we ever support YUV
- * formats this needs to be revised.
- */
- drm_hdmi_avi_infoframe_quant_range(frame, connector, mode, rgb_quant_range);
- drm_hdmi_avi_infoframe_colorimetry(frame, conn_state);
- drm_hdmi_avi_infoframe_bars(frame, conn_state);
- infoframe->set = true;
- return 0;
- }
- static int hdmi_generate_spd_infoframe(const struct drm_connector *connector,
- struct drm_connector_state *conn_state)
- {
- struct drm_connector_hdmi_infoframe *infoframe =
- &conn_state->hdmi.infoframes.spd;
- struct hdmi_spd_infoframe *frame =
- &infoframe->data.spd;
- int ret;
- infoframe->set = false;
- ret = hdmi_spd_infoframe_init(frame,
- connector->hdmi.vendor,
- connector->hdmi.product);
- if (ret)
- return ret;
- frame->sdi = HDMI_SPD_SDI_PC;
- infoframe->set = true;
- return 0;
- }
- static int hdmi_generate_hdr_infoframe(const struct drm_connector *connector,
- struct drm_connector_state *conn_state)
- {
- struct drm_connector_hdmi_infoframe *infoframe =
- &conn_state->hdmi.infoframes.hdr_drm;
- struct hdmi_drm_infoframe *frame =
- &infoframe->data.drm;
- int ret;
- infoframe->set = false;
- if (connector->max_bpc < 10)
- return 0;
- if (!conn_state->hdr_output_metadata)
- return 0;
- ret = drm_hdmi_infoframe_set_hdr_metadata(frame, conn_state);
- if (ret)
- return ret;
- infoframe->set = true;
- return 0;
- }
- static int hdmi_generate_hdmi_vendor_infoframe(const struct drm_connector *connector,
- struct drm_connector_state *conn_state)
- {
- const struct drm_display_info *info = &connector->display_info;
- const struct drm_display_mode *mode =
- connector_state_get_mode(conn_state);
- struct drm_connector_hdmi_infoframe *infoframe =
- &conn_state->hdmi.infoframes.hdmi;
- struct hdmi_vendor_infoframe *frame =
- &infoframe->data.vendor.hdmi;
- int ret;
- infoframe->set = false;
- if (!info->has_hdmi_infoframe)
- return 0;
- ret = drm_hdmi_vendor_infoframe_from_display_mode(frame, connector, mode);
- if (ret)
- return ret;
- infoframe->set = true;
- return 0;
- }
- static int
- hdmi_generate_infoframes(const struct drm_connector *connector,
- struct drm_connector_state *conn_state)
- {
- const struct drm_display_info *info = &connector->display_info;
- int ret;
- if (!info->is_hdmi)
- return 0;
- ret = hdmi_generate_avi_infoframe(connector, conn_state);
- if (ret)
- return ret;
- ret = hdmi_generate_spd_infoframe(connector, conn_state);
- if (ret)
- return ret;
- /*
- * Audio Infoframes will be generated by ALSA, and updated by
- * drm_atomic_helper_connector_hdmi_update_audio_infoframe().
- */
- ret = hdmi_generate_hdr_infoframe(connector, conn_state);
- if (ret)
- return ret;
- ret = hdmi_generate_hdmi_vendor_infoframe(connector, conn_state);
- if (ret)
- return ret;
- return 0;
- }
- /**
- * drm_atomic_helper_connector_hdmi_check() - Helper to check HDMI connector atomic state
- * @connector: DRM Connector
- * @state: the DRM State object
- *
- * Provides a default connector state check handler for HDMI connectors.
- * Checks that a desired connector update is valid, and updates various
- * fields of derived state.
- *
- * RETURNS:
- * Zero on success, or an errno code otherwise.
- */
- int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector,
- struct drm_atomic_state *state)
- {
- struct drm_connector_state *old_conn_state =
- drm_atomic_get_old_connector_state(state, connector);
- struct drm_connector_state *new_conn_state =
- drm_atomic_get_new_connector_state(state, connector);
- const struct drm_display_mode *mode =
- connector_state_get_mode(new_conn_state);
- int ret;
- new_conn_state->hdmi.is_limited_range = hdmi_is_limited_range(connector, new_conn_state);
- ret = hdmi_compute_config(connector, new_conn_state, mode);
- if (ret)
- return ret;
- ret = hdmi_generate_infoframes(connector, new_conn_state);
- if (ret)
- return ret;
- if (old_conn_state->hdmi.broadcast_rgb != new_conn_state->hdmi.broadcast_rgb ||
- old_conn_state->hdmi.output_bpc != new_conn_state->hdmi.output_bpc ||
- old_conn_state->hdmi.output_format != new_conn_state->hdmi.output_format) {
- struct drm_crtc *crtc = new_conn_state->crtc;
- struct drm_crtc_state *crtc_state;
- crtc_state = drm_atomic_get_crtc_state(state, crtc);
- if (IS_ERR(crtc_state))
- return PTR_ERR(crtc_state);
- crtc_state->mode_changed = true;
- }
- return 0;
- }
- EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_check);
- static int clear_device_infoframe(struct drm_connector *connector,
- enum hdmi_infoframe_type type)
- {
- const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
- struct drm_device *dev = connector->dev;
- int ret;
- drm_dbg_kms(dev, "Clearing infoframe type 0x%x\n", type);
- if (!funcs || !funcs->clear_infoframe) {
- drm_dbg_kms(dev, "Function not implemented, bailing.\n");
- return 0;
- }
- ret = funcs->clear_infoframe(connector, type);
- if (ret) {
- drm_dbg_kms(dev, "Call failed: %d\n", ret);
- return ret;
- }
- return 0;
- }
- static int clear_infoframe(struct drm_connector *connector,
- struct drm_connector_hdmi_infoframe *old_frame)
- {
- int ret;
- ret = clear_device_infoframe(connector, old_frame->data.any.type);
- if (ret)
- return ret;
- return 0;
- }
- static int write_device_infoframe(struct drm_connector *connector,
- union hdmi_infoframe *frame)
- {
- const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
- struct drm_device *dev = connector->dev;
- u8 buffer[HDMI_INFOFRAME_SIZE(MAX)];
- int ret;
- int len;
- drm_dbg_kms(dev, "Writing infoframe type %x\n", frame->any.type);
- if (!funcs || !funcs->write_infoframe) {
- drm_dbg_kms(dev, "Function not implemented, bailing.\n");
- return -EINVAL;
- }
- len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer));
- if (len < 0)
- return len;
- ret = funcs->write_infoframe(connector, frame->any.type, buffer, len);
- if (ret) {
- drm_dbg_kms(dev, "Call failed: %d\n", ret);
- return ret;
- }
- return 0;
- }
- static int write_infoframe(struct drm_connector *connector,
- struct drm_connector_hdmi_infoframe *new_frame)
- {
- int ret;
- ret = write_device_infoframe(connector, &new_frame->data);
- if (ret)
- return ret;
- return 0;
- }
- static int write_or_clear_infoframe(struct drm_connector *connector,
- struct drm_connector_hdmi_infoframe *old_frame,
- struct drm_connector_hdmi_infoframe *new_frame)
- {
- if (new_frame->set)
- return write_infoframe(connector, new_frame);
- if (old_frame->set && !new_frame->set)
- return clear_infoframe(connector, old_frame);
- return 0;
- }
- /**
- * drm_atomic_helper_connector_hdmi_update_infoframes - Update the Infoframes
- * @connector: A pointer to the HDMI connector
- * @state: The HDMI connector state to generate the infoframe from
- *
- * This function is meant for HDMI connector drivers to write their
- * infoframes. It will typically be used in a
- * @drm_connector_helper_funcs.atomic_enable implementation.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
- int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *connector,
- struct drm_atomic_state *state)
- {
- struct drm_connector_state *old_conn_state =
- drm_atomic_get_old_connector_state(state, connector);
- struct drm_connector_state *new_conn_state =
- drm_atomic_get_new_connector_state(state, connector);
- struct drm_display_info *info = &connector->display_info;
- int ret;
- if (!info->is_hdmi)
- return 0;
- mutex_lock(&connector->hdmi.infoframes.lock);
- ret = write_or_clear_infoframe(connector,
- &old_conn_state->hdmi.infoframes.avi,
- &new_conn_state->hdmi.infoframes.avi);
- if (ret)
- goto out;
- if (connector->hdmi.infoframes.audio.set) {
- ret = write_infoframe(connector,
- &connector->hdmi.infoframes.audio);
- if (ret)
- goto out;
- }
- ret = write_or_clear_infoframe(connector,
- &old_conn_state->hdmi.infoframes.hdr_drm,
- &new_conn_state->hdmi.infoframes.hdr_drm);
- if (ret)
- goto out;
- ret = write_or_clear_infoframe(connector,
- &old_conn_state->hdmi.infoframes.spd,
- &new_conn_state->hdmi.infoframes.spd);
- if (ret)
- goto out;
- if (info->has_hdmi_infoframe) {
- ret = write_or_clear_infoframe(connector,
- &old_conn_state->hdmi.infoframes.hdmi,
- &new_conn_state->hdmi.infoframes.hdmi);
- if (ret)
- goto out;
- }
- out:
- mutex_unlock(&connector->hdmi.infoframes.lock);
- return ret;
- }
- EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_update_infoframes);
- /**
- * drm_atomic_helper_connector_hdmi_update_audio_infoframe - Update the Audio Infoframe
- * @connector: A pointer to the HDMI connector
- * @frame: A pointer to the audio infoframe to write
- *
- * This function is meant for HDMI connector drivers to update their
- * audio infoframe. It will typically be used in one of the ALSA hooks
- * (most likely prepare).
- *
- * Returns:
- * Zero on success, error code on failure.
- */
- int
- drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector *connector,
- struct hdmi_audio_infoframe *frame)
- {
- struct drm_connector_hdmi_infoframe *infoframe =
- &connector->hdmi.infoframes.audio;
- struct drm_display_info *info = &connector->display_info;
- int ret;
- if (!info->is_hdmi)
- return 0;
- mutex_lock(&connector->hdmi.infoframes.lock);
- memcpy(&infoframe->data, frame, sizeof(infoframe->data));
- infoframe->set = true;
- ret = write_infoframe(connector, infoframe);
- mutex_unlock(&connector->hdmi.infoframes.lock);
- return ret;
- }
- EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_update_audio_infoframe);
- /**
- * drm_atomic_helper_connector_hdmi_clear_audio_infoframe - Stop sending the Audio Infoframe
- * @connector: A pointer to the HDMI connector
- *
- * This function is meant for HDMI connector drivers to stop sending their
- * audio infoframe. It will typically be used in one of the ALSA hooks
- * (most likely shutdown).
- *
- * Returns:
- * Zero on success, error code on failure.
- */
- int
- drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *connector)
- {
- struct drm_connector_hdmi_infoframe *infoframe =
- &connector->hdmi.infoframes.audio;
- struct drm_display_info *info = &connector->display_info;
- int ret;
- if (!info->is_hdmi)
- return 0;
- mutex_lock(&connector->hdmi.infoframes.lock);
- infoframe->set = false;
- ret = clear_infoframe(connector, infoframe);
- memset(&infoframe->data, 0, sizeof(infoframe->data));
- mutex_unlock(&connector->hdmi.infoframes.lock);
- return ret;
- }
- EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_clear_audio_infoframe);
|