[v3,03/10] lib: Move DisplayPort CRC functions to common lib

Message ID 20240507155413.266057-4-panikiel@google.com (mailing list archive)
State New
Delegated to: Hans Verkuil
Headers
Series Add Chameleon v3 video support |

Commit Message

Paweł Anikiel May 7, 2024, 3:54 p.m. UTC
  The CRC functions found in drivers/gpu/drm/display/drm_dp_mst_topology.c
may be useful for other non-DRM code that deals with DisplayPort, e.g.
v4l2 drivers for DP receivers. Move these functions to /lib.

Signed-off-by: Paweł Anikiel <panikiel@google.com>
---
 drivers/gpu/drm/display/Kconfig               |  1 +
 drivers/gpu/drm/display/drm_dp_mst_topology.c | 76 ++----------------
 include/linux/crc-dp.h                        | 10 +++
 lib/Kconfig                                   |  8 ++
 lib/Makefile                                  |  1 +
 lib/crc-dp.c                                  | 78 +++++++++++++++++++
 6 files changed, 103 insertions(+), 71 deletions(-)
 create mode 100644 include/linux/crc-dp.h
 create mode 100644 lib/crc-dp.c
  

Patch

diff --git a/drivers/gpu/drm/display/Kconfig b/drivers/gpu/drm/display/Kconfig
index c0f56888c328..eda19645201d 100644
--- a/drivers/gpu/drm/display/Kconfig
+++ b/drivers/gpu/drm/display/Kconfig
@@ -14,6 +14,7 @@  config DRM_DISPLAY_HELPER
 config DRM_DISPLAY_DP_HELPER
 	bool
 	depends on DRM_DISPLAY_HELPER
+	select CRC_DP
 	help
 	  DRM display helpers for DisplayPort.
 
diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c
index 03d528209426..54ba98d3bc6f 100644
--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c
@@ -22,6 +22,7 @@ 
 
 #include <linux/bitfield.h>
 #include <linux/delay.h>
+#include <linux/crc-dp.h>
 #include <linux/errno.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
@@ -195,73 +196,6 @@  drm_dp_mst_rad_to_str(const u8 rad[8], u8 lct, char *out, size_t len)
 }
 
 /* sideband msg handling */
-static u8 drm_dp_msg_header_crc4(const uint8_t *data, size_t num_nibbles)
-{
-	u8 bitmask = 0x80;
-	u8 bitshift = 7;
-	u8 array_index = 0;
-	int number_of_bits = num_nibbles * 4;
-	u8 remainder = 0;
-
-	while (number_of_bits != 0) {
-		number_of_bits--;
-		remainder <<= 1;
-		remainder |= (data[array_index] & bitmask) >> bitshift;
-		bitmask >>= 1;
-		bitshift--;
-		if (bitmask == 0) {
-			bitmask = 0x80;
-			bitshift = 7;
-			array_index++;
-		}
-		if ((remainder & 0x10) == 0x10)
-			remainder ^= 0x13;
-	}
-
-	number_of_bits = 4;
-	while (number_of_bits != 0) {
-		number_of_bits--;
-		remainder <<= 1;
-		if ((remainder & 0x10) != 0)
-			remainder ^= 0x13;
-	}
-
-	return remainder;
-}
-
-static u8 drm_dp_msg_data_crc4(const uint8_t *data, u8 number_of_bytes)
-{
-	u8 bitmask = 0x80;
-	u8 bitshift = 7;
-	u8 array_index = 0;
-	int number_of_bits = number_of_bytes * 8;
-	u16 remainder = 0;
-
-	while (number_of_bits != 0) {
-		number_of_bits--;
-		remainder <<= 1;
-		remainder |= (data[array_index] & bitmask) >> bitshift;
-		bitmask >>= 1;
-		bitshift--;
-		if (bitmask == 0) {
-			bitmask = 0x80;
-			bitshift = 7;
-			array_index++;
-		}
-		if ((remainder & 0x100) == 0x100)
-			remainder ^= 0xd5;
-	}
-
-	number_of_bits = 8;
-	while (number_of_bits != 0) {
-		number_of_bits--;
-		remainder <<= 1;
-		if ((remainder & 0x100) != 0)
-			remainder ^= 0xd5;
-	}
-
-	return remainder & 0xff;
-}
 static inline u8 drm_dp_calc_sb_hdr_size(struct drm_dp_sideband_msg_hdr *hdr)
 {
 	u8 size = 3;
@@ -284,7 +218,7 @@  static void drm_dp_encode_sideband_msg_hdr(struct drm_dp_sideband_msg_hdr *hdr,
 		(hdr->msg_len & 0x3f);
 	buf[idx++] = (hdr->somt << 7) | (hdr->eomt << 6) | (hdr->seqno << 4);
 
-	crc4 = drm_dp_msg_header_crc4(buf, (idx * 2) - 1);
+	crc4 = crc_dp_msg_header(buf, (idx * 2) - 1);
 	buf[idx - 1] |= (crc4 & 0xf);
 
 	*len = idx;
@@ -305,7 +239,7 @@  static bool drm_dp_decode_sideband_msg_hdr(const struct drm_dp_mst_topology_mgr
 	len += ((buf[0] & 0xf0) >> 4) / 2;
 	if (len > buflen)
 		return false;
-	crc4 = drm_dp_msg_header_crc4(buf, (len * 2) - 1);
+	crc4 = crc_dp_msg_header(buf, (len * 2) - 1);
 
 	if ((crc4 & 0xf) != (buf[len - 1] & 0xf)) {
 		drm_dbg_kms(mgr->dev, "crc4 mismatch 0x%x 0x%x\n", crc4, buf[len - 1]);
@@ -725,7 +659,7 @@  static void drm_dp_crc_sideband_chunk_req(u8 *msg, u8 len)
 {
 	u8 crc4;
 
-	crc4 = drm_dp_msg_data_crc4(msg, len);
+	crc4 = crc_dp_msg_data(msg, len);
 	msg[len] = crc4;
 }
 
@@ -782,7 +716,7 @@  static bool drm_dp_sideband_append_payload(struct drm_dp_sideband_msg_rx *msg,
 
 	if (msg->curchunk_idx >= msg->curchunk_len) {
 		/* do CRC */
-		crc4 = drm_dp_msg_data_crc4(msg->chunk, msg->curchunk_len - 1);
+		crc4 = crc_dp_msg_data(msg->chunk, msg->curchunk_len - 1);
 		if (crc4 != msg->chunk[msg->curchunk_len - 1])
 			print_hex_dump(KERN_DEBUG, "wrong crc",
 				       DUMP_PREFIX_NONE, 16, 1,
diff --git a/include/linux/crc-dp.h b/include/linux/crc-dp.h
new file mode 100644
index 000000000000..b63435c82b96
--- /dev/null
+++ b/include/linux/crc-dp.h
@@ -0,0 +1,10 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_CRC_DP_H
+#define _LINUX_CRC_DP_H
+
+#include <linux/types.h>
+
+u8 crc_dp_msg_header(const uint8_t *data, size_t num_nibbles);
+u8 crc_dp_msg_data(const uint8_t *data, u8 number_of_bytes);
+
+#endif /* _LINUX_CRC_DP_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 4557bb8a5256..d2836dacf10d 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -168,6 +168,14 @@  config CRC_ITU_T
 	  the kernel tree does. Such modules that use library CRC ITU-T V.41
 	  functions require M here.
 
+config CRC_DP
+	tristate "CRC DisplayPort MST functions"
+	help
+	  This option is provided for the case where no in-kernel-tree
+	  modules require CRC DisplayPort MST functions, but a module built outside
+	  the kernel tree does. Such modules that use library CRC DisplayPort MST
+	  functions require M here.
+
 config CRC32
 	tristate "CRC32/CRC32c functions"
 	default y
diff --git a/lib/Makefile b/lib/Makefile
index ffc6b2341b45..82edf655036b 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -186,6 +186,7 @@  obj-$(CONFIG_CRC7)	+= crc7.o
 obj-$(CONFIG_LIBCRC32C)	+= libcrc32c.o
 obj-$(CONFIG_CRC8)	+= crc8.o
 obj-$(CONFIG_CRC64_ROCKSOFT) += crc64-rocksoft.o
+obj-$(CONFIG_CRC_DP)	+= crc-dp.o
 obj-$(CONFIG_XXHASH)	+= xxhash.o
 obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o
 
diff --git a/lib/crc-dp.c b/lib/crc-dp.c
new file mode 100644
index 000000000000..95b58bc436d4
--- /dev/null
+++ b/lib/crc-dp.c
@@ -0,0 +1,78 @@ 
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/crc-dp.h>
+
+/*
+ * Sideband MSG Header CRC
+ * Defined in DisplayPort 1.2 spec, section 2.11.3.1.9
+ */
+u8 crc_dp_msg_header(const uint8_t *data, size_t num_nibbles)
+{
+	u8 bitmask = 0x80;
+	u8 bitshift = 7;
+	u8 array_index = 0;
+	int number_of_bits = num_nibbles * 4;
+	u8 remainder = 0;
+
+	while (number_of_bits != 0) {
+		number_of_bits--;
+		remainder <<= 1;
+		remainder |= (data[array_index] & bitmask) >> bitshift;
+		bitmask >>= 1;
+		bitshift--;
+		if (bitmask == 0) {
+			bitmask = 0x80;
+			bitshift = 7;
+			array_index++;
+		}
+		if ((remainder & 0x10) == 0x10)
+			remainder ^= 0x13;
+	}
+
+	number_of_bits = 4;
+	while (number_of_bits != 0) {
+		number_of_bits--;
+		remainder <<= 1;
+		if ((remainder & 0x10) != 0)
+			remainder ^= 0x13;
+	}
+
+	return remainder;
+}
+
+/*
+ * Sideband MSG Data CRC
+ * Defined in DisplayPort 1.2 spec, section 2.11.3.2.2
+ */
+u8 crc_dp_msg_data(const uint8_t *data, u8 number_of_bytes)
+{
+	u8 bitmask = 0x80;
+	u8 bitshift = 7;
+	u8 array_index = 0;
+	int number_of_bits = number_of_bytes * 8;
+	u16 remainder = 0;
+
+	while (number_of_bits != 0) {
+		number_of_bits--;
+		remainder <<= 1;
+		remainder |= (data[array_index] & bitmask) >> bitshift;
+		bitmask >>= 1;
+		bitshift--;
+		if (bitmask == 0) {
+			bitmask = 0x80;
+			bitshift = 7;
+			array_index++;
+		}
+		if ((remainder & 0x100) == 0x100)
+			remainder ^= 0xd5;
+	}
+
+	number_of_bits = 8;
+	while (number_of_bits != 0) {
+		number_of_bits--;
+		remainder <<= 1;
+		if ((remainder & 0x100) != 0)
+			remainder ^= 0xd5;
+	}
+
+	return remainder & 0xff;
+}