diff --git a/common/cmd_mem.c b/common/cmd_mem.c
index 12dbc1609c..95b49b2100 100644
--- a/common/cmd_mem.c
+++ b/common/cmd_mem.c
@@ -32,6 +32,7 @@
 #ifdef CONFIG_HAS_DATAFLASH
 #include <dataflash.h>
 #endif
+#include <hash.h>
 #include <watchdog.h>
 #include <asm/io.h>
 #include <linux/compiler.h>
@@ -1098,89 +1099,27 @@ mod_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[])
 
 #ifdef CONFIG_CMD_CRC32
 
-#ifndef CONFIG_CRC32_VERIFY
-
 static int do_mem_crc(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	ulong addr, length;
-	ulong crc;
-	ulong *ptr;
+	int flags = 0;
+	int ac;
+	char * const *av;
 
 	if (argc < 3)
 		return CMD_RET_USAGE;
 
-	addr = simple_strtoul (argv[1], NULL, 16);
-	addr += base_address;
-
-	length = simple_strtoul (argv[2], NULL, 16);
-
-	crc = crc32_wd (0, (const uchar *) addr, length, CHUNKSZ_CRC32);
-
-	printf ("CRC32 for %08lx ... %08lx ==> %08lx\n",
-			addr, addr + length - 1, crc);
-
-	if (argc > 3) {
-		ptr = (ulong *) simple_strtoul (argv[3], NULL, 16);
-		*ptr = crc;
-	}
-
-	return 0;
-}
-
-#else	/* CONFIG_CRC32_VERIFY */
-
-int do_mem_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
-{
-	ulong addr, length;
-	ulong crc;
-	ulong *ptr;
-	ulong vcrc;
-	int verify;
-	int ac;
-	char * const *av;
-
-	if (argc < 3) {
-usage:
-		return CMD_RET_USAGE;
-	}
-
 	av = argv + 1;
 	ac = argc - 1;
+#ifdef CONFIG_HASH_VERIFY
 	if (strcmp(*av, "-v") == 0) {
-		verify = 1;
+		flags |= HASH_FLAG_VERIFY;
 		av++;
 		ac--;
-		if (ac < 3)
-			goto usage;
-	} else
-		verify = 0;
-
-	addr = simple_strtoul(*av++, NULL, 16);
-	addr += base_address;
-	length = simple_strtoul(*av++, NULL, 16);
-
-	crc = crc32_wd (0, (const uchar *) addr, length, CHUNKSZ_CRC32);
-
-	if (!verify) {
-		printf ("CRC32 for %08lx ... %08lx ==> %08lx\n",
-				addr, addr + length - 1, crc);
-		if (ac > 2) {
-			ptr = (ulong *) simple_strtoul (*av++, NULL, 16);
-			*ptr = crc;
-		}
-	} else {
-		vcrc = simple_strtoul(*av++, NULL, 16);
-		if (vcrc != crc) {
-			printf ("CRC32 for %08lx ... %08lx ==> %08lx != %08lx ** ERROR **\n",
-					addr, addr + length - 1, crc, vcrc);
-			return 1;
-		}
 	}
+#endif
 
-	return 0;
-
+	return hash_command("crc32", flags, cmdtp, flag, ac, av);
 }
-#endif	/* CONFIG_CRC32_VERIFY */
 
 #endif
 
diff --git a/common/hash.c b/common/hash.c
index 462853d172..ef6fe375d2 100644
--- a/common/hash.c
+++ b/common/hash.c
@@ -34,13 +34,19 @@
  * crypto could perhaps add named version of these algorithms here.
  */
 static struct hash_algo hash_algo[] = {
-#ifdef CONFIG_SHA1
+	/*
+	 * This is CONFIG_CMD_SHA1SUM instead of CONFIG_SHA1 since otherwise
+	 * it bloats the code for boards which use SHA1 but not the 'hash'
+	 * or 'sha1sum' commands.
+	 */
+#ifdef CONFIG_CMD_SHA1SUM
 	{
 		"SHA1",
 		SHA1_SUM_LEN,
 		sha1_csum_wd,
 		CHUNKSZ_SHA1,
 	},
+#define MULTI_HASH
 #endif
 #ifdef CONFIG_SHA256
 	{
@@ -49,9 +55,27 @@ static struct hash_algo hash_algo[] = {
 		sha256_csum_wd,
 		CHUNKSZ_SHA256,
 	},
+#define MULTI_HASH
 #endif
+	{
+		"CRC32",
+		4,
+		crc32_wd_buf,
+		CHUNKSZ_CRC32,
+	},
 };
 
+#if defined(CONFIG_HASH_VERIFY) || defined(CONFIG_CMD_HASH)
+#define MULTI_HASH
+#endif
+
+/* Try to minimize code size for boards that don't want much hashing */
+#ifdef MULTI_HASH
+#define multi_hash()	1
+#else
+#define multi_hash()	0
+#endif
+
 /**
  * store_result: Store the resulting sum to an address or variable
  *
@@ -192,10 +216,7 @@ static void show_hash(struct hash_algo *algo, ulong addr, ulong len,
 int hash_command(const char *algo_name, int flags, cmd_tbl_t *cmdtp, int flag,
 		 int argc, char * const argv[])
 {
-	struct hash_algo *algo;
 	ulong addr, len;
-	u8 output[HASH_MAX_DIGEST_SIZE];
-	u8 vsum[HASH_MAX_DIGEST_SIZE];
 
 	if (argc < 2)
 		return CMD_RET_USAGE;
@@ -203,52 +224,73 @@ int hash_command(const char *algo_name, int flags, cmd_tbl_t *cmdtp, int flag,
 	addr = simple_strtoul(*argv++, NULL, 16);
 	len = simple_strtoul(*argv++, NULL, 16);
 
-	algo = find_hash_algo(algo_name);
-	if (!algo) {
-		printf("Unknown hash algorithm '%s'\n", algo_name);
-		return CMD_RET_USAGE;
-	}
-	argc -= 2;
+	if (multi_hash()) {
+		struct hash_algo *algo;
+		u8 output[HASH_MAX_DIGEST_SIZE];
+		u8 vsum[HASH_MAX_DIGEST_SIZE];
 
-	if (algo->digest_size > HASH_MAX_DIGEST_SIZE) {
-		puts("HASH_MAX_DIGEST_SIZE exceeded\n");
-		return 1;
-	}
-
-	algo->hash_func_ws((const unsigned char *)addr, len, output,
-			   algo->chunk_size);
-
-	/* Try to avoid code bloat when verify is not needed */
-#ifdef CONFIG_HASH_VERIFY
-	if (flags & HASH_FLAG_VERIFY) {
-#else
-	if (0) {
-#endif
-		if (!argc)
+		algo = find_hash_algo(algo_name);
+		if (!algo) {
+			printf("Unknown hash algorithm '%s'\n", algo_name);
 			return CMD_RET_USAGE;
-		if (parse_verify_sum(algo, *argv, vsum,
+		}
+		argc -= 2;
+
+		if (algo->digest_size > HASH_MAX_DIGEST_SIZE) {
+			puts("HASH_MAX_DIGEST_SIZE exceeded\n");
+			return 1;
+		}
+
+		algo->hash_func_ws((const unsigned char *)addr, len, output,
+				   algo->chunk_size);
+
+		/* Try to avoid code bloat when verify is not needed */
+#ifdef CONFIG_HASH_VERIFY
+		if (flags & HASH_FLAG_VERIFY) {
+#else
+		if (0) {
+#endif
+			if (!argc)
+				return CMD_RET_USAGE;
+			if (parse_verify_sum(algo, *argv, vsum,
 					flags & HASH_FLAG_ENV)) {
-			printf("ERROR: %s does not contain a valid %s sum\n",
-				*argv, algo->name);
-			return 1;
-		}
-		if (memcmp(output, vsum, algo->digest_size) != 0) {
-			int i;
+				printf("ERROR: %s does not contain a valid "
+					"%s sum\n", *argv, algo->name);
+				return 1;
+			}
+			if (memcmp(output, vsum, algo->digest_size) != 0) {
+				int i;
 
+				show_hash(algo, addr, len, output);
+				printf(" != ");
+				for (i = 0; i < algo->digest_size; i++)
+					printf("%02x", vsum[i]);
+				puts(" ** ERROR **\n");
+				return 1;
+			}
+		} else {
 			show_hash(algo, addr, len, output);
-			printf(" != ");
-			for (i = 0; i < algo->digest_size; i++)
-				printf("%02x", vsum[i]);
-			puts(" ** ERROR **\n");
-			return 1;
-		}
-	} else {
-		show_hash(algo, addr, len, output);
-		printf("\n");
+			printf("\n");
 
-		if (argc) {
-			store_result(algo, output, *argv,
-				flags & HASH_FLAG_ENV);
+			if (argc) {
+				store_result(algo, output, *argv,
+					flags & HASH_FLAG_ENV);
+			}
+		}
+
+	/* Horrible code size hack for boards that just want crc32 */
+	} else {
+		ulong crc;
+		ulong *ptr;
+
+		crc = crc32_wd(0, (const uchar *)addr, len, CHUNKSZ_CRC32);
+
+		printf("CRC32 for %08lx ... %08lx ==> %08lx\n",
+				addr, addr + len - 1, crc);
+
+		if (argc > 3) {
+			ptr = (ulong *)simple_strtoul(argv[3], NULL, 16);
+			*ptr = crc;
 		}
 	}
 
diff --git a/include/hash.h b/include/hash.h
index 88fa2b5a57..f2b2c4520d 100644
--- a/include/hash.h
+++ b/include/hash.h
@@ -22,7 +22,7 @@
 #ifndef _HASH_H
 #define _HASH_H
 
-#ifdef CONFIG_SHA1SUM_VERIFY
+#if defined(CONFIG_SHA1SUM_VERIFY) || defined(CONFIG_CRC32_VERIFY)
 #define CONFIG_HASH_VERIFY
 #endif
 
diff --git a/include/u-boot/crc.h b/include/u-boot/crc.h
index 07badbfc5a..08e509edb4 100644
--- a/include/u-boot/crc.h
+++ b/include/u-boot/crc.h
@@ -30,4 +30,15 @@ uint32_t crc32 (uint32_t, const unsigned char *, uint);
 uint32_t crc32_wd (uint32_t, const unsigned char *, uint, uint);
 uint32_t crc32_no_comp (uint32_t, const unsigned char *, uint);
 
+/**
+ * crc32_wd_buf - Perform CRC32 on a buffer and return result in buffer
+ *
+ * @input:	Input buffer
+ * @ilen:	Input buffer length
+ * @output:	Place to put checksum result (4 bytes)
+ * @chunk_sz:	Trigger watchdog after processing this many bytes
+ */
+void crc32_wd_buf(const unsigned char *input, uint ilen,
+		    unsigned char *output, uint chunk_sz);
+
 #endif /* _UBOOT_CRC_H */
diff --git a/lib/crc32.c b/lib/crc32.c
index 27335a3ed9..76205da4f3 100644
--- a/lib/crc32.c
+++ b/lib/crc32.c
@@ -249,3 +249,12 @@ uint32_t ZEXPORT crc32_wd (uint32_t crc,
 
 	return crc;
 }
+
+void crc32_wd_buf(const unsigned char *input, unsigned int ilen,
+		unsigned char *output, unsigned int chunk_sz)
+{
+	uint32_t crc;
+
+	crc = crc32_wd(0, input, ilen, chunk_sz);
+	memcpy(output, &crc, sizeof(crc));
+}