mmc: omap_hsmmc: add support for pre_req and post_req
pre_req() runs dma_map_sg(), post_req() runs dma_unmap_sg. If not calling pre_req() before omap_hsmmc_request(), dma_map_sg will be issued before starting the transfer. It is optional to use pre_req(). If issuing pre_req(), post_req() must be called as well. Signed-off-by: Per Forlin <per.forlin@linaro.org> Reviewed-by: Venkatraman S <svenkatr@ti.com> Tested-by: Sourav Poddar <sourav.poddar@ti.com> Signed-off-by: Chris Ball <cjb@laptop.org>
This commit is contained in:
Родитель
aa8b683a7d
Коммит
9782aff8df
|
@ -141,6 +141,11 @@
|
|||
#define OMAP_HSMMC_WRITE(base, reg, val) \
|
||||
__raw_writel((val), (base) + OMAP_HSMMC_##reg)
|
||||
|
||||
struct omap_hsmmc_next {
|
||||
unsigned int dma_len;
|
||||
s32 cookie;
|
||||
};
|
||||
|
||||
struct omap_hsmmc_host {
|
||||
struct device *dev;
|
||||
struct mmc_host *mmc;
|
||||
|
@ -184,6 +189,7 @@ struct omap_hsmmc_host {
|
|||
int reqs_blocked;
|
||||
int use_reg;
|
||||
int req_in_progress;
|
||||
struct omap_hsmmc_next next_data;
|
||||
|
||||
struct omap_mmc_platform_data *pdata;
|
||||
};
|
||||
|
@ -1346,8 +1352,9 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
|
|||
return;
|
||||
}
|
||||
|
||||
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
|
||||
omap_hsmmc_get_dma_dir(host, data));
|
||||
if (!data->host_cookie)
|
||||
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
|
||||
omap_hsmmc_get_dma_dir(host, data));
|
||||
|
||||
req_in_progress = host->req_in_progress;
|
||||
dma_ch = host->dma_ch;
|
||||
|
@ -1365,6 +1372,45 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
|
|||
}
|
||||
}
|
||||
|
||||
static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
|
||||
struct mmc_data *data,
|
||||
struct omap_hsmmc_next *next)
|
||||
{
|
||||
int dma_len;
|
||||
|
||||
if (!next && data->host_cookie &&
|
||||
data->host_cookie != host->next_data.cookie) {
|
||||
printk(KERN_WARNING "[%s] invalid cookie: data->host_cookie %d"
|
||||
" host->next_data.cookie %d\n",
|
||||
__func__, data->host_cookie, host->next_data.cookie);
|
||||
data->host_cookie = 0;
|
||||
}
|
||||
|
||||
/* Check if next job is already prepared */
|
||||
if (next ||
|
||||
(!next && data->host_cookie != host->next_data.cookie)) {
|
||||
dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
|
||||
data->sg_len,
|
||||
omap_hsmmc_get_dma_dir(host, data));
|
||||
|
||||
} else {
|
||||
dma_len = host->next_data.dma_len;
|
||||
host->next_data.dma_len = 0;
|
||||
}
|
||||
|
||||
|
||||
if (dma_len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (next) {
|
||||
next->dma_len = dma_len;
|
||||
data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
|
||||
} else
|
||||
host->dma_len = dma_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to configure and start DMA for the MMC card
|
||||
*/
|
||||
|
@ -1398,9 +1444,10 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
|
|||
mmc_hostname(host->mmc), ret);
|
||||
return ret;
|
||||
}
|
||||
ret = omap_hsmmc_pre_dma_transfer(host, data, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
|
||||
data->sg_len, omap_hsmmc_get_dma_dir(host, data));
|
||||
host->dma_ch = dma_ch;
|
||||
host->dma_sg_idx = 0;
|
||||
|
||||
|
@ -1480,6 +1527,35 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
|
||||
int err)
|
||||
{
|
||||
struct omap_hsmmc_host *host = mmc_priv(mmc);
|
||||
struct mmc_data *data = mrq->data;
|
||||
|
||||
if (host->use_dma) {
|
||||
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
|
||||
omap_hsmmc_get_dma_dir(host, data));
|
||||
data->host_cookie = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
|
||||
bool is_first_req)
|
||||
{
|
||||
struct omap_hsmmc_host *host = mmc_priv(mmc);
|
||||
|
||||
if (mrq->data->host_cookie) {
|
||||
mrq->data->host_cookie = 0;
|
||||
return ;
|
||||
}
|
||||
|
||||
if (host->use_dma)
|
||||
if (omap_hsmmc_pre_dma_transfer(host, mrq->data,
|
||||
&host->next_data))
|
||||
mrq->data->host_cookie = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Request function. for read/write operation
|
||||
*/
|
||||
|
@ -1928,6 +2004,8 @@ static int omap_hsmmc_disable_fclk(struct mmc_host *mmc, int lazy)
|
|||
static const struct mmc_host_ops omap_hsmmc_ops = {
|
||||
.enable = omap_hsmmc_enable_fclk,
|
||||
.disable = omap_hsmmc_disable_fclk,
|
||||
.post_req = omap_hsmmc_post_req,
|
||||
.pre_req = omap_hsmmc_pre_req,
|
||||
.request = omap_hsmmc_request,
|
||||
.set_ios = omap_hsmmc_set_ios,
|
||||
.get_cd = omap_hsmmc_get_cd,
|
||||
|
@ -2077,6 +2155,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
|
|||
host->mapbase = res->start;
|
||||
host->base = ioremap(host->mapbase, SZ_4K);
|
||||
host->power_mode = MMC_POWER_OFF;
|
||||
host->next_data.cookie = 1;
|
||||
|
||||
platform_set_drvdata(pdev, host);
|
||||
INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect);
|
||||
|
|
Загрузка…
Ссылка в новой задаче