Merge branch 'master' of git://git.denx.de/u-boot-mmc

This commit is contained in:
Tom Rini 2014-01-09 11:05:32 -05:00
commit 8401bfa91e
13 changed files with 289 additions and 26 deletions

View File

@ -0,0 +1,12 @@
/*
* (C) Copyright 2013 Altera Corporation <www.altera.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _SOCFPGA_DWMMC_H_
#define _SOCFPGA_DWMMC_H_
extern int socfpga_dwmmc_init(u32 regbase, int bus_width, int index);
#endif /* _SOCFPGA_SDMMC_H_ */

View File

@ -19,4 +19,69 @@ extern unsigned long sys_mgr_init_table[CONFIG_HPS_PINMUX_NUM];
#define CONFIG_SYSMGR_PINMUXGRP_OFFSET (0x400)
#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel) \
((((drvsel) << 0) & 0x7) | (((smplsel) << 3) & 0x38))
struct socfpga_system_manager {
u32 siliconid1;
u32 siliconid2;
u32 _pad_0x8_0xf[2];
u32 wddbg;
u32 bootinfo;
u32 hpsinfo;
u32 parityinj;
u32 fpgaintfgrp_gbl;
u32 fpgaintfgrp_indiv;
u32 fpgaintfgrp_module;
u32 _pad_0x2c_0x2f;
u32 scanmgrgrp_ctrl;
u32 _pad_0x34_0x3f[3];
u32 frzctrl_vioctrl;
u32 _pad_0x44_0x4f[3];
u32 frzctrl_hioctrl;
u32 frzctrl_src;
u32 frzctrl_hwctrl;
u32 _pad_0x5c_0x5f;
u32 emacgrp_ctrl;
u32 emacgrp_l3master;
u32 _pad_0x68_0x6f[2];
u32 dmagrp_ctrl;
u32 dmagrp_persecurity;
u32 _pad_0x78_0x7f[2];
u32 iswgrp_handoff[8];
u32 _pad_0xa0_0xbf[8];
u32 romcodegrp_ctrl;
u32 romcodegrp_cpu1startaddr;
u32 romcodegrp_initswstate;
u32 romcodegrp_initswlastld;
u32 romcodegrp_bootromswstate;
u32 __pad_0xd4_0xdf[3];
u32 romcodegrp_warmramgrp_enable;
u32 romcodegrp_warmramgrp_datastart;
u32 romcodegrp_warmramgrp_length;
u32 romcodegrp_warmramgrp_execution;
u32 romcodegrp_warmramgrp_crc;
u32 __pad_0xf4_0xff[3];
u32 romhwgrp_ctrl;
u32 _pad_0x104_0x107;
u32 sdmmcgrp_ctrl;
u32 sdmmcgrp_l3master;
u32 nandgrp_bootstrap;
u32 nandgrp_l3master;
u32 usbgrp_l3master;
u32 _pad_0x11c_0x13f[9];
u32 eccgrp_l2;
u32 eccgrp_ocram;
u32 eccgrp_usb0;
u32 eccgrp_usb1;
u32 eccgrp_emac0;
u32 eccgrp_emac1;
u32 eccgrp_dma;
u32 eccgrp_can0;
u32 eccgrp_can1;
u32 eccgrp_nand;
u32 eccgrp_qspi;
u32 eccgrp_sdmmc;
};
#endif /* _SYSTEM_MANAGER_H_ */

View File

@ -340,6 +340,28 @@ static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
}
#endif /* CONFIG_SUPPORT_EMMC_BOOT */
}
else if (argc == 3 && strcmp(argv[1], "setdsr") == 0) {
struct mmc *mmc = find_mmc_device(curr_device);
u32 val = simple_strtoul(argv[2], NULL, 16);
int ret;
if (!mmc) {
printf("no mmc device at slot %x\n", curr_device);
return 1;
}
ret = mmc_set_dsr(mmc, val);
printf("set dsr %s\n", (!ret) ? "OK, force rescan" : "ERROR");
if (!ret) {
mmc->has_init = 0;
if (mmc_init(mmc))
return 1;
else
return 0;
}
return ret;
}
state = MMC_INVALID;
if (argc == 5 && strcmp(argv[1], "read") == 0)
state = MMC_READ;
@ -423,5 +445,6 @@ U_BOOT_CMD(
"mmc bootpart <device num> <boot part size MB> <RPMB part size MB>\n"
" - change sizes of boot and RPMB partitions of specified device\n"
#endif
"mmc setdsr - set DSR register value\n"
);
#endif /* !CONFIG_GENERIC_MMC */

53
doc/README.socfpga Normal file
View File

@ -0,0 +1,53 @@
--------------------------------------------
SOCFPGA Documentation for U-Boot and SPL
--------------------------------------------
This README is about U-Boot and SPL support for Altera's ARM Cortex-A9MPCore
based SOCFPGA. To know more about the hardware itself, please refer to
www.altera.com.
--------------------------------------------
socfpga_dw_mmc
--------------------------------------------
Here are macro and detailed configuration required to enable DesignWare SDMMC
controller support within SOCFPGA
#define CONFIG_MMC
-> To enable the SD MMC framework support
#define CONFIG_SDMMC_BASE (SOCFPGA_SDMMC_ADDRESS)
-> The base address of CSR register for DesignWare SDMMC controller
#define CONFIG_GENERIC_MMC
-> Enable the generic MMC driver
#define CONFIG_SYS_MMC_MAX_BLK_COUNT 256
-> Using smaller max blk cnt to avoid flooding the limited stack in OCRAM
#define CONFIG_DWMMC
-> Enable the common DesignWare SDMMC controller framework
#define CONFIG_SOCFPGA_DWMMC
-> Enable the SOCFPGA specific driver for DesignWare SDMMC controller
#define CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH 1024
-> The FIFO depth for SOCFPGA DesignWare SDMMC controller
#define CONFIG_SOCFPGA_DWMMC_DRVSEL 3
-> Phase-shifted clock of sdmmc_clk for controller to drive command and data to
the card to meet hold time requirements. SD clock is running at 50MHz and
drvsel is set to shift 135 degrees (3 * 45 degrees). With that, the hold time
is 135 / 360 * 20ns = 7.5ns.
#define CONFIG_SOCFPGA_DWMMC_SMPSEL 0
-> Phase-shifted clock of sdmmc_clk used to sample the command and data from
the card
#define CONFIG_SOCFPGA_DWMMC_BUS_WIDTH 4
-> Bus width of data line which either 1, 4 or 8 and based on board routing.
#define CONFIG_SOCFPGA_DWMMC_BUS_HZ 50000000
-> The clock rate to controller. Do note the controller have a wrapper which
divide the clock from PLL by 4.

View File

@ -28,6 +28,7 @@ obj-$(CONFIG_TEGRA_MMC) += tegra_mmc.o
obj-$(CONFIG_DWMMC) += dw_mmc.o
obj-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o
obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
else

36
drivers/mmc/dw_mmc.c Normal file → Executable file
View File

@ -6,6 +6,7 @@
* SPDX-License-Identifier: GPL-2.0+
*/
#include <bouncebuf.h>
#include <common.h>
#include <malloc.h>
#include <mmc.h>
@ -41,11 +42,13 @@ static void dwmci_set_idma_desc(struct dwmci_idmac *idmac,
}
static void dwmci_prepare_data(struct dwmci_host *host,
struct mmc_data *data, struct dwmci_idmac *cur_idmac)
struct mmc_data *data,
struct dwmci_idmac *cur_idmac,
void *bounce_buffer)
{
unsigned long ctrl;
unsigned int i = 0, flags, cnt, blk_cnt;
ulong data_start, data_end, start_addr;
ulong data_start, data_end;
blk_cnt = data->blocks;
@ -55,11 +58,6 @@ static void dwmci_prepare_data(struct dwmci_host *host,
data_start = (ulong)cur_idmac;
dwmci_writel(host, DWMCI_DBADDR, (unsigned int)cur_idmac);
if (data->flags == MMC_DATA_READ)
start_addr = (unsigned int)data->dest;
else
start_addr = (unsigned int)data->src;
do {
flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH ;
flags |= (i == 0) ? DWMCI_IDMAC_FS : 0;
@ -70,7 +68,7 @@ static void dwmci_prepare_data(struct dwmci_host *host,
cnt = data->blocksize * 8;
dwmci_set_idma_desc(cur_idmac, flags, cnt,
start_addr + (i * PAGE_SIZE));
(u32)bounce_buffer + (i * PAGE_SIZE));
if (blk_cnt <= 8)
break;
@ -117,6 +115,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
u32 retry = 10000;
u32 mask, ctrl;
ulong start = get_timer(0);
struct bounce_buffer bbstate;
while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) {
if (get_timer(start) > timeout) {
@ -127,8 +126,19 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL);
if (data)
dwmci_prepare_data(host, data, cur_idmac);
if (data) {
if (data->flags == MMC_DATA_READ) {
bounce_buffer_start(&bbstate, (void*)data->dest,
data->blocksize *
data->blocks, GEN_BB_WRITE);
} else {
bounce_buffer_start(&bbstate, (void*)data->src,
data->blocksize *
data->blocks, GEN_BB_READ);
}
dwmci_prepare_data(host, data, cur_idmac,
bbstate.bounce_buffer);
}
dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg);
@ -204,6 +214,8 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
ctrl = dwmci_readl(host, DWMCI_CTRL);
ctrl &= ~(DWMCI_DMA_EN);
dwmci_writel(host, DWMCI_CTRL, ctrl);
bounce_buffer_stop(&bbstate);
}
udelay(100);
@ -336,9 +348,9 @@ int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk)
struct mmc *mmc;
int err = 0;
mmc = malloc(sizeof(struct mmc));
mmc = calloc(sizeof(struct mmc), 1);
if (!mmc) {
printf("mmc malloc fail!\n");
printf("mmc calloc fail!\n");
return -1;
}

View File

@ -877,6 +877,7 @@ static int mmc_startup(struct mmc *mmc)
mmc->tran_speed = freq * mult;
mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
if (IS_SD(mmc))
@ -907,6 +908,14 @@ static int mmc_startup(struct mmc *mmc)
if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
cmd.cmdidx = MMC_CMD_SET_DSR;
cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
cmd.resp_type = MMC_RSP_NONE;
if (mmc_send_cmd(mmc, &cmd, NULL))
printf("MMC: SET_DSR failed\n");
}
/* Select the card, and put it into Transfer Mode */
if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
cmd.cmdidx = MMC_CMD_SELECT_CARD;
@ -1163,6 +1172,9 @@ static int mmc_send_if_cond(struct mmc *mmc)
int mmc_register(struct mmc *mmc)
{
/* Setup dsr related values */
mmc->dsr_imp = 0;
mmc->dsr = 0xffffffff;
/* Setup the universal parts of the block interface just once */
mmc->block_dev.if_type = IF_TYPE_MMC;
mmc->block_dev.dev = cur_dev_num++;
@ -1280,6 +1292,12 @@ int mmc_init(struct mmc *mmc)
return err;
}
int mmc_set_dsr(struct mmc *mmc, u16 val)
{
mmc->dsr = val;
return 0;
}
/*
* CPU and board-specific MMC initializations. Aliased function
* signals caller to move on

View File

@ -24,7 +24,8 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
if (timeout == 0) {
printf("Reset 0x%x never completed.\n", (int)mask);
printf("%s: Reset 0x%x never completed.\n",
__func__, (int)mask);
return;
}
timeout--;
@ -79,7 +80,8 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
do {
stat = sdhci_readl(host, SDHCI_INT_STATUS);
if (stat & SDHCI_INT_ERROR) {
printf("Error detected in status(0x%X)!\n", stat);
printf("%s: Error detected in status(0x%X)!\n",
__func__, stat);
return -1;
}
if (stat & rdy) {
@ -102,7 +104,7 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
if (timeout-- > 0)
udelay(10);
else {
printf("Transfer data timeout\n");
printf("%s: Transfer data timeout\n", __func__);
return -1;
}
} while (!(stat & SDHCI_INT_DATA_END));
@ -147,7 +149,7 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
if (time >= cmd_timeout) {
printf("MMC: %d busy ", mmc_dev);
printf("%s: MMC: %d busy ", __func__, mmc_dev);
if (2 * cmd_timeout <= CONFIG_SDHCI_CMD_MAX_TIMEOUT) {
cmd_timeout += cmd_timeout;
printf("timeout increasing to: %u ms.\n",
@ -179,7 +181,7 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
if (data)
flags |= SDHCI_CMD_DATA;
/*Set Transfer mode regarding to data flag*/
/* Set Transfer mode regarding to data flag */
if (data != 0) {
sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
mode = SDHCI_TRNS_BLK_CNT_EN;
@ -230,7 +232,7 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
if (host->quirks & SDHCI_QUIRK_BROKEN_R1B)
return 0;
else {
printf("Timeout for status update!\n");
printf("%s: Timeout for status update!\n", __func__);
return TIMEOUT;
}
}
@ -307,7 +309,8 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
& SDHCI_CLOCK_INT_STABLE)) {
if (timeout == 0) {
printf("Internal clock never stabilised.\n");
printf("%s: Internal clock never stabilised.\n",
__func__);
return -1;
}
timeout--;
@ -397,7 +400,8 @@ int sdhci_init(struct mmc *mmc)
if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) {
aligned_buffer = memalign(8, 512*1024);
if (!aligned_buffer) {
printf("Aligned buffer alloc failed!!!");
printf("%s: Aligned buffer alloc failed!!!\n",
__func__);
return -1;
}
}
@ -418,8 +422,8 @@ int sdhci_init(struct mmc *mmc)
}
/* Enable only interrupts served by the SD controller */
sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK
, SDHCI_INT_ENABLE);
sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK,
SDHCI_INT_ENABLE);
/* Mask all sdhci interrupt sources */
sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);
@ -433,7 +437,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
mmc = malloc(sizeof(struct mmc));
if (!mmc) {
printf("mmc malloc fail!\n");
printf("%s: mmc malloc fail!\n", __func__);
return -1;
}
@ -450,7 +454,8 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
caps = sdhci_readl(host, SDHCI_CAPABILITIES);
#ifdef CONFIG_MMC_SDMA
if (!(caps & SDHCI_CAN_DO_SDMA)) {
printf("Your controller don't support sdma!!\n");
printf("%s: Your controller doesn't support SDMA!!\n",
__func__);
return -1;
}
#endif
@ -467,7 +472,8 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
mmc->f_max *= 1000000;
}
if (mmc->f_max == 0) {
printf("Hardware doesn't specify base clock frequency\n");
printf("%s: Hardware doesn't specify base clock frequency\n",
__func__);
return -1;
}
if (min_clk)

View File

@ -0,0 +1,68 @@
/*
* (C) Copyright 2013 Altera Corporation <www.altera.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <malloc.h>
#include <dwmmc.h>
#include <asm/arch/dwmmc.h>
#include <asm/arch/clock_manager.h>
#include <asm/arch/system_manager.h>
static const struct socfpga_clock_manager *clock_manager_base =
(void *)SOCFPGA_CLKMGR_ADDRESS;
static const struct socfpga_system_manager *system_manager_base =
(void *)SOCFPGA_SYSMGR_ADDRESS;
static char *SOCFPGA_NAME = "SOCFPGA DWMMC";
static void socfpga_dwmci_clksel(struct dwmci_host *host)
{
unsigned int drvsel;
unsigned int smplsel;
/* Disable SDMMC clock. */
clrbits_le32(&clock_manager_base->per_pll_en,
CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK);
/* Configures drv_sel and smpl_sel */
drvsel = CONFIG_SOCFPGA_DWMMC_DRVSEL;
smplsel = CONFIG_SOCFPGA_DWMMC_SMPSEL;
debug("%s: drvsel %d smplsel %d\n", __func__, drvsel, smplsel);
writel(SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel),
&system_manager_base->sdmmcgrp_ctrl);
debug("%s: SYSMGR_SDMMCGRP_CTRL_REG = 0x%x\n", __func__,
readl(&system_manager_base->sdmmcgrp_ctrl));
/* Enable SDMMC clock */
setbits_le32(&clock_manager_base->per_pll_en,
CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK);
}
int socfpga_dwmmc_init(u32 regbase, int bus_width, int index)
{
struct dwmci_host *host = NULL;
host = calloc(sizeof(struct dwmci_host), 1);
if (!host) {
printf("dwmci_host calloc fail!\n");
return -1;
}
host->name = SOCFPGA_NAME;
host->ioaddr = (void *)regbase;
host->buswidth = bus_width;
host->clksel = socfpga_dwmci_clksel;
host->dev_index = index;
/* fixed clock divide by 4 which due to the SDMMC wrapper */
host->bus_hz = CONFIG_SOCFPGA_DWMMC_BUS_HZ;
host->fifoth_val = MSIZE(0x2) |
RX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2 - 1) |
TX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2);
return add_dwmci(host, host->bus_hz, 400000);
}

View File

@ -85,6 +85,7 @@
#define CONFIG_DWMMC
#define CONFIG_EXYNOS_DWMMC
#define CONFIG_SUPPORT_EMMC_BOOT
#define CONFIG_BOUNCE_BUFFER
#define CONFIG_BOARD_EARLY_INIT_F

View File

@ -102,6 +102,7 @@
#define CONFIG_DWMMC
#define CONFIG_EXYNOS_DWMMC
#define CONFIG_SUPPORT_EMMC_BOOT
#define CONFIG_BOUNCE_BUFFER
#define CONFIG_BOARD_EARLY_INIT_F

View File

@ -36,6 +36,7 @@
#define CONFIG_EFI_PARTITION
#define CONFIG_PARTITION_UUIDS
#define CONFIG_CMD_PART
#define CONFIG_HSMMC2_8BIT
/* Required support for the TCA642X GPIO we have on the uEVM */
#define CONFIG_TCA642X

View File

@ -262,6 +262,8 @@ struct mmc {
uint card_caps;
uint host_caps;
uint ocr;
uint dsr;
uint dsr_imp;
uint scr[2];
uint csd[4];
uint cid[4];
@ -304,7 +306,7 @@ int board_mmc_getcd(struct mmc *mmc);
int mmc_switch_part(int dev_num, unsigned int part_num);
int mmc_getcd(struct mmc *mmc);
int mmc_getwp(struct mmc *mmc);
void spl_mmc_load(void) __noreturn;
int mmc_set_dsr(struct mmc *mmc, u16 val);
/* Function to change the size of boot partition and rpmb partitions */
int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
unsigned long rpmbsize);