platform: msm_shared: Enable crypto HW version check

Crypto HW version prior to 5.1.0 has a hardware bug which
requires descriptor addresses to be burst aligned. Restrict
this behaviour to older crypto HW by checking the crypto HW version.

Change-Id: I14905ffbc559f6876b474c80cf37394e264fe385
CRs-Fixed: 595242
diff --git a/platform/msm_shared/crypto5_eng.c b/platform/msm_shared/crypto5_eng.c
index 3fecd61..c954a7f 100644
--- a/platform/msm_shared/crypto5_eng.c
+++ b/platform/msm_shared/crypto5_eng.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -414,19 +414,45 @@
 	crypto_SHA256_ctx *sha256_ctx = (crypto_SHA256_ctx *) ctx_ptr;
 	uint32_t wr_flags = BAM_DESC_NWD_FLAG | BAM_DESC_INT_FLAG | BAM_DESC_EOT_FLAG;
 	uint32_t ret_status;
+	uint32_t minor_ver = 0;
+	uint8_t *buffer = NULL;
 
-	/* A H/W bug on Crypto 5.0.0 enforces a rule that the desc lengths must be burst aligned. */
-	if ((uint32_t) data_ptr & (CRYPTO_BURST_LEN - 1))
+	/* Bits 23:16 - minor version */
+	minor_ver = (readl(CRYPTO_VERSION(dev->base)) & 0x00FF0000) >> 16;
+
+	/* A H/W bug on Crypto 5.0.0 enforces a rule that the desc lengths must be burst aligned.
+	 * This bug is fixed in 5.1.0 onwards.*/
+
+	if(minor_ver == 0)
 	{
-		dprintf(CRITICAL, "Crypto send data failed\n");
-		dprintf(CRITICAL, "Data start not aligned at burst length.\n");
-		ret_status = CRYPTO_ERR_FAIL;
-		goto CRYPTO_SEND_DATA_ERR;
+		if ((uint32_t) data_ptr & (CRYPTO_BURST_LEN - 1))
+		{
+			dprintf(CRITICAL, "Data start not aligned at burst length.\n");
+
+			buffer = (uint8_t *)memalign(CRYPTO_BURST_LEN, sha256_ctx->bytes_to_write);
+			if(!buffer)
+			{
+				dprintf(CRITICAL, "ERROR: Failed to allocate burst aligned crypto buffer\n");
+				ret_status = CRYPTO_ERR_FAIL;
+				goto CRYPTO_SEND_DATA_ERR;
+			}
+
+			memset(buffer, 0, sha256_ctx->bytes_to_write);
+			memcpy(buffer, data_ptr, sha256_ctx->bytes_to_write);
+		}
 	}
 
-	arch_clean_invalidate_cache_range((addr_t) data_ptr, sha256_ctx->bytes_to_write);
+	if(buffer)
+	{
+		arch_clean_invalidate_cache_range((addr_t) buffer, sha256_ctx->bytes_to_write);
 
-	bam_status = ADD_WRITE_DESC(&dev->bam, data_ptr, sha256_ctx->bytes_to_write, wr_flags);
+		bam_status = ADD_WRITE_DESC(&dev->bam, buffer, sha256_ctx->bytes_to_write, wr_flags);
+	}
+	else
+	{
+		arch_clean_invalidate_cache_range((addr_t) data_ptr, sha256_ctx->bytes_to_write);
+		bam_status = ADD_WRITE_DESC(&dev->bam, data_ptr, sha256_ctx->bytes_to_write, wr_flags);
+	}
 
 	if (bam_status)
 	{
@@ -459,6 +485,9 @@
 
 CRYPTO_SEND_DATA_ERR:
 
+	if(buffer)
+		free(buffer);
+
 	return ret_status;
 }