mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-29 07:33:29 +08:00
Merge branch 'master' of git://git.denx.de/u-boot-mmc
This commit is contained in:
commit
d0b961684e
@ -9,7 +9,6 @@
|
||||
#include <common.h>
|
||||
#include <spl.h>
|
||||
#include <asm/u-boot.h>
|
||||
#include <asm/utils.h>
|
||||
#include <mmc.h>
|
||||
#include <fat.h>
|
||||
#include <version.h>
|
||||
@ -45,8 +44,10 @@ static int mmc_load_image_raw(struct mmc *mmc, unsigned long sector)
|
||||
(void *)spl_image.load_addr);
|
||||
|
||||
end:
|
||||
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
|
||||
if (err == 0)
|
||||
printf("spl: mmc blk read err - %lu\n", err);
|
||||
#endif
|
||||
|
||||
return (err == 0);
|
||||
}
|
||||
@ -58,7 +59,9 @@ static int mmc_load_image_raw_os(struct mmc *mmc)
|
||||
CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR,
|
||||
CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS,
|
||||
(void *)CONFIG_SYS_SPL_ARGS_ADDR)) {
|
||||
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
|
||||
printf("mmc args blk read error\n");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -84,9 +87,11 @@ static int mmc_load_image_fat(struct mmc *mmc, const char *filename)
|
||||
err = file_fat_read(filename, (u8 *)spl_image.load_addr, 0);
|
||||
|
||||
end:
|
||||
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
|
||||
if (err <= 0)
|
||||
printf("spl: error reading image %s, err - %d\n",
|
||||
filename, err);
|
||||
#endif
|
||||
|
||||
return (err <= 0);
|
||||
}
|
||||
@ -99,8 +104,10 @@ static int mmc_load_image_fat_os(struct mmc *mmc)
|
||||
err = file_fat_read(CONFIG_SPL_FAT_LOAD_ARGS_NAME,
|
||||
(void *)CONFIG_SYS_SPL_ARGS_ADDR, 0);
|
||||
if (err <= 0) {
|
||||
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
|
||||
printf("spl: error reading image %s, err - %d\n",
|
||||
CONFIG_SPL_FAT_LOAD_ARGS_NAME, err);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -120,13 +127,17 @@ void spl_mmc_load_image(void)
|
||||
/* We register only one device. So, the dev id is always 0 */
|
||||
mmc = find_mmc_device(0);
|
||||
if (!mmc) {
|
||||
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
|
||||
puts("spl: mmc device not found!!\n");
|
||||
#endif
|
||||
hang();
|
||||
}
|
||||
|
||||
err = mmc_init(mmc);
|
||||
if (err) {
|
||||
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
|
||||
printf("spl: mmc init failed: err - %d\n", err);
|
||||
#endif
|
||||
hang();
|
||||
}
|
||||
|
||||
@ -145,7 +156,9 @@ void spl_mmc_load_image(void)
|
||||
err = fat_register_device(&mmc->block_dev,
|
||||
CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION);
|
||||
if (err) {
|
||||
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
|
||||
printf("spl: fat register err - %d\n", err);
|
||||
#endif
|
||||
hang();
|
||||
}
|
||||
|
||||
@ -155,7 +168,9 @@ void spl_mmc_load_image(void)
|
||||
err = mmc_load_image_fat(mmc, CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
|
||||
puts("spl: wrong MMC boot mode\n");
|
||||
#endif
|
||||
hang();
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,8 @@ COBJS-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o
|
||||
COBJS-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
|
||||
ifdef CONFIG_SPL_BUILD
|
||||
COBJS-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
|
||||
else
|
||||
COBJS-$(CONFIG_GENERIC_MMC) += mmc_write.o
|
||||
endif
|
||||
|
||||
COBJS := $(COBJS-y)
|
||||
|
@ -41,12 +41,11 @@ static void dwmci_set_idma_desc(struct dwmci_idmac *idmac,
|
||||
}
|
||||
|
||||
static void dwmci_prepare_data(struct dwmci_host *host,
|
||||
struct mmc_data *data)
|
||||
struct mmc_data *data, struct dwmci_idmac *cur_idmac)
|
||||
{
|
||||
unsigned long ctrl;
|
||||
unsigned int i = 0, flags, cnt, blk_cnt;
|
||||
ulong data_start, data_end, start_addr;
|
||||
ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac, data->blocks);
|
||||
|
||||
|
||||
blk_cnt = data->blocks;
|
||||
@ -73,7 +72,7 @@ static void dwmci_prepare_data(struct dwmci_host *host,
|
||||
dwmci_set_idma_desc(cur_idmac, flags, cnt,
|
||||
start_addr + (i * PAGE_SIZE));
|
||||
|
||||
if(blk_cnt < 8)
|
||||
if (blk_cnt <= 8)
|
||||
break;
|
||||
blk_cnt -= 8;
|
||||
cur_idmac++;
|
||||
@ -111,6 +110,8 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
struct mmc_data *data)
|
||||
{
|
||||
struct dwmci_host *host = (struct dwmci_host *)mmc->priv;
|
||||
ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac,
|
||||
data ? DIV_ROUND_UP(data->blocks, 8) : 0);
|
||||
int flags = 0, i;
|
||||
unsigned int timeout = 100000;
|
||||
u32 retry = 10000;
|
||||
@ -127,7 +128,7 @@ 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);
|
||||
dwmci_prepare_data(host, data, cur_idmac);
|
||||
|
||||
dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg);
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <malloc.h>
|
||||
#include <linux/list.h>
|
||||
#include <div64.h>
|
||||
#include "mmc_private.h"
|
||||
|
||||
/* Set block count limit because of 16 bit register limit on some hardware*/
|
||||
#ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
|
||||
@ -52,14 +53,10 @@ int __board_mmc_getcd(struct mmc *mmc) {
|
||||
int board_mmc_getcd(struct mmc *mmc)__attribute__((weak,
|
||||
alias("__board_mmc_getcd")));
|
||||
|
||||
static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
struct mmc_data *data)
|
||||
int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
|
||||
{
|
||||
struct mmc_data backup;
|
||||
int ret;
|
||||
|
||||
memset(&backup, 0, sizeof(backup));
|
||||
|
||||
#ifdef CONFIG_MMC_TRACE
|
||||
int i;
|
||||
u8 *ptr;
|
||||
@ -114,7 +111,7 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mmc_send_status(struct mmc *mmc, int timeout)
|
||||
int mmc_send_status(struct mmc *mmc, int timeout)
|
||||
{
|
||||
struct mmc_cmd cmd;
|
||||
int err, retries = 5;
|
||||
@ -135,8 +132,10 @@ static int mmc_send_status(struct mmc *mmc, int timeout)
|
||||
MMC_STATE_PRG)
|
||||
break;
|
||||
else if (cmd.response[0] & MMC_STATUS_MASK) {
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
printf("Status Error: 0x%08X\n",
|
||||
cmd.response[0]);
|
||||
#endif
|
||||
return COMM_ERR;
|
||||
}
|
||||
} else if (--retries < 0)
|
||||
@ -151,14 +150,16 @@ static int mmc_send_status(struct mmc *mmc, int timeout)
|
||||
printf("CURR STATE:%d\n", status);
|
||||
#endif
|
||||
if (timeout <= 0) {
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
printf("Timeout waiting card ready\n");
|
||||
#endif
|
||||
return TIMEOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_set_blocklen(struct mmc *mmc, int len)
|
||||
int mmc_set_blocklen(struct mmc *mmc, int len)
|
||||
{
|
||||
struct mmc_cmd cmd;
|
||||
|
||||
@ -181,179 +182,13 @@ struct mmc *find_mmc_device(int dev_num)
|
||||
return m;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
printf("MMC Device %d not found\n", dev_num);
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt)
|
||||
{
|
||||
struct mmc_cmd cmd;
|
||||
ulong end;
|
||||
int err, start_cmd, end_cmd;
|
||||
|
||||
if (mmc->high_capacity)
|
||||
end = start + blkcnt - 1;
|
||||
else {
|
||||
end = (start + blkcnt - 1) * mmc->write_bl_len;
|
||||
start *= mmc->write_bl_len;
|
||||
}
|
||||
|
||||
if (IS_SD(mmc)) {
|
||||
start_cmd = SD_CMD_ERASE_WR_BLK_START;
|
||||
end_cmd = SD_CMD_ERASE_WR_BLK_END;
|
||||
} else {
|
||||
start_cmd = MMC_CMD_ERASE_GROUP_START;
|
||||
end_cmd = MMC_CMD_ERASE_GROUP_END;
|
||||
}
|
||||
|
||||
cmd.cmdidx = start_cmd;
|
||||
cmd.cmdarg = start;
|
||||
cmd.resp_type = MMC_RSP_R1;
|
||||
|
||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
cmd.cmdidx = end_cmd;
|
||||
cmd.cmdarg = end;
|
||||
|
||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
cmd.cmdidx = MMC_CMD_ERASE;
|
||||
cmd.cmdarg = SECURE_ERASE;
|
||||
cmd.resp_type = MMC_RSP_R1b;
|
||||
|
||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
puts("mmc erase failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt)
|
||||
{
|
||||
int err = 0;
|
||||
struct mmc *mmc = find_mmc_device(dev_num);
|
||||
lbaint_t blk = 0, blk_r = 0;
|
||||
int timeout = 1000;
|
||||
|
||||
if (!mmc)
|
||||
return -1;
|
||||
|
||||
if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
|
||||
printf("\n\nCaution! Your devices Erase group is 0x%x\n"
|
||||
"The erase range would be change to "
|
||||
"0x" LBAF "~0x" LBAF "\n\n",
|
||||
mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),
|
||||
((start + blkcnt + mmc->erase_grp_size)
|
||||
& ~(mmc->erase_grp_size - 1)) - 1);
|
||||
|
||||
while (blk < blkcnt) {
|
||||
blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
|
||||
mmc->erase_grp_size : (blkcnt - blk);
|
||||
err = mmc_erase_t(mmc, start + blk, blk_r);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
blk += blk_r;
|
||||
|
||||
/* Waiting for the ready status */
|
||||
if (mmc_send_status(mmc, timeout))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return blk;
|
||||
}
|
||||
|
||||
static ulong
|
||||
mmc_write_blocks(struct mmc *mmc, lbaint_t start, lbaint_t blkcnt, const void*src)
|
||||
{
|
||||
struct mmc_cmd cmd;
|
||||
struct mmc_data data;
|
||||
int timeout = 1000;
|
||||
|
||||
if ((start + blkcnt) > mmc->block_dev.lba) {
|
||||
printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
|
||||
start + blkcnt, mmc->block_dev.lba);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (blkcnt == 0)
|
||||
return 0;
|
||||
else if (blkcnt == 1)
|
||||
cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
|
||||
else
|
||||
cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
|
||||
|
||||
if (mmc->high_capacity)
|
||||
cmd.cmdarg = start;
|
||||
else
|
||||
cmd.cmdarg = start * mmc->write_bl_len;
|
||||
|
||||
cmd.resp_type = MMC_RSP_R1;
|
||||
|
||||
data.src = src;
|
||||
data.blocks = blkcnt;
|
||||
data.blocksize = mmc->write_bl_len;
|
||||
data.flags = MMC_DATA_WRITE;
|
||||
|
||||
if (mmc_send_cmd(mmc, &cmd, &data)) {
|
||||
printf("mmc write failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* SPI multiblock writes terminate using a special
|
||||
* token, not a STOP_TRANSMISSION request.
|
||||
*/
|
||||
if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
|
||||
cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
|
||||
cmd.cmdarg = 0;
|
||||
cmd.resp_type = MMC_RSP_R1b;
|
||||
if (mmc_send_cmd(mmc, &cmd, NULL)) {
|
||||
printf("mmc fail to send stop cmd\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Waiting for the ready status */
|
||||
if (mmc_send_status(mmc, timeout))
|
||||
return 0;
|
||||
|
||||
return blkcnt;
|
||||
}
|
||||
|
||||
static ulong
|
||||
mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void*src)
|
||||
{
|
||||
lbaint_t cur, blocks_todo = blkcnt;
|
||||
|
||||
struct mmc *mmc = find_mmc_device(dev_num);
|
||||
if (!mmc)
|
||||
return 0;
|
||||
|
||||
if (mmc_set_blocklen(mmc, mmc->write_bl_len))
|
||||
return 0;
|
||||
|
||||
do {
|
||||
cur = (blocks_todo > mmc->b_max) ? mmc->b_max : blocks_todo;
|
||||
if(mmc_write_blocks(mmc, start, cur, src) != cur)
|
||||
return 0;
|
||||
blocks_todo -= cur;
|
||||
start += cur;
|
||||
src += cur * mmc->write_bl_len;
|
||||
} while (blocks_todo > 0);
|
||||
|
||||
return blkcnt;
|
||||
}
|
||||
|
||||
static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
|
||||
lbaint_t blkcnt)
|
||||
{
|
||||
@ -385,7 +220,9 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
|
||||
cmd.cmdarg = 0;
|
||||
cmd.resp_type = MMC_RSP_R1b;
|
||||
if (mmc_send_cmd(mmc, &cmd, NULL)) {
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
printf("mmc fail to send stop cmd\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -405,8 +242,10 @@ static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst)
|
||||
return 0;
|
||||
|
||||
if ((start + blkcnt) > mmc->block_dev.lba) {
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
|
||||
start + blkcnt, mmc->block_dev.lba);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1268,6 +1107,7 @@ static int mmc_startup(struct mmc *mmc)
|
||||
mmc->block_dev.blksz = mmc->read_bl_len;
|
||||
mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
|
||||
mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x",
|
||||
mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
|
||||
(mmc->cid[3] >> 16) & 0xffff);
|
||||
@ -1277,6 +1117,11 @@ static int mmc_startup(struct mmc *mmc)
|
||||
(mmc->cid[2] >> 24) & 0xff);
|
||||
sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
|
||||
(mmc->cid[2] >> 16) & 0xf);
|
||||
#else
|
||||
mmc->block_dev.vendor[0] = 0;
|
||||
mmc->block_dev.product[0] = 0;
|
||||
mmc->block_dev.revision[0] = 0;
|
||||
#endif
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
|
||||
init_part(&mmc->block_dev);
|
||||
#endif
|
||||
@ -1343,7 +1188,9 @@ int mmc_start_init(struct mmc *mmc)
|
||||
|
||||
if (mmc_getcd(mmc) == 0) {
|
||||
mmc->has_init = 0;
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
printf("MMC: no card present\n");
|
||||
#endif
|
||||
return NO_CARD_ERR;
|
||||
}
|
||||
|
||||
@ -1378,7 +1225,9 @@ int mmc_start_init(struct mmc *mmc)
|
||||
err = mmc_send_op_cond(mmc);
|
||||
|
||||
if (err && err != IN_PROGRESS) {
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
printf("Card did not respond to voltage select!\n");
|
||||
#endif
|
||||
return UNUSABLE_ERR;
|
||||
}
|
||||
}
|
||||
@ -1434,6 +1283,8 @@ static int __def_mmc_init(bd_t *bis)
|
||||
int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
|
||||
int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
|
||||
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||
|
||||
void print_mmc_devices(char separator)
|
||||
{
|
||||
struct mmc *m;
|
||||
@ -1451,6 +1302,10 @@ void print_mmc_devices(char separator)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#else
|
||||
void print_mmc_devices(char separator) { }
|
||||
#endif
|
||||
|
||||
int get_mmc_num(void)
|
||||
{
|
||||
return cur_dev_num;
|
||||
|
45
drivers/mmc/mmc_private.h
Normal file
45
drivers/mmc/mmc_private.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2008,2010 Freescale Semiconductor, Inc
|
||||
* Andy Fleming
|
||||
*
|
||||
* Based (loosely) on the Linux code
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef _MMC_PRIVATE_H_
|
||||
#define _MMC_PRIVATE_H_
|
||||
|
||||
#include <mmc.h>
|
||||
|
||||
extern int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
struct mmc_data *data);
|
||||
extern int mmc_send_status(struct mmc *mmc, int timeout);
|
||||
extern int mmc_set_blocklen(struct mmc *mmc, int len);
|
||||
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
|
||||
extern unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt);
|
||||
|
||||
extern ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt,
|
||||
const void *src);
|
||||
|
||||
#else /* CONFIG_SPL_BUILD */
|
||||
|
||||
/* SPL will never write or erase, declare dummies to reduce code size. */
|
||||
|
||||
static inline unsigned long mmc_berase(int dev_num, lbaint_t start,
|
||||
lbaint_t blkcnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt,
|
||||
const void *src)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SPL_BUILD */
|
||||
|
||||
#endif /* _MMC_PRIVATE_H_ */
|
179
drivers/mmc/mmc_write.c
Normal file
179
drivers/mmc/mmc_write.c
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2008, Freescale Semiconductor, Inc
|
||||
* Andy Fleming
|
||||
*
|
||||
* Based vaguely on the Linux code
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <part.h>
|
||||
#include "mmc_private.h"
|
||||
|
||||
static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt)
|
||||
{
|
||||
struct mmc_cmd cmd;
|
||||
ulong end;
|
||||
int err, start_cmd, end_cmd;
|
||||
|
||||
if (mmc->high_capacity) {
|
||||
end = start + blkcnt - 1;
|
||||
} else {
|
||||
end = (start + blkcnt - 1) * mmc->write_bl_len;
|
||||
start *= mmc->write_bl_len;
|
||||
}
|
||||
|
||||
if (IS_SD(mmc)) {
|
||||
start_cmd = SD_CMD_ERASE_WR_BLK_START;
|
||||
end_cmd = SD_CMD_ERASE_WR_BLK_END;
|
||||
} else {
|
||||
start_cmd = MMC_CMD_ERASE_GROUP_START;
|
||||
end_cmd = MMC_CMD_ERASE_GROUP_END;
|
||||
}
|
||||
|
||||
cmd.cmdidx = start_cmd;
|
||||
cmd.cmdarg = start;
|
||||
cmd.resp_type = MMC_RSP_R1;
|
||||
|
||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
cmd.cmdidx = end_cmd;
|
||||
cmd.cmdarg = end;
|
||||
|
||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
cmd.cmdidx = MMC_CMD_ERASE;
|
||||
cmd.cmdarg = SECURE_ERASE;
|
||||
cmd.resp_type = MMC_RSP_R1b;
|
||||
|
||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
puts("mmc erase failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt)
|
||||
{
|
||||
int err = 0;
|
||||
struct mmc *mmc = find_mmc_device(dev_num);
|
||||
lbaint_t blk = 0, blk_r = 0;
|
||||
int timeout = 1000;
|
||||
|
||||
if (!mmc)
|
||||
return -1;
|
||||
|
||||
if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
|
||||
printf("\n\nCaution! Your devices Erase group is 0x%x\n"
|
||||
"The erase range would be change to "
|
||||
"0x" LBAF "~0x" LBAF "\n\n",
|
||||
mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),
|
||||
((start + blkcnt + mmc->erase_grp_size)
|
||||
& ~(mmc->erase_grp_size - 1)) - 1);
|
||||
|
||||
while (blk < blkcnt) {
|
||||
blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
|
||||
mmc->erase_grp_size : (blkcnt - blk);
|
||||
err = mmc_erase_t(mmc, start + blk, blk_r);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
blk += blk_r;
|
||||
|
||||
/* Waiting for the ready status */
|
||||
if (mmc_send_status(mmc, timeout))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return blk;
|
||||
}
|
||||
|
||||
static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start,
|
||||
lbaint_t blkcnt, const void *src)
|
||||
{
|
||||
struct mmc_cmd cmd;
|
||||
struct mmc_data data;
|
||||
int timeout = 1000;
|
||||
|
||||
if ((start + blkcnt) > mmc->block_dev.lba) {
|
||||
printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
|
||||
start + blkcnt, mmc->block_dev.lba);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (blkcnt == 0)
|
||||
return 0;
|
||||
else if (blkcnt == 1)
|
||||
cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
|
||||
else
|
||||
cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
|
||||
|
||||
if (mmc->high_capacity)
|
||||
cmd.cmdarg = start;
|
||||
else
|
||||
cmd.cmdarg = start * mmc->write_bl_len;
|
||||
|
||||
cmd.resp_type = MMC_RSP_R1;
|
||||
|
||||
data.src = src;
|
||||
data.blocks = blkcnt;
|
||||
data.blocksize = mmc->write_bl_len;
|
||||
data.flags = MMC_DATA_WRITE;
|
||||
|
||||
if (mmc_send_cmd(mmc, &cmd, &data)) {
|
||||
printf("mmc write failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* SPI multiblock writes terminate using a special
|
||||
* token, not a STOP_TRANSMISSION request.
|
||||
*/
|
||||
if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
|
||||
cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
|
||||
cmd.cmdarg = 0;
|
||||
cmd.resp_type = MMC_RSP_R1b;
|
||||
if (mmc_send_cmd(mmc, &cmd, NULL)) {
|
||||
printf("mmc fail to send stop cmd\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Waiting for the ready status */
|
||||
if (mmc_send_status(mmc, timeout))
|
||||
return 0;
|
||||
|
||||
return blkcnt;
|
||||
}
|
||||
|
||||
ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void *src)
|
||||
{
|
||||
lbaint_t cur, blocks_todo = blkcnt;
|
||||
|
||||
struct mmc *mmc = find_mmc_device(dev_num);
|
||||
if (!mmc)
|
||||
return 0;
|
||||
|
||||
if (mmc_set_blocklen(mmc, mmc->write_bl_len))
|
||||
return 0;
|
||||
|
||||
do {
|
||||
cur = (blocks_todo > mmc->b_max) ? mmc->b_max : blocks_todo;
|
||||
if (mmc_write_blocks(mmc, start, cur, src) != cur)
|
||||
return 0;
|
||||
blocks_todo -= cur;
|
||||
start += cur;
|
||||
src += cur * mmc->write_bl_len;
|
||||
} while (blocks_todo > 0);
|
||||
|
||||
return blkcnt;
|
||||
}
|
@ -288,6 +288,30 @@ static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit)
|
||||
|
||||
mmc_reg_out(&mmc_base->sysctl, bit, bit);
|
||||
|
||||
/*
|
||||
* CMD(DAT) lines reset procedures are slightly different
|
||||
* for OMAP3 and OMAP4(AM335x,OMAP5,DRA7xx).
|
||||
* According to OMAP3 TRM:
|
||||
* Set SRC(SRD) bit in MMCHS_SYSCTL register to 0x1 and wait until it
|
||||
* returns to 0x0.
|
||||
* According to OMAP4(AM335x,OMAP5,DRA7xx) TRMs, CMD(DATA) lines reset
|
||||
* procedure steps must be as follows:
|
||||
* 1. Initiate CMD(DAT) line reset by writing 0x1 to SRC(SRD) bit in
|
||||
* MMCHS_SYSCTL register (SD_SYSCTL for AM335x).
|
||||
* 2. Poll the SRC(SRD) bit until it is set to 0x1.
|
||||
* 3. Wait until the SRC (SRD) bit returns to 0x0
|
||||
* (reset procedure is completed).
|
||||
*/
|
||||
#if defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
|
||||
defined(CONFIG_AM33XX)
|
||||
if (!(readl(&mmc_base->sysctl) & bit)) {
|
||||
start = get_timer(0);
|
||||
while (!(readl(&mmc_base->sysctl) & bit)) {
|
||||
if (get_timer(0) - start > MAX_RETRY_MS)
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
start = get_timer(0);
|
||||
while ((readl(&mmc_base->sysctl) & bit) != 0) {
|
||||
if (get_timer(0) - start > MAX_RETRY_MS) {
|
||||
@ -376,6 +400,7 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||
}
|
||||
|
||||
writel(cmd->cmdarg, &mmc_base->arg);
|
||||
udelay(20); /* To fix "No status update" error on eMMC */
|
||||
writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd);
|
||||
|
||||
start = get_timer(0);
|
||||
@ -480,7 +505,7 @@ static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
|
||||
unsigned int count;
|
||||
|
||||
/*
|
||||
* Start Polled Read
|
||||
* Start Polled Write
|
||||
*/
|
||||
count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
|
||||
count /= 4;
|
||||
@ -586,6 +611,8 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
|
||||
{
|
||||
struct mmc *mmc = &hsmmc_dev[dev_index];
|
||||
struct omap_hsmmc_data *priv_data = &hsmmc_dev_data[dev_index];
|
||||
uint host_caps_val = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS |
|
||||
MMC_MODE_HC;
|
||||
|
||||
sprintf(mmc->name, "OMAP SD/MMC");
|
||||
mmc->send_cmd = mmc_send_cmd;
|
||||
@ -600,11 +627,20 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
|
||||
#ifdef OMAP_HSMMC2_BASE
|
||||
case 1:
|
||||
priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE;
|
||||
#if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
|
||||
defined(CONFIG_DRA7XX)) && defined(CONFIG_HSMMC2_8BIT)
|
||||
/* Enable 8-bit interface for eMMC on OMAP4/5 or DRA7XX */
|
||||
host_caps_val |= MMC_MODE_8BIT;
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
#ifdef OMAP_HSMMC3_BASE
|
||||
case 2:
|
||||
priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE;
|
||||
#if defined(CONFIG_DRA7XX) && defined(CONFIG_HSMMC3_8BIT)
|
||||
/* Enable 8-bit interface for eMMC on DRA7XX */
|
||||
host_caps_val |= MMC_MODE_8BIT;
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
@ -620,8 +656,7 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
|
||||
mmc->getwp = omap_mmc_getwp;
|
||||
|
||||
mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
|
||||
mmc->host_caps = (MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS |
|
||||
MMC_MODE_HC) & ~host_caps_mask;
|
||||
mmc->host_caps = host_caps_val & ~host_caps_mask;
|
||||
|
||||
mmc->f_min = 400000;
|
||||
|
||||
|
@ -72,7 +72,7 @@ int s5p_sdhci_init(u32 regbase, int index, int bus_width)
|
||||
|
||||
host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE |
|
||||
SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR |
|
||||
SDHCI_QUIRK_WAIT_SEND_CMD;
|
||||
SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_USE_WIDE8;
|
||||
host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
|
||||
host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
|
||||
|
||||
@ -81,6 +81,8 @@ int s5p_sdhci_init(u32 regbase, int index, int bus_width)
|
||||
host->index = index;
|
||||
|
||||
host->host_caps = MMC_MODE_HC;
|
||||
if (bus_width == 8)
|
||||
host->host_caps |= MMC_MODE_8BIT;
|
||||
|
||||
return add_sdhci(host, 52000000, 400000);
|
||||
}
|
||||
|
@ -68,10 +68,9 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
|
||||
unsigned int stat, rdy, mask, timeout, block = 0;
|
||||
#ifdef CONFIG_MMC_SDMA
|
||||
unsigned char ctrl;
|
||||
ctrl = sdhci_readl(host, SDHCI_HOST_CONTROL);
|
||||
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
|
||||
ctrl &= ~SDHCI_CTRL_DMA_MASK;
|
||||
ctrl |= SDHCI_CTRL_SDMA;
|
||||
sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL);
|
||||
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
|
||||
#endif
|
||||
|
||||
timeout = 1000000;
|
||||
@ -254,7 +253,7 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
|
||||
if (clock == 0)
|
||||
return 0;
|
||||
|
||||
if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) {
|
||||
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
|
||||
/* Version 3.00 divisors must be a multiple of 2. */
|
||||
if (mmc->f_max <= clock)
|
||||
div = 1;
|
||||
@ -347,10 +346,11 @@ void sdhci_set_ios(struct mmc *mmc)
|
||||
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
|
||||
if (mmc->bus_width == 8) {
|
||||
ctrl &= ~SDHCI_CTRL_4BITBUS;
|
||||
if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300)
|
||||
if ((SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) ||
|
||||
(host->quirks & SDHCI_QUIRK_USE_WIDE8))
|
||||
ctrl |= SDHCI_CTRL_8BITBUS;
|
||||
} else {
|
||||
if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300)
|
||||
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
|
||||
ctrl &= ~SDHCI_CTRL_8BITBUS;
|
||||
if (mmc->bus_width == 4)
|
||||
ctrl |= SDHCI_CTRL_4BITBUS;
|
||||
@ -437,7 +437,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
|
||||
if (max_clk)
|
||||
mmc->f_max = max_clk;
|
||||
else {
|
||||
if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300)
|
||||
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
|
||||
mmc->f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK)
|
||||
>> SDHCI_CLOCK_BASE_SHIFT;
|
||||
else
|
||||
@ -452,7 +452,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
|
||||
if (min_clk)
|
||||
mmc->f_min = min_clk;
|
||||
else {
|
||||
if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300)
|
||||
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
|
||||
mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_300;
|
||||
else
|
||||
mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_200;
|
||||
@ -470,7 +470,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
|
||||
mmc->voltages |= host->voltages;
|
||||
|
||||
mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT;
|
||||
if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) {
|
||||
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
|
||||
if (caps & SDHCI_CAN_DO_8BIT)
|
||||
mmc->host_caps |= MMC_MODE_8BIT;
|
||||
}
|
||||
|
@ -1015,10 +1015,10 @@ static inline phys_addr_t map_to_sysmem(void *ptr)
|
||||
* of a function scoped static buffer. It can not be used to create a cache
|
||||
* line aligned global buffer.
|
||||
*/
|
||||
#define PAD_COUNT(s, pad) ((s - 1) / pad + 1)
|
||||
#define PAD_COUNT(s, pad) (((s) - 1) / (pad) + 1)
|
||||
#define PAD_SIZE(s, pad) (PAD_COUNT(s, pad) * pad)
|
||||
#define ALLOC_ALIGN_BUFFER_PAD(type, name, size, align, pad) \
|
||||
char __##name[ROUND(PAD_SIZE(size * sizeof(type), pad), align) \
|
||||
char __##name[ROUND(PAD_SIZE((size) * sizeof(type), pad), align) \
|
||||
+ (align - 1)]; \
|
||||
\
|
||||
type *name = (type *) ALIGN((uintptr_t)__##name, align)
|
||||
|
@ -335,7 +335,11 @@ int mmc_start_init(struct mmc *mmc);
|
||||
void mmc_set_preinit(struct mmc *mmc, int preinit);
|
||||
|
||||
#ifdef CONFIG_GENERIC_MMC
|
||||
#ifdef CONFIG_MMC_SPI
|
||||
#define mmc_host_is_spi(mmc) ((mmc)->host_caps & MMC_MODE_SPI)
|
||||
#else
|
||||
#define mmc_host_is_spi(mmc) 0
|
||||
#endif
|
||||
struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode);
|
||||
#else
|
||||
int mmc_legacy_init(int verbose);
|
||||
|
@ -192,6 +192,8 @@
|
||||
#define SDHCI_SPEC_200 1
|
||||
#define SDHCI_SPEC_300 2
|
||||
|
||||
#define SDHCI_GET_VERSION(x) (x->version & SDHCI_SPEC_VER_MASK)
|
||||
|
||||
/*
|
||||
* End of controller registers.
|
||||
*/
|
||||
@ -210,6 +212,7 @@
|
||||
#define SDHCI_QUIRK_NO_CD (1 << 5)
|
||||
#define SDHCI_QUIRK_WAIT_SEND_CMD (1 << 6)
|
||||
#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1 << 7)
|
||||
#define SDHCI_QUIRK_USE_WIDE8 (1 << 8)
|
||||
|
||||
/* to make gcc happy */
|
||||
struct sdhci_host;
|
||||
|
Loading…
Reference in New Issue
Block a user