diff mbox

[2/2] drm: mipi: Add software-calculated ECC & CRC flags

Message ID 1439392340-17130-2-git-send-email-seanpaul@chromium.org (mailing list archive)
State New, archived
Headers show

Commit Message

Sean Paul Aug. 12, 2015, 3:12 p.m. UTC
Allow ECC and CRC for a packet to be calculated in software.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
 drivers/gpu/drm/drm_mipi_dsi.c | 56 ++++++++++++++++++++++++++++++++++++++++--
 include/drm/drm_mipi_dsi.h     |  6 +++++
 2 files changed, 60 insertions(+), 2 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index 2d5ca8ee..77390e6 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -312,6 +312,54 @@  bool mipi_dsi_packet_format_is_long(u8 type)
 }
 EXPORT_SYMBOL(mipi_dsi_packet_format_is_long);
 
+#define BIT_VAL(x, nr) ((x & BIT(nr)) >> nr)
+#define XOR13(x, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13) \
+	(BIT_VAL(x, b1) ^ BIT_VAL(x, b2) ^ BIT_VAL(x, b3) ^ BIT_VAL(x, b4) ^ \
+	 BIT_VAL(x, b5) ^ BIT_VAL(x, b6) ^ BIT_VAL(x, b7) ^ BIT_VAL(x, b8) ^ \
+	 BIT_VAL(x, b9) ^ BIT_VAL(x, b10) ^ BIT_VAL(x, b11) ^ \
+	 BIT_VAL(x, b12) ^ BIT_VAL(x, b13))
+#define XOR14(x, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14) \
+	(XOR13(x, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13) ^ \
+	 BIT_VAL(x, b14))
+
+static u8 mipi_dsi_calculate_ecc(const u8 *header)
+{
+	u8 ecc;
+	u32 v = header[2] << 16 | header[1] << 8 | header[0];
+
+	ecc = XOR14(v, 0, 1, 2, 4, 5, 7, 10, 11, 13, 16, 20, 21, 22, 23) |
+	      XOR14(v, 0, 1, 3, 4, 6, 8, 10, 12, 14, 17, 20, 21, 22, 23) << 1 |
+	      XOR13(v, 0, 2, 3, 5, 6, 9, 11, 12, 15, 18, 20, 21, 22) << 2 |
+	      XOR13(v, 1, 2, 3, 7, 8, 9, 13, 14, 15, 19, 20, 21, 23) << 3 |
+	      XOR13(v, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19, 20, 22, 23) << 4 |
+	      XOR13(v, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23) << 5;
+	return ecc;
+}
+
+static u16 mipi_dsi_calculate_crc(struct mipi_dsi_packet *packet)
+{
+	static const u16 gen_code = 0x8408;
+	size_t i, j;
+	u16 ret = 0xFFFF;
+
+	/* If the packet is zero-length, return 0xFFFF as the checksum */
+	if (packet->payload_length == 0)
+		return 0xFFFF;
+
+	for (i = 0; i < packet->payload_length; i++) {
+		u8 d = packet->payload[i];
+
+		for (j = 0; j < 8; j++) {
+			if (((ret & 1) ^ (d & 1)) > 0)
+				ret = ((ret >> 1) & 0x7FFF) ^ gen_code;
+			else
+				ret = (ret >> 1) & 0x7FFF;
+			d = (d >> 1) & 0x7F;
+		}
+	}
+	return ret;
+}
+
 /**
  * mipi_dsi_create_packet - create a packet from a message according to the
  *     DSI protocol
@@ -337,8 +385,6 @@  int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
 	memset(packet, 0, sizeof(*packet));
 	packet->header[0] = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f);
 
-	/* TODO: compute ECC if hardware support is not available */
-
 	/*
 	 * Long write packets contain the word count in header bytes 1 and 2.
 	 * The payload follows the header and is word count bytes long.
@@ -359,8 +405,14 @@  int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
 		packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0;
 	}
 
+	if (msg->flags & MIPI_DSI_MSG_SW_ECC)
+		packet->header[3] = mipi_dsi_calculate_ecc(packet->header);
+
 	packet->size = sizeof(packet->header) + packet->payload_length;
 
+	if (msg->flags & MIPI_DSI_MSG_SW_CRC)
+		packet->checksum = mipi_dsi_calculate_crc(packet);
+
 	return 0;
 }
 EXPORT_SYMBOL(mipi_dsi_create_packet);
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index f1d8d0d..49d52ba 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -21,6 +21,10 @@  struct mipi_dsi_device;
 #define MIPI_DSI_MSG_REQ_ACK	BIT(0)
 /* use Low Power Mode to transmit message */
 #define MIPI_DSI_MSG_USE_LPM	BIT(1)
+/* calculate ECC in software */
+#define MIPI_DSI_MSG_SW_ECC	BIT(2)
+/* calculate checksum in software */
+#define MIPI_DSI_MSG_SW_CRC	BIT(3)
 
 /**
  * struct mipi_dsi_msg - read/write DSI buffer
@@ -54,12 +58,14 @@  bool mipi_dsi_packet_format_is_long(u8 type);
  *     Packet Data, and ECC)
  * @payload_length: number of bytes in the payload
  * @payload: a pointer to a buffer containing the payload, if any
+ * @checksum: the CRC of the payload (only applies to long packets)
  */
 struct mipi_dsi_packet {
 	size_t size;
 	u8 header[4];
 	size_t payload_length;
 	const u8 *payload;
+	u16 checksum;
 };
 
 int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,