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:
@@ -141,6 +141,11 @@
|
|||||||
#define OMAP_HSMMC_WRITE(base, reg, val) \
|
#define OMAP_HSMMC_WRITE(base, reg, val) \
|
||||||
__raw_writel((val), (base) + OMAP_HSMMC_##reg)
|
__raw_writel((val), (base) + OMAP_HSMMC_##reg)
|
||||||
|
|
||||||
|
struct omap_hsmmc_next {
|
||||||
|
unsigned int dma_len;
|
||||||
|
s32 cookie;
|
||||||
|
};
|
||||||
|
|
||||||
struct omap_hsmmc_host {
|
struct omap_hsmmc_host {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct mmc_host *mmc;
|
struct mmc_host *mmc;
|
||||||
@@ -184,6 +189,7 @@ struct omap_hsmmc_host {
|
|||||||
int reqs_blocked;
|
int reqs_blocked;
|
||||||
int use_reg;
|
int use_reg;
|
||||||
int req_in_progress;
|
int req_in_progress;
|
||||||
|
struct omap_hsmmc_next next_data;
|
||||||
|
|
||||||
struct omap_mmc_platform_data *pdata;
|
struct omap_mmc_platform_data *pdata;
|
||||||
};
|
};
|
||||||
@@ -1346,6 +1352,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!data->host_cookie)
|
||||||
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
|
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
|
||||||
omap_hsmmc_get_dma_dir(host, data));
|
omap_hsmmc_get_dma_dir(host, data));
|
||||||
|
|
||||||
@@ -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
|
* 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);
|
mmc_hostname(host->mmc), ret);
|
||||||
return 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_ch = dma_ch;
|
||||||
host->dma_sg_idx = 0;
|
host->dma_sg_idx = 0;
|
||||||
|
|
||||||
@@ -1480,6 +1527,35 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
|
|||||||
return 0;
|
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
|
* 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 = {
|
static const struct mmc_host_ops omap_hsmmc_ops = {
|
||||||
.enable = omap_hsmmc_enable_fclk,
|
.enable = omap_hsmmc_enable_fclk,
|
||||||
.disable = omap_hsmmc_disable_fclk,
|
.disable = omap_hsmmc_disable_fclk,
|
||||||
|
.post_req = omap_hsmmc_post_req,
|
||||||
|
.pre_req = omap_hsmmc_pre_req,
|
||||||
.request = omap_hsmmc_request,
|
.request = omap_hsmmc_request,
|
||||||
.set_ios = omap_hsmmc_set_ios,
|
.set_ios = omap_hsmmc_set_ios,
|
||||||
.get_cd = omap_hsmmc_get_cd,
|
.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->mapbase = res->start;
|
||||||
host->base = ioremap(host->mapbase, SZ_4K);
|
host->base = ioremap(host->mapbase, SZ_4K);
|
||||||
host->power_mode = MMC_POWER_OFF;
|
host->power_mode = MMC_POWER_OFF;
|
||||||
|
host->next_data.cookie = 1;
|
||||||
|
|
||||||
platform_set_drvdata(pdev, host);
|
platform_set_drvdata(pdev, host);
|
||||||
INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect);
|
INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect);
|
||||||
|
Reference in New Issue
Block a user