From dae6c6ba95f61326e8012c2fec372a6735ba46b9 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Tue, 3 Dec 2013 12:17:34 +0530 Subject: include/mmc.h: Remove declaration for spl_mmc_load() The spl_mmc_load() was removed while converting to CONFIG_SPL_FRAMEWORK usage the definition was removed but the declaration was missed. This patch removes this declaration. Signed-off-by: Lad, Prabhakar Acked-by: Pantelis Antoniou diff --git a/include/mmc.h b/include/mmc.h index cb558da..8f51c93 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -304,7 +304,6 @@ 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; /* 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); -- cgit v0.10.2 From fd26b5490bef8e8a37e33a9b3c4960d7a8734067 Mon Sep 17 00:00:00 2001 From: Chin Liang See Date: Wed, 18 Dec 2013 11:16:01 -0600 Subject: mmc/dwmmc: Using calloc instead malloc To enhance the SDMMC DesignWare driver to use calloc instead of malloc. This will avoid the incident that uninitialized members of mmc structure are later used for NULL comparison. Signed-off-by: Chin Liang See Cc: Rajeshwari Shinde Cc: Jaehoon Chung Cc: Mischa Jonker Cc: Alexey Brodkin Cc: Andy Fleming Cc: Pantelis Antoniou Acked-by: Pantelis Antoniou diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c old mode 100644 new mode 100755 index 19d9b0b..82abe19 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -336,9 +336,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; } -- cgit v0.10.2 From f931483e4e41b7f3d738077040385b1776f635dc Mon Sep 17 00:00:00 2001 From: Lubomir Popov Date: Thu, 19 Dec 2013 17:14:02 +0200 Subject: ARM: omap5_uevm: Enable 8-bit eMMC access All prerequisites are already available, so why not enable 8-bit access - it is a matter of a define in the board file only. Signed-off-by: Lubomir Popov Acked-by: Pantelis Antoniou diff --git a/include/configs/omap5_uevm.h b/include/configs/omap5_uevm.h index 2f128b8..76c5106 100644 --- a/include/configs/omap5_uevm.h +++ b/include/configs/omap5_uevm.h @@ -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 -- cgit v0.10.2 From 2a7a210e2cb724f4a941786e58878baf6edce846 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Thu, 26 Dec 2013 15:29:07 +0400 Subject: mmc/dwmmc: use bounce buffer for data exchange between CPU and MMC controller Bounce buffer implementation takes care of proper data buffer alignemt and correct flush/invalidation of data cache at once so we no longer depend on input data variety and make sure CPU and MMC controller deal with expected data in case of enabled data cache. Bounce buffer requires to add its definition (CONFIG_BOUNCE_BUFFER) in board configuration, otherwise corresponding library won't be compiled and linker will fail to build resulting executable. Difference since v1 - fixed compile-time warning with type casting to "void *": Slight edit to remove UTF8 characters in the commit message. Acked-by: Jaehoon Chung Tested-by: Jaehoon Chung Acked-by: Pantelis Antoniou ==== passing argument 2 of 'bounce_buffer_start' discards 'const' qualifier from pointer target type ==== Signed-off-by: Alexey Brodkin Cc: Mischa Jonker Cc: Alim Akhtar Cc: Rajeshwari Shinde Cc: Jaehoon Chung Cc: Amar Cc: Kyungmin Park Cc: Minkyu Kang Cc: Simon Glass Cc: Pantelis Antoniou Cc: Andy Fleming diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 82abe19..4cec5aa 100755 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -6,6 +6,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ +#include #include #include #include @@ -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); diff --git a/include/configs/arndale.h b/include/configs/arndale.h index a3cb56b..3d29caf 100644 --- a/include/configs/arndale.h +++ b/include/configs/arndale.h @@ -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 diff --git a/include/configs/exynos5250-dt.h b/include/configs/exynos5250-dt.h index 8fb904c..b39bafc 100644 --- a/include/configs/exynos5250-dt.h +++ b/include/configs/exynos5250-dt.h @@ -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 -- cgit v0.10.2 From 30e6d979fa9da56a5badcb981cdddd58638d3375 Mon Sep 17 00:00:00 2001 From: Darwin Rambo Date: Thu, 19 Dec 2013 15:13:25 -0800 Subject: mmc: Minor cleanup of sdhci.c Fixup prints to show where the print is done from, and a few minor formatting/grammar issues. Signed-off-by: Darwin Rambo Acked-by: Pantelis Antoniou diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 46ae9cb..1e86b92 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -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) -- cgit v0.10.2 From ab71188ce87ebb66192a5bdbbb9d58052bd32d93 Mon Sep 17 00:00:00 2001 From: Markus Niebel Date: Mon, 16 Dec 2013 13:40:46 +0100 Subject: mmc: add setdsr support The eMMC and the SD-Card specifications describe the optional SET_DSR command. During measurements at our lab we found that some cards implementing this feature having really strong driver strengts per default. This can lead to voltage peaks above the specification of the host on signal edges for data sent from a card to the host. Since availability of a given card type may be shorter than the time a certain hardware will be produced it is useful to have support for this command (Alternative would be changing termination resistors and adapting the driver strength of the host to the used card.) Following proposal for an implementation: - new field that reflects CSD field DSR_IMP in struct mmc - new field for design specific DSR value in struct mmc - board code can set DSR value in mmc struct just after registering an controller - mmc_startup sends the the stored DSR value before selecting a card, if DSR_IMP is set Additionally the mmc command is extended to make is possible to play around with different DSR values. The concept was tested on a i.MX53 based platform using a Micron eMMC card where the default DSR is 0x0400 (12mA) but in our design 0x0100 (0x0100) were enough. To use this feature for instance on a mx53loco one have to add a call to mmc_set_dsr() in board_mmc_init() after calling fsl_esdhc_initialize() for the eMMC. Signed-off-by: Markus Niebel Acked-by: Pantelis Antoniou diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c index 67a94a7..da5fef9 100644 --- a/common/cmd_mmc.c +++ b/common/cmd_mmc.c @@ -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 \n" " - change sizes of boot and RPMB partitions of specified device\n" #endif + "mmc setdsr - set DSR register value\n" ); #endif /* !CONFIG_GENERIC_MMC */ diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index e1461a9..c6a1c23 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -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 diff --git a/include/mmc.h b/include/mmc.h index 8f51c93..e1060b9 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -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,6 +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); +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); -- cgit v0.10.2 From c5c1af21764d9423b45c1d03e835c4547a8bc5cb Mon Sep 17 00:00:00 2001 From: Chin Liang See Date: Mon, 30 Dec 2013 18:26:14 -0600 Subject: socfpga/dwmmc: Adding DesignWare MMC driver support for SOCFPGA To add the DesignWare MMC driver support for Altera SOCFPGA. It required information such as clocks and bus width from platform specific files (SOCFPGA handoff files) Signed-off-by: Chin Liang See Cc: Rajeshwari Shinde Cc: Jaehoon Chung Cc: Pantelis Antoniou Cc: Wolfgang Denk Acked-by: Pantelis Antoniou diff --git a/arch/arm/include/asm/arch-socfpga/dwmmc.h b/arch/arm/include/asm/arch-socfpga/dwmmc.h new file mode 100644 index 0000000..945eb64 --- /dev/null +++ b/arch/arm/include/asm/arch-socfpga/dwmmc.h @@ -0,0 +1,12 @@ +/* + * (C) Copyright 2013 Altera Corporation + * + * 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_ */ diff --git a/arch/arm/include/asm/arch-socfpga/system_manager.h b/arch/arm/include/asm/arch-socfpga/system_manager.h index d965d25..838d210 100644 --- a/arch/arm/include/asm/arch-socfpga/system_manager.h +++ b/arch/arm/include/asm/arch-socfpga/system_manager.h @@ -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_ */ diff --git a/doc/README.socfpga b/doc/README.socfpga new file mode 100644 index 0000000..cfcbbfe --- /dev/null +++ b/doc/README.socfpga @@ -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. diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 1ed26ca..e793ed9 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -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 diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c new file mode 100644 index 0000000..bc53a5d --- /dev/null +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -0,0 +1,68 @@ +/* + * (C) Copyright 2013 Altera Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +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); +} + -- cgit v0.10.2