[U-Boot-Users] [PATCH] Add eSDHC driver

This is the SD/MMC controller on several of Freescale's more recent parts ---
Hi Andy, Where could we find the driver that works with MMCv4 on at91sam9x? Best regards
Pierre, I don't have a driver that works on at91sam9x, I'm afraid. I have a driver that nearly works on an mpc837x. However, some of it is certainly right, and that may help you. Also, some of it is wrong (I get intermittent failures on MMC cards), and maybe someone will look at this driver, and see what I'm doing wrong.
Makefile | 2 + drivers/mmc/Makefile | 46 ++ drivers/mmc/fsl_esdhc.c | 1111 ++++++++++++++++++++++++++++++++++++ drivers/mmc/fsl_esdhc.h | 208 +++++++ include/asm-ppc/arch-mpc83xx/mmc.h | 1 + 5 files changed, 1368 insertions(+), 0 deletions(-) create mode 100644 drivers/mmc/Makefile create mode 100644 drivers/mmc/fsl_esdhc.c create mode 100644 drivers/mmc/fsl_esdhc.h create mode 100644 include/asm-ppc/arch-mpc83xx/mmc.h
diff --git a/Makefile b/Makefile index e5b4210..cd614a5 100644 --- a/Makefile +++ b/Makefile @@ -214,6 +214,7 @@ LIBS += drivers/hwmon/libhwmon.a LIBS += drivers/i2c/libi2c.a LIBS += drivers/input/libinput.a LIBS += drivers/misc/libmisc.a +LIBS += drivers/mmc/libmmc.a LIBS += drivers/mtd/libmtd.a LIBS += drivers/mtd/nand/libnand.a LIBS += drivers/mtd/nand_legacy/libnand_legacy.a @@ -383,6 +384,7 @@ TAG_SUBDIRS += drivers/hwmon TAG_SUBDIRS += drivers/i2c TAG_SUBDIRS += drivers/input TAG_SUBDIRS += drivers/misc +TAG_SUBDIRS += drivers/mmc TAG_SUBDIRS += drivers/mtd TAG_SUBDIRS += drivers/mtd/nand TAG_SUBDIRS += drivers/mtd/nand_legacy diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile new file mode 100644 index 0000000..06e4e88 --- /dev/null +++ b/drivers/mmc/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB := $(obj)libmmc.a + +COBJS-y += fsl_esdhc.o + +COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c new file mode 100644 index 0000000..29af92a --- /dev/null +++ b/drivers/mmc/fsl_esdhc.c @@ -0,0 +1,1111 @@ +/* + * Copyright 2007, Freescale Semiconductor, Inc + * Andy Fleming + * + * Based vaguely on the pxa mmc code: + * (C) Copyright 2003 + * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <config.h> +#include <common.h> +#include <command.h> +#include <mmc.h> +#include <part.h> +#include <malloc.h> +#include <asm/io.h> + +#include "fsl_esdhc.h" + +#ifdef CONFIG_MMC +DECLARE_GLOBAL_DATA_PTR; + +struct fsl_esdhc { + uint dsaddr; + uint blkattr; + uint cmdarg; + uint xfertyp; + uint cmdrsp0; + uint cmdrsp1; + uint cmdrsp2; + uint cmdrsp3; + uint datport; + uint prsstat; + uint proctl; + uint sysctl; + uint irqstat; + uint irqstaten; + uint irqsigen; + uint autoc12err; + uint hostcapblt; + uint wml; + char reserved1[8]; + uint fevt; + char reserved2[168]; + uint hostver; + char reserved3[780]; + uint scr; +}; + +enum { + MMC_CMD_RSP_NONE, + MMC_CMD_R1 = 1, + MMC_CMD_R1b, + MMC_CMD_R2, + MMC_CMD_R3, + MMC_CMD_R4, + MMC_CMD_R5, + MMC_CMD_R5b, + MMC_CMD_R6, + MMC_CMD_R7 +}; + +uint xfertyps[] = { + XFERTYP_RSPTYP_NONE, + XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN, + XFERTYP_RSPTYP_48_BUSY | XFERTYP_CICEN | XFERTYP_CCCEN, + XFERTYP_RSPTYP_136 | XFERTYP_CCCEN, + XFERTYP_RSPTYP_48, + XFERTYP_RSPTYP_48, + XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN, + XFERTYP_RSPTYP_48_BUSY | XFERTYP_CICEN | XFERTYP_CCCEN, + XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN, + XFERTYP_RSPTYP_48 | XFERTYP_CICEN | XFERTYP_CCCEN +}; + +struct mmc { + volatile void * regs; + uint version; + int high_capacity; + uint mode; + uint ocr; + uint scr[2]; + uint csd[4]; + char cid[16]; + ushort rca; + uint tran_speed; + uint read_bl_len; + uint write_bl_len; + u64 capacity; + block_dev_desc_t block_dev; +}; + +static struct mmc *mmc_dev; + +block_dev_desc_t *mmc_get_dev(int dev) +{ + return (dev == 0) ? &mmc_dev->block_dev : NULL; +} + +struct mmc_cmd { + ushort cmdidx; + int resp_type; + uint cmdarg; + char response[18]; + uint flags; +}; + +struct mmc_data { + char * buffer; + uint flags; + int blocks; + int blocksize; +}; + +/* Return the XFERTYP flags for a given command and data packet */ +uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) +{ + uint xfertyp = 0; + + if (data) { + xfertyp |= XFERTYP_DPSEL | XFERTYP_DMAEN; + + if (data->blocks > 1) { + xfertyp |= XFERTYP_MSBSEL; + xfertyp |= XFERTYP_BCEN; + } + + if (data->flags & MMC_DATA_READ) + xfertyp |= XFERTYP_DTDSEL; + } + + xfertyp |= xfertyps[cmd->resp_type]; + + return xfertyp; +} + + +/* + * Sends a command out on the bus. Takes the mmc pointer, + * a command pointer, and an optional data pointer. + */ +static int +mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) +{ + uint xfertyp; + uint irqstat; + volatile struct fsl_esdhc *regs = mmc->regs; + + regs->irqstat = -1; + + sync(); + + /* Wait for the bus to be idle */ + while ((regs->prsstat & PRSSTAT_CICHB) || + (regs->prsstat & PRSSTAT_CIDHB)) + sync(); + + while (regs->prsstat & PRSSTAT_DLA) + sync(); + + /* Wait at least 8 SD clock cycles before the next command */ + /* + * Note: This is way more than 8 cycles, but 1ms seems to + * resolve timing issues with some cards + */ + udelay(1000); + + /* Set up for a data transfer if we have one */ + if (data) { + uint wml_value; + int timeout; + + wml_value = data->blocksize/4; + + if (data->flags & MMC_DATA_READ) { + if (wml_value > 0x10) + wml_value = 0x10; + + wml_value = 0x100000 | wml_value; + } else { + if (wml_value > 0x80) + wml_value = 0x80; + + wml_value = wml_value << 16 | 0x10; + } + + regs->dsaddr = (uint)data->buffer; + + sync(); + + regs->wml = wml_value; + + sync(); + + regs->blkattr = data->blocks << 16 | data->blocksize; + + sync(); + + timeout = __ilog2(mmc->tran_speed/10); + timeout -= 13; + + if (timeout > 14) + timeout = 14; + + if (timeout < 0) + timeout = 0; + + regs->sysctl &= ~0x000f0000; + + sync(); + + regs->sysctl |= timeout << 16; + + sync(); + } + + /* Figure out the transfer arguments */ + xfertyp = esdhc_xfertyp(cmd, data); + + /* Send the command */ + regs->cmdarg = cmd->cmdarg; + sync(); + regs->xfertyp = XFERTYP_CMD(cmd->cmdidx) | xfertyp; + + sync(); + /* Wait for the command to complete */ + while (!(regs->irqstat & IRQSTAT_CC)) + sync(); + + irqstat = regs->irqstat; + + sync(); + + regs->irqstat = irqstat; + + sync(); + + if (irqstat & CMD_ERR) + return COMM_ERR; + + if (irqstat & IRQSTAT_CTOE) + return TIMEOUT; + + /* Copy the response to the response buffer */ + if (cmd->resp_type == MMC_CMD_R2) { + ((uint *)(cmd->response))[0] = + (regs->cmdrsp3 << 8) | (regs->cmdrsp2 >> 24); + ((uint *)(cmd->response))[1] = + (regs->cmdrsp2 << 8) | (regs->cmdrsp1 >> 24); + ((uint *)(cmd->response))[2] = + (regs->cmdrsp1 << 8) | (regs->cmdrsp0 >> 24); + ((uint *)(cmd->response))[3] = (regs->cmdrsp0 << 8); + } else + ((uint *)(cmd->response))[0] = regs->cmdrsp0; + + /* Wait until all of the blocks are transferred */ + if (data) { + do { + irqstat = regs->irqstat; + + if (irqstat & DATA_ERR) + return COMM_ERR; + + if (irqstat & IRQSTAT_DTOE) + return TIMEOUT; + sync(); + } while (!(irqstat & IRQSTAT_TC) && + (regs->prsstat & PRSSTAT_DLA)); + } + + regs->irqstat = -1; + sync(); + + return 0; +} + +void set_sysctl(struct mmc *mmc, int clock) +{ + int sdhc_clk = gd->sdhc_clk; + int div, pre_div; + volatile struct fsl_esdhc *regs = mmc->regs; + uint clk; + + if (sdhc_clk / 16 > clock) { + for (pre_div = 2; pre_div < 256; pre_div *= 2) + if ((sdhc_clk / pre_div) <= (clock * 16)) + break; + } else + pre_div = 2; + + for (div = 1; div <= 16; div++) + if ((sdhc_clk / (div * pre_div)) <= clock) + break; + + pre_div >>= 1; + div -= 1; + + clk = (pre_div << 8) | (div << 4); + regs->sysctl &= ~0x0000fff0; + sync(); + regs->sysctl |= clk; + sync(); + + udelay(10000); + + regs->sysctl |= SYSCTL_PEREN; +} + + +int +mmc_block_write(ulong dst, uchar *src, int len) +{ +#warning write not yet implemented + return 0; +} + +int mmc_set_blocklen(struct mmc *mmc, int len) +{ + struct mmc_cmd cmd; + + cmd.cmdidx = SET_BLOCKLEN; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = len; + cmd.flags = 0; + + return mmc_send_cmd(mmc, &cmd, NULL); +} + +int +mmc_read(ulong src, uchar *dst, int size) +{ + struct mmc_cmd cmd; + struct mmc_data data; + int err; + char * buffer; + int stoperr = 0; + struct mmc *mmc = mmc_dev; + int blklen = mmc->read_bl_len; + int startblock = src / blklen; + int endblock = (src + size - 1) / blklen; + int blkcnt = endblock - startblock + 1; + + /* Make a buffer big enough to hold all the blocks we might read */ + buffer = malloc(blkcnt * blklen); + + if (!buffer) { + printf("Could not allocate buffer for MMC read!\n"); + return -1; + } + +#warning deal with larger reads (more than 65536 blks) and partial block reads + /* We only support full block reads from the card */ + err = mmc_set_blocklen(mmc, mmc->read_bl_len); + + if (err) + return err; + + if (blkcnt > 1) + cmd.cmdidx = READ_MULTIPLE_BLOCKS; + else + cmd.cmdidx = READ_SINGLE_BLOCK; + + if (mmc->high_capacity) + cmd.cmdarg = startblock; + else + cmd.cmdarg = startblock * blklen; + + cmd.resp_type = MMC_CMD_R1; + cmd.flags = 0; + + data.buffer = buffer; + data.blocks = blkcnt; + data.blocksize = blklen; + data.flags = MMC_DATA_READ; + + err = mmc_send_cmd(mmc, &cmd, &data); + + if (blkcnt > 1) { + cmd.cmdidx = STOP_TRANSMISSION; + cmd.cmdarg = 0; + cmd.resp_type = MMC_CMD_R1b; + cmd.flags = 0; + stoperr = mmc_send_cmd(mmc, &cmd, NULL); + } + + + if (err) + return err; + + memcpy(dst, buffer + (src & (blklen - 1)), size); + + free(buffer); + + return stoperr; +} + +int +mmc_write(uchar *src, ulong dst, int size) +{ + return 0; +} + +ulong +mmc_bread(int dev_num, ulong blknr, ulong blkcnt, void *dst) +{ + int err; + ulong src = blknr * mmc_dev->read_bl_len; + + err = mmc_read(src, dst, blkcnt * mmc_dev->read_bl_len); + + if (err) { + printf("block read failed: %d\n", err); + return 0; + } + + return blkcnt; +} + +int mmc_go_idle(struct mmc* mmc) +{ + struct mmc_cmd cmd; + int err; + + udelay(1000); + + cmd.cmdidx = GO_IDLE_STATE; + cmd.cmdarg = 0; + cmd.resp_type = MMC_CMD_RSP_NONE; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + udelay(2000); + + return 0; +} + +int +sd_send_op_cond(struct mmc *mmc) +{ + int timeout = 1000; + int err; + struct mmc_cmd cmd; + + do { + cmd.cmdidx = APP_CMD; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = 0; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + cmd.cmdidx = SD_SEND_OP_COND; + cmd.resp_type = MMC_CMD_R3; + cmd.cmdarg = 0xff8000; + + if (mmc->version == SD_VERSION_2) + cmd.cmdarg |= 0x40000000; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + udelay(1000); + } while ((!(cmd.response[0] & OCR_BUSY)) && timeout--); + + if (timeout <= 0) + return UNUSABLE_ERR; + + if (mmc->version != SD_VERSION_2) + mmc->version = SD_VERSION_1_0; + + mmc->ocr = ((uint *)(cmd.response))[0]; + + mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); + mmc->rca = 0; + + return 0; +} + +int mmc_send_op_cond(struct mmc *mmc) +{ + int timeout = 1000; + struct mmc_cmd cmd; + int err; + + /* Some cards seem to need this */ + mmc_go_idle(mmc); + + do { + cmd.cmdidx = MMC_SEND_OP_COND; + cmd.resp_type = MMC_CMD_R3; + cmd.cmdarg = 0x40ff8000; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + udelay(1000); + } while (!(cmd.response[0] & OCR_BUSY) && timeout--); + + if (timeout <= 0) + return UNUSABLE_ERR; + + mmc->version = MMC_VERSION_UNKNOWN; + mmc->ocr = ((uint *)(cmd.response))[0]; + + mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); + mmc->rca = 0; + + return 0; +} + + +int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd) +{ + struct mmc_cmd cmd; + struct mmc_data data; + int err; + + /* Get the Card Status Register */ + cmd.cmdidx = SEND_EXT_CSD; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = 0; + cmd.flags = 0; + + data.buffer = ext_csd; + data.blocks = 1; + data.blocksize = 512; + data.flags = MMC_DATA_READ; + + err = mmc_send_cmd(mmc, &cmd, &data); + + return err; +} + + +int mmc_change_freq(struct mmc *mmc) +{ + struct mmc_cmd cmd; + char ext_csd[512]; + char cardtype; + int err; + + mmc->mode = 0; + + /* Only version 4 supports high-speed */ + if (mmc->version < MMC_VERSION_4) + return 0; + + mmc->mode |= MMC_MODE_4BIT; + + err = mmc_send_ext_csd(mmc, ext_csd); + + if (err) + return err; + + if (ext_csd[212] || ext_csd[213] || ext_csd[214] || ext_csd[215]) + mmc->high_capacity = 1; + + cardtype = ext_csd[196] & 0xf; + + /* Set the card to use High Speed */ + cmd.cmdidx = MMC_SWITCH; + cmd.resp_type = MMC_CMD_R1b; + cmd.cmdarg = 0x1b90100; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + /* Now check to see that it worked */ + err = mmc_send_ext_csd(mmc, ext_csd); + + if (err) + return err; + + /* No high-speed support */ + if (!ext_csd[185]) + return 0; + + /* High Speed is set, there are two types: 52MHz and 26MHz */ + if (cardtype & MMC_HS_52MHZ) + mmc->mode |= MMC_MODE_HS_52MHz | MMC_MODE_HS; + else + mmc->mode |= MMC_MODE_HS; + + return 0; +} + +int sd_change_freq(struct mmc *mmc) +{ + int err; + struct mmc_cmd cmd; + uint scr[2]; + uint switch_status[16]; + struct mmc_data data; + int timeout; + + mmc->mode = 0; + + /* Read the SCR to find out if this card supports higher speeds */ + cmd.cmdidx = APP_CMD; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = mmc->rca << 16; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + cmd.cmdidx = SEND_SCR; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = 0; + cmd.flags = 0; + + timeout = 3; + +retry_scr: + data.buffer = (char *)&scr; + data.blocksize = 8; + data.blocks = 1; + data.flags = MMC_DATA_READ; + + err = mmc_send_cmd(mmc, &cmd, &data); + + if (err) { + if (timeout--) + goto retry_scr; + + return err; + } + + mmc->scr[0] = scr[0]; + mmc->scr[1] = scr[1]; + + switch ((mmc->scr[0] >> 24) & 0xf) { + case 0: + mmc->version = SD_VERSION_1_0; + break; + case 1: + mmc->version = SD_VERSION_1_10; + break; + case 2: + mmc->version = SD_VERSION_2; + break; + default: + mmc->version = SD_VERSION_1_0; + break; + } + + /* Version 1.0 doesn't support switching */ + if (mmc->version == SD_VERSION_1_0) + return 0; + + timeout = 4; + while (timeout--) { + /* Switch the frequency */ + cmd.cmdidx = SWITCH_FUNC; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = 0xfffff1; + cmd.flags = 0; + + data.buffer = (char *)&switch_status; + data.blocksize = 64; + data.blocks = 1; + data.flags = MMC_DATA_READ; + + err = mmc_send_cmd(mmc, &cmd, &data); + + if (err) + return err; + + /* The high-speed function is busy. Try again */ + if (!switch_status[7] & SD_HIGHSPEED_BUSY) + break; + } + + if (mmc->scr[0] & SD_DATA_4BIT) + mmc->mode |= MMC_MODE_4BIT; + + /* If high-speed isn't supported, we return */ + if (!(switch_status[3] & SD_HIGHSPEED_SUPPORTED)) + return 0; + + cmd.cmdidx = SWITCH_FUNC; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = 0x80fffff1; + cmd.flags = 0; + + data.buffer = (char *)&switch_status; + data.blocksize = 64; + data.blocks = 1; + data.flags = MMC_DATA_READ; + + err = mmc_send_cmd(mmc, &cmd, &data); + + if (err) + return err; + + if ((switch_status[4] & 0x0f000000) == 0x01000000) + mmc->mode |= MMC_MODE_HS; + + return 0; +} + +/* frequency bases */ +/* divided by 10 to be nice to platforms without floating point */ +int fbase[] = { + 10000, + 100000, + 1000000, + 10000000, +}; + +/* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice + * to platforms without floating point. + */ +int multipliers[] = { + 0, /* reserved */ + 10, + 12, + 13, + 15, + 20, + 25, + 30, + 35, + 40, + 45, + 50, + 55, + 60, + 70, + 80, +}; + + +int mmc_startup(struct mmc *mmc) +{ + int err; + uint mult, freq; + uint cmult, csize; + struct mmc_cmd cmd; + volatile struct fsl_esdhc *regs = mmc->regs; + + /* Put the Card in Identify Mode */ + cmd.cmdidx = ALL_SEND_CID; + cmd.resp_type = MMC_CMD_R2; + cmd.cmdarg = 0; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + memcpy(mmc->cid, cmd.response, 16); + + /* + * For MMC cards, set the Relative Address. + * For SD cards, get the Relatvie Address. + * This also puts the cards into Standby State + */ + cmd.cmdidx = SEND_RELATIVE_ADDR; + cmd.cmdarg = mmc->rca << 16; + cmd.resp_type = MMC_CMD_R6; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + if (IS_SD(mmc)) + mmc->rca = (((uint *)(cmd.response))[0] >> 16) & 0xffff; + + /* Get the Card-Specific Data */ + cmd.cmdidx = SEND_CSD; + cmd.resp_type = MMC_CMD_R2; + cmd.cmdarg = mmc->rca << 16; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + mmc->csd[0] = ((uint *)(cmd.response))[0]; + mmc->csd[1] = ((uint *)(cmd.response))[1]; + mmc->csd[2] = ((uint *)(cmd.response))[2]; + mmc->csd[3] = ((uint *)(cmd.response))[3]; + + if (mmc->version == MMC_VERSION_UNKNOWN) { + int version = (cmd.response[0] >> 2) & 0xf; + + switch (version) { + case 0: + mmc->version = MMC_VERSION_1_2; + break; + case 1: + mmc->version = MMC_VERSION_1_4; + break; + case 2: + mmc->version = MMC_VERSION_2_2; + break; + case 3: + mmc->version = MMC_VERSION_3; + break; + case 4: + mmc->version = MMC_VERSION_4; + break; + default: + mmc->version = MMC_VERSION_1_2; + break; + } + } + + /* divide frequency by 10, since the mults are 10x bigger */ + freq = fbase[(cmd.response[3] & 0x7)]; + mult = multipliers[((cmd.response[3] >> 3) & 0xf)]; + + mmc->tran_speed = freq * mult; + + mmc->read_bl_len = 1 << ((((uint *)(cmd.response))[1] >> 16) & 0xf); + + if (IS_SD(mmc)) + mmc->write_bl_len = mmc->read_bl_len; + else + mmc->write_bl_len = 1 << ((((uint *)(cmd.response))[3] >> 22) & 0xf); + + csize = (mmc->csd[1] & 0x3ff) << 2 | (mmc->csd[2] & 0xc0000000) >> 30; + cmult = (mmc->csd[2] & 0x00038000) >> 15; + + mmc->capacity = (csize + 1) << (cmult + 2); + mmc->capacity *= mmc->read_bl_len; + + if (mmc->read_bl_len > 512) + mmc->read_bl_len = 512; + + if (mmc->write_bl_len > 512) + mmc->write_bl_len = 512; + + /* Select the card, and put it into Transfer Mode */ + cmd.cmdidx = SELECT_CARD; + cmd.resp_type = MMC_CMD_R1b; + cmd.cmdarg = mmc->rca << 16; + cmd.flags = 0; + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + if (IS_SD(mmc)) + err = sd_change_freq(mmc); + else + err = mmc_change_freq(mmc); + + if (err) + return err; + + if (IS_SD(mmc)) { + if (mmc->mode & MMC_MODE_4BIT) { + cmd.cmdidx = APP_CMD; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = mmc->rca << 16; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + if (err) + return err; + + cmd.cmdidx = SET_BUS_WIDTH; + cmd.resp_type = MMC_CMD_R1; + cmd.cmdarg = 2; + cmd.flags = 0; + err = mmc_send_cmd(mmc, &cmd, NULL); + if (err) + return err; + + regs->proctl |= PROCTL_DTW_4; + } + + if (mmc->mode & MMC_MODE_HS) + set_sysctl(mmc, 50000000); + else + set_sysctl(mmc, 25000000); + } else { + if (mmc->mode & MMC_MODE_4BIT) { + /* Set the card to use 4 bit*/ + cmd.cmdidx = MMC_SWITCH; + cmd.resp_type = MMC_CMD_R1b; + cmd.cmdarg = 0x1b70100; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + regs->proctl |= PROCTL_DTW_4; + } else if (mmc->mode & MMC_MODE_8BIT) { + /* Set the card to use 8 bit*/ + cmd.cmdidx = MMC_SWITCH; + cmd.resp_type = MMC_CMD_R1b; + cmd.cmdarg = 0x1b70200; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + regs->proctl |= PROCTL_DTW_8; + } + + if (mmc->mode & MMC_MODE_HS) { + if (mmc->mode & MMC_MODE_HS_52MHz) + set_sysctl(mmc, 52000000); + else + set_sysctl(mmc, 26000000); + } else + set_sysctl(mmc, 20000000); + } + + /* fill in device description */ + mmc->block_dev.if_type = IF_TYPE_MMC; + mmc->block_dev.part_type = PART_TYPE_DOS; + mmc->block_dev.dev = 0; + mmc->block_dev.lun = 0; + mmc->block_dev.type = 0; + mmc->block_dev.blksz = mmc->read_bl_len; + mmc->block_dev.lba = mmc->capacity/mmc->read_bl_len; + sprintf(mmc->block_dev.vendor,"Man %02x%02x%02x Snr %02x%02x%02x%02x", + mmc->cid[0], mmc->cid[1], mmc->cid[2], + mmc->cid[9], mmc->cid[10], mmc->cid[11], mmc->cid[12]); + sprintf(mmc->block_dev.product,"%c%c%c%c%c", mmc->cid[3], + mmc->cid[4], mmc->cid[5], mmc->cid[6], mmc->cid[7]); + sprintf(mmc->block_dev.revision,"%d.%d", mmc->cid[8] >> 4, + mmc->cid[8] & 0xf); + mmc->block_dev.removable = 1; + mmc->block_dev.block_read = mmc_bread; + + init_part(&mmc->block_dev); + + return 0; +} + +int mmc_send_if_cond(struct mmc *mmc) +{ + struct mmc_cmd cmd; + int err; + + cmd.cmdidx = SEND_IF_COND; + cmd.cmdarg = 0x1aa; + cmd.resp_type = MMC_CMD_R7; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + + if (err) + return err; + + if (((uint *)(cmd.response))[0] != 0x1aa) + return UNUSABLE_ERR; + else + mmc->version = SD_VERSION_2; + + return 0; +} + +int +mmc_init(int verbose) +{ + volatile immap_t *im = (immap_t *) CFG_IMMR; + struct fsl_esdhc *regs = (struct fsl_esdhc *)&im->sdhc; + int timeout = 1000; + struct mmc *mmc; + int err; + + mmc = malloc(sizeof(struct mmc)); + + mmc->regs = regs; + + if (mmc_dev) + free(mmc_dev); + + mmc_dev = mmc; + + regs->sysctl = SYSCTL_HCKEN | SYSCTL_IPGEN; + + /* Set the clock speed */ + set_sysctl(mmc, 400000); + + /* Disable the BRR and BWR bits in IRQSTAT */ + regs->irqstaten &= ~(IRQSTATEN_BRR | IRQSTATEN_BWR); + + /* Put the PROCTL reg back to the default */ + regs->proctl = PROCTL_INIT; + + while (!(regs->prsstat & PRSSTAT_CINS) && timeout--) + udelay(1000); + + if (timeout <= 0) + return NO_CARD_ERR; + + /* Reset the Card */ + err = mmc_go_idle(mmc); + + if (err) + return err; + + /* Test for SD version 2 */ + err = mmc_send_if_cond(mmc); + + /* If we got an error other than timeout, we bail */ + if (err && err != TIMEOUT) + return err; + + /* Now try to get the SD card's operating condition */ + err = sd_send_op_cond(mmc); + + /* If the command timed out, we check for an MMC card */ + if (err == TIMEOUT) { + err = mmc_send_op_cond(mmc); + + if (err) { + printf("Card did not respond to voltage select!\n"); + return UNUSABLE_ERR; + } + } + + err = mmc_startup(mmc); + + if (err) + printf("Returning with err %d\n", err); + + return err; +} + +int +mmc2info(ulong addr) +{ + /* Hmm... */ + return 0; +} + +static void print_mmcinfo(struct mmc *mmc) +{ + printf("Manufacturer: %x\n", mmc->cid[0] >> 24); + printf("OEM: %x\n", (mmc->cid[0] >> 8) & 0xffff); + printf("Name: %c%c%c%c%c\n", mmc->cid[0] & 0xff, + (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, + (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff); + + printf("Tran Speed: %d\n", mmc->tran_speed); + printf("Rd Block Len: %d\n", mmc->read_bl_len); + + printf("%s version %d.%d\n", IS_SD(mmc) ? "SD" : "MMC", + (mmc->version >> 4) & 0xf, mmc->version & 0xf); + + printf("High Capacity: %s\n", mmc->high_capacity ? "Yes" : "No"); + printf("Capacity: %d\n", mmc->capacity); + + printf("Bus Width: %d-bit\n", (mmc->mode & MMC_MODE_4BIT) ? 4 : + (mmc->mode & MMC_MODE_8BIT) ? 8 : 1); +} + +int do_mmcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + if (mmc_dev) + print_mmcinfo(mmc_dev); + else + printf("Call mmcinit first\n"); + + return 0; +} + +U_BOOT_CMD(mmcinfo, 1, 0, do_mmcinfo, "mmcinfo -- display MMC info\n", NULL); + +#endif /* CONFIG_MMC */ diff --git a/drivers/mmc/fsl_esdhc.h b/drivers/mmc/fsl_esdhc.h new file mode 100644 index 0000000..cf5f2d1 --- /dev/null +++ b/drivers/mmc/fsl_esdhc.h @@ -0,0 +1,208 @@ +/* + * FSL SD/MMC Defines + *------------------------------------------------------------------- + * + * Copyright 2007-2008, Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + *------------------------------------------------------------------- + * + */ + +#ifndef __FSL_ESDHC_H__ +#define __FSL_ESDHC_H__ + +#define SD_VERSION_SD 0x20000 +#define SD_VERSION_2 (SD_VERSION_SD | 0x20) +#define SD_VERSION_1_0 (SD_VERSION_SD | 0x10) +#define SD_VERSION_1_10 (SD_VERSION_SD | 0x1a) +#define MMC_VERSION_MMC 0x10000 +#define MMC_VERSION_UNKNOWN (MMC_VERSION_MMC) +#define MMC_VERSION_1_2 (MMC_VERSION_MMC | 0x12) +#define MMC_VERSION_1_4 (MMC_VERSION_MMC | 0x14) +#define MMC_VERSION_2_2 (MMC_VERSION_MMC | 0x22) +#define MMC_VERSION_3 (MMC_VERSION_MMC | 0x30) +#define MMC_VERSION_4 (MMC_VERSION_MMC | 0x40) + +#define MMC_MODE_HS 0x001 +#define MMC_MODE_HS_52MHz 0x010 +#define MMC_MODE_4BIT 0x100 +#define MMC_MODE_8BIT 0x200 + +#define SD_DATA_4BIT 0x00040000 + +#define IS_SD(x) (mmc->version & SD_VERSION_SD) + +#define MMC_DATA_READ 1 +#define MMC_DATA_WRITE 2 + +#define NO_CARD_ERR -16 /* No SD/MMC card inserted */ +#define UNUSABLE_ERR -17 /* Unusable Card */ +#define COMM_ERR -18 /* Communications Error */ +#define TIMEOUT -19 + +#define GO_IDLE_STATE 0x0 +#define SEND_IF_COND (8) + +#define APP_CMD (55) + +#define MMC_SEND_OP_COND (1) + +#define SD_SEND_OP_COND (41) + +#define ALL_SEND_CID (2) + +#define SEND_RELATIVE_ADDR (3) + +#define SELECT_CARD (7) + +#define SEND_SCR (51) + +#define SEND_EXT_CSD (8) + +#define SEND_CSD (9) + +#define SEND_STATUS (13) + +#define SWITCH_FUNC (6) +#define MMC_SWITCH (6) + +#define SET_BUS_WIDTH (6) + +#define STOP_TRANSMISSION (12) + +#define SET_BLOCKLEN (16) + +#define READ_SINGLE_BLOCK (17) +#define READ_MULTIPLE_BLOCKS (18) + +#define SD_HIGHSPEED_BUSY 0x00020000 +#define SD_HIGHSPEED_SUPPORTED 0x00020000 + +#define MMC_HS_TIMING 0x00000100 +#define MMC_HS_52MHZ 0x2 + +#define OCR_BUSY 0x80 +#define OCR_HCS 0x40000000 + +/* FSL eSDHC-specific constants */ +#define SYSCTL 0x0002e02c +#define SYSCTL_INITA 0x08000000 +#define SYSCTL_PEREN 0x00000004 +#define SYSCTL_HCKEN 0x00000002 +#define SYSCTL_IPGEN 0x00000001 + +#define IRQSTAT 0x0002e030 +#define IRQSTAT_DMAE (0x10000000) +#define IRQSTAT_AC12E (0x01000000) +#define IRQSTAT_DEBE (0x00400000) +#define IRQSTAT_DCE (0x00200000) +#define IRQSTAT_DTOE (0x00100000) +#define IRQSTAT_CIE (0x00080000) +#define IRQSTAT_CEBE (0x00040000) +#define IRQSTAT_CCE (0x00020000) +#define IRQSTAT_CTOE (0x00010000) +#define IRQSTAT_CINT (0x00000100) +#define IRQSTAT_CRM (0x00000080) +#define IRQSTAT_CINS (0x00000040) +#define IRQSTAT_BRR (0x00000020) +#define IRQSTAT_BWR (0x00000010) +#define IRQSTAT_DINT (0x00000008) +#define IRQSTAT_BGE (0x00000004) +#define IRQSTAT_TC (0x00000002) +#define IRQSTAT_CC (0x00000001) + +#define CMD_ERR (IRQSTAT_CIE | IRQSTAT_CEBE | IRQSTAT_CCE) +#define DATA_ERR (IRQSTAT_DEBE | IRQSTAT_DCE | IRQSTAT_DTOE) + +#define IRQSTATEN 0x0002e034 +#define IRQSTATEN_DMAE (0x10000000) +#define IRQSTATEN_AC12E (0x01000000) +#define IRQSTATEN_DEBE (0x00400000) +#define IRQSTATEN_DCE (0x00200000) +#define IRQSTATEN_DTOE (0x00100000) +#define IRQSTATEN_CIE (0x00080000) +#define IRQSTATEN_CEBE (0x00040000) +#define IRQSTATEN_CCE (0x00020000) +#define IRQSTATEN_CTOE (0x00010000) +#define IRQSTATEN_CINT (0x00000100) +#define IRQSTATEN_CRM (0x00000080) +#define IRQSTATEN_CINS (0x00000040) +#define IRQSTATEN_BRR (0x00000020) +#define IRQSTATEN_BWR (0x00000010) +#define IRQSTATEN_DINT (0x00000008) +#define IRQSTATEN_BGE (0x00000004) +#define IRQSTATEN_TC (0x00000002) +#define IRQSTATEN_CC (0x00000001) + +#define PRSSTAT 0x0002e024 +#define PRSSTAT_CLSL (0x00800000) +#define PRSSTAT_WPSPL (0x00080000) +#define PRSSTAT_CDPL (0x00040000) +#define PRSSTAT_CINS (0x00010000) +#define PRSSTAT_BREN (0x00000800) +#define PRSSTAT_DLA (0x00000004) +#define PRSSTAT_CICHB (0x00000002) +#define PRSSTAT_CIDHB (0x00000001) + +#define PROCTL 0x0002e028 +#define PROCTL_INIT 0x00000020 +#define PROCTL_DTW_4 0x00000002 +#define PROCTL_DTW_8 0x00000004 + +#define CMDARG 0x0002e008 + +#define XFERTYP 0x0002e00c +#define XFERTYP_CMD(x) ((x & 0x3f) << 24) +#define XFERTYP_CMDTYP_NORMAL 0x0 +#define XFERTYP_CMDTYP_SUSPEND 0x00400000 +#define XFERTYP_CMDTYP_RESUME 0x00800000 +#define XFERTYP_CMDTYP_ABORT 0x00c00000 +#define XFERTYP_DPSEL 0x00200000 +#define XFERTYP_CICEN 0x00100000 +#define XFERTYP_CCCEN 0x00080000 +#define XFERTYP_RSPTYP_NONE 0 +#define XFERTYP_RSPTYP_136 0x00010000 +#define XFERTYP_RSPTYP_48 0x00020000 +#define XFERTYP_RSPTYP_48_BUSY 0x00030000 +#define XFERTYP_MSBSEL 0x00000020 +#define XFERTYP_DTDSEL 0x00000010 +#define XFERTYP_AC12EN 0x00000004 +#define XFERTYP_BCEN 0x00000002 +#define XFERTYP_DMAEN 0x00000001 + +#define CINS_TIMEOUT 1000 + +#define DSADDR 0x2e004 + +#define CMDRSP0 0x2e010 +#define CMDRSP1 0x2e014 +#define CMDRSP2 0x2e018 +#define CMDRSP3 0x2e01c + +#define DATPORT 0x2e020 + +#define WML 0x2e044 +#define WML_WRITE 0x00010000 + +#define BLKATTR 0x2e004 +#define BLKATTR_CNT(x) ((x & 0xffff) << 16) +#define BLKATTR_SIZE(x) (x & 0x1fff) +#define MAX_BLK_CNT 0x7fff /* so malloc will have enough room with 32M */ + + +#endif /* __FSL_ESDHC_H__ */ diff --git a/include/asm-ppc/arch-mpc83xx/mmc.h b/include/asm-ppc/arch-mpc83xx/mmc.h new file mode 100644 index 0000000..d5034f4 --- /dev/null +++ b/include/asm-ppc/arch-mpc83xx/mmc.h @@ -0,0 +1 @@ +/* Stub file to satisfy odd requirement for <arch/mmc.h> */

On Tue, Apr 22, 2008 at 10:07:46AM -0500, Andy Fleming wrote:
This is the SD/MMC controller on several of Freescale's more recent parts
Cool. Is there Linux version pending? Does anybody working on it yet?
Thanks.

Pierre Savary wrote:
Where could we find the driver that works with MMCv4 on at91sam9x?
Andy Fleming wrote:
Pierre, I don't have a driver that works on at91sam9x, I'm afraid.
Here's an MMC v2.x AT91SAM9260 patch for Atmel modified u-boot 1.1.5. You will need to define GPIO pins for other AT91SAM9 processors, etc.
If you really need an MMC v4.x AT91SAM9 MCI driver for 1.1.5 fast, you probably could cut and paste the v4.x code you need from Andy's MMC driver into the MMC v2.x MCI driver this patch provides.
BTW, if anyone knows why MMC 4 bit is disabled for AT91SAM9261 in the MCI Linux driver, I'd like to hear the reasons why.
--- u-boot_at91sam9260_mmc.patch (AT91 MCI driver) ---
diff -burN u-boot-1.1.5/board/at91sam9260ek/at91sam9260ek.c u-boot-1.1.5.klk/board/at91sam9260ek/at91sam9260ek.c --- u-boot-1.1.5/board/at91sam9260ek/at91sam9260ek.c 2007-08-21 17:06:36.000000000 +0200 +++ u-boot-1.1.5.klk/board/at91sam9260ek/at91sam9260ek.c 2007-08-23 08:37:42.000000000 +0200 @@ -109,6 +109,24 @@ }
+#ifdef CONFIG_MMC +#if (CONFIG_COMMANDS & CFG_CMD_MMC) +int AT91F_MMC_Hardware_Init(void) +{ + AT91C_BASE_PIOA->PIO_ASR = (1 << 8 ); /* periph A select register */ + AT91C_BASE_PIOA->PIO_BSR |= 0x3B; /* periph B select register */ + AT91C_BASE_PIOA->PIO_PDR |= 0x13B; /* PIO disable register */ + AT91C_BASE_PIOA->PIO_PPUDR |= 0x13B; /* Pull up disable register */ + + AT91C_BASE_PMC->PMC_PCER = (1 << 9); +} +#endif /* CONFIG_COMMANDS & CFG_CMD_MMC */ +#endif /* CONFIG_MMC */ + + + + + #ifdef CONFIG_DRIVER_ETHER #if (CONFIG_COMMANDS & CFG_CMD_NET)
diff -burN u-boot-1.1.5/common/cmd_nvedit.c u-boot-1.1.5.klk/common/cmd_nvedit.c --- u-boot-1.1.5/common/cmd_nvedit.c 2006-10-20 17:54:33.000000000 +0200 +++ u-boot-1.1.5.klk/common/cmd_nvedit.c 2007-08-23 09:26:18.000000000 +0200 @@ -530,6 +530,7 @@ return (-1); }
+#ifndef CFG_ENV_IS_NOWHERE #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) || \ ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_FLASH)) == \ (CFG_CMD_ENV|CFG_CMD_FLASH)) || \ @@ -544,7 +545,7 @@ return (saveenv() ? 1 : 0); }
- +#endif #endif
@@ -587,7 +588,7 @@ "setenv name\n" " - delete environment variable 'name'\n" ); - +#ifndef CFG_ENV_IS_NOWHERE #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) || \ ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_FLASH)) == \ (CFG_CMD_ENV|CFG_CMD_FLASH)) || \ @@ -600,6 +601,7 @@ );
#endif /* CFG_CMD_ENV */ +#endif
#if (CONFIG_COMMANDS & CFG_CMD_ASKENV)
diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.c u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.c --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.c 1970-01-01 01:00:00.000000000 +0100 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.c 2007-08-23 09:45:46.000000000 +0200 @@ -0,0 +1,572 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> + +#ifdef CONFIG_MMC + +#include <part.h> +#include <mmc.h> + +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/byteorder.h> +//#include <asm/arch/clk.h> +//#include <asm/arch/memory-map.h> +#include <asm/arch/hardware.h> //klk + +#include "atmel_mci.h" +#undef DEBUG +#ifdef DEBUG +#define pr_debug(fmt, args...) printf(fmt, ##args) +#else +#define pr_debug(...) do { } while(0) +#endif + +#ifndef CFG_MMC_CLK_OD +#define CFG_MMC_CLK_OD 375000 +#endif + +#ifndef CFG_MMC_CLK_PP +#define CFG_MMC_CLK_PP 20000000 +#endif + +#ifndef CFG_MMC_OP_COND +#define CFG_MMC_OP_COND 0x00100000 +#endif + +#define MMC_DEFAULT_BLKLEN 512 +#define MMC_DEFAULT_RCA 1 + +static unsigned int mmc_rca; +static int mmc_card_is_sd; +static block_dev_desc_t mmc_blkdev; + +block_dev_desc_t *mmc_get_dev(int dev) +{ + return &mmc_blkdev; +} + +static void mci_set_mode(unsigned long hz, unsigned long blklen) +{ + unsigned long bus_hz; + unsigned long clkdiv; + + // bus_hz = get_mci_clk_rate(); + bus_hz = AT91C_MASTER_CLOCK; + clkdiv = (bus_hz / hz) / 2 - 1; + + pr_debug("mmc: setting clock %lu Hz, block size %lu\n", + hz, blklen); + + if (clkdiv & ~255UL) { + clkdiv = 255; + pr_debug("mmc: clock %lu too low; setting CLKDIV to 255\n", + hz); + } + + blklen &= 0xfffc; + mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv) + | MMCI_BF(BLKLEN, blklen) + | MMCI_BIT(RDPROOF) + | MMCI_BIT(WRPROOF))); +} + +#define RESP_NO_CRC 1 +#define R1 MMCI_BF(RSPTYP, 1) +#define R2 MMCI_BF(RSPTYP, 2) +#define R3 (R1 | RESP_NO_CRC) +#define R6 R1 +#define NID MMCI_BF(MAXLAT, 0) +#define NCR MMCI_BF(MAXLAT, 1) +#define TRCMD_START MMCI_BF(TRCMD, 1) +#define TRDIR_READ MMCI_BF(TRDIR, 1) +#define TRTYP_BLOCK MMCI_BF(TRTYP, 0) +#define INIT_CMD MMCI_BF(SPCMD, 1) +#define OPEN_DRAIN MMCI_BF(OPDCMD, 1) + +#define ERROR_FLAGS (MMCI_BIT(DTOE) \ + | MMCI_BIT(RDIRE) \ + | MMCI_BIT(RENDE) \ + | MMCI_BIT(RINDE) \ + | MMCI_BIT(RTOE)) + +static int +mmc_cmd(unsigned long cmd, unsigned long arg, + void *resp, unsigned long flags) +{ + unsigned long *response = resp; + int i, response_words = 0; + unsigned long error_flags; + u32 status; + + AT91F_MMC_Hardware_Init(); + + pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n", + cmd, arg, flags); + + error_flags = ERROR_FLAGS; + if (!(flags & RESP_NO_CRC)) + error_flags |= MMCI_BIT(RCRCE); + + flags &= ~MMCI_BF(CMDNB, ~0UL); + + if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_48_BIT_RESP) + response_words = 1; + else if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_136_BIT_RESP) + response_words = 4; + + mmci_writel(ARGR, arg); + mmci_writel(CMDR, cmd | flags); + do { + udelay(40); + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(CMDRDY))); + + pr_debug("mmc: status 0x%08lx\n", status); + + if (status & ERROR_FLAGS) { + pr_debug("mmc: command %lu failed (status: 0x%08lx)\n", + cmd, status); + return -EIO; + } + + if (response_words) + pr_debug("mmc: response:"); + + for (i = 0; i < response_words; i++) { + response[i] = mmci_readl(RSPR); + pr_debug(" %08lx", response[i]); + } + pr_debug("\n"); + + return 0; +} + +static int mmc_acmd(unsigned long cmd, unsigned long arg, + void *resp, unsigned long flags) +{ + unsigned long aresp[4]; + int ret; + + /* + * Seems like the APP_CMD part of an ACMD has 64 cycles max + * latency even though the ACMD part doesn't. This isn't + * entirely clear in the SD Card spec, but some cards refuse + * to work if we attempt to use 5 cycles max latency here... + */ + ret = mmc_cmd(MMC_CMD_APP_CMD, 0, aresp, + R1 | NCR | (flags & OPEN_DRAIN)); + if (ret) + return ret; + if ((aresp[0] & (R1_ILLEGAL_COMMAND | R1_APP_CMD)) != R1_APP_CMD) + return -ENODEV; + + ret = mmc_cmd(cmd, arg, resp, flags); + return ret; +} + +static unsigned long +mmc_bread(int dev, unsigned long start, lbaint_t blkcnt, + unsigned long *buffer) +{ + int ret, i = 0; + unsigned long resp[4]; + unsigned long card_status, data; + unsigned long wordcount; + u32 status; + + if (blkcnt == 0) + return 0; + + pr_debug("mmc_bread: dev %d, start %lx, blkcnt %lx\n", + dev, start, blkcnt); + + /* Put the device into Transfer state */ + ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 | NCR); + if (ret) goto fail; + + /* Set block length */ + ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR); + if (ret) goto fail; + + pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR)); + + for (i = 0; i < blkcnt; i++, start++) { + ret = mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK, + start * mmc_blkdev.blksz, resp, + (R1 | NCR | TRCMD_START | TRDIR_READ + | TRTYP_BLOCK)); + if (ret) goto fail; + + ret = -EIO; + wordcount = 0; + do { + do { + status = mmci_readl(SR); + if (status & (ERROR_FLAGS | MMCI_BIT(OVRE))) + goto fail; + } while (!(status & MMCI_BIT(RXRDY))); + + if (status & MMCI_BIT(RXRDY)) { + data = mmci_readl(RDR); + /* pr_debug("%x\n", data); */ + *buffer++ = data; + wordcount++; + } + } while(wordcount < (mmc_blkdev.blksz / 4)); + + pr_debug("mmc: read %u words, waiting for BLKE\n", wordcount); + + do { + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(BLKE))); + + putc('.'); + } + +out: + /* Put the device back into Standby state */ + mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR); + return i; + +fail: + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("mmc: bread failed, card status = %08x\n", card_status); + goto out; +} + +static void mmc_parse_cid(struct mmc_cid *cid, unsigned long *resp) +{ + cid->mid = resp[0] >> 24; + cid->oid = (resp[0] >> 8) & 0xffff; + cid->pnm[0] = resp[0]; + cid->pnm[1] = resp[1] >> 24; + cid->pnm[2] = resp[1] >> 16; + cid->pnm[3] = resp[1] >> 8; + cid->pnm[4] = resp[1]; + cid->pnm[5] = resp[2] >> 24; + cid->pnm[6] = 0; + cid->prv = resp[2] >> 16; + cid->psn = (resp[2] << 16) | (resp[3] >> 16); + cid->mdt = resp[3] >> 8; +} + +static void sd_parse_cid(struct mmc_cid *cid, unsigned long *resp) +{ + cid->mid = resp[0] >> 24; + cid->oid = (resp[0] >> 8) & 0xffff; + cid->pnm[0] = resp[0]; + cid->pnm[1] = resp[1] >> 24; + cid->pnm[2] = resp[1] >> 16; + cid->pnm[3] = resp[1] >> 8; + cid->pnm[4] = resp[1]; + cid->pnm[5] = 0; + cid->pnm[6] = 0; + cid->prv = resp[2] >> 24; + cid->psn = (resp[2] << 8) | (resp[3] >> 24); + cid->mdt = (resp[3] >> 8) & 0x0fff; +} + +static void mmc_dump_cid(const struct mmc_cid *cid) +{ + printf("Manufacturer ID: %02lX\n", cid->mid); + printf("OEM/Application ID: %04lX\n", cid->oid); + printf("Product name: %s\n", cid->pnm); + printf("Product Revision: %lu.%lu\n", + cid->prv >> 4, cid->prv & 0x0f); + printf("Product Serial Number: %lu\n", cid->psn); + printf("Manufacturing Date: %02lu/%02lu\n", + cid->mdt >> 4, cid->mdt & 0x0f); +} + +static void mmc_dump_csd(const struct mmc_csd *csd) +{ + unsigned long *csd_raw = (unsigned long *)csd; + pr_debug("CSD data: %08lx %08lx %08lx %08lx\n", + csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]); + pr_debug("CSD structure version: 1.%u\n", csd->csd_structure); + pr_debug("MMC System Spec version: %u\n", csd->spec_vers); + pr_debug("Card command classes: %03x\n", csd->ccc); + pr_debug("Read block length: %u\n", 1 << csd->read_bl_len); + if (csd->read_bl_partial) + puts("Supports partial reads\n"); + else + puts("Does not support partial reads\n"); + pr_debug("Write block length: %u\n", 1 << csd->write_bl_len); + if (csd->write_bl_partial) + puts("Supports partial writes\n"); + else + puts("Does not support partial writes\n"); + if (csd->wp_grp_enable) + pr_debug("Supports group WP: %u\n", csd->wp_grp_size + 1); + else + puts("Does not support group WP\n"); + pr_debug("Card capacity: %u bytes\n", + (csd->c_size + 1) * (1 << (csd->c_size_mult + 2)) * + (1 << csd->read_bl_len)); + pr_debug("File format: %u/%u\n", + csd->file_format_grp, csd->file_format); + puts("Write protection: "); + if (csd->perm_write_protect) + puts(" permanent"); + if (csd->tmp_write_protect) + puts(" temporary"); + putc('\n'); +} + +static int mmc_idle_cards(void) +{ + int ret; + + /* Reset and initialize all cards */ + ret = mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, NULL, 0); + + if (ret) + return ret; + pr_debug(" ret: %i\n",ret); + /* Keep the bus idle for 74 clock cycles */ + return mmc_cmd(0, 0, NULL, INIT_CMD); +} + +static int sd_init_card(struct mmc_cid *cid, int verbose) +{ + unsigned long resp[4]; + int i, ret = 0; + + mmc_idle_cards(); + for (i = 0; i < 1000; i++) { + ret = mmc_acmd(MMC_ACMD_SD_SEND_OP_COND, CFG_MMC_OP_COND, + resp, R3 | NID); + if (ret || (resp[0] & 0x80000000)) + break; + ret = -ETIMEDOUT; + } + + if (ret) + return ret; + + ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID); + if (ret) + return ret; + sd_parse_cid(cid, resp); + if (verbose) + mmc_dump_cid(cid); + + /* Get RCA of the card that responded */ + ret = mmc_cmd(MMC_CMD_SD_SEND_RELATIVE_ADDR, 0, resp, R6 | NCR); + if (ret) + return ret; + + mmc_rca = resp[0] >> 16; + if (verbose) + pr_debug("SD Card detected (RCA %u)\n", mmc_rca); + mmc_card_is_sd = 1; + return 0; +} + +static int mmc_init_card(struct mmc_cid *cid, int verbose) +{ + unsigned long resp[4]; + int i, ret = 0; + + mmc_idle_cards(); + + for (i = 0; i < 1000; i++) { + ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CFG_MMC_OP_COND, resp, + R3 | NID | OPEN_DRAIN); + if (ret || (resp[0] & 0x80000000)) + { + break; + } + ret = -ETIMEDOUT; + } + pr_debug("4\n"); + pr_debug("ret : %i\n",ret); + if (ret) + return ret; + pr_debug("5\n"); + /* Get CID of all cards. FIXME: Support more than one card */ + ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID | OPEN_DRAIN); + if (ret) + return ret; + mmc_parse_cid(cid, resp); + if (verbose) + mmc_dump_cid(cid); + + /* Set Relative Address of the card that responded */ + ret = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, mmc_rca << 16, resp, + R1 | NCR | OPEN_DRAIN); + return ret; +} + +static void mci_set_data_timeout(struct mmc_csd *csd) +{ + static const unsigned int dtomul_to_shift[] = { + 0, 4, 7, 8, 10, 12, 16, 20, + }; + static const unsigned int taac_exp[] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, + }; + static const unsigned int taac_mant[] = { + 0, 10, 12, 13, 15, 60, 25, 30, + 35, 40, 45, 50, 55, 60, 70, 80, + }; + unsigned int timeout_ns, timeout_clks; + unsigned int e, m; + unsigned int dtocyc, dtomul; + unsigned int shift; + u32 dtor; + + e = csd->taac & 0x07; + m = (csd->taac >> 3) & 0x0f; + + timeout_ns = (taac_exp[e] * taac_mant[m] + 9) / 10; + timeout_clks = csd->nsac * 100; + + timeout_clks += (((timeout_ns + 9) / 10) + * ((CFG_MMC_CLK_PP + 99999) / 100000) + 9999) / 10000; + if (!mmc_card_is_sd) + timeout_clks *= 10; + else + timeout_clks *= 100; + + dtocyc = timeout_clks; + dtomul = 0; + while (dtocyc > 15 && dtomul < 8) { + dtomul++; + shift = dtomul_to_shift[dtomul]; + dtocyc = (timeout_clks + (1 << shift) - 1) >> shift; + } + + if (dtomul >= 8) { + dtomul = 7; + dtocyc = 15; + puts("Warning: Using maximum data timeout\n"); + } + + dtor = (MMCI_BF(DTOMUL, dtomul) + | MMCI_BF(DTOCYC, dtocyc)); + mmci_writel(DTOR, dtor); + + pr_debug("mmc: Using %u cycles data timeout (DTOR=0x%x)\n", + dtocyc << shift, dtor); +} + +int mmc_init(int verbose) +{ + struct mmc_cid cid; + struct mmc_csd csd; + unsigned int max_blksz; + int ret,aux; + + AT91F_MMC_Hardware_Init(); + + pr_debug("0\n"); + /* Initialize controller */ + mmci_writel(CR, MMCI_BIT(SWRST)); + mmci_writel(CR, MMCI_BIT(MCIEN)); + mmci_writel(DTOR, 0x5f); + mmci_writel(IDR, ~0UL); + mmci_writel(SDCR, 0x1); + mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); +/* //mmci_writel(CR, MMCI_BIT(SWRST)); + mmci_writel(CR, 0x00000001); + mmci_writel(DTOR, 0x0000007F); + mmci_writel(IDR, 0xFFFFFFFF); + mmci_writel(SDCR, 0x00000001); + //mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); + mmci_writel(MR, 0x02009B4A); */ + + pr_debug("1\n"); + + mmc_card_is_sd = 0; + + ret = sd_init_card(&cid, verbose); + if (ret) { + mmc_rca = MMC_DEFAULT_RCA; + ret = mmc_init_card(&cid, verbose); + } + pr_debug("6\n"); + if (ret) + return ret; + pr_debug("7\n"); + /* Get CSD from the card */ + ret = mmc_cmd(MMC_CMD_SEND_CSD, mmc_rca << 16, &csd, R2 | NCR); + if (ret) + return ret; + if (verbose) + mmc_dump_csd(&csd); + + mci_set_data_timeout(&csd); + + /* Initialize the blockdev structure */ + mmc_blkdev.if_type = IF_TYPE_MMC; + mmc_blkdev.part_type = PART_TYPE_DOS; + mmc_blkdev.block_read = mmc_bread; + sprintf((char *)mmc_blkdev.vendor, + "Man %02x%04x Snr %08x", + cid.mid, cid.oid, cid.psn); + strncpy((char *)mmc_blkdev.product, cid.pnm, + sizeof(mmc_blkdev.product)); + sprintf((char *)mmc_blkdev.revision, "%x %x", + cid.prv >> 4, cid.prv & 0x0f); + + /* + * If we can't use 512 byte blocks, refuse to deal with the + * card. Tons of code elsewhere seems to depend on this. + */ + max_blksz = 1 << csd.read_bl_len; + // if (max_blksz < 512 || (max_blksz > 512 && !csd.read_bl_partial)) { + // pr_debug("Card does not support 512 byte reads, aborting.\n"); + // return -ENODEV; + // } + mmc_blkdev.blksz = 512; + mmc_blkdev.lba = (csd.c_size + 1) * (1 << (csd.c_size_mult + 2)); + + mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz); + +#if 0 + if (fat_register_device(&mmc_blkdev, 1)) + pr_debug("Could not register MMC fat device\n"); +#else + init_part(&mmc_blkdev); +#endif + + return 0; +} + +int mmc_read(ulong src, uchar *dst, int size) +{ + return -ENOSYS; +} + +int mmc_write(uchar *src, ulong dst, int size) +{ + return -ENOSYS; +} + +int mmc2info(ulong addr) +{ + return 0; +} + +#endif /* CONFIG_MMC */ diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.h u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.h --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.h 1970-01-01 01:00:00.000000000 +0100 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.h 2007-08-17 10:43:17.000000000 +0200 @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef __CPU_AT32AP_ATMEL_MCI_H__ +#define __CPU_AT32AP_ATMEL_MCI_H__ + +/* Atmel MultiMedia Card Interface (MCI) registers */ +#define MMCI_CR 0x0000 +#define MMCI_MR 0x0004 +#define MMCI_DTOR 0x0008 +#define MMCI_SDCR 0x000c +#define MMCI_ARGR 0x0010 +#define MMCI_CMDR 0x0014 +#define MMCI_RSPR 0x0020 +#define MMCI_RSPR1 0x0024 +#define MMCI_RSPR2 0x0028 +#define MMCI_RSPR3 0x002c +#define MMCI_RDR 0x0030 +#define MMCI_TDR 0x0034 +#define MMCI_SR 0x0040 +#define MMCI_IER 0x0044 +#define MMCI_IDR 0x0048 +#define MMCI_IMR 0x004c + +/* Bitfields in CR */ +#define MMCI_MCIEN_OFFSET 0 +#define MMCI_MCIEN_SIZE 1 +#define MMCI_MCIDIS_OFFSET 1 +#define MMCI_MCIDIS_SIZE 1 +#define MMCI_PWSEN_OFFSET 2 +#define MMCI_PWSEN_SIZE 1 +#define MMCI_PWSDIS_OFFSET 3 +#define MMCI_PWSDIS_SIZE 1 +#define MMCI_SWRST_OFFSET 7 +#define MMCI_SWRST_SIZE 1 + +/* Bitfields in MR */ +#define MMCI_CLKDIV_OFFSET 0 +#define MMCI_CLKDIV_SIZE 8 +#define MMCI_PWSDIV_OFFSET 8 +#define MMCI_PWSDIV_SIZE 3 +#define MMCI_RDPROOF_OFFSET 11 +#define MMCI_RDPROOF_SIZE 1 +#define MMCI_WRPROOF_OFFSET 12 +#define MMCI_WRPROOF_SIZE 1 +#define MMCI_PDCPADV_OFFSET 14 +#define MMCI_PDCPADV_SIZE 1 +#define MMCI_PDCMODE_OFFSET 15 +#define MMCI_PDCMODE_SIZE 1 +#define MMCI_BLKLEN_OFFSET 16 +#define MMCI_BLKLEN_SIZE 16 + +/* Bitfields in DTOR */ +#define MMCI_DTOCYC_OFFSET 0 +#define MMCI_DTOCYC_SIZE 4 +#define MMCI_DTOMUL_OFFSET 4 +#define MMCI_DTOMUL_SIZE 3 + +/* Bitfields in SDCR */ +#define MMCI_SCDSEL_OFFSET 0 +#define MMCI_SCDSEL_SIZE 4 +#define MMCI_SCDBUS_OFFSET 7 +#define MMCI_SCDBUS_SIZE 1 + +/* Bitfields in ARGR */ +#define MMCI_ARG_OFFSET 0 +#define MMCI_ARG_SIZE 32 + +/* Bitfields in CMDR */ +#define MMCI_CMDNB_OFFSET 0 +#define MMCI_CMDNB_SIZE 6 +#define MMCI_RSPTYP_OFFSET 6 +#define MMCI_RSPTYP_SIZE 2 +#define MMCI_SPCMD_OFFSET 8 +#define MMCI_SPCMD_SIZE 3 +#define MMCI_OPDCMD_OFFSET 11 +#define MMCI_OPDCMD_SIZE 1 +#define MMCI_MAXLAT_OFFSET 12 +#define MMCI_MAXLAT_SIZE 1 +#define MMCI_TRCMD_OFFSET 16 +#define MMCI_TRCMD_SIZE 2 +#define MMCI_TRDIR_OFFSET 18 +#define MMCI_TRDIR_SIZE 1 +#define MMCI_TRTYP_OFFSET 19 +#define MMCI_TRTYP_SIZE 2 + +/* Bitfields in RSPRx */ +#define MMCI_RSP_OFFSET 0 +#define MMCI_RSP_SIZE 32 + +/* Bitfields in SR/IER/IDR/IMR */ +#define MMCI_CMDRDY_OFFSET 0 +#define MMCI_CMDRDY_SIZE 1 +#define MMCI_RXRDY_OFFSET 1 +#define MMCI_RXRDY_SIZE 1 +#define MMCI_TXRDY_OFFSET 2 +#define MMCI_TXRDY_SIZE 1 +#define MMCI_BLKE_OFFSET 3 +#define MMCI_BLKE_SIZE 1 +#define MMCI_DTIP_OFFSET 4 +#define MMCI_DTIP_SIZE 1 +#define MMCI_NOTBUSY_OFFSET 5 +#define MMCI_NOTBUSY_SIZE 1 +#define MMCI_ENDRX_OFFSET 6 +#define MMCI_ENDRX_SIZE 1 +#define MMCI_ENDTX_OFFSET 7 +#define MMCI_ENDTX_SIZE 1 +#define MMCI_RXBUFF_OFFSET 14 +#define MMCI_RXBUFF_SIZE 1 +#define MMCI_TXBUFE_OFFSET 15 +#define MMCI_TXBUFE_SIZE 1 +#define MMCI_RINDE_OFFSET 16 +#define MMCI_RINDE_SIZE 1 +#define MMCI_RDIRE_OFFSET 17 +#define MMCI_RDIRE_SIZE 1 +#define MMCI_RCRCE_OFFSET 18 +#define MMCI_RCRCE_SIZE 1 +#define MMCI_RENDE_OFFSET 19 +#define MMCI_RENDE_SIZE 1 +#define MMCI_RTOE_OFFSET 20 +#define MMCI_RTOE_SIZE 1 +#define MMCI_DCRCE_OFFSET 21 +#define MMCI_DCRCE_SIZE 1 +#define MMCI_DTOE_OFFSET 22 +#define MMCI_DTOE_SIZE 1 +#define MMCI_OVRE_OFFSET 30 +#define MMCI_OVRE_SIZE 1 +#define MMCI_UNRE_OFFSET 31 +#define MMCI_UNRE_SIZE 1 + +/* Constants for DTOMUL */ +#define MMCI_DTOMUL_1_CYCLE 0 +#define MMCI_DTOMUL_16_CYCLES 1 +#define MMCI_DTOMUL_128_CYCLES 2 +#define MMCI_DTOMUL_256_CYCLES 3 +#define MMCI_DTOMUL_1024_CYCLES 4 +#define MMCI_DTOMUL_4096_CYCLES 5 +#define MMCI_DTOMUL_65536_CYCLES 6 +#define MMCI_DTOMUL_1048576_CYCLES 7 + +/* Constants for RSPTYP */ +#define MMCI_RSPTYP_NO_RESP 0 +#define MMCI_RSPTYP_48_BIT_RESP 1 +#define MMCI_RSPTYP_136_BIT_RESP 2 + +/* Constants for SPCMD */ +#define MMCI_SPCMD_NO_SPEC_CMD 0 +#define MMCI_SPCMD_INIT_CMD 1 +#define MMCI_SPCMD_SYNC_CMD 2 +#define MMCI_SPCMD_INT_CMD 4 +#define MMCI_SPCMD_INT_RESP 5 + +/* Constants for TRCMD */ +#define MMCI_TRCMD_NO_TRANS 0 +#define MMCI_TRCMD_START_TRANS 1 +#define MMCI_TRCMD_STOP_TRANS 2 + +/* Constants for TRTYP */ +#define MMCI_TRTYP_BLOCK 0 +#define MMCI_TRTYP_MULTI_BLOCK 1 +#define MMCI_TRTYP_STREAM 2 + +/* Bit manipulation macros */ +#define MMCI_BIT(name) \ + (1 << MMCI_##name##_OFFSET) +#define MMCI_BF(name,value) \ + (((value) & ((1 << MMCI_##name##_SIZE) - 1)) \ + << MMCI_##name##_OFFSET) +#define MMCI_BFEXT(name,value) \ + (((value) >> MMCI_##name##_OFFSET)\ + & ((1 << MMCI_##name##_SIZE) - 1)) +#define MMCI_BFINS(name,value,old) \ + (((old) & ~(((1 << MMCI_##name##_SIZE) - 1) \ + << MMCI_##name##_OFFSET)) \ + | MMCI_BF(name,value)) + +/* Register access macros */ +#define mmci_readl(reg) \ + readl((void *)MMCI_BASE + MMCI_##reg) +#define mmci_writel(reg,value) \ + writel((value), (void *)MMCI_BASE + MMCI_##reg) + +#endif /* __CPU_AT32AP_ATMEL_MCI_H__ */ diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/config.mk u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/config.mk --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/config.mk 2007-08-21 17:06:35.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/config.mk 2007-08-16 13:34:14.000000000 +0200 @@ -19,10 +19,10 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, # MA 02111-1307 USA -# +#PLATFORM_RELFLAGS += $(call cc-option,-msoft-float,)
PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 -PLATFORM_RELFLAGS += $(call cc-option,-msoft-float,) +PLATFORM_RELFLAGS += $(call cc-option,)
PLATFORM_CPPFLAGS += -march=armv5te PLATFORM_CPPFLAGS += $(call cc-option,-mtune=arm926ejs,) diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/Makefile u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/Makefile --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/Makefile 2007-08-21 17:06:36.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/Makefile 2007-08-23 09:14:21.000000000 +0200 @@ -26,8 +26,8 @@ LIB = lib$(SOC).a
-OBJS = serial.o interrupts.o usb_ohci.o lcd.o ether.o spi.o -SOBJS = +OBJS = serial.o interrupts.o usb_ohci.o ether.o spi.o +SOBJS = atmel_mci.o
all: .depend $(LIB)
diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/spi.c u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/spi.c --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/spi.c 2007-08-21 17:06:35.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/spi.c 2007-08-23 10:36:47.000000000 +0200 @@ -184,6 +184,20 @@ { unsigned int timeout;
+#ifdef CONFIG_AT91SAM9260EK + /* Configure PIO controllers to periph mode */ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, // PIO controller base address + ((unsigned int) AT91C_PA1_SPI0_MOSI) | + ((unsigned int) AT91C_PA3_SPI0_NPCS0) | + ((unsigned int) AT91C_PA0_SPI0_MISO) | + ((unsigned int) AT91C_PA2_SPI0_SPCK), /* Peripheral A */ + 0); /* Peripheral B */ + /* Configure PIO controllers to periph mode */ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOC, /* PIO controller base address */ + 0, /* Peripheral A */ + ((unsigned int) AT91C_PC11_SPI0_NPCS1)); /* Peripheral B */ +#endif + pDesc->state = BUSY;
/* Disable PDC TX and RX channels */ diff -burN u-boot-1.1.5/cpu/arm926ejs/config.mk u-boot-1.1.5.klk/cpu/arm926ejs/config.mk --- u-boot-1.1.5/cpu/arm926ejs/config.mk 2006-10-20 17:54:33.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/config.mk 2007-08-16 13:34:42.000000000 +0200 @@ -20,10 +20,10 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, # MA 02111-1307 USA # - -PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ - -msoft-float - +# +#PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ +# -msoft-float +PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 PLATFORM_CPPFLAGS += -march=armv4 # ======================================================================== = # diff -burN u-boot-1.1.5/disk/part.c u-boot-1.1.5.klk/disk/part.c --- u-boot-1.1.5/disk/part.c 2006-10-20 17:54:33.000000000 +0200 +++ u-boot-1.1.5.klk/disk/part.c 2007-08-23 08:29:56.000000000 +0200 @@ -36,6 +36,7 @@ #if ((CONFIG_COMMANDS & CFG_CMD_IDE) || \ (CONFIG_COMMANDS & CFG_CMD_SCSI) || \ (CONFIG_COMMANDS & CFG_CMD_USB) || \ + (CONFIG_COMMANDS & CFG_CMD_MMC) || \ defined(CONFIG_MMC) || \ defined(CONFIG_SYSTEMACE) )
@@ -126,6 +127,8 @@ #if ((CONFIG_COMMANDS & CFG_CMD_IDE) || \ (CONFIG_COMMANDS & CFG_CMD_SCSI) || \ (CONFIG_COMMANDS & CFG_CMD_USB) || \ + (CONFIG_COMMANDS & CFG_CMD_MMC) || \ + defined(CONFIG_MMC) || \ defined(CONFIG_SYSTEMACE) )
#if defined(CONFIG_MAC_PARTITION) || \ diff -burN u-boot-1.1.5/include/asm-arm/arch-at91sam926x/mmc.h u-boot-1.1.5.klk/include/asm-arm/arch-at91sam926x/mmc.h --- u-boot-1.1.5/include/asm-arm/arch-at91sam926x/mmc.h 1970-01-01 01:00:00.000000000 +0100 +++ u-boot-1.1.5.klk/include/asm-arm/arch-at91sam926x/mmc.h 2007-08-17 10:44:42.000000000 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef __ASM_AVR32_MMC_H +#define __ASM_AVR32_MMC_H + +struct mmc_cid { + unsigned long psn; + unsigned short oid; + unsigned char mid; + unsigned char prv; + unsigned char mdt; + char pnm[7]; +}; + +struct mmc_csd +{ + u8 csd_structure:2, + spec_vers:4, + rsvd1:2; + u8 taac; + u8 nsac; + u8 tran_speed; + u16 ccc:12, + read_bl_len:4; + u64 read_bl_partial:1, + write_blk_misalign:1, + read_blk_misalign:1, + dsr_imp:1, + rsvd2:2, + c_size:12, + vdd_r_curr_min:3, + vdd_r_curr_max:3, + vdd_w_curr_min:3, + vdd_w_curr_max:3, + c_size_mult:3, + sector_size:5, + erase_grp_size:5, + wp_grp_size:5, + wp_grp_enable:1, + default_ecc:2, + r2w_factor:3, + write_bl_len:4, + write_bl_partial:1, + rsvd3:5; + u8 file_format_grp:1, + copy:1, + perm_write_protect:1, + tmp_write_protect:1, + file_format:2, + ecc:2; + u8 crc:7; + u8 one:1; +}; + +/* MMC Command numbers */ +#define MMC_CMD_GO_IDLE_STATE 0 +#define MMC_CMD_SEND_OP_COND 1 +#define MMC_CMD_ALL_SEND_CID 2 +#define MMC_CMD_SET_RELATIVE_ADDR 3 +#define MMC_CMD_SD_SEND_RELATIVE_ADDR 3 +#define MMC_CMD_SET_DSR 4 +#define MMC_CMD_SELECT_CARD 7 +#define MMC_CMD_SEND_CSD 9 +#define MMC_CMD_SEND_CID 10 +#define MMC_CMD_SEND_STATUS 13 +#define MMC_CMD_SET_BLOCKLEN 16 +#define MMC_CMD_READ_SINGLE_BLOCK 17 +#define MMC_CMD_READ_MULTIPLE_BLOCK 18 +#define MMC_CMD_WRITE_BLOCK 24 +#define MMC_CMD_APP_CMD 55 + +#define MMC_ACMD_SD_SEND_OP_COND 41 + +#define R1_ILLEGAL_COMMAND (1 << 22) +#define R1_APP_CMD (1 << 5) + +#endif /* __ASM_AVR32_MMC_H */ diff -burN u-boot-1.1.5/include/configs/at91sam9260ek.h u-boot-1.1.5.klk/include/configs/at91sam9260ek.h --- u-boot-1.1.5/include/configs/at91sam9260ek.h 2007-08-21 17:06:36.000000000 +0200 +++ u-boot-1.1.5.klk/include/configs/at91sam9260ek.h 2007-08-23 10:51:43.000000000 +0200 @@ -88,6 +88,8 @@ CFG_CMD_FLASH | \ CFG_CMD_AUTOSCRIPT | \ CFG_CMD_NAND | \ + CFG_CMD_MMC | \ + CFG_CMD_EXT2 | \ CFG_CMD_FAT ) & \ ~(CFG_CMD_BDI | \ CFG_CMD_IMLS | \ @@ -225,6 +227,7 @@ #undef CFG_ENV_IS_IN_FLASH #define CFG_ENV_IS_IN_DATAFLASH 1 #undef CFG_ENV_IS_IN_NAND +#undef CFG_ENV_IS_NOWHERE
/*#define CONFIG_MTD_DEBUG 1 #define CONFIG_MTD_DEBUG_VERBOSE MTD_DEBUG_LEVEL3 @@ -241,6 +244,10 @@ #define CFG_ENV_SIZE 0x4000 /* 0x8000 */ #endif
+#ifdef CFG_ENV_IS_NOWHERE +#define CFG_ENV_SIZE 0x4000 +#endif + #ifdef CFG_ENV_IS_IN_FLASH #ifdef CONFIG_BOOTBINFUNC #define CFG_ENV_ADDR (PHYS_FLASH_1 + 0x60000) /* after u-boot.bin */ @@ -257,6 +264,10 @@ #define CONFIG_DOS_PARTITION 1 #define LITTLEENDIAN 1
+/* MMC */ +#define CONFIG_MMC 1 +#define MMCI_BASE 0xFFFA8000 + #define CFG_LOAD_ADDR 0x23f00000 /* default load address */
#ifdef CONFIG_BOOTBINFUNC

Thanks for that... but it's my own patch ;)
Pierre
-----Message d'origine----- De : u-boot-users-bounces@lists.sourceforge.net [mailto:u-boot-users-bounces@lists.sourceforge.net] De la part de Ken.Fuchs@bench.com Envoyé : mercredi 23 avril 2008 21:23 À : pierre.savary@kerlink.fr Cc : u-boot-users@lists.sourceforge.net; afleming@freescale.com; drzeus-mmc@drzeus.cx Objet : Re: [U-Boot-Users] [PATCH] Add eSDHC driver
Pierre Savary wrote:
Where could we find the driver that works with MMCv4 on at91sam9x?
Andy Fleming wrote:
Pierre, I don't have a driver that works on at91sam9x, I'm afraid.
Here's an MMC v2.x AT91SAM9260 patch for Atmel modified u-boot 1.1.5. You will need to define GPIO pins for other AT91SAM9 processors, etc.
If you really need an MMC v4.x AT91SAM9 MCI driver for 1.1.5 fast, you probably could cut and paste the v4.x code you need from Andy's MMC driver into the MMC v2.x MCI driver this patch provides.
BTW, if anyone knows why MMC 4 bit is disabled for AT91SAM9261 in the MCI Linux driver, I'd like to hear the reasons why.
--- u-boot_at91sam9260_mmc.patch (AT91 MCI driver) ---
diff -burN u-boot-1.1.5/board/at91sam9260ek/at91sam9260ek.c u-boot-1.1.5.klk/board/at91sam9260ek/at91sam9260ek.c --- u-boot-1.1.5/board/at91sam9260ek/at91sam9260ek.c 2007-08-21 17:06:36.000000000 +0200 +++ u-boot-1.1.5.klk/board/at91sam9260ek/at91sam9260ek.c 2007-08-23 08:37:42.000000000 +0200 @@ -109,6 +109,24 @@ }
+#ifdef CONFIG_MMC +#if (CONFIG_COMMANDS & CFG_CMD_MMC) +int AT91F_MMC_Hardware_Init(void) +{ + AT91C_BASE_PIOA->PIO_ASR = (1 << 8 ); /* periph A select register */ + AT91C_BASE_PIOA->PIO_BSR |= 0x3B; /* periph B select register */ + AT91C_BASE_PIOA->PIO_PDR |= 0x13B; /* PIO disable register */ + AT91C_BASE_PIOA->PIO_PPUDR |= 0x13B; /* Pull up disable register */ + + AT91C_BASE_PMC->PMC_PCER = (1 << 9); +} +#endif /* CONFIG_COMMANDS & CFG_CMD_MMC */ +#endif /* CONFIG_MMC */ + + + + + #ifdef CONFIG_DRIVER_ETHER #if (CONFIG_COMMANDS & CFG_CMD_NET)
diff -burN u-boot-1.1.5/common/cmd_nvedit.c u-boot-1.1.5.klk/common/cmd_nvedit.c --- u-boot-1.1.5/common/cmd_nvedit.c 2006-10-20 17:54:33.000000000 +0200 +++ u-boot-1.1.5.klk/common/cmd_nvedit.c 2007-08-23 09:26:18.000000000 +0200 @@ -530,6 +530,7 @@ return (-1); }
+#ifndef CFG_ENV_IS_NOWHERE #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) || \ ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_FLASH)) == \ (CFG_CMD_ENV|CFG_CMD_FLASH)) || \ @@ -544,7 +545,7 @@ return (saveenv() ? 1 : 0); }
- +#endif #endif
@@ -587,7 +588,7 @@ "setenv name\n" " - delete environment variable 'name'\n" ); - +#ifndef CFG_ENV_IS_NOWHERE #if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) || \ ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_FLASH)) == \ (CFG_CMD_ENV|CFG_CMD_FLASH)) || \ @@ -600,6 +601,7 @@ );
#endif /* CFG_CMD_ENV */ +#endif
#if (CONFIG_COMMANDS & CFG_CMD_ASKENV)
diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.c u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.c --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.c 1970-01-01 01:00:00.000000000 +0100 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.c 2007-08-23 09:45:46.000000000 +0200 @@ -0,0 +1,572 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> + +#ifdef CONFIG_MMC + +#include <part.h> +#include <mmc.h> + +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/byteorder.h> +//#include <asm/arch/clk.h> +//#include <asm/arch/memory-map.h> +#include <asm/arch/hardware.h> //klk + +#include "atmel_mci.h" +#undef DEBUG +#ifdef DEBUG +#define pr_debug(fmt, args...) printf(fmt, ##args) +#else +#define pr_debug(...) do { } while(0) +#endif + +#ifndef CFG_MMC_CLK_OD +#define CFG_MMC_CLK_OD 375000 +#endif + +#ifndef CFG_MMC_CLK_PP +#define CFG_MMC_CLK_PP 20000000 +#endif + +#ifndef CFG_MMC_OP_COND +#define CFG_MMC_OP_COND 0x00100000 +#endif + +#define MMC_DEFAULT_BLKLEN 512 +#define MMC_DEFAULT_RCA 1 + +static unsigned int mmc_rca; +static int mmc_card_is_sd; +static block_dev_desc_t mmc_blkdev; + +block_dev_desc_t *mmc_get_dev(int dev) +{ + return &mmc_blkdev; +} + +static void mci_set_mode(unsigned long hz, unsigned long blklen) +{ + unsigned long bus_hz; + unsigned long clkdiv; + + // bus_hz = get_mci_clk_rate(); + bus_hz = AT91C_MASTER_CLOCK; + clkdiv = (bus_hz / hz) / 2 - 1; + + pr_debug("mmc: setting clock %lu Hz, block size %lu\n", + hz, blklen); + + if (clkdiv & ~255UL) { + clkdiv = 255; + pr_debug("mmc: clock %lu too low; setting CLKDIV to 255\n", + hz); + } + + blklen &= 0xfffc; + mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv) + | MMCI_BF(BLKLEN, blklen) + | MMCI_BIT(RDPROOF) + | MMCI_BIT(WRPROOF))); +} + +#define RESP_NO_CRC 1 +#define R1 MMCI_BF(RSPTYP, 1) +#define R2 MMCI_BF(RSPTYP, 2) +#define R3 (R1 | RESP_NO_CRC) +#define R6 R1 +#define NID MMCI_BF(MAXLAT, 0) +#define NCR MMCI_BF(MAXLAT, 1) +#define TRCMD_START MMCI_BF(TRCMD, 1) +#define TRDIR_READ MMCI_BF(TRDIR, 1) +#define TRTYP_BLOCK MMCI_BF(TRTYP, 0) +#define INIT_CMD MMCI_BF(SPCMD, 1) +#define OPEN_DRAIN MMCI_BF(OPDCMD, 1) + +#define ERROR_FLAGS (MMCI_BIT(DTOE) \ + | MMCI_BIT(RDIRE) \ + | MMCI_BIT(RENDE) \ + | MMCI_BIT(RINDE) \ + | MMCI_BIT(RTOE)) + +static int +mmc_cmd(unsigned long cmd, unsigned long arg, + void *resp, unsigned long flags) +{ + unsigned long *response = resp; + int i, response_words = 0; + unsigned long error_flags; + u32 status; + + AT91F_MMC_Hardware_Init(); + + pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n", + cmd, arg, flags); + + error_flags = ERROR_FLAGS; + if (!(flags & RESP_NO_CRC)) + error_flags |= MMCI_BIT(RCRCE); + + flags &= ~MMCI_BF(CMDNB, ~0UL); + + if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_48_BIT_RESP) + response_words = 1; + else if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_136_BIT_RESP) + response_words = 4; + + mmci_writel(ARGR, arg); + mmci_writel(CMDR, cmd | flags); + do { + udelay(40); + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(CMDRDY))); + + pr_debug("mmc: status 0x%08lx\n", status); + + if (status & ERROR_FLAGS) { + pr_debug("mmc: command %lu failed (status: 0x%08lx)\n", + cmd, status); + return -EIO; + } + + if (response_words) + pr_debug("mmc: response:"); + + for (i = 0; i < response_words; i++) { + response[i] = mmci_readl(RSPR); + pr_debug(" %08lx", response[i]); + } + pr_debug("\n"); + + return 0; +} + +static int mmc_acmd(unsigned long cmd, unsigned long arg, + void *resp, unsigned long flags) +{ + unsigned long aresp[4]; + int ret; + + /* + * Seems like the APP_CMD part of an ACMD has 64 cycles max + * latency even though the ACMD part doesn't. This isn't + * entirely clear in the SD Card spec, but some cards refuse + * to work if we attempt to use 5 cycles max latency here... + */ + ret = mmc_cmd(MMC_CMD_APP_CMD, 0, aresp, + R1 | NCR | (flags & OPEN_DRAIN)); + if (ret) + return ret; + if ((aresp[0] & (R1_ILLEGAL_COMMAND | R1_APP_CMD)) != R1_APP_CMD) + return -ENODEV; + + ret = mmc_cmd(cmd, arg, resp, flags); + return ret; +} + +static unsigned long +mmc_bread(int dev, unsigned long start, lbaint_t blkcnt, + unsigned long *buffer) +{ + int ret, i = 0; + unsigned long resp[4]; + unsigned long card_status, data; + unsigned long wordcount; + u32 status; + + if (blkcnt == 0) + return 0; + + pr_debug("mmc_bread: dev %d, start %lx, blkcnt %lx\n", + dev, start, blkcnt); + + /* Put the device into Transfer state */ + ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 | NCR); + if (ret) goto fail; + + /* Set block length */ + ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR); + if (ret) goto fail; + + pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR)); + + for (i = 0; i < blkcnt; i++, start++) { + ret = mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK, + start * mmc_blkdev.blksz, resp, + (R1 | NCR | TRCMD_START | TRDIR_READ + | TRTYP_BLOCK)); + if (ret) goto fail; + + ret = -EIO; + wordcount = 0; + do { + do { + status = mmci_readl(SR); + if (status & (ERROR_FLAGS | MMCI_BIT(OVRE))) + goto fail; + } while (!(status & MMCI_BIT(RXRDY))); + + if (status & MMCI_BIT(RXRDY)) { + data = mmci_readl(RDR); + /* pr_debug("%x\n", data); */ + *buffer++ = data; + wordcount++; + } + } while(wordcount < (mmc_blkdev.blksz / 4)); + + pr_debug("mmc: read %u words, waiting for BLKE\n", wordcount); + + do { + status = mmci_readl(SR); + } while (!(status & MMCI_BIT(BLKE))); + + putc('.'); + } + +out: + /* Put the device back into Standby state */ + mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR); + return i; + +fail: + mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); + pr_debug("mmc: bread failed, card status = %08x\n", card_status); + goto out; +} + +static void mmc_parse_cid(struct mmc_cid *cid, unsigned long *resp) +{ + cid->mid = resp[0] >> 24; + cid->oid = (resp[0] >> 8) & 0xffff; + cid->pnm[0] = resp[0]; + cid->pnm[1] = resp[1] >> 24; + cid->pnm[2] = resp[1] >> 16; + cid->pnm[3] = resp[1] >> 8; + cid->pnm[4] = resp[1]; + cid->pnm[5] = resp[2] >> 24; + cid->pnm[6] = 0; + cid->prv = resp[2] >> 16; + cid->psn = (resp[2] << 16) | (resp[3] >> 16); + cid->mdt = resp[3] >> 8; +} + +static void sd_parse_cid(struct mmc_cid *cid, unsigned long *resp) +{ + cid->mid = resp[0] >> 24; + cid->oid = (resp[0] >> 8) & 0xffff; + cid->pnm[0] = resp[0]; + cid->pnm[1] = resp[1] >> 24; + cid->pnm[2] = resp[1] >> 16; + cid->pnm[3] = resp[1] >> 8; + cid->pnm[4] = resp[1]; + cid->pnm[5] = 0; + cid->pnm[6] = 0; + cid->prv = resp[2] >> 24; + cid->psn = (resp[2] << 8) | (resp[3] >> 24); + cid->mdt = (resp[3] >> 8) & 0x0fff; +} + +static void mmc_dump_cid(const struct mmc_cid *cid) +{ + printf("Manufacturer ID: %02lX\n", cid->mid); + printf("OEM/Application ID: %04lX\n", cid->oid); + printf("Product name: %s\n", cid->pnm); + printf("Product Revision: %lu.%lu\n", + cid->prv >> 4, cid->prv & 0x0f); + printf("Product Serial Number: %lu\n", cid->psn); + printf("Manufacturing Date: %02lu/%02lu\n", + cid->mdt >> 4, cid->mdt & 0x0f); +} + +static void mmc_dump_csd(const struct mmc_csd *csd) +{ + unsigned long *csd_raw = (unsigned long *)csd; + pr_debug("CSD data: %08lx %08lx %08lx %08lx\n", + csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]); + pr_debug("CSD structure version: 1.%u\n", csd->csd_structure); + pr_debug("MMC System Spec version: %u\n", csd->spec_vers); + pr_debug("Card command classes: %03x\n", csd->ccc); + pr_debug("Read block length: %u\n", 1 << csd->read_bl_len); + if (csd->read_bl_partial) + puts("Supports partial reads\n"); + else + puts("Does not support partial reads\n"); + pr_debug("Write block length: %u\n", 1 << csd->write_bl_len); + if (csd->write_bl_partial) + puts("Supports partial writes\n"); + else + puts("Does not support partial writes\n"); + if (csd->wp_grp_enable) + pr_debug("Supports group WP: %u\n", csd->wp_grp_size + 1); + else + puts("Does not support group WP\n"); + pr_debug("Card capacity: %u bytes\n", + (csd->c_size + 1) * (1 << (csd->c_size_mult + 2)) * + (1 << csd->read_bl_len)); + pr_debug("File format: %u/%u\n", + csd->file_format_grp, csd->file_format); + puts("Write protection: "); + if (csd->perm_write_protect) + puts(" permanent"); + if (csd->tmp_write_protect) + puts(" temporary"); + putc('\n'); +} + +static int mmc_idle_cards(void) +{ + int ret; + + /* Reset and initialize all cards */ + ret = mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, NULL, 0); + + if (ret) + return ret; + pr_debug(" ret: %i\n",ret); + /* Keep the bus idle for 74 clock cycles */ + return mmc_cmd(0, 0, NULL, INIT_CMD); +} + +static int sd_init_card(struct mmc_cid *cid, int verbose) +{ + unsigned long resp[4]; + int i, ret = 0; + + mmc_idle_cards(); + for (i = 0; i < 1000; i++) { + ret = mmc_acmd(MMC_ACMD_SD_SEND_OP_COND, CFG_MMC_OP_COND, + resp, R3 | NID); + if (ret || (resp[0] & 0x80000000)) + break; + ret = -ETIMEDOUT; + } + + if (ret) + return ret; + + ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID); + if (ret) + return ret; + sd_parse_cid(cid, resp); + if (verbose) + mmc_dump_cid(cid); + + /* Get RCA of the card that responded */ + ret = mmc_cmd(MMC_CMD_SD_SEND_RELATIVE_ADDR, 0, resp, R6 | NCR); + if (ret) + return ret; + + mmc_rca = resp[0] >> 16; + if (verbose) + pr_debug("SD Card detected (RCA %u)\n", mmc_rca); + mmc_card_is_sd = 1; + return 0; +} + +static int mmc_init_card(struct mmc_cid *cid, int verbose) +{ + unsigned long resp[4]; + int i, ret = 0; + + mmc_idle_cards(); + + for (i = 0; i < 1000; i++) { + ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CFG_MMC_OP_COND, resp, + R3 | NID | OPEN_DRAIN); + if (ret || (resp[0] & 0x80000000)) + { + break; + } + ret = -ETIMEDOUT; + } + pr_debug("4\n"); + pr_debug("ret : %i\n",ret); + if (ret) + return ret; + pr_debug("5\n"); + /* Get CID of all cards. FIXME: Support more than one card */ + ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID | OPEN_DRAIN); + if (ret) + return ret; + mmc_parse_cid(cid, resp); + if (verbose) + mmc_dump_cid(cid); + + /* Set Relative Address of the card that responded */ + ret = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, mmc_rca << 16, resp, + R1 | NCR | OPEN_DRAIN); + return ret; +} + +static void mci_set_data_timeout(struct mmc_csd *csd) +{ + static const unsigned int dtomul_to_shift[] = { + 0, 4, 7, 8, 10, 12, 16, 20, + }; + static const unsigned int taac_exp[] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, + }; + static const unsigned int taac_mant[] = { + 0, 10, 12, 13, 15, 60, 25, 30, + 35, 40, 45, 50, 55, 60, 70, 80, + }; + unsigned int timeout_ns, timeout_clks; + unsigned int e, m; + unsigned int dtocyc, dtomul; + unsigned int shift; + u32 dtor; + + e = csd->taac & 0x07; + m = (csd->taac >> 3) & 0x0f; + + timeout_ns = (taac_exp[e] * taac_mant[m] + 9) / 10; + timeout_clks = csd->nsac * 100; + + timeout_clks += (((timeout_ns + 9) / 10) + * ((CFG_MMC_CLK_PP + 99999) / 100000) + 9999) / 10000; + if (!mmc_card_is_sd) + timeout_clks *= 10; + else + timeout_clks *= 100; + + dtocyc = timeout_clks; + dtomul = 0; + while (dtocyc > 15 && dtomul < 8) { + dtomul++; + shift = dtomul_to_shift[dtomul]; + dtocyc = (timeout_clks + (1 << shift) - 1) >> shift; + } + + if (dtomul >= 8) { + dtomul = 7; + dtocyc = 15; + puts("Warning: Using maximum data timeout\n"); + } + + dtor = (MMCI_BF(DTOMUL, dtomul) + | MMCI_BF(DTOCYC, dtocyc)); + mmci_writel(DTOR, dtor); + + pr_debug("mmc: Using %u cycles data timeout (DTOR=0x%x)\n", + dtocyc << shift, dtor); +} + +int mmc_init(int verbose) +{ + struct mmc_cid cid; + struct mmc_csd csd; + unsigned int max_blksz; + int ret,aux; + + AT91F_MMC_Hardware_Init(); + + pr_debug("0\n"); + /* Initialize controller */ + mmci_writel(CR, MMCI_BIT(SWRST)); + mmci_writel(CR, MMCI_BIT(MCIEN)); + mmci_writel(DTOR, 0x5f); + mmci_writel(IDR, ~0UL); + mmci_writel(SDCR, 0x1); + mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); +/* //mmci_writel(CR, MMCI_BIT(SWRST)); + mmci_writel(CR, 0x00000001); + mmci_writel(DTOR, 0x0000007F); + mmci_writel(IDR, 0xFFFFFFFF); + mmci_writel(SDCR, 0x00000001); + //mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); + mmci_writel(MR, 0x02009B4A); */ + + pr_debug("1\n"); + + mmc_card_is_sd = 0; + + ret = sd_init_card(&cid, verbose); + if (ret) { + mmc_rca = MMC_DEFAULT_RCA; + ret = mmc_init_card(&cid, verbose); + } + pr_debug("6\n"); + if (ret) + return ret; + pr_debug("7\n"); + /* Get CSD from the card */ + ret = mmc_cmd(MMC_CMD_SEND_CSD, mmc_rca << 16, &csd, R2 | NCR); + if (ret) + return ret; + if (verbose) + mmc_dump_csd(&csd); + + mci_set_data_timeout(&csd); + + /* Initialize the blockdev structure */ + mmc_blkdev.if_type = IF_TYPE_MMC; + mmc_blkdev.part_type = PART_TYPE_DOS; + mmc_blkdev.block_read = mmc_bread; + sprintf((char *)mmc_blkdev.vendor, + "Man %02x%04x Snr %08x", + cid.mid, cid.oid, cid.psn); + strncpy((char *)mmc_blkdev.product, cid.pnm, + sizeof(mmc_blkdev.product)); + sprintf((char *)mmc_blkdev.revision, "%x %x", + cid.prv >> 4, cid.prv & 0x0f); + + /* + * If we can't use 512 byte blocks, refuse to deal with the + * card. Tons of code elsewhere seems to depend on this. + */ + max_blksz = 1 << csd.read_bl_len; + // if (max_blksz < 512 || (max_blksz > 512 && !csd.read_bl_partial)) { + // pr_debug("Card does not support 512 byte reads, aborting.\n"); + // return -ENODEV; + // } + mmc_blkdev.blksz = 512; + mmc_blkdev.lba = (csd.c_size + 1) * (1 << (csd.c_size_mult + 2)); + + mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz); + +#if 0 + if (fat_register_device(&mmc_blkdev, 1)) + pr_debug("Could not register MMC fat device\n"); +#else + init_part(&mmc_blkdev); +#endif + + return 0; +} + +int mmc_read(ulong src, uchar *dst, int size) +{ + return -ENOSYS; +} + +int mmc_write(uchar *src, ulong dst, int size) +{ + return -ENOSYS; +} + +int mmc2info(ulong addr) +{ + return 0; +} + +#endif /* CONFIG_MMC */ diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.h u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.h --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/atmel_mci.h 1970-01-01 01:00:00.000000000 +0100 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/atmel_mci.h 2007-08-17 10:43:17.000000000 +0200 @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2005-2006 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef __CPU_AT32AP_ATMEL_MCI_H__ +#define __CPU_AT32AP_ATMEL_MCI_H__ + +/* Atmel MultiMedia Card Interface (MCI) registers */ +#define MMCI_CR 0x0000 +#define MMCI_MR 0x0004 +#define MMCI_DTOR 0x0008 +#define MMCI_SDCR 0x000c +#define MMCI_ARGR 0x0010 +#define MMCI_CMDR 0x0014 +#define MMCI_RSPR 0x0020 +#define MMCI_RSPR1 0x0024 +#define MMCI_RSPR2 0x0028 +#define MMCI_RSPR3 0x002c +#define MMCI_RDR 0x0030 +#define MMCI_TDR 0x0034 +#define MMCI_SR 0x0040 +#define MMCI_IER 0x0044 +#define MMCI_IDR 0x0048 +#define MMCI_IMR 0x004c + +/* Bitfields in CR */ +#define MMCI_MCIEN_OFFSET 0 +#define MMCI_MCIEN_SIZE 1 +#define MMCI_MCIDIS_OFFSET 1 +#define MMCI_MCIDIS_SIZE 1 +#define MMCI_PWSEN_OFFSET 2 +#define MMCI_PWSEN_SIZE 1 +#define MMCI_PWSDIS_OFFSET 3 +#define MMCI_PWSDIS_SIZE 1 +#define MMCI_SWRST_OFFSET 7 +#define MMCI_SWRST_SIZE 1 + +/* Bitfields in MR */ +#define MMCI_CLKDIV_OFFSET 0 +#define MMCI_CLKDIV_SIZE 8 +#define MMCI_PWSDIV_OFFSET 8 +#define MMCI_PWSDIV_SIZE 3 +#define MMCI_RDPROOF_OFFSET 11 +#define MMCI_RDPROOF_SIZE 1 +#define MMCI_WRPROOF_OFFSET 12 +#define MMCI_WRPROOF_SIZE 1 +#define MMCI_PDCPADV_OFFSET 14 +#define MMCI_PDCPADV_SIZE 1 +#define MMCI_PDCMODE_OFFSET 15 +#define MMCI_PDCMODE_SIZE 1 +#define MMCI_BLKLEN_OFFSET 16 +#define MMCI_BLKLEN_SIZE 16 + +/* Bitfields in DTOR */ +#define MMCI_DTOCYC_OFFSET 0 +#define MMCI_DTOCYC_SIZE 4 +#define MMCI_DTOMUL_OFFSET 4 +#define MMCI_DTOMUL_SIZE 3 + +/* Bitfields in SDCR */ +#define MMCI_SCDSEL_OFFSET 0 +#define MMCI_SCDSEL_SIZE 4 +#define MMCI_SCDBUS_OFFSET 7 +#define MMCI_SCDBUS_SIZE 1 + +/* Bitfields in ARGR */ +#define MMCI_ARG_OFFSET 0 +#define MMCI_ARG_SIZE 32 + +/* Bitfields in CMDR */ +#define MMCI_CMDNB_OFFSET 0 +#define MMCI_CMDNB_SIZE 6 +#define MMCI_RSPTYP_OFFSET 6 +#define MMCI_RSPTYP_SIZE 2 +#define MMCI_SPCMD_OFFSET 8 +#define MMCI_SPCMD_SIZE 3 +#define MMCI_OPDCMD_OFFSET 11 +#define MMCI_OPDCMD_SIZE 1 +#define MMCI_MAXLAT_OFFSET 12 +#define MMCI_MAXLAT_SIZE 1 +#define MMCI_TRCMD_OFFSET 16 +#define MMCI_TRCMD_SIZE 2 +#define MMCI_TRDIR_OFFSET 18 +#define MMCI_TRDIR_SIZE 1 +#define MMCI_TRTYP_OFFSET 19 +#define MMCI_TRTYP_SIZE 2 + +/* Bitfields in RSPRx */ +#define MMCI_RSP_OFFSET 0 +#define MMCI_RSP_SIZE 32 + +/* Bitfields in SR/IER/IDR/IMR */ +#define MMCI_CMDRDY_OFFSET 0 +#define MMCI_CMDRDY_SIZE 1 +#define MMCI_RXRDY_OFFSET 1 +#define MMCI_RXRDY_SIZE 1 +#define MMCI_TXRDY_OFFSET 2 +#define MMCI_TXRDY_SIZE 1 +#define MMCI_BLKE_OFFSET 3 +#define MMCI_BLKE_SIZE 1 +#define MMCI_DTIP_OFFSET 4 +#define MMCI_DTIP_SIZE 1 +#define MMCI_NOTBUSY_OFFSET 5 +#define MMCI_NOTBUSY_SIZE 1 +#define MMCI_ENDRX_OFFSET 6 +#define MMCI_ENDRX_SIZE 1 +#define MMCI_ENDTX_OFFSET 7 +#define MMCI_ENDTX_SIZE 1 +#define MMCI_RXBUFF_OFFSET 14 +#define MMCI_RXBUFF_SIZE 1 +#define MMCI_TXBUFE_OFFSET 15 +#define MMCI_TXBUFE_SIZE 1 +#define MMCI_RINDE_OFFSET 16 +#define MMCI_RINDE_SIZE 1 +#define MMCI_RDIRE_OFFSET 17 +#define MMCI_RDIRE_SIZE 1 +#define MMCI_RCRCE_OFFSET 18 +#define MMCI_RCRCE_SIZE 1 +#define MMCI_RENDE_OFFSET 19 +#define MMCI_RENDE_SIZE 1 +#define MMCI_RTOE_OFFSET 20 +#define MMCI_RTOE_SIZE 1 +#define MMCI_DCRCE_OFFSET 21 +#define MMCI_DCRCE_SIZE 1 +#define MMCI_DTOE_OFFSET 22 +#define MMCI_DTOE_SIZE 1 +#define MMCI_OVRE_OFFSET 30 +#define MMCI_OVRE_SIZE 1 +#define MMCI_UNRE_OFFSET 31 +#define MMCI_UNRE_SIZE 1 + +/* Constants for DTOMUL */ +#define MMCI_DTOMUL_1_CYCLE 0 +#define MMCI_DTOMUL_16_CYCLES 1 +#define MMCI_DTOMUL_128_CYCLES 2 +#define MMCI_DTOMUL_256_CYCLES 3 +#define MMCI_DTOMUL_1024_CYCLES 4 +#define MMCI_DTOMUL_4096_CYCLES 5 +#define MMCI_DTOMUL_65536_CYCLES 6 +#define MMCI_DTOMUL_1048576_CYCLES 7 + +/* Constants for RSPTYP */ +#define MMCI_RSPTYP_NO_RESP 0 +#define MMCI_RSPTYP_48_BIT_RESP 1 +#define MMCI_RSPTYP_136_BIT_RESP 2 + +/* Constants for SPCMD */ +#define MMCI_SPCMD_NO_SPEC_CMD 0 +#define MMCI_SPCMD_INIT_CMD 1 +#define MMCI_SPCMD_SYNC_CMD 2 +#define MMCI_SPCMD_INT_CMD 4 +#define MMCI_SPCMD_INT_RESP 5 + +/* Constants for TRCMD */ +#define MMCI_TRCMD_NO_TRANS 0 +#define MMCI_TRCMD_START_TRANS 1 +#define MMCI_TRCMD_STOP_TRANS 2 + +/* Constants for TRTYP */ +#define MMCI_TRTYP_BLOCK 0 +#define MMCI_TRTYP_MULTI_BLOCK 1 +#define MMCI_TRTYP_STREAM 2 + +/* Bit manipulation macros */ +#define MMCI_BIT(name) \ + (1 << MMCI_##name##_OFFSET) +#define MMCI_BF(name,value) \ + (((value) & ((1 << MMCI_##name##_SIZE) - 1)) \ + << MMCI_##name##_OFFSET) +#define MMCI_BFEXT(name,value) \ + (((value) >> MMCI_##name##_OFFSET)\ + & ((1 << MMCI_##name##_SIZE) - 1)) +#define MMCI_BFINS(name,value,old) \ + (((old) & ~(((1 << MMCI_##name##_SIZE) - 1) \ + << MMCI_##name##_OFFSET)) \ + | MMCI_BF(name,value)) + +/* Register access macros */ +#define mmci_readl(reg) \ + readl((void *)MMCI_BASE + MMCI_##reg) +#define mmci_writel(reg,value) \ + writel((value), (void *)MMCI_BASE + MMCI_##reg) + +#endif /* __CPU_AT32AP_ATMEL_MCI_H__ */ diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/config.mk u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/config.mk --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/config.mk 2007-08-21 17:06:35.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/config.mk 2007-08-16 13:34:14.000000000 +0200 @@ -19,10 +19,10 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, # MA 02111-1307 USA -# +#PLATFORM_RELFLAGS += $(call cc-option,-msoft-float,)
PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 -PLATFORM_RELFLAGS += $(call cc-option,-msoft-float,) +PLATFORM_RELFLAGS += $(call cc-option,)
PLATFORM_CPPFLAGS += -march=armv5te PLATFORM_CPPFLAGS += $(call cc-option,-mtune=arm926ejs,) diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/Makefile u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/Makefile --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/Makefile 2007-08-21 17:06:36.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/Makefile 2007-08-23 09:14:21.000000000 +0200 @@ -26,8 +26,8 @@ LIB = lib$(SOC).a
-OBJS = serial.o interrupts.o usb_ohci.o lcd.o ether.o spi.o -SOBJS = +OBJS = serial.o interrupts.o usb_ohci.o ether.o spi.o +SOBJS = atmel_mci.o
all: .depend $(LIB)
diff -burN u-boot-1.1.5/cpu/arm926ejs/at91sam926x/spi.c u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/spi.c --- u-boot-1.1.5/cpu/arm926ejs/at91sam926x/spi.c 2007-08-21 17:06:35.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/at91sam926x/spi.c 2007-08-23 10:36:47.000000000 +0200 @@ -184,6 +184,20 @@ { unsigned int timeout;
+#ifdef CONFIG_AT91SAM9260EK + /* Configure PIO controllers to periph mode */ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, // PIO controller base address + ((unsigned int) AT91C_PA1_SPI0_MOSI) | + ((unsigned int) AT91C_PA3_SPI0_NPCS0) | + ((unsigned int) AT91C_PA0_SPI0_MISO) | + ((unsigned int) AT91C_PA2_SPI0_SPCK), /* Peripheral A */ + 0); /* Peripheral B */ + /* Configure PIO controllers to periph mode */ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOC, /* PIO controller base address */ + 0, /* Peripheral A */ + ((unsigned int) AT91C_PC11_SPI0_NPCS1)); /* Peripheral B */ +#endif + pDesc->state = BUSY;
/* Disable PDC TX and RX channels */ diff -burN u-boot-1.1.5/cpu/arm926ejs/config.mk u-boot-1.1.5.klk/cpu/arm926ejs/config.mk --- u-boot-1.1.5/cpu/arm926ejs/config.mk 2006-10-20 17:54:33.000000000 +0200 +++ u-boot-1.1.5.klk/cpu/arm926ejs/config.mk 2007-08-16 13:34:42.000000000 +0200 @@ -20,10 +20,10 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, # MA 02111-1307 USA # - -PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ - -msoft-float - +# +#PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ +# -msoft-float +PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 PLATFORM_CPPFLAGS += -march=armv4 # ======================================================================== = # diff -burN u-boot-1.1.5/disk/part.c u-boot-1.1.5.klk/disk/part.c --- u-boot-1.1.5/disk/part.c 2006-10-20 17:54:33.000000000 +0200 +++ u-boot-1.1.5.klk/disk/part.c 2007-08-23 08:29:56.000000000 +0200 @@ -36,6 +36,7 @@ #if ((CONFIG_COMMANDS & CFG_CMD_IDE) || \ (CONFIG_COMMANDS & CFG_CMD_SCSI) || \ (CONFIG_COMMANDS & CFG_CMD_USB) || \ + (CONFIG_COMMANDS & CFG_CMD_MMC) || \ defined(CONFIG_MMC) || \ defined(CONFIG_SYSTEMACE) )
@@ -126,6 +127,8 @@ #if ((CONFIG_COMMANDS & CFG_CMD_IDE) || \ (CONFIG_COMMANDS & CFG_CMD_SCSI) || \ (CONFIG_COMMANDS & CFG_CMD_USB) || \ + (CONFIG_COMMANDS & CFG_CMD_MMC) || \ + defined(CONFIG_MMC) || \ defined(CONFIG_SYSTEMACE) )
#if defined(CONFIG_MAC_PARTITION) || \ diff -burN u-boot-1.1.5/include/asm-arm/arch-at91sam926x/mmc.h u-boot-1.1.5.klk/include/asm-arm/arch-at91sam926x/mmc.h --- u-boot-1.1.5/include/asm-arm/arch-at91sam926x/mmc.h 1970-01-01 01:00:00.000000000 +0100 +++ u-boot-1.1.5.klk/include/asm-arm/arch-at91sam926x/mmc.h 2007-08-17 10:44:42.000000000 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2004-2006 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef __ASM_AVR32_MMC_H +#define __ASM_AVR32_MMC_H + +struct mmc_cid { + unsigned long psn; + unsigned short oid; + unsigned char mid; + unsigned char prv; + unsigned char mdt; + char pnm[7]; +}; + +struct mmc_csd +{ + u8 csd_structure:2, + spec_vers:4, + rsvd1:2; + u8 taac; + u8 nsac; + u8 tran_speed; + u16 ccc:12, + read_bl_len:4; + u64 read_bl_partial:1, + write_blk_misalign:1, + read_blk_misalign:1, + dsr_imp:1, + rsvd2:2, + c_size:12, + vdd_r_curr_min:3, + vdd_r_curr_max:3, + vdd_w_curr_min:3, + vdd_w_curr_max:3, + c_size_mult:3, + sector_size:5, + erase_grp_size:5, + wp_grp_size:5, + wp_grp_enable:1, + default_ecc:2, + r2w_factor:3, + write_bl_len:4, + write_bl_partial:1, + rsvd3:5; + u8 file_format_grp:1, + copy:1, + perm_write_protect:1, + tmp_write_protect:1, + file_format:2, + ecc:2; + u8 crc:7; + u8 one:1; +}; + +/* MMC Command numbers */ +#define MMC_CMD_GO_IDLE_STATE 0 +#define MMC_CMD_SEND_OP_COND 1 +#define MMC_CMD_ALL_SEND_CID 2 +#define MMC_CMD_SET_RELATIVE_ADDR 3 +#define MMC_CMD_SD_SEND_RELATIVE_ADDR 3 +#define MMC_CMD_SET_DSR 4 +#define MMC_CMD_SELECT_CARD 7 +#define MMC_CMD_SEND_CSD 9 +#define MMC_CMD_SEND_CID 10 +#define MMC_CMD_SEND_STATUS 13 +#define MMC_CMD_SET_BLOCKLEN 16 +#define MMC_CMD_READ_SINGLE_BLOCK 17 +#define MMC_CMD_READ_MULTIPLE_BLOCK 18 +#define MMC_CMD_WRITE_BLOCK 24 +#define MMC_CMD_APP_CMD 55 + +#define MMC_ACMD_SD_SEND_OP_COND 41 + +#define R1_ILLEGAL_COMMAND (1 << 22) +#define R1_APP_CMD (1 << 5) + +#endif /* __ASM_AVR32_MMC_H */ diff -burN u-boot-1.1.5/include/configs/at91sam9260ek.h u-boot-1.1.5.klk/include/configs/at91sam9260ek.h --- u-boot-1.1.5/include/configs/at91sam9260ek.h 2007-08-21 17:06:36.000000000 +0200 +++ u-boot-1.1.5.klk/include/configs/at91sam9260ek.h 2007-08-23 10:51:43.000000000 +0200 @@ -88,6 +88,8 @@ CFG_CMD_FLASH | \ CFG_CMD_AUTOSCRIPT | \ CFG_CMD_NAND | \ + CFG_CMD_MMC | \ + CFG_CMD_EXT2 | \ CFG_CMD_FAT ) & \ ~(CFG_CMD_BDI | \ CFG_CMD_IMLS | \ @@ -225,6 +227,7 @@ #undef CFG_ENV_IS_IN_FLASH #define CFG_ENV_IS_IN_DATAFLASH 1 #undef CFG_ENV_IS_IN_NAND +#undef CFG_ENV_IS_NOWHERE
/*#define CONFIG_MTD_DEBUG 1 #define CONFIG_MTD_DEBUG_VERBOSE MTD_DEBUG_LEVEL3 @@ -241,6 +244,10 @@ #define CFG_ENV_SIZE 0x4000 /* 0x8000 */ #endif
+#ifdef CFG_ENV_IS_NOWHERE +#define CFG_ENV_SIZE 0x4000 +#endif + #ifdef CFG_ENV_IS_IN_FLASH #ifdef CONFIG_BOOTBINFUNC #define CFG_ENV_ADDR (PHYS_FLASH_1 + 0x60000) /* after u-boot.bin */ @@ -257,6 +264,10 @@ #define CONFIG_DOS_PARTITION 1 #define LITTLEENDIAN 1
+/* MMC */ +#define CONFIG_MMC 1 +#define MMCI_BASE 0xFFFA8000 + #define CFG_LOAD_ADDR 0x23f00000 /* default load address */
#ifdef CONFIG_BOOTBINFUNC
------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javao ne _______________________________________________ U-Boot-Users mailing list U-Boot-Users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/u-boot-users
participants (4)
-
Andy Fleming
-
Anton Vorontsov
-
Ken.Fuchs@bench.com
-
Pierre Savary