Commit 586667b4 authored by Alexander Dyachenko's avatar Alexander Dyachenko Committed by Sergei Poselenov

RM 1947: Copy the newer mmc and fsl_esdhc drivers from the Vybrid U-Boot repository

(cherry picked from commit 85502fd1becd71b365b71f4a8fd308ae4953025e)
parent bdf130d6
/*
* Copyright 2007, Freescale Semiconductor, Inc
* Copyright 2007, 2010-2012 Freescale Semiconductor, Inc
* Andy Fleming
*
* Based vaguely on the pxa mmc code:
......@@ -58,7 +58,8 @@ struct fsl_esdhc {
uint autoc12err;
uint hostcapblt;
uint wml;
char reserved1[8];
uint mixctrl;
char reserved1[4];
uint fevt;
char reserved2[168];
uint hostver;
......@@ -72,11 +73,16 @@ uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)
uint xfertyp = 0;
if (data) {
xfertyp |= XFERTYP_DPSEL | XFERTYP_DMAEN;
xfertyp |= XFERTYP_DPSEL;
#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
xfertyp |= XFERTYP_DMAEN;
#endif
if (data->blocks > 1) {
xfertyp |= XFERTYP_MSBSEL;
xfertyp |= XFERTYP_BCEN;
#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111
xfertyp |= XFERTYP_AC12EN;
#endif
}
if (data->flags & MMC_DATA_READ)
......@@ -94,42 +100,139 @@ uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)
else if (cmd->resp_type & MMC_RSP_PRESENT)
xfertyp |= XFERTYP_RSPTYP_48;
#ifdef CONFIG_MX53
if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
xfertyp |= XFERTYP_CMDTYP_ABORT;
#endif
return XFERTYP_CMD(cmd->cmdidx) | xfertyp;
}
#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
/*
* PIO Read/Write Mode reduce the performace as DMA is not used in this mode.
*/
static void
esdhc_pio_read_write(struct mmc *mmc, struct mmc_data *data)
{
struct fsl_esdhc_cfg *cfg = mmc->priv;
struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
uint blocks;
char *buffer;
uint databuf;
uint size;
uint irqstat;
uint timeout;
if (data->flags & MMC_DATA_READ) {
blocks = data->blocks;
buffer = data->dest;
while (blocks) {
timeout = PIO_TIMEOUT;
size = data->blocksize;
irqstat = esdhc_read32(&regs->irqstat);
while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BREN)
&& --timeout);
if (timeout <= 0) {
printf("\nData Read Failed in PIO Mode.");
return;
}
while (size && (!(irqstat & IRQSTAT_TC))) {
#ifndef CONFIG_VYBRID
udelay(100); /* Wait before last byte transfer complete */
#endif
irqstat = esdhc_read32(&regs->irqstat);
databuf = in_le32(&regs->datport);
*((uint *)buffer) = databuf;
buffer += 4;
size -= 4;
}
blocks--;
}
} else {
blocks = data->blocks;
buffer = (char *)data->src;
while (blocks) {
timeout = PIO_TIMEOUT;
size = data->blocksize;
irqstat = esdhc_read32(&regs->irqstat);
while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BWEN)
&& --timeout);
if (timeout <= 0) {
printf("\nData Write Failed in PIO Mode.");
return;
}
while (size && (!(irqstat & IRQSTAT_TC))) {
udelay(100); /* Wait before last byte transfer complete */
databuf = *((uint *)buffer);
buffer += 4;
size -= 4;
irqstat = esdhc_read32(&regs->irqstat);
out_le32(&regs->datport, databuf);
}
blocks--;
}
}
}
#endif
static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
{
uint wml_value;
int timeout;
struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
uint wml_value;
wml_value = data->blocksize/4;
if (data->flags & MMC_DATA_READ) {
if (wml_value > 0x10)
wml_value = 0x10;
wml_value = 0x100000 | wml_value;
if (wml_value > WML_RD_WML_MAX)
wml_value = WML_RD_WML_MAX_VAL;
esdhc_clrsetbits32(&regs->wml, WML_RD_WML_MASK, wml_value);
esdhc_write32(&regs->dsaddr, (u32)data->dest);
} else {
if (wml_value > 0x80)
wml_value = 0x80;
if (wml_value > WML_WR_WML_MAX)
wml_value = WML_WR_WML_MAX_VAL;
if ((esdhc_read32(&regs->prsstat) & PRSSTAT_WPSPL) == 0) {
printf("\nThe SD card is locked. Can not write to a locked card.\n\n");
return TIMEOUT;
}
wml_value = wml_value << 16 | 0x10;
esdhc_clrsetbits32(&regs->wml, WML_WR_WML_MASK,
wml_value << 16);
esdhc_write32(&regs->dsaddr, (u32)data->src);
}
esdhc_write32(&regs->wml, wml_value);
#else /* CONFIG_SYS_FSL_ESDHC_USE_PIO */
if (!(data->flags & MMC_DATA_READ)) {
if ((esdhc_read32(&regs->prsstat) & PRSSTAT_WPSPL) == 0) {
printf("\nThe SD card is locked. "
"Can not write to a locked card.\n\n");
return TIMEOUT;
}
esdhc_write32(&regs->dsaddr, (u32)data->src);
} else
esdhc_write32(&regs->dsaddr, (u32)data->dest);
#endif /* CONFIG_SYS_FSL_ESDHC_USE_PIO */
esdhc_write32(&regs->blkattr, data->blocks << 16 | data->blocksize);
/* Calculate the timeout period for data transactions */
timeout = fls(mmc->tran_speed/10) - 1;
/*
* 1)Timeout period = (2^(timeout+13)) SD Clock cycles
* 2)Timeout period should be minimum 0.250sec as per SD Card spec
* So, Number of SD Clock cycles for 0.25sec should be minimum
* (SD Clock/sec * 0.25 sec) SD Clock cycles
* = (mmc->tran_speed * 1/4) SD Clock cycles
* As 1) >= 2)
* => (2^(timeout+13)) >= mmc->tran_speed * 1/4
* Taking log2 both the sides
* => timeout + 13 >= log2(mmc->tran_speed/4)
* Rounding up to next power of 2
* => timeout + 13 = log2(mmc->tran_speed/4) + 1
* => timeout + 13 = fls(mmc->tran_speed/4)
*/
timeout = fls(mmc->tran_speed/4);
timeout -= 13;
if (timeout > 14)
......@@ -138,6 +241,11 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
if (timeout < 0)
timeout = 0;
#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC_A001
if ((timeout == 4) || (timeout == 8) || (timeout == 12))
timeout++;
#endif
esdhc_clrsetbits32(&regs->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16);
return 0;
......@@ -156,6 +264,11 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111
if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
return 0;
#endif
esdhc_write32(&regs->irqstat, -1);
sync();
......@@ -189,8 +302,13 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
/* Send the command */
esdhc_write32(&regs->cmdarg, cmd->cmdarg);
#if defined(CONFIG_FSL_USDHC)
esdhc_write32(&regs->mixctrl,
(esdhc_read32(&regs->mixctrl) & 0xFFFFFF80) | (xfertyp & 0x7F));
esdhc_write32(&regs->xfertyp, xfertyp & 0xFFFF0000);
#else
esdhc_write32(&regs->xfertyp, xfertyp);
#endif
/* Wait for the command to complete */
while (!(esdhc_read32(&regs->irqstat) & IRQSTAT_CC))
;
......@@ -221,16 +339,20 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
/* Wait until all of the blocks are transferred */
if (data) {
#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
esdhc_pio_read_write(mmc, data);
#else
do {
irqstat = esdhc_read32(&regs->irqstat);
if (irqstat & DATA_ERR)
return COMM_ERR;
if (irqstat & IRQSTAT_DTOE)
return TIMEOUT;
if (irqstat & DATA_ERR)
return COMM_ERR;
} while (!(irqstat & IRQSTAT_TC) &&
(esdhc_read32(&regs->prsstat) & PRSSTAT_DLA));
#endif
}
esdhc_write32(&regs->irqstat, -1);
......@@ -265,18 +387,13 @@ void set_sysctl(struct mmc *mmc, uint clock)
clk = (pre_div << 8) | (div << 4);
/* On imx the clock must be stopped before changing frequency */
if (cfg->clk_enable)
esdhc_clrbits32(&regs->sysctl, SYSCTL_CKEN);
esdhc_clrbits32(&regs->sysctl, SYSCTL_CKEN);
esdhc_clrsetbits32(&regs->sysctl, SYSCTL_CLOCK_MASK, clk);
udelay(10000);
clk = SYSCTL_PEREN;
/* On imx systems the clock must be explicitely enabled */
if (cfg->clk_enable)
clk |= SYSCTL_CKEN;
clk = SYSCTL_PEREN | SYSCTL_CKEN;
esdhc_setbits32(&regs->sysctl, clk);
}
......@@ -304,12 +421,6 @@ static int esdhc_init(struct mmc *mmc)
struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
int timeout = 1000;
int ret = 0;
u8 card_absent;
/* Enable cache snooping */
if (cfg && !cfg->no_snoop)
esdhc_write32(&regs->scr, 0x00000040);
/* Reset the entire host controller */
esdhc_write32(&regs->sysctl, SYSCTL_RSTA);
......@@ -318,10 +429,17 @@ static int esdhc_init(struct mmc *mmc)
while ((esdhc_read32(&regs->sysctl) & SYSCTL_RSTA) && --timeout)
udelay(1000);
/* Enable cache snooping */
if (cfg && !cfg->no_snoop) {
asm volatile("" ::: "memory");
esdhc_write32(&regs->scr, 0x00000040);
}
esdhc_write32(&regs->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN);
/* Set the initial clock speed */
set_sysctl(mmc, 400000);
mmc_set_clock(mmc, 400000);
/* Disable the BRR and BWR bits in IRQSTAT */
esdhc_clrbits32(&regs->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR);
......@@ -332,50 +450,81 @@ static int esdhc_init(struct mmc *mmc)
/* Set timout to the maximum value */
esdhc_clrsetbits32(&regs->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16);
/* Check if there is a callback for detecting the card */
if (board_mmc_getcd(&card_absent, mmc)) {
timeout = 1000;
while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_CINS) &&
--timeout)
udelay(1000);
return 0;
}
if (timeout <= 0)
ret = NO_CARD_ERR;
} else {
if (card_absent)
ret = NO_CARD_ERR;
}
static int esdhc_getcd(struct mmc *mmc)
{
struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
int timeout = 1000;
while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_CINS) && --timeout)
udelay(1000);
return timeout > 0;
}
return ret;
static void esdhc_reset(struct fsl_esdhc *regs)
{
unsigned long timeout = 100; /* wait max 100 ms */
/* reset the controller */
esdhc_write32(&regs->sysctl, SYSCTL_RSTA);
/* hardware clears the bit when it is done */
while ((esdhc_read32(&regs->sysctl) & SYSCTL_RSTA) && --timeout)
udelay(1000);
if (!timeout)
printf("MMC/SD: Reset never completed.\n");
}
int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
{
struct fsl_esdhc *regs;
struct mmc *mmc;
u32 caps;
u32 caps, voltage_caps;
if (!cfg)
return -1;
mmc = malloc(sizeof(struct mmc));
sprintf(mmc->name, "FSL_ESDHC");
sprintf(mmc->name, "FSL_SDHC");
regs = (struct fsl_esdhc *)cfg->esdhc_base;
/* First reset the eSDHC controller */
esdhc_reset(regs);
mmc->priv = cfg;
mmc->send_cmd = esdhc_send_cmd;
mmc->set_ios = esdhc_set_ios;
mmc->init = esdhc_init;
mmc->getcd = esdhc_getcd;
voltage_caps = 0;
caps = regs->hostcapblt;
#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC135
caps = caps & ~(ESDHC_HOSTCAPBLT_SRS |
ESDHC_HOSTCAPBLT_VS18 | ESDHC_HOSTCAPBLT_VS30);
#endif
if (caps & ESDHC_HOSTCAPBLT_VS18)
mmc->voltages |= MMC_VDD_165_195;
voltage_caps |= MMC_VDD_165_195;
if (caps & ESDHC_HOSTCAPBLT_VS30)
mmc->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
voltage_caps |= MMC_VDD_29_30 | MMC_VDD_30_31;
if (caps & ESDHC_HOSTCAPBLT_VS33)
mmc->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
voltage_caps |= MMC_VDD_32_33 | MMC_VDD_33_34;
#ifdef CONFIG_SYS_SD_VOLTAGE
mmc->voltages = CONFIG_SYS_SD_VOLTAGE;
#else
mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
#endif
if ((mmc->voltages & voltage_caps) == 0) {
printf("voltage not supported by controller\n");
return -1;
}
mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
......@@ -383,8 +532,9 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
mmc->f_min = 400000;
mmc->f_max = MIN(gd->sdhc_clk, 50000000);
mmc->f_max = MIN(gd->sdhc_clk, 52000000);
mmc->b_max = 0;
mmc_register(mmc);
return 0;
......@@ -397,6 +547,9 @@ int fsl_esdhc_mmc_init(bd_t *bis)
cfg = malloc(sizeof(struct fsl_esdhc_cfg));
memset(cfg, 0, sizeof(struct fsl_esdhc_cfg));
cfg->esdhc_base = CONFIG_SYS_FSL_ESDHC_ADDR;
#ifdef CONFIG_ESDHC_NO_SNOOP
cfg->no_snoop = 1;
#endif
return fsl_esdhc_initialize(bis, cfg);
}
......@@ -404,17 +557,19 @@ int fsl_esdhc_mmc_init(bd_t *bis)
void fdt_fixup_esdhc(void *blob, bd_t *bd)
{
const char *compat = "fsl,esdhc";
const char *status = "okay";
#ifdef CONFIG_FSL_ESDHC_PIN_MUX
if (!hwconfig("esdhc")) {
status = "disabled";
goto out;
do_fixup_by_compat(blob, compat, "status", "disabled",
8 + 1, 1);
return;
}
#endif
do_fixup_by_compat_u32(blob, compat, "clock-frequency",
gd->sdhc_clk, 1);
out:
do_fixup_by_compat(blob, compat, "status", status,
strlen(status) + 1, 1);
do_fixup_by_compat(blob, compat, "status", "okay",
4 + 1, 1);
}
#endif
This diff is collapsed.
......@@ -54,4 +54,15 @@ static inline void invalidate_l2_cache(void)
void l2_cache_enable(void);
void l2_cache_disable(void);
/*
* The current upper bound for ARM L1 data cache line sizes is 64 bytes. We
* use that value for aligning DMA buffers unless the board config has specified
* an alternate cache line size.
*/
#ifdef CONFIG_SYS_CACHELINE_SIZE
#define ARCH_DMA_MINALIGN CONFIG_SYS_CACHELINE_SIZE
#else
#define ARCH_DMA_MINALIGN 64
#endif
#endif /* _ASM_CACHE_H */
......@@ -790,4 +790,70 @@ int cpu_release(int nr, int argc, char *argv[]);
#define ALIGN(x,a) __ALIGN_MASK((x),(typeof(x))(a)-1)
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
/*
* ARCH_DMA_MINALIGN is defined in asm/cache.h for each architecture. It
* is used to align DMA buffers.
*/
#ifndef __ASSEMBLY__
#include <asm/cache.h>
#endif
/*
* The ALLOC_CACHE_ALIGN_BUFFER macro is used to allocate a buffer on the
* stack that meets the minimum architecture alignment requirements for DMA.
* Such a buffer is useful for DMA operations where flushing and invalidating
* the cache before and after a read and/or write operation is required for
* correct operations.
*
* When called the macro creates an array on the stack that is sized such
* that:
*
* 1) The beginning of the array can be advanced enough to be aligned.
*
* 2) The size of the aligned portion of the array is a multiple of the minimum
* architecture alignment required for DMA.
*
* 3) The aligned portion contains enough space for the original number of
* elements requested.
*
* The macro then creates a pointer to the aligned portion of this array and
* assigns to the pointer the address of the first element in the aligned
* portion of the array.
*
* Calling the macro as:
*
* ALLOC_CACHE_ALIGN_BUFFER(uint32_t, buffer, 1024);
*
* Will result in something similar to saying:
*
* uint32_t buffer[1024];
*
* The following differences exist:
*
* 1) The resulting buffer is guaranteed to be aligned to the value of
* ARCH_DMA_MINALIGN.
*
* 2) The buffer variable created by the macro is a pointer to the specified
* type, and NOT an array of the specified type. This can be very important
* if you want the address of the buffer, which you probably do, to pass it
* to the DMA hardware. The value of &buffer is different in the two cases.
* In the macro case it will be the address of the pointer, not the address
* of the space reserved for the buffer. However, in the second case it
* would be the address of the buffer. So if you are replacing hard coded
* stack buffers with this macro you need to make sure you remove the & from
* the locations where you are taking the address of the buffer.
*
* Note that the size parameter is the number of array elements to allocate,
* not the number of bytes.
*
* This macro can not be used outside of function scope, or for the creation
* of a function scoped static buffer. It can not be used to create a cache
* line aligned global buffer.
*/
#define ALLOC_CACHE_ALIGN_BUFFER(type, name, size) \
char __##name[ROUND(size * sizeof(type), ARCH_DMA_MINALIGN) + \
ARCH_DMA_MINALIGN - 1]; \
\
type *name = (type *) ALIGN((uintptr_t)__##name, ARCH_DMA_MINALIGN)
#endif /* __COMMON_H_ */
......@@ -16,5 +16,6 @@
#define CONFIG_GZIP 1
#define CONFIG_ZLIB 1
#define CONFIG_PARTITIONS 1
#endif
......@@ -2,7 +2,7 @@
* FSL SD/MMC Defines
*-------------------------------------------------------------------
*
* Copyright 2007-2008, Freescale Semiconductor, Inc
* Copyright 2007-2008,2010-2011 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
......@@ -39,6 +39,7 @@
#define SYSCTL_PEREN 0x00000004
#define SYSCTL_HCKEN 0x00000002
#define SYSCTL_IPGEN 0x00000001
#define SYSCTL_RSTA 0x01000000
#define IRQSTAT 0x0002e030
#define IRQSTAT_DMAE (0x10000000)
......@@ -89,6 +90,7 @@
#define PRSSTAT_CDPL (0x00040000)
#define PRSSTAT_CINS (0x00010000)
#define PRSSTAT_BREN (0x00000800)
#define PRSSTAT_BWEN (0x00000400)
#define PRSSTAT_DLA (0x00000004)
#define PRSSTAT_CICHB (0x00000002)
#define PRSSTAT_CIDHB (0x00000001)
......@@ -120,6 +122,7 @@
#define XFERTYP_DMAEN 0x00000001
#define CINS_TIMEOUT 1000
#define PIO_TIMEOUT 100000
#define DSADDR 0x2e004
......@@ -132,6 +135,21 @@
#define WML 0x2e044
#define WML_WRITE 0x00010000
#ifdef CONFIG_FSL_SDHC_V2_3
#define WML_RD_WML_MAX 0x80
#define WML_WR_WML_MAX 0x80
#define WML_RD_WML_MAX_VAL 0x0
#define WML_WR_WML_MAX_VAL 0x0
#define WML_RD_WML_MASK 0x7f
#define WML_WR_WML_MASK 0x7f0000
#else
#define WML_RD_WML_MAX 0x10
#define WML_WR_WML_MAX 0x80
#define WML_RD_WML_MAX_VAL 0x10
#define WML_WR_WML_MAX_VAL 0x80
#define WML_RD_WML_MASK 0xff
#define WML_WR_WML_MASK 0xff0000
#endif
#define BLKATTR 0x2e004
#define BLKATTR_CNT(x) ((x & 0xffff) << 16)
......@@ -148,7 +166,6 @@
struct fsl_esdhc_cfg {
u32 esdhc_base;
u32 no_snoop;
u32 clk_enable;
};
/* Select the correct accessors depending on endianess */
......
/*
* Copyright 2008, Freescale Semiconductor, Inc
* Copyright 2008,2010 Freescale Semiconductor, Inc
* Andy Fleming
*
* Based (loosely) on the Linux code
......@@ -14,7 +14,7 @@
*
* 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
* 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
......@@ -44,6 +44,8 @@
#define MMC_MODE_HS_52MHz 0x010
#define MMC_MODE_4BIT 0x100
#define MMC_MODE_8BIT 0x200
#define MMC_MODE_SPI 0x400
#define MMC_MODE_HC 0x800
#define SD_DATA_4BIT 0x00040000
......@@ -74,13 +76,20 @@
#define MMC_CMD_READ_MULTIPLE_BLOCK 18
#define MMC_CMD_WRITE_SINGLE_BLOCK 24
#define MMC_CMD_WRITE_MULTIPLE_BLOCK 25
#define MMC_CMD_ERASE_GROUP_START 35
#define MMC_CMD_ERASE_GROUP_END 36
#define MMC_CMD_ERASE 38
#define MMC_CMD_APP_CMD 55
#define MMC_CMD_SPI_READ_OCR 58