summaryrefslogtreecommitdiff
path: root/drivers/video/hdmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/hdmi.c')
-rw-r--r--drivers/video/hdmi.c133
1 files changed, 74 insertions, 59 deletions
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index e70792b3e367..45b42f14a750 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -21,6 +21,7 @@
* DEALINGS IN THE SOFTWARE.
*/
+#include <drm/display/drm_dp.h>
#include <linux/bitops.h>
#include <linux/bug.h>
#include <linux/errno.h>
@@ -221,14 +222,18 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
const char *vendor, const char *product)
{
+ size_t len;
+
memset(frame, 0, sizeof(*frame));
frame->type = HDMI_INFOFRAME_TYPE_SPD;
frame->version = 1;
frame->length = HDMI_SPD_INFOFRAME_SIZE;
- strncpy(frame->vendor, vendor, sizeof(frame->vendor));
- strncpy(frame->product, product, sizeof(frame->product));
+ len = strlen(vendor);
+ memcpy(frame->vendor, vendor, min(len, sizeof(frame->vendor)));
+ len = strlen(product);
+ memcpy(frame->product, product, min(len, sizeof(frame->product)));
return 0;
}
@@ -377,12 +382,34 @@ static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *fr
*
* Returns 0 on success or a negative error code on failure.
*/
-int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
+int hdmi_audio_infoframe_check(const struct hdmi_audio_infoframe *frame)
{
return hdmi_audio_infoframe_check_only(frame);
}
EXPORT_SYMBOL(hdmi_audio_infoframe_check);
+static void
+hdmi_audio_infoframe_pack_payload(const struct hdmi_audio_infoframe *frame,
+ u8 *buffer)
+{
+ u8 channels;
+
+ if (frame->channels >= 2)
+ channels = frame->channels - 1;
+ else
+ channels = 0;
+
+ buffer[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7);
+ buffer[1] = ((frame->sample_frequency & 0x7) << 2) |
+ (frame->sample_size & 0x3);
+ buffer[2] = frame->coding_type_ext & 0x1f;
+ buffer[3] = frame->channel_allocation;
+ buffer[4] = (frame->level_shift_value & 0xf) << 3;
+
+ if (frame->downmix_inhibit)
+ buffer[4] |= BIT(7);
+}
+
/**
* hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
* @frame: HDMI audio infoframe
@@ -400,7 +427,6 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_check);
ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
void *buffer, size_t size)
{
- unsigned char channels;
u8 *ptr = buffer;
size_t length;
int ret;
@@ -416,28 +442,13 @@ ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
memset(buffer, 0, size);
- if (frame->channels >= 2)
- channels = frame->channels - 1;
- else
- channels = 0;
-
ptr[0] = frame->type;
ptr[1] = frame->version;
ptr[2] = frame->length;
ptr[3] = 0; /* checksum */
- /* start infoframe payload */
- ptr += HDMI_INFOFRAME_HEADER_SIZE;
-
- ptr[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7);
- ptr[1] = ((frame->sample_frequency & 0x7) << 2) |
- (frame->sample_size & 0x3);
- ptr[2] = frame->coding_type_ext & 0x1f;
- ptr[3] = frame->channel_allocation;
- ptr[4] = (frame->level_shift_value & 0xf) << 3;
-
- if (frame->downmix_inhibit)
- ptr[4] |= BIT(7);
+ hdmi_audio_infoframe_pack_payload(frame,
+ ptr + HDMI_INFOFRAME_HEADER_SIZE);
hdmi_infoframe_set_checksum(buffer, length);
@@ -476,6 +487,43 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
/**
+ * hdmi_audio_infoframe_pack_for_dp - Pack a HDMI Audio infoframe for DisplayPort
+ *
+ * @frame: HDMI Audio infoframe
+ * @sdp: Secondary data packet for DisplayPort.
+ * @dp_version: DisplayPort version to be encoded in the header
+ *
+ * Packs a HDMI Audio Infoframe to be sent over DisplayPort. This function
+ * fills the secondary data packet to be used for DisplayPort.
+ *
+ * Return: Number of total written bytes or a negative errno on failure.
+ */
+ssize_t
+hdmi_audio_infoframe_pack_for_dp(const struct hdmi_audio_infoframe *frame,
+ struct dp_sdp *sdp, u8 dp_version)
+{
+ int ret;
+
+ ret = hdmi_audio_infoframe_check(frame);
+ if (ret)
+ return ret;
+
+ memset(sdp->db, 0, sizeof(sdp->db));
+
+ /* Secondary-data packet header */
+ sdp->sdp_header.HB0 = 0;
+ sdp->sdp_header.HB1 = frame->type;
+ sdp->sdp_header.HB2 = DP_SDP_AUDIO_INFOFRAME_HB2;
+ sdp->sdp_header.HB3 = (dp_version & 0x3f) << 2;
+
+ hdmi_audio_infoframe_pack_payload(frame, sdp->db);
+
+ /* Return size = frame length + four HB for sdp_header */
+ return frame->length + 4;
+}
+EXPORT_SYMBOL(hdmi_audio_infoframe_pack_for_dp);
+
+/**
* hdmi_vendor_infoframe_init() - initialize an HDMI vendor infoframe
* @frame: HDMI vendor infoframe
*
@@ -495,7 +543,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
* value
*/
frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
- frame->length = 4;
+ frame->length = HDMI_VENDOR_INFOFRAME_SIZE;
return 0;
}
@@ -847,34 +895,6 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
}
/**
- * hdmi_infoframe_check() - check a HDMI infoframe
- * @frame: HDMI infoframe
- *
- * Validates that the infoframe is consistent and updates derived fields
- * (eg. length) based on other fields.
- *
- * Returns 0 on success or a negative error code on failure.
- */
-int
-hdmi_infoframe_check(union hdmi_infoframe *frame)
-{
- switch (frame->any.type) {
- case HDMI_INFOFRAME_TYPE_AVI:
- return hdmi_avi_infoframe_check(&frame->avi);
- case HDMI_INFOFRAME_TYPE_SPD:
- return hdmi_spd_infoframe_check(&frame->spd);
- case HDMI_INFOFRAME_TYPE_AUDIO:
- return hdmi_audio_infoframe_check(&frame->audio);
- case HDMI_INFOFRAME_TYPE_VENDOR:
- return hdmi_vendor_any_infoframe_check(&frame->vendor);
- default:
- WARN(1, "Bad infoframe type %d\n", frame->any.type);
- return -EINVAL;
- }
-}
-EXPORT_SYMBOL(hdmi_infoframe_check);
-
-/**
* hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
* @frame: HDMI infoframe
* @buffer: destination buffer
@@ -1262,17 +1282,11 @@ static void hdmi_spd_infoframe_log(const char *level,
struct device *dev,
const struct hdmi_spd_infoframe *frame)
{
- u8 buf[17];
-
hdmi_infoframe_log_header(level, dev,
(const struct hdmi_any_infoframe *)frame);
- memset(buf, 0, sizeof(buf));
-
- strncpy(buf, frame->vendor, 8);
- hdmi_log(" vendor: %s\n", buf);
- strncpy(buf, frame->product, 16);
- hdmi_log(" product: %s\n", buf);
+ hdmi_log(" vendor: %.8s\n", frame->vendor);
+ hdmi_log(" product: %.16s\n", frame->product);
hdmi_log(" source device information: %s (0x%x)\n",
hdmi_spd_sdi_get_name(frame->sdi), frame->sdi);
}
@@ -1688,7 +1702,8 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
}
/**
- * hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe
+ * hdmi_vendor_any_infoframe_unpack() - unpack binary buffer to a HDMI
+ * vendor infoframe
* @frame: HDMI Vendor infoframe
* @buffer: source buffer
* @size: size of buffer