提交 9782aff8 编写于 作者: P Per Forlin 提交者: Chris Ball

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: NPer Forlin <per.forlin@linaro.org>
Reviewed-by: NVenkatraman S <svenkatr@ti.com>
Tested-by: NSourav Poddar <sourav.poddar@ti.com>
Signed-off-by: NChris Ball <cjb@laptop.org>
上级 aa8b683a
...@@ -141,6 +141,11 @@ ...@@ -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 { ...@@ -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,8 +1352,9 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) ...@@ -1346,8 +1352,9 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
return; return;
} }
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, if (!data->host_cookie)
omap_hsmmc_get_dma_dir(host, data)); 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; req_in_progress = host->req_in_progress;
dma_ch = host->dma_ch; dma_ch = host->dma_ch;
...@@ -1365,6 +1372,45 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册