mirror of
https://git.codelinaro.org/clo/qsdk/oss/boot/u-boot-2016.git
synced 2026-02-12 19:10:14 +01:00
ipq807x: mmc: Enabled SDHCI ADMA support
This patch enables SDHCI mode and also supports data transfer using ADMA method. Change-Id: Ia3187fec9024ad0972ca720cf0b9ddc6a59b906c Signed-off-by: Vasudevan Murugesan <vmuruges@codeaurora.org>
This commit is contained in:
parent
9bf4639e22
commit
7fd4f44ace
7 changed files with 211 additions and 5 deletions
|
|
@ -68,8 +68,11 @@ extern struct dumpinfo_t dumpinfo_s[];
|
|||
extern int dump_entries_s;
|
||||
|
||||
#define MSM_SDC1_BASE 0x7824000
|
||||
#define MSM_SDC1_MCI_HC_MODE 0x7824078
|
||||
#define MSM_SDC1_SDHCI_BASE 0x7824900
|
||||
#define MMC_IDENTIFY_MODE 0
|
||||
#define MMC_DATA_TRANSFER_MODE 1
|
||||
#define MMC_DATA_TRANSFER_SDHCI_MODE 2
|
||||
#define MMC_MODE_HC 0x800
|
||||
|
||||
#endif /* __QCA_COMMON_H_ */
|
||||
|
|
|
|||
|
|
@ -18,9 +18,14 @@
|
|||
#include <mmc.h>
|
||||
#include <asm/arch-qca-common/smem.h>
|
||||
#include "qca_common.h"
|
||||
#include <sdhci.h>
|
||||
|
||||
#ifdef CONFIG_QCA_MMC
|
||||
#ifndef CONFIG_SDHCI_SUPPORT
|
||||
extern qca_mmc mmc_host;
|
||||
#else
|
||||
extern struct sdhci_host mmc_host;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -26,11 +26,17 @@
|
|||
#include <mmc.h>
|
||||
#include <usb.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <sdhci.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define GCNT_PSHOLD 0x004AB000
|
||||
|
||||
#ifndef CONFIG_SDHCI_SUPPORT
|
||||
qca_mmc mmc_host;
|
||||
#else
|
||||
struct sdhci_host mmc_host;
|
||||
#endif
|
||||
|
||||
extern asmlinkage void __invoke_psci_fn_smc(unsigned long, unsigned long, unsigned long, unsigned long);
|
||||
|
||||
|
|
@ -238,6 +244,17 @@ void emmc_clock_config(int mode)
|
|||
/* Delay for clock operation complete */
|
||||
udelay(10);
|
||||
}
|
||||
if (mode == MMC_DATA_TRANSFER_SDHCI_MODE) {
|
||||
/* PLL0 - 192Mhz */
|
||||
writel(0x20B, GCC_SDCC1_APPS_CFG_RCGR);
|
||||
/* Delay for clock operation complete */
|
||||
udelay(10);
|
||||
writel(0x1, GCC_SDCC1_APPS_M);
|
||||
writel(0xFC, GCC_SDCC1_APPS_N);
|
||||
writel(0xFD, GCC_SDCC1_APPS_D);
|
||||
/* Delay for clock operation complete */
|
||||
udelay(10);
|
||||
}
|
||||
/* Update APPS_CMD_RCGR to reflect source selection */
|
||||
writel(readl(GCC_SDCC1_APPS_CMD_RCGR)|0x1, GCC_SDCC1_APPS_CMD_RCGR);
|
||||
/* Add 10us delay for clock update to complete */
|
||||
|
|
@ -255,6 +272,21 @@ void board_mmc_deinit(void)
|
|||
emmc_clock_disable();
|
||||
}
|
||||
|
||||
void emmc_clock_reset(void)
|
||||
{
|
||||
writel(0x1, GCC_SDCC1_BCR);
|
||||
udelay(10);
|
||||
writel(0x0, GCC_SDCC1_BCR);
|
||||
}
|
||||
|
||||
void emmc_sdhci_init(void)
|
||||
{
|
||||
writel(readl(MSM_SDC1_MCI_HC_MODE) & (~0x1), MSM_SDC1_MCI_HC_MODE);
|
||||
writel(readl(MSM_SDC1_BASE) | (1 << 7), MSM_SDC1_BASE); //SW_RST
|
||||
udelay(10);
|
||||
writel(readl(MSM_SDC1_MCI_HC_MODE) | (0x1), MSM_SDC1_MCI_HC_MODE);
|
||||
}
|
||||
|
||||
void eth_clock_enable(void)
|
||||
{
|
||||
int tlmm_base = 0x1025000;
|
||||
|
|
@ -384,11 +416,30 @@ int board_mmc_init(bd_t *bis)
|
|||
int ret;
|
||||
qca_smem_flash_info_t *sfi = &qca_smem_flash_info;
|
||||
|
||||
#ifndef CONFIG_SDHCI_SUPPORT
|
||||
mmc_host.base = MSM_SDC1_BASE;
|
||||
mmc_host.clk_mode = MMC_IDENTIFY_MODE;
|
||||
emmc_clock_config(mmc_host.clk_mode);
|
||||
|
||||
ret = qca_mmc_init(bis, &mmc_host);
|
||||
#else
|
||||
mmc_host.ioaddr = (void *)MSM_SDC1_SDHCI_BASE;
|
||||
mmc_host.voltages = MMC_VDD_165_195;
|
||||
mmc_host.version = SDHCI_SPEC_300;
|
||||
mmc_host.cfg.part_type = PART_TYPE_EFI;
|
||||
mmc_host.quirks = SDHCI_QUIRK_BROKEN_VOLTAGE;
|
||||
|
||||
emmc_clock_disable();
|
||||
emmc_clock_reset();
|
||||
udelay(10);
|
||||
emmc_clock_config(MMC_DATA_TRANSFER_SDHCI_MODE);
|
||||
emmc_sdhci_init();
|
||||
|
||||
if (add_sdhci(&mmc_host, 200000000, 400000)) {
|
||||
printf("add_sdhci fail!\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ret && sfi->flash_type == SMEM_BOOT_MMC_FLASH) {
|
||||
ret = board_mmc_env_init();
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#define GCC_SDCC1_APPS_N 0x1842010
|
||||
#define GCC_SDCC1_APPS_D 0x1842014
|
||||
#define GCC_BLSP1_UART1_APPS_CBCR 0x0180203c
|
||||
#define GCC_SDCC1_BCR 0x01842000
|
||||
|
||||
#define GCC_BLSP1_UART2_APPS_CFG_RCGR 0x01803038
|
||||
#define GCC_BLSP1_UART2_APPS_M 0x0180303C
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ void *aligned_buffer = (void *)CONFIG_FIXED_SDHCI_ALIGNED_BUFFER;
|
|||
void *aligned_buffer;
|
||||
#endif
|
||||
|
||||
#define CACHE_LINE_SIZE (CONFIG_SYS_CACHELINE_SIZE)
|
||||
|
||||
static void sdhci_reset(struct sdhci_host *host, u8 mask)
|
||||
{
|
||||
unsigned long timeout;
|
||||
|
|
@ -67,6 +69,103 @@ static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MMC_ADMA
|
||||
static struct adma_desc *sdhci_prepare_descriptors(void *data, uint32_t len)
|
||||
{
|
||||
struct adma_desc *list;
|
||||
uint32_t list_len = 0;
|
||||
uint32_t remain = 0;
|
||||
uint32_t i;
|
||||
uint32_t table_len = 0;
|
||||
|
||||
if (len <= SDHCI_ADMA_DESC_LINE_SZ) {
|
||||
list = (struct adma_desc *) memalign(CACHE_LINE_SIZE, sizeof(struct adma_desc));
|
||||
|
||||
if (!list) {
|
||||
printf("Error allocating memory\n");
|
||||
assert(0);
|
||||
}
|
||||
|
||||
list[0].addr = (uint32_t)data;
|
||||
list[0].len = (len < SDHCI_ADMA_DESC_LINE_SZ) ? len : (SDHCI_ADMA_DESC_LINE_SZ & 0xffff);
|
||||
list[0].tran_att = SDHCI_ADMA_TRANS_VALID | SDHCI_ADMA_TRANS_DATA
|
||||
| SDHCI_ADMA_TRANS_END;
|
||||
|
||||
invalidate_dcache_range((uint32_t)list & ~(CACHE_LINE_SIZE - 1),
|
||||
ALIGN((uint32_t)list + sizeof(struct adma_desc),CACHE_LINE_SIZE));
|
||||
|
||||
} else {
|
||||
list_len = len / SDHCI_ADMA_DESC_LINE_SZ;
|
||||
remain = len - (list_len * SDHCI_ADMA_DESC_LINE_SZ);
|
||||
|
||||
if (remain)
|
||||
list_len++;
|
||||
|
||||
table_len = (list_len * sizeof(struct adma_desc));
|
||||
|
||||
list = (struct adma_desc *) memalign( CACHE_LINE_SIZE, table_len);
|
||||
|
||||
if (!list) {
|
||||
printf("Allocating memory failed\n");
|
||||
assert(0);
|
||||
}
|
||||
|
||||
memset((void *) list, 0, table_len);
|
||||
|
||||
for (i = 0; i < (list_len - 1); i++) {
|
||||
list[i].addr = (uint32_t)data;
|
||||
list[i].len = (SDHCI_ADMA_DESC_LINE_SZ & 0xffff);
|
||||
list[i].tran_att = SDHCI_ADMA_TRANS_VALID | SDHCI_ADMA_TRANS_DATA;
|
||||
data += SDHCI_ADMA_DESC_LINE_SZ;
|
||||
len -= SDHCI_ADMA_DESC_LINE_SZ;
|
||||
}
|
||||
|
||||
list[list_len - 1].addr = (uint32_t)data;
|
||||
list[list_len - 1].len = (len < SDHCI_ADMA_DESC_LINE_SZ) ? len : (SDHCI_ADMA_DESC_LINE_SZ & 0xffff);
|
||||
list[list_len - 1].tran_att = SDHCI_ADMA_TRANS_VALID | SDHCI_ADMA_TRANS_DATA |
|
||||
SDHCI_ADMA_TRANS_END;
|
||||
}
|
||||
|
||||
invalidate_dcache_range((uint32_t)list & ~(CACHE_LINE_SIZE - 1),
|
||||
ALIGN((uint32_t)list + table_len,CACHE_LINE_SIZE));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
struct adma_desc *sdhci_adma_transfer(struct sdhci_host *host, struct mmc_data *data)
|
||||
{
|
||||
uint32_t sz;
|
||||
void *dataptr;
|
||||
struct adma_desc *adma_addr;
|
||||
|
||||
dataptr = data->dest;
|
||||
|
||||
if (data->blocksize)
|
||||
sz = data->blocks * data->blocksize;
|
||||
else
|
||||
sz = data->blocks * SDHCI_MMC_BLK_SZ;
|
||||
|
||||
/* Prepare adma descriptors */
|
||||
adma_addr = sdhci_prepare_descriptors(dataptr, sz);
|
||||
|
||||
/* Write adma address to adma register */
|
||||
sdhci_writel(host, (uint32_t) adma_addr, SDHCI_ADM_ADDR_REG);
|
||||
|
||||
/* Write the block size */
|
||||
if (data->blocksize)
|
||||
sdhci_writew(host, data->blocksize, SDHCI_BLOCK_SIZE);
|
||||
else
|
||||
sdhci_writew(host, SDHCI_MMC_BLK_SZ, SDHCI_BLOCK_SIZE);
|
||||
|
||||
/*
|
||||
* Write block count in block count register
|
||||
*/
|
||||
sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
|
||||
|
||||
return adma_addr;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
|
||||
unsigned int start_addr)
|
||||
{
|
||||
|
|
@ -223,6 +322,11 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
|
|||
sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS);
|
||||
mode |= SDHCI_TRNS_DMA;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MMC_ADMA
|
||||
mode |= SDHCI_TRNS_DMA;
|
||||
sdhci_adma_transfer(host, data);
|
||||
#endif
|
||||
sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
|
||||
data->blocksize),
|
||||
SDHCI_BLOCK_SIZE);
|
||||
|
|
@ -236,6 +340,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
|
|||
#ifdef CONFIG_MMC_SDMA
|
||||
flush_cache(start_addr, trans_bytes);
|
||||
#endif
|
||||
udelay(5);
|
||||
sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND);
|
||||
start = get_timer(0);
|
||||
do {
|
||||
|
|
@ -440,7 +545,7 @@ static int sdhci_init(struct mmc *mmc)
|
|||
}
|
||||
}
|
||||
|
||||
sdhci_set_power(host, fls(mmc->cfg->voltages) - 1);
|
||||
sdhci_set_power(host, fls(host->cfg.voltages) - 1);
|
||||
|
||||
if (host->quirks & SDHCI_QUIRK_NO_CD) {
|
||||
unsigned int status;
|
||||
|
|
@ -525,7 +630,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
|
|||
if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE)
|
||||
host->cfg.voltages |= host->voltages;
|
||||
|
||||
host->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT;
|
||||
host->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_8BIT;
|
||||
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
|
||||
if (caps & SDHCI_CAN_DO_8BIT)
|
||||
host->cfg.host_caps |= MMC_MODE_8BIT;
|
||||
|
|
@ -543,5 +648,9 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
|
|||
return -1;
|
||||
}
|
||||
|
||||
host->dev_num = host->mmc->block_dev.dev;
|
||||
host->mmc->has_init = 0;
|
||||
host->mmc->init_in_progress = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,6 +163,8 @@ extern loff_t board_env_size;
|
|||
#define CONFIG_EFI_PARTITION
|
||||
#define CONFIG_ENV_IS_IN_MMC
|
||||
#define CONFIG_SYS_MMC_ENV_DEV 0
|
||||
#define CONFIG_SDHCI_SUPPORT
|
||||
#define CONFIG_MMC_ADMA
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include <asm/io.h>
|
||||
#include <mmc.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
/*
|
||||
* Controller registers
|
||||
|
|
@ -194,6 +193,8 @@
|
|||
#define SDHCI_SPEC_300 2
|
||||
|
||||
#define SDHCI_GET_VERSION(x) (x->version & SDHCI_SPEC_VER_MASK)
|
||||
#define SDHCI_ADM_ADDR_REG (0x058)
|
||||
#define SDHCI_BLKSZ_REG (0x004)
|
||||
|
||||
/*
|
||||
* End of controller registers.
|
||||
|
|
@ -215,6 +216,32 @@
|
|||
#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1 << 7)
|
||||
#define SDHCI_QUIRK_USE_WIDE8 (1 << 8)
|
||||
|
||||
/*
|
||||
* Adma related macros
|
||||
*/
|
||||
#define SDHCI_BLK_LEN_MASK 0x00030000
|
||||
#define SDHCI_BLK_LEN_BIT 16
|
||||
#define SDHCI_BLK_ADMA_MASK 0x00080000
|
||||
#define SDHCI_INT_STS_TRANS_COMPLETE BIT(1)
|
||||
#define SDHCI_STATE_CMD_DAT_MASK 0x0003
|
||||
#define SDHCI_INT_STS_CMD_COMPLETE BIT(0)
|
||||
#define SDHCI_ERR_INT_STAT_MASK 0x8000
|
||||
#define SDHCI_ADMA_DESC_LINE_SZ 65536
|
||||
#define SDHCI_ADMA_MAX_TRANS_SZ (65535 * 512)
|
||||
#define SDHCI_ADMA_TRANS_VALID BIT(0)
|
||||
#define SDHCI_ADMA_TRANS_END BIT(1)
|
||||
#define SDHCI_ADMA_TRANS_DATA BIT(5)
|
||||
#define SDHCI_MMC_BLK_SZ 512
|
||||
#define SDHCI_MMC_CUR_BLK_CNT_BIT 16
|
||||
#define SDHCI_MMC_BLK_SZ_BIT 0
|
||||
#define SDHCI_TRANS_MULTI BIT(5)
|
||||
#define SDHCI_TRANS_SINGLE (0 << 5)
|
||||
#define SDHCI_BLK_CNT_EN BIT(1)
|
||||
#define SDHCI_DMA_EN BIT(0)
|
||||
#define SDHCI_AUTO_CMD23_EN BIT(3)
|
||||
#define SDHCI_AUTO_CMD12_EN BIT(2)
|
||||
#define SDHCI_ADMA_32BIT BIT(4)
|
||||
|
||||
/* to make gcc happy */
|
||||
struct sdhci_host;
|
||||
|
||||
|
|
@ -234,6 +261,15 @@ struct sdhci_ops {
|
|||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Descriptor table for adma
|
||||
*/
|
||||
struct adma_desc {
|
||||
uint16_t tran_att;
|
||||
uint16_t len;
|
||||
uint32_t addr;
|
||||
};
|
||||
|
||||
struct sdhci_host {
|
||||
char *name;
|
||||
void *ioaddr;
|
||||
|
|
@ -246,8 +282,7 @@ struct sdhci_host {
|
|||
int index;
|
||||
|
||||
int bus_width;
|
||||
struct gpio_desc pwr_gpio; /* Power GPIO */
|
||||
struct gpio_desc cd_gpio; /* Card Detect GPIO */
|
||||
int dev_num;
|
||||
|
||||
void (*set_control_reg)(struct sdhci_host *host);
|
||||
void (*set_clock)(int dev_index, unsigned int div);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue