[PATCH 4/9] lib: Move DisplayPort CRC functions to common lib

From: Paweł Anikiel
Date: Mon Feb 12 2024 - 08:21:41 EST


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@xxxxxxxxxx>
---
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

diff --git a/drivers/gpu/drm/display/Kconfig b/drivers/gpu/drm/display/Kconfig
index 09712b88a5b8..c615f50152f2 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 f7c6b60629c2..ada1f90fa808 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 5ddda7c2ed9b..28f9f6cfec9f 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -171,6 +171,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 6b09731d8e61..e4d7ffa260b3 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -188,6 +188,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;
+}
--
2.43.0.687.g38aa6559b0-goog