-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

MicroSD card support for Neo Freerunner U-Boot :-)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org

iD8DBQFHs1A/OjLpvpq7dMoRApO4AJwNOFnbx7WX+Yi0zX8azXEZIYcXLACeLXEG
jYi3nrZush/uGk8Gz6oc8Ks=
=+WNz
-----END PGP SIGNATURE-----
introduce-uboot-glamo-mmc.patch

From: Andy Green <[EMAIL PROTECTED]>

This ports the Glamo MMC driver from Linux to U-Boot.

U-Boot is a lot less welcoming than Linux for MMC, you have
to do your own MMC stack as well as the driver.  I took the
opportunity to add SDHC support, at least it works for my
4GB SDHC card in block mode well enough to load and boot
into a kernel from a FAT partition.  Its also tested on a
non-SDHC 512MB SD 2.0.0 card in byte addressing mode.

I also enabled and tested 4-bit mode, it always enables it
but it should be okay for any modern microSD card.  It also
cranks all cards up to 16MHz, again it should be okay given
the card format is so new. Speed is not bad at around
1MByte/sec read, it's fine for normal use.

Write is implemented but I didn't test it, I doubt it would
see much use in U-Boot.

The card is depowered before exit to Linux so it will be
detected normally there.

I also found in my travels that ext2 support seems broken
in U-Boot but I didn't explore it any further after deciding
it didn't seem to be anything I was doing.  FAT support
works though.

I was able to put a kernel and rootfs entirely on the SD card
by fdisking two partitions on there, first a small FAT one for
the kernel uImage and second a large ext2 one for the rootfs.
This worked fine and surprising quickly booted to a shell
prompt entirely from microSD.  I had to configure Linux to have
EXT2 support in the monolithic kernel.

To do this kind of thing use the following U-Boot type commands
(assumes a file "kernel" in top level directory of first
partition on card is the U-Boot kernel image)

mmcinit
fatload mmc 1 0x32000000 kernel
setenv bootargs rootfstype=vfat root=/dev/mmcblk0p1 console=ttySAC2,115200 console=tty0 loglevel=2
bootm 0x32000000

The existing setup had CONFIG_MMC associate only with the S3C
driver from GTA01 so I added an additional CONFIG_ to tell
between them for GTA01 and GTA02 configs.

Signed-off-by: Andy Green <[EMAIL PROTECTED]>
---

 board/neo1973/gta02/Makefile    |    2 
 board/neo1973/gta02/glamo-mmc.c |  826 +++++++++++++++++++++++++++++++++++++++
 board/neo1973/gta02/glamo-mmc.h |  149 +++++++
 common/cmd_bootm.c              |    6 
 cpu/arm920t/s3c24x0/mmc.c       |    4 
 include/configs/neo1973_gta01.h |    1 
 include/configs/neo1973_gta02.h |    5 
 7 files changed, 989 insertions(+), 4 deletions(-)
 create mode 100644 board/neo1973/gta02/glamo-mmc.c
 create mode 100644 board/neo1973/gta02/glamo-mmc.h


diff --git a/board/neo1973/gta02/Makefile b/board/neo1973/gta02/Makefile
index 27b2d89..be8b7f6 100644
--- a/board/neo1973/gta02/Makefile
+++ b/board/neo1973/gta02/Makefile
@@ -25,7 +25,7 @@ include $(TOPDIR)/config.mk
 
 LIB	= lib$(BOARD).a
 
-OBJS	:= gta02.o pcf50633.o nand.o nor.o ../common/cmd_neo1973.o \
+OBJS	:= gta02.o pcf50633.o nand.o nor.o glamo-mmc.o ../common/cmd_neo1973.o \
 	   ../common/gsmver.o \
 	   ../common/jbt6k74.o ../common/udc.o ../common/bootmenu.o
 SOBJS	:= ../common/lowlevel_init.o
diff --git a/board/neo1973/gta02/glamo-mmc.c b/board/neo1973/gta02/glamo-mmc.c
new file mode 100644
index 0000000..0413242
--- /dev/null
+++ b/board/neo1973/gta02/glamo-mmc.c
@@ -0,0 +1,826 @@
+/*
+ *  linux/drivers/mmc/host/glamo-mmc.c - Glamo MMC driver
+ *
+ *  Copyright (C) 2007 OpenMoko, Inc,  Andy Green <[EMAIL PROTECTED]>
+ *  Based on the Glamo MCI driver that was -->
+ *
+ *  Copyright (C) 2007 OpenMoko, Inc,  Andy Green <[EMAIL PROTECTED]>
+ *  Based on S3C MMC driver that was:
+ *  Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel <[EMAIL PROTECTED]>
+ *
+ *  and
+ *
+ *  Based on S3C MMC driver that was (original copyright notice ---->)
+ *
+ * (C) Copyright 2006 by OpenMoko, Inc.
+ * Author: Harald Welte <[EMAIL PROTECTED]>
+ *
+ * based on u-boot pxa MMC driver and linux/drivers/mmc/s3c2410mci.c
+ * (C) 2005-2005 Thomas Kleffel
+ *
+ *  Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel <[EMAIL PROTECTED]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <mmc.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <part.h>
+#include <fat.h>
+#include <pcf50633.h>
+
+#include "glamo-regs.h"
+#include "glamo-mmc.h"
+
+#if defined(CONFIG_MMC) && defined(CONFIG_MMC_GLAMO)
+
+#define MMC_BLOCK_SIZE_BITS 9
+#define MMC_BLOCK_SIZE (1 << MMC_BLOCK_SIZE_BITS)
+
+#define GLAMO_REG(x) (*(volatile u16 *)(CONFIG_GLAMO_BASE + x))
+#define GLAMO_INTRAM_OFFSET (8 * 1024 * 1024)
+#define GLAMO_FB_SIZE ((8 * 1024 * 1024) - 0x10000)
+#define GLAMO_START_OF_MMC_INTMEM ((volatile u16 *)(CONFIG_GLAMO_BASE + \
+				  GLAMO_INTRAM_OFFSET + GLAMO_FB_SIZE))
+
+static int ccnt;
+static block_dev_desc_t mmc_dev;
+static mmc_csd_t mmc_csd;
+static int mmc_ready = 0;
+static int wide = 0;
+static enum card_type card_type = CARDTYPE_NONE;
+
+block_dev_desc_t * mmc_get_dev(int dev)
+{
+	return (block_dev_desc_t *)&mmc_dev;
+}
+
+static void
+glamo_reg_write(u_int16_t val, u_int16_t reg)
+{
+	GLAMO_REG(reg) = val;
+}
+
+static u_int16_t
+glamo_reg_read(u_int16_t reg)
+{
+	return GLAMO_REG(reg);
+}
+
+unsigned char CRC7(u8 * pu8, int cnt)
+{
+	u8 crc = 0;
+
+	while (cnt--) {
+		int n;
+		u8 d = *pu8++;
+		for (n = 0; n < 8; n++) {
+			crc <<= 1;
+			if ((d & 0x80) ^ (crc & 0x80))
+				crc ^= 0x09;
+			d <<= 1;
+		}
+	}
+	return (crc << 1) | 1;
+}
+
+ulong mmc_bread(int dev_num, ulong blknr, ulong blkcnt, void *dst)
+{
+	ulong src = blknr * MMC_BLOCK_SIZE;
+
+	if (!blkcnt)
+		return 0;
+
+/*	printf("mmc_bread(%d, %ld, %ld, %p)\n", dev_num, blknr, blkcnt, dst); */
+	mmc_read(src, dst, blkcnt * MMC_BLOCK_SIZE);
+	return blkcnt;
+}
+
+/* MMC_DEFAULT_RCA should probably be just 1, but this may break other code
+   that expects it to be shifted. */
+static u_int16_t rca = MMC_DEFAULT_RCA >> 16;
+
+static void do_pio_read(u16 *buf, int count_words)
+{
+	volatile u16 *from_ptr = GLAMO_START_OF_MMC_INTMEM;
+
+	while (count_words--)
+		*buf++ = *from_ptr++;
+}
+
+static void do_pio_write(u16 *buf, int count_words)
+{
+	volatile u16 *to_ptr = GLAMO_START_OF_MMC_INTMEM;
+
+	while (count_words--)
+		*to_ptr++ = *buf++;
+}
+
+
+static int mmc_cmd(int opcode, int arg, int flags,
+		   int data_size, int data_blocks,
+		   int will_stop, u16 *resp)
+{
+	u16 * pu16 = (u16 *)&resp[0];
+	u16 * reg_resp = (u16 *)(CONFIG_GLAMO_BASE + GLAMO_REGOFS_MMC +
+				 GLAMO_REG_MMC_CMD_RSP1);
+	u16 status;
+	int n;
+	u8 u8a[6];
+	u16 fire = 0;
+	int cmd_is_stop = 0;
+	int error = 0;
+
+#if 0
+	printf("mmc_cmd(opcode=%d, arg=0x%08X, flags=0x%x, "
+	       "data_size=%d, data_blocks=%d, will_stop=%d, resp=%p)\n",
+	       opcode, arg, flags, data_size, data_blocks, will_stop, resp);
+#endif
+	switch (opcode) {
+	case MMC_STOP_TRANSMISSION:
+		cmd_is_stop = 1;
+		break;
+	default:
+		break;
+	}
+
+	ccnt++;
+
+	 /* this guy has data to read/write? */
+	if ((!cmd_is_stop) && (flags & (MMC_DATA_WRITE | MMC_DATA_READ))) {
+		/*
+		* the S-Media-internal RAM offset for our MMC buffer
+		*/
+		glamo_reg_write((u16)GLAMO_FB_SIZE,
+			GLAMO_REGOFS_MMC + GLAMO_REG_MMC_WDATADS1);
+		glamo_reg_write((u16)(GLAMO_FB_SIZE >> 16),
+			GLAMO_REGOFS_MMC + GLAMO_REG_MMC_WDATADS2);
+		glamo_reg_write((u16)GLAMO_FB_SIZE,
+			GLAMO_REGOFS_MMC + GLAMO_REG_MMC_RDATADS1);
+		glamo_reg_write((u16)(GLAMO_FB_SIZE >> 16),
+			GLAMO_REGOFS_MMC + GLAMO_REG_MMC_RDATADS2);
+
+		/* set up the block info */
+		glamo_reg_write(data_size, GLAMO_REGOFS_MMC +
+					   GLAMO_REG_MMC_DATBLKLEN);
+		glamo_reg_write(data_blocks, GLAMO_REGOFS_MMC +
+					     GLAMO_REG_MMC_DATBLKCNT);
+	}
+
+	/* if we can't do it, reject as busy */
+	if (!glamo_reg_read(GLAMO_REGOFS_MMC + GLAMO_REG_MMC_RB_STAT1) &
+	     GLAMO_STAT1_MMC_IDLE)
+		return -1;
+
+	/* create an array in wire order for CRC computation */
+	u8a[0] = 0x40 | (opcode & 0x3f);
+	u8a[1] = (arg >> 24);
+	u8a[2] = (arg >> 16);
+	u8a[3] = (arg >> 8);
+	u8a[4] = arg;
+	u8a[5] = CRC7(&u8a[0], 5); /* CRC7 on first 5 bytes of packet */
+
+	/* issue the wire-order array including CRC in register order */
+	glamo_reg_write((u8a[4] << 8) | u8a[5],
+			GLAMO_REGOFS_MMC + GLAMO_REG_MMC_CMD_REG1);
+	glamo_reg_write((u8a[2] << 8) | u8a[3],
+			GLAMO_REGOFS_MMC + GLAMO_REG_MMC_CMD_REG2);
+	glamo_reg_write((u8a[0] << 8) | u8a[1],
+			GLAMO_REGOFS_MMC + GLAMO_REG_MMC_CMD_REG3);
+
+	/* command index toggle */
+	fire |= (ccnt & 1) << 12;
+
+	/* set type of command */
+	switch (mmc_cmd_type(flags)) {
+	case MMC_CMD_BC:
+		fire |= GLAMO_FIRE_MMC_CMDT_BNR;
+		break;
+	case MMC_CMD_BCR:
+		fire |= GLAMO_FIRE_MMC_CMDT_BR;
+		break;
+	case MMC_CMD_AC:
+		fire |= GLAMO_FIRE_MMC_CMDT_AND;
+		break;
+	case MMC_CMD_ADTC:
+		fire |= GLAMO_FIRE_MMC_CMDT_AD;
+		break;
+	}
+	/*
+	 * if it expects a response, set the type expected
+	 *
+	 * R1, Length  : 48bit, Normal response
+	 * R1b, Length : 48bit, same R1, but added card busy status
+	 * R2, Length  : 136bit (really 128 bits with CRC snipped)
+	 * R3, Length  : 48bit (OCR register value)
+	 * R4, Length  : 48bit, SDIO_OP_CONDITION, Reverse SDIO Card
+	 * R5, Length  : 48bit, IO_RW_DIRECTION, Reverse SDIO Card
+	 * R6, Length  : 48bit (RCA register)
+	 * R7, Length  : 48bit (interface condition, VHS(voltage supplied),
+	 *                     check pattern, CRC7)
+	 */
+	switch (mmc_resp_type(flags)) {
+	case MMC_RSP_R6: /* same index as R7 and R1 */
+		fire |= GLAMO_FIRE_MMC_RSPT_R1;
+		break;
+	case MMC_RSP_R1B:
+		fire |= GLAMO_FIRE_MMC_RSPT_R1b;
+		break;
+	case MMC_RSP_R2:
+		fire |= GLAMO_FIRE_MMC_RSPT_R2;
+		break;
+	case MMC_RSP_R3:
+		fire |= GLAMO_FIRE_MMC_RSPT_R3;
+		break;
+	/* R4 and R5 supported by chip not defined in linux/mmc/core.h (sdio) */
+	}
+	/*
+	 * From the command index, set up the command class in the host ctrllr
+	 *
+	 * missing guys present on chip but couldn't figure out how to use yet:
+	 *     0x0 "stream read"
+	 *     0x9 "cancel running command"
+	 */
+	switch (opcode) {
+	case MMC_READ_SINGLE_BLOCK:
+		fire |= GLAMO_FIRE_MMC_CC_SBR; /* single block read */
+		break;
+	case MMC_SWITCH: /* 64 byte payload */
+	case 0x33: /* observed issued by MCI */
+	case MMC_READ_MULTIPLE_BLOCK:
+		/* we will get an interrupt off this */
+		if (!will_stop)
+			/* multiblock no stop */
+			fire |= GLAMO_FIRE_MMC_CC_MBRNS;
+		else
+			 /* multiblock with stop */
+			fire |= GLAMO_FIRE_MMC_CC_MBRS;
+		break;
+	case MMC_WRITE_BLOCK:
+		fire |= GLAMO_FIRE_MMC_CC_SBW; /* single block write */
+		break;
+	case MMC_WRITE_MULTIPLE_BLOCK:
+		if (will_stop)
+			 /* multiblock with stop */
+			fire |= GLAMO_FIRE_MMC_CC_MBWS;
+		else
+			 /* multiblock NO stop-- 'RESERVED'? */
+			fire |= GLAMO_FIRE_MMC_CC_MBWNS;
+		break;
+	case MMC_STOP_TRANSMISSION:
+		fire |= GLAMO_FIRE_MMC_CC_STOP; /* STOP */
+		break;
+	default:
+		fire |= GLAMO_FIRE_MMC_CC_BASIC; /* "basic command" */
+		break;
+	}
+	/* enforce timeout */
+	glamo_reg_write(0xfff, GLAMO_REGOFS_MMC + GLAMO_REG_MMC_TIMEOUT);
+
+	/* Generate interrupt on txfer; drive strength max */
+	glamo_reg_write((glamo_reg_read(GLAMO_REGOFS_MMC +
+					GLAMO_REG_MMC_BASIC) & 0xfe) |
+			 0x0800 | GLAMO_BASIC_MMC_NO_CLK_RD_WAIT |
+			 GLAMO_BASIC_MMC_EN_COMPL_INT |
+			 GLAMO_BASIC_MMC_EN_DR_STR0 |
+			 GLAMO_BASIC_MMC_EN_DR_STR1,
+			GLAMO_REGOFS_MMC + GLAMO_REG_MMC_BASIC);
+
+	/* send the command out on the wire */
+	/* dev_info(&host->pdev->dev, "Using FIRE %04X\n", fire); */
+	glamo_reg_write(fire, GLAMO_REGOFS_MMC + GLAMO_REG_MMC_CMD_FIRE);
+
+	/*
+	 * we must spin until response is ready or timed out
+	 * -- we don't get interrupts unless there is a bulk rx
+	 */
+	do
+		status = glamo_reg_read(GLAMO_REGOFS_MMC +
+					GLAMO_REG_MMC_RB_STAT1);
+	while ((((status >> 15) & 1) != (ccnt & 1)) ||
+		(!(status & (GLAMO_STAT1_MMC_RB_RRDY |
+			     GLAMO_STAT1_MMC_RTOUT |
+			     GLAMO_STAT1_MMC_DTOUT |
+			     GLAMO_STAT1_MMC_BWERR |
+			     GLAMO_STAT1_MMC_BRERR))));
+
+	if (status & (GLAMO_STAT1_MMC_RTOUT | GLAMO_STAT1_MMC_DTOUT))
+		error = -4;
+	if (status & (GLAMO_STAT1_MMC_BWERR | GLAMO_STAT1_MMC_BRERR))
+		error = -5;
+
+	if (cmd_is_stop)
+		return 0;
+
+	if (error) {
+		printf("cmd 0x%x, arg 0x%x flags 0x%x\n", opcode, arg, flags);
+		printf("Error after cmd: 0x%x\n", error);
+		goto done;
+	}
+	/*
+	 * mangle the response registers in two different exciting
+	 * undocumented ways discovered by trial and error
+	 */
+	if (mmc_resp_type(flags) == MMC_RSP_R2)
+		/* grab the response */
+		for (n = 0; n < 8; n++) /* super mangle power 1 */
+			pu16[n ^ 6] = reg_resp[n];
+	else
+		for (n = 0; n < 3; n++) /* super mangle power 2 */
+			pu16[n] = (reg_resp[n] >> 8) |
+				  (reg_resp[n + 1] << 8);
+	/*
+	 * if we don't have bulk data to take care of, we're done
+	 */
+	if (!(flags & (MMC_DATA_READ | MMC_DATA_WRITE)))
+		goto done;
+
+	/* enforce timeout */
+	glamo_reg_write(0xfff, GLAMO_REGOFS_MMC + GLAMO_REG_MMC_TIMEOUT);
+	/*
+	 * spin
+	 */
+	while (!(glamo_reg_read(GLAMO_REG_IRQ_STATUS) & GLAMO_IRQ_MMC))
+		;
+	/* ack this interrupt source */
+	glamo_reg_write(GLAMO_IRQ_MMC, GLAMO_REG_IRQ_CLEAR);
+
+	if (status & GLAMO_STAT1_MMC_DTOUT)
+		error = -1;
+	if (status & (GLAMO_STAT1_MMC_BWERR | GLAMO_STAT1_MMC_BRERR))
+		error = -2;
+	if (status & GLAMO_STAT1_MMC_RTOUT)
+		error = -5;
+	if (error) {
+		printf("cmd 0x%x, arg 0x%x flags 0x%x\n", opcode, arg, flags);
+		printf("Error after resp: 0x%x\n", status);
+		goto done;
+	}
+#if 0
+	if (flags & MMC_DATA_READ) {
+		volatile u8 * pu8 = (volatile u8 *)GLAMO_START_OF_MMC_INTMEM;
+		for (n = 0; n < 512; n += 16) {
+			int n1;
+			for (n1 = 0; n1 < 16; n1++) {
+				printf("%02X ", pu8[n + n1]);
+			}
+			printf("\n");
+		}
+	}
+#endif
+	return 0;
+
+done:
+	return error;
+}
+
+static void glamo_mci_reset(void)
+{
+	/* reset MMC controller */
+	glamo_reg_write(GLAMO_CLOCK_MMC_RESET | GLAMO_CLOCK_MMC_DG_TCLK |
+		   GLAMO_CLOCK_MMC_EN_TCLK | GLAMO_CLOCK_MMC_DG_M9CLK |
+		   GLAMO_CLOCK_MMC_EN_M9CLK,
+		  GLAMO_REG_CLOCK_MMC);
+	udelay(100000);
+	/* and disable reset */
+	glamo_reg_write(GLAMO_CLOCK_MMC_DG_TCLK |
+		   GLAMO_CLOCK_MMC_EN_TCLK | GLAMO_CLOCK_MMC_DG_M9CLK |
+		   GLAMO_CLOCK_MMC_EN_M9CLK,
+		   GLAMO_REG_CLOCK_MMC);
+}
+
+
+static u_int8_t ldo_voltage(unsigned int millivolts)
+{
+	if (millivolts < 900)
+		return 0;
+	else if (millivolts > 3600)
+		return 0x1f;
+
+	millivolts -= 900;
+	return millivolts / 100;
+}
+
+int mmc_read(ulong src, uchar *dst, int size)
+{
+	int resp;
+	u8 response[16];
+	int size_original = size;
+
+	if ((!size) || (size & (MMC_BLOCK_SIZE - 1))) {
+		printf("Bad size %d\n", size);
+		return 0;
+	}
+
+	if (((int)dst) & 1) {
+		printf("Bad align on dst\n");
+		return 0;
+	}
+
+	resp = mmc_cmd(MMC_SET_BLOCKLEN, MMC_BLOCK_SIZE,
+		       MMC_CMD_AC | MMC_RSP_R1, 0, 0, 0,
+		       (u16 *)&response[0]);
+
+	while (size) {
+		switch (card_type) {
+		case CARDTYPE_SDHC: /* block addressing */
+			resp = mmc_cmd(MMC_READ_SINGLE_BLOCK,
+				       src >> MMC_BLOCK_SIZE_BITS,
+				       MMC_CMD_ADTC | MMC_RSP_R1 |
+				       MMC_DATA_READ, MMC_BLOCK_SIZE, 1, 0,
+				       (u16 *)&response[0]);
+			break;
+		default: /* byte addressing */
+			resp = mmc_cmd(MMC_READ_SINGLE_BLOCK, src,
+				MMC_CMD_ADTC | MMC_RSP_R1 | MMC_DATA_READ,
+				MMC_BLOCK_SIZE, 1, 0,
+				(u16 *)&response[0]);
+			break;
+		}
+		do_pio_read((u16 *)dst, MMC_BLOCK_SIZE >> 1);
+
+		if (size >= MMC_BLOCK_SIZE)
+			size -= MMC_BLOCK_SIZE;
+		else
+			size = 0;
+		dst += MMC_BLOCK_SIZE;
+		src += MMC_BLOCK_SIZE;
+	}
+	return size_original;
+}
+
+int mmc_write(uchar *src, ulong dst, int size)
+{
+	int resp;
+	u8 response[16];
+	int size_original = size;
+
+	if ((!size) || (size & (MMC_BLOCK_SIZE - 1))) {
+		printf("Bad size %d\n", size);
+		return 0;
+	}
+
+	if (((int)dst) & 1) {
+		printf("Bad align on dst\n");
+		return 0;
+	}
+
+	resp = mmc_cmd(MMC_SET_BLOCKLEN, MMC_BLOCK_SIZE,
+		       MMC_CMD_AC | MMC_RSP_R1, 0, 0, 0,
+		       (u16 *)&response[0]);
+
+	while (size) {
+		do_pio_write((u16 *)src, MMC_BLOCK_SIZE >> 1);
+		switch (card_type) {
+		case CARDTYPE_SDHC: /* block addressing */
+			resp = mmc_cmd(MMC_WRITE_BLOCK,
+				       dst >> MMC_BLOCK_SIZE_BITS,
+				       MMC_CMD_ADTC | MMC_RSP_R1 |
+								MMC_DATA_WRITE,
+				       MMC_BLOCK_SIZE, 1, 0,
+				       (u16 *)&response[0]);
+			break;
+		default: /* byte addressing */
+			resp = mmc_cmd(MMC_WRITE_BLOCK, dst,
+				       MMC_CMD_ADTC | MMC_RSP_R1 |
+								MMC_DATA_WRITE,
+				       MMC_BLOCK_SIZE, 1, 0,
+				       (u16 *)&response[0]);
+			break;
+		}
+		if (size >= MMC_BLOCK_SIZE)
+			size -= MMC_BLOCK_SIZE;
+		else
+			size = 0;
+		dst += MMC_BLOCK_SIZE;
+		src += MMC_BLOCK_SIZE;
+	}
+	return size_original;
+}
+
+static void print_mmc_cid(mmc_cid_t *cid)
+{
+	printf("MMC found. Card desciption is:\n");
+	printf("Manufacturer ID = %02x%02x%02x\n",
+		cid->id[0], cid->id[1], cid->id[2]);
+	printf("HW/FW Revision = %x %x\n",cid->hwrev, cid->fwrev);
+	cid->hwrev = cid->fwrev = 0;	/* null terminate string */
+	printf("Product Name = %s\n",cid->name);
+	printf("Serial Number = %02x%02x%02x\n",
+		cid->sn[0], cid->sn[1], cid->sn[2]);
+	printf("Month = %d\n",cid->month);
+	printf("Year = %d\n",1997 + cid->year);
+}
+
+static void print_sd_cid(const struct sd_cid *cid)
+{
+	printf("Card Type:          ");
+	switch (card_type) {
+	case CARDTYPE_NONE:
+		printf("(None)\n");
+		break;
+	case CARDTYPE_MMC:
+		printf("MMC\n");
+		break;
+	case CARDTYPE_SD:
+		printf("SD\n");
+		break;
+	case CARDTYPE_SD20:
+		printf("SD 2.0\n");
+		break;
+	case CARDTYPE_SDHC:
+		printf("SD 2.0 SDHC\n");
+		break;
+	}
+	printf("Manufacturer:       0x%02x, OEM \"%c%c\"\n",
+	    cid->mid, cid->oid_0, cid->oid_1);
+	printf("Product name:       \"%c%c%c%c%c\", revision %d.%d\n",
+	    cid->pnm_0, cid->pnm_1, cid->pnm_2, cid->pnm_3, cid->pnm_4,
+	    cid->prv >> 4, cid->prv & 15);
+	printf("Serial number:      %u\n",
+	    cid->psn_0 << 24 | cid->psn_1 << 16 | cid->psn_2 << 8 |
+	    cid->psn_3);
+	printf("Manufacturing date: %d/%d\n",
+	    cid->mdt_1 & 15,
+	    2000+((cid->mdt_0 & 15) << 4)+((cid->mdt_1 & 0xf0) >> 4));
+/*	printf("CRC:                0x%02x, b0 = %d\n",
+	    cid->crc >> 1, cid->crc & 1); */
+}
+
+
+int mmc_init(int verbose)
+{
+ 	int retries = 14, rc = -ENODEV;
+	int resp, count_reset = 0;
+	u8 response[16];
+	mmc_cid_t *mmc_cid = (mmc_cid_t *)response;
+	struct sd_cid *sd_cid = (struct sd_cid *)response;
+	u32 hcs = 0;
+
+	card_type = CARDTYPE_NONE;
+
+	/* enable engine */
+
+	glamo_reg_write(GLAMO_CLOCK_MMC_EN_M9CLK |
+			GLAMO_CLOCK_MMC_EN_TCLK |
+			GLAMO_CLOCK_MMC_DG_M9CLK |
+			GLAMO_CLOCK_MMC_DG_TCLK, GLAMO_REG_CLOCK_MMC);
+	glamo_reg_write(glamo_reg_read(GLAMO_REG_HOSTBUS(2)) |
+			GLAMO_HOSTBUS2_MMIO_EN_MMC, GLAMO_REG_HOSTBUS(2));
+
+	/* controller reset */
+
+	glamo_mci_reset();
+
+	/* power the sdcard slot */
+
+	pcf50633_reg_write(PCF50633_REG_HCLDOOUT, ldo_voltage(3300));
+	udelay(10000);
+	pcf50633_reg_write(PCF50633_REG_HCLDOOUT + 1,
+		pcf50633_reg_read(PCF50633_REG_HCLDOOUT + 1) | 1); /* on */
+	udelay(10000);
+
+	/* start the clock -- slowly (50MHz / 250 == 195kHz */
+
+	glamo_reg_write((glamo_reg_read(GLAMO_REG_CLOCK_GEN8) & 0xff00) | 250,
+			 GLAMO_REG_CLOCK_GEN8);
+
+	/* enable clock to divider input */
+
+	glamo_reg_write(glamo_reg_read(
+		GLAMO_REG_CLOCK_GEN5_1) | GLAMO_CLOCK_GEN51_EN_DIV_TCLK,
+		GLAMO_REG_CLOCK_GEN5_1);
+
+	udelay(100000);
+
+	/* set bus width to 1 */
+
+	glamo_reg_write((glamo_reg_read(GLAMO_REGOFS_MMC +
+			 GLAMO_REG_MMC_BASIC) &
+			 (~GLAMO_BASIC_MMC_EN_4BIT_DATA)),
+					GLAMO_REGOFS_MMC + GLAMO_REG_MMC_BASIC);
+
+	/* reset */
+
+	resp = mmc_cmd(MMC_GO_IDLE_STATE, 0, MMC_CMD_BCR, 0, 0, 0,
+		       (u16 *)&response[0]);
+
+	udelay(100000);
+
+	/* SDHC card? */
+
+	resp = mmc_cmd(SD_SEND_IF_COND, 0x000001aa,
+		MMC_CMD_BCR | MMC_RSP_R7, 0, 0, 0,
+		(u16 *)&response[0]);
+	if (!resp && (response[0] == 0xaa)) {
+		card_type = CARDTYPE_SD20; /* 2.0 SD, may not be SDHC */
+		hcs = 0x40000000;
+	}
+
+	/* Well, either way let's say hello in SD card protocol */
+
+	while (retries--) {
+
+		udelay(100000);
+
+		resp = mmc_cmd(MMC_APP_CMD, 0x00000000,
+			MMC_CMD_AC | MMC_RSP_R1, 0, 0, 0,
+			(u16 *)&response[0]);
+		if (resp)
+			continue;
+		resp = mmc_cmd(SD_APP_OP_COND, hcs | 0x00300000,
+			MMC_CMD_BCR | MMC_RSP_R3, 0, 0, 0,
+			(u16 *)&response[0]);
+		if (resp)
+			continue;
+
+		if (response[3] & (1 << 6)) /* asserts block addressing */
+			card_type = CARDTYPE_SDHC;
+
+		if (response[3] & (1 << 7)) { /* not busy */
+			if (card_type == CARDTYPE_NONE)
+				card_type = CARDTYPE_SD;
+			break;
+		}
+	}
+	if (retries < 0)
+		return 1;
+
+	if (card_type == CARDTYPE_NONE) {
+		retries = 10;
+		printf("failed to detect SD Card, trying MMC\n");
+		do {
+			resp = mmc_cmd(MMC_SEND_OP_COND, 0x00ffc000,
+				       MMC_CMD_BCR | MMC_RSP_R3, 0, 0, 0,
+				       (u16 *)&response[0]);
+			debug("resp %x %x\n", response[0], response[1]);
+			udelay(50);
+		} while (retries-- && !(response[3] & 0x80));
+		if (retries >= 0)
+			card_type = CARDTYPE_MMC;
+		else
+			return 1;
+	}
+
+	/* fill in device description */
+	mmc_dev.if_type = IF_TYPE_MMC;
+	mmc_dev.part_type = PART_TYPE_DOS;
+	mmc_dev.dev = 0;
+	mmc_dev.lun = 0;
+	mmc_dev.type = 0;
+	mmc_dev.removable = 0;
+	mmc_dev.block_read = mmc_bread;
+	mmc_dev.blksz = 512;
+	mmc_dev.lba = 1 << 16; /* 64K x 512 blocks = 32MB default */
+
+	/* try to get card id */
+	resp = mmc_cmd(MMC_ALL_SEND_CID, hcs,
+			MMC_CMD_BCR | MMC_RSP_R2, 0, 0, 0,
+			(u16 *)&response[0]);
+	if (resp)
+		return 1;
+
+	switch (card_type) {
+	case CARDTYPE_MMC:
+		/* TODO configure mmc driver depending on card
+			attributes */
+
+		if (verbose)
+			print_mmc_cid(mmc_cid);
+		sprintf((char *) mmc_dev.vendor,
+			"Man %02x%02x%02x Snr %02x%02x%02x",
+			mmc_cid->id[0], mmc_cid->id[1], mmc_cid->id[2],
+			mmc_cid->sn[0], mmc_cid->sn[1], mmc_cid->sn[2]);
+		sprintf((char *) mmc_dev.product, "%s", mmc_cid->name);
+		sprintf((char *) mmc_dev.revision, "%x %x",
+			mmc_cid->hwrev, mmc_cid->fwrev);
+
+		/* MMC exists, get CSD too */
+		resp = mmc_cmd(MMC_SET_RELATIVE_ADDR, MMC_DEFAULT_RCA,
+				MMC_CMD_AC | MMC_RSP_R1, 0, 0, 0,
+				(u16 *)&response[0]);
+		break;
+
+	case CARDTYPE_SD:
+	case CARDTYPE_SD20:
+	case CARDTYPE_SDHC:
+		if (verbose)
+			print_sd_cid(sd_cid);
+		sprintf((char *) mmc_dev.vendor,
+			"Man %02 OEM %c%c \"%c%c%c%c%c\"",
+			sd_cid->mid, sd_cid->oid_0, sd_cid->oid_1,
+			sd_cid->pnm_0, sd_cid->pnm_1, sd_cid->pnm_2,
+			sd_cid->pnm_3, sd_cid->pnm_4);
+		sprintf((char *) mmc_dev.product, "%d",
+			sd_cid->psn_0 << 24 | sd_cid->psn_1 << 16 |
+			sd_cid->psn_2 << 8 | sd_cid->psn_3);
+		sprintf((char *) mmc_dev.revision, "%d.%d",
+			sd_cid->prv >> 4, sd_cid->prv & 15);
+
+		resp = mmc_cmd(SD_SEND_RELATIVE_ADDR, MMC_DEFAULT_RCA,
+				MMC_CMD_BCR | MMC_RSP_R6, 0, 0, 0,
+				(u16 *)&response[0]);
+		rca = response[2] | (response[3] << 8);
+		break;
+
+	default:
+		return 1;
+	}
+
+	/* grab the CSD */
+
+	resp = mmc_cmd(MMC_SEND_CSD, rca << 16,
+			MMC_CMD_AC | MMC_RSP_R2, 0, 0, 0,
+			(u16 *)&response[0]);
+	if (!resp) {
+		mmc_csd_t *csd = (mmc_csd_t *)response;
+
+		memcpy(&mmc_csd, csd, sizeof(csd));
+		rc = 0;
+		mmc_ready = 1;
+		/* FIXME add verbose printout for csd */
+		/* printf("READ_BL_LEN=%u, C_SIZE_MULT=%u, C_SIZE=%u\n",
+			csd->read_bl_len, csd->c_size_mult1,
+			csd->c_size); */
+		mmc_dev.blksz = 512;
+		mmc_dev.lba = (((unsigned long)1 << csd->c_size_mult1) *
+				(unsigned long)csd->c_size) >> 9;
+		printf("MMC/SD size:        %dMiB\n", mmc_dev.lba >> 1);
+	}
+
+	resp = mmc_cmd(MMC_SELECT_CARD, rca<<16, MMC_CMD_AC | MMC_RSP_R1,
+		       0, 0, 0, (u16 *)&response[0]);
+	if (resp)
+		return 1;
+
+#ifdef CONFIG_MMC_WIDE
+	/* yay 4-bit! */
+	if (card_type == CARDTYPE_SD || card_type == CARDTYPE_SDHC) {
+		resp = mmc_cmd(MMC_APP_CMD, rca<<16, MMC_CMD_AC | MMC_RSP_R1,
+		       0, 0, 0, (u16 *)&response[0]);
+		resp = mmc_cmd(MMC_SWITCH, 0x02, MMC_CMD_AC | MMC_RSP_R1B,
+		       0, 0, 0, (u16 *)&response[0]);
+		wide = 1;
+		glamo_reg_write(glamo_reg_read(GLAMO_REGOFS_MMC +
+			 GLAMO_REG_MMC_BASIC) | GLAMO_BASIC_MMC_EN_4BIT_DATA,
+					GLAMO_REGOFS_MMC + GLAMO_REG_MMC_BASIC);
+	}
+#endif
+
+	/* crank the clock to the final speed, 16MHz */
+
+	glamo_reg_write((glamo_reg_read(GLAMO_REG_CLOCK_GEN8) & 0xff00) | 2,
+			 GLAMO_REG_CLOCK_GEN8);
+
+	fat_register_device(&mmc_dev, 1); /* partitions start counting with 1 */
+
+	return rc;
+}
+
+void mmc_depower(void)
+{
+	u8 response[16];
+
+	/* reset */
+	mmc_cmd(MMC_GO_IDLE_STATE, 0, MMC_CMD_BCR, 0, 0, 0,
+		(u16 *)&response[0]);
+
+	/* hold engine reset, remove clocks */
+
+	glamo_reg_write(GLAMO_CLOCK_MMC_RESET, GLAMO_REG_CLOCK_MMC);
+
+	/* disable engine */
+
+	glamo_reg_write(0, GLAMO_REG_CLOCK_MMC);
+	glamo_reg_write(glamo_reg_read(GLAMO_REG_HOSTBUS(2)) &
+			(~GLAMO_HOSTBUS2_MMIO_EN_MMC), GLAMO_REG_HOSTBUS(2));
+
+	/* remove power */
+
+	pcf50633_reg_write(PCF50633_REG_HCLDOOUT + 1,
+		pcf50633_reg_read(PCF50633_REG_HCLDOOUT + 1) & ~1); /* off */
+}
+
+int
+mmc_ident(block_dev_desc_t *dev)
+{
+	return 0;
+}
+
+int
+mmc2info(ulong addr)
+{
+	/* FIXME hard codes to 32 MB device */
+	if (addr >= CFG_MMC_BASE && addr < CFG_MMC_BASE + 0x02000000)
+		return 1;
+
+	return 0;
+}
+
+
+#endif /* defined(CONFIG_MMC) && defined(CONFIG_MMC_GLAMO) */
diff --git a/board/neo1973/gta02/glamo-mmc.h b/board/neo1973/gta02/glamo-mmc.h
new file mode 100644
index 0000000..3f2294c
--- /dev/null
+++ b/board/neo1973/gta02/glamo-mmc.h
@@ -0,0 +1,149 @@
+#ifndef __GLAMO_MMC_H__
+#define __GLAMO_MMC_H__
+
+/* Standard MMC commands (4.1)           type  argument     response */
+   /* class 1 */
+#define MMC_GO_IDLE_STATE         0   /* bc                          */
+#define MMC_SEND_OP_COND          1   /* bcr  [31:0] OCR         R3  */
+#define MMC_ALL_SEND_CID          2   /* bcr                     R2  */
+#define MMC_SET_RELATIVE_ADDR     3   /* ac   [31:16] RCA        R1  */
+#define MMC_SET_DSR               4   /* bc   [31:16] RCA            */
+#define MMC_SWITCH                6   /* ac   [31:0] See below   R1b */
+#define MMC_SELECT_CARD           7   /* ac   [31:16] RCA        R1  */
+#define MMC_SEND_EXT_CSD          8   /* adtc                    R1  */
+#define MMC_SEND_CSD              9   /* ac   [31:16] RCA        R2  */
+#define MMC_SEND_CID             10   /* ac   [31:16] RCA        R2  */
+#define MMC_READ_DAT_UNTIL_STOP  11   /* adtc [31:0] dadr        R1  */
+#define MMC_STOP_TRANSMISSION    12   /* ac                      R1b */
+#define MMC_SEND_STATUS          13   /* ac   [31:16] RCA        R1  */
+#define MMC_GO_INACTIVE_STATE    15   /* ac   [31:16] RCA            */
+#define MMC_SPI_READ_OCR         58   /* spi                  spi_R3 */
+#define MMC_SPI_CRC_ON_OFF       59   /* spi  [0:0] flag      spi_R1 */
+
+#define SD_SEND_RELATIVE_ADDR     3   /* bcr                     R6  */
+#define SD_SEND_IF_COND           8   /* bcr  [11:0] See below   R7  */
+
+  /* class 2 */
+#define MMC_SET_BLOCKLEN         16   /* ac   [31:0] block len   R1  */
+#define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
+#define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
+
+  /* class 3 */
+#define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
+
+  /* class 4 */
+#define MMC_SET_BLOCK_COUNT      23   /* adtc [31:0] data addr   R1  */
+#define MMC_WRITE_BLOCK          24   /* adtc [31:0] data addr   R1  */
+#define MMC_WRITE_MULTIPLE_BLOCK 25   /* adtc                    R1  */
+#define MMC_PROGRAM_CID          26   /* adtc                    R1  */
+#define MMC_PROGRAM_CSD          27   /* adtc                    R1  */
+
+  /* class 6 */
+#define MMC_SET_WRITE_PROT       28   /* ac   [31:0] data addr   R1b */
+#define MMC_CLR_WRITE_PROT       29   /* ac   [31:0] data addr   R1b */
+#define MMC_SEND_WRITE_PROT      30   /* adtc [31:0] wpdata addr R1  */
+
+  /* class 5 */
+#define MMC_ERASE_GROUP_START    35   /* ac   [31:0] data addr   R1  */
+#define MMC_ERASE_GROUP_END      36   /* ac   [31:0] data addr   R1  */
+#define MMC_ERASE                38   /* ac                      R1b */
+
+  /* class 9 */
+#define MMC_FAST_IO              39   /* ac   <Complex>          R4  */
+#define MMC_GO_IRQ_STATE         40   /* bcr                     R5  */
+
+  /* class 7 */
+#define MMC_LOCK_UNLOCK          42   /* adtc                    R1b */
+
+  /* class 8 */
+#define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */
+#define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1  */
+
+#define SD_APP_SET_BUS_WIDTH      6   /* ac   [1:0] bus width    R1  */
+#define SD_APP_SEND_NUM_WR_BLKS  22   /* adtc                    R1  */
+#define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
+#define SD_APP_SEND_SCR          51   /* adtc                    R1  */
+
+
+#define MMC_RSP_PRESENT	(1 << 0)
+#define MMC_RSP_136	(1 << 1)		/* 136 bit response */
+#define MMC_RSP_CRC	(1 << 2)		/* expect valid crc */
+#define MMC_RSP_BUSY	(1 << 3)		/* card may send busy */
+#define MMC_RSP_OPCODE	(1 << 4)		/* response contains opcode */
+
+#define MMC_CMD_MASK	(3 << 5)		/* non-SPI command type */
+#define MMC_CMD_AC	(0 << 5)
+#define MMC_CMD_ADTC	(1 << 5)
+#define MMC_CMD_BC	(2 << 5)
+#define MMC_CMD_BCR	(3 << 5)
+
+#define MMC_RSP_SPI_S1	(1 << 7)		/* one status byte */
+#define MMC_RSP_SPI_S2	(1 << 8)		/* second byte */
+#define MMC_RSP_SPI_B4	(1 << 9)		/* four data bytes */
+#define MMC_RSP_SPI_BUSY (1 << 10)		/* card may send busy */
+
+/*
+ * These are the native response types, and correspond to valid bit
+ * patterns of the above flags.  One additional valid pattern
+ * is all zeros, which means we don't expect a response.
+ */
+#define MMC_RSP_NONE	(0)
+#define MMC_RSP_R1	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R1B	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
+#define MMC_RSP_R2	(MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
+#define MMC_RSP_R3	(MMC_RSP_PRESENT)
+#define MMC_RSP_R4	(MMC_RSP_PRESENT)
+#define MMC_RSP_R5	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R6	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R7	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+
+#define mmc_resp_type(f) ((f) & (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC |\
+				 MMC_RSP_BUSY | MMC_RSP_OPCODE))
+#define mmc_cmd_type(f) ((f) & MMC_CMD_MASK)
+
+/*
+ * These are the SPI response types for MMC, SD, and SDIO cards.
+ * Commands return R1, with maybe more info.  Zero is an error type;
+ * callers must always provide the appropriate MMC_RSP_SPI_Rx flags.
+ */
+#define MMC_RSP_SPI_R1	(MMC_RSP_SPI_S1)
+#define MMC_RSP_SPI_R1B	(MMC_RSP_SPI_S1|MMC_RSP_SPI_BUSY)
+#define MMC_RSP_SPI_R2	(MMC_RSP_SPI_S1|MMC_RSP_SPI_S2)
+#define MMC_RSP_SPI_R3	(MMC_RSP_SPI_S1|MMC_RSP_SPI_B4)
+#define MMC_RSP_SPI_R4	(MMC_RSP_SPI_S1|MMC_RSP_SPI_B4)
+#define MMC_RSP_SPI_R5	(MMC_RSP_SPI_S1|MMC_RSP_SPI_S2)
+#define MMC_RSP_SPI_R7	(MMC_RSP_SPI_S1|MMC_RSP_SPI_B4)
+
+#define MMC_DATA_WRITE	(1 << 8)
+#define MMC_DATA_READ	(1 << 9)
+#define MMC_DATA_STREAM	(1 << 10)
+
+struct sd_cid {
+	char		pnm_0;	/* product name */
+	char		oid_1;	/* OEM/application ID */
+	char		oid_0;
+	uint8_t		mid;	/* manufacturer ID */
+	char		pnm_4;
+	char		pnm_3;
+	char		pnm_2;
+	char		pnm_1;
+	uint8_t		psn_2;	/* product serial number */
+	uint8_t		psn_1;
+	uint8_t		psn_0;	/* MSB */
+	uint8_t		prv;	/* product revision */
+	uint8_t		crc;	/* CRC7 checksum, b0 is unused and set to 1 */
+	uint8_t		mdt_1;	/* manufacturing date, LSB, RRRRyyyy yyyymmmm */
+	uint8_t		mdt_0;	/* MSB */
+	uint8_t		psn_3;	/* LSB */
+};
+
+enum card_type {
+	CARDTYPE_NONE = 0,
+	CARDTYPE_MMC,
+	CARDTYPE_SD,
+	CARDTYPE_SD20,
+	CARDTYPE_SDHC
+};
+
+
+#endif /* __GLAMO_MMC_H__ */
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 9546729..471d884 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -43,6 +43,8 @@
 #include <ft_build.h>
 #endif
 
+void mmc_depower(void);
+
 DECLARE_GLOBAL_DATA_PTR;
 
 /*cmd_boot.c*/
@@ -297,6 +299,10 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 	}
 	show_boot_progress (6);
 
+#ifdef CONFIG_DEPOWER_MMC_ON_BOOT
+	mmc_depower();
+#endif
+
 	/*
 	 * We have reached the point of no return: we are going to
 	 * overwrite all exception vector code, so we cannot easily
diff --git a/cpu/arm920t/s3c24x0/mmc.c b/cpu/arm920t/s3c24x0/mmc.c
index d056538..d81ba8c 100644
--- a/cpu/arm920t/s3c24x0/mmc.c
+++ b/cpu/arm920t/s3c24x0/mmc.c
@@ -31,7 +31,7 @@
 #include <part.h>
 #include <fat.h>
 
-#ifdef CONFIG_MMC
+#if defined(CONFIG_MMC) && defined(CONFIG_MMC_S3C)
 
 #define CONFIG_MMC_WIDE
 
@@ -536,4 +536,4 @@ mmc2info(ulong addr)
 	return 0;
 }
 
-#endif	/* CONFIG_MMC */
+#endif	/* defined(CONFIG_MMC) && defined(CONFIG_MMC_S3C) */
diff --git a/include/configs/neo1973_gta01.h b/include/configs/neo1973_gta01.h
index a9ac6e9..d94a036 100644
--- a/include/configs/neo1973_gta01.h
+++ b/include/configs/neo1973_gta01.h
@@ -218,6 +218,7 @@
 #define CFG_MAX_NAND_DEVICE	1
 
 #define CONFIG_MMC		1
+#define CONFIG_MMC_S3C 1
 #define CFG_MMC_BASE		0xff000000
 
 /* EXT2 driver */
diff --git a/include/configs/neo1973_gta02.h b/include/configs/neo1973_gta02.h
index 04158f2..adc3d32 100644
--- a/include/configs/neo1973_gta02.h
+++ b/include/configs/neo1973_gta02.h
@@ -218,8 +218,11 @@
 #define CFG_NAND_BASE		0x4e000000
 #define CFG_MAX_NAND_DEVICE	1
 
-#define CONFIG_MMC		1
+#define CONFIG_MMC 1
+#define CONFIG_MMC_WIDE 1
+#define CONFIG_MMC_GLAMO		1
 #define CFG_MMC_BASE		0xff000000
+#define CONFIG_DEPOWER_MMC_ON_BOOT 1
 
 /* EXT2 driver */
 #define CONFIG_EXT2		1

Reply via email to