summaryrefslogtreecommitdiffstats
path: root/sound/soc/sh/rcar/dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sh/rcar/dma.c')
-rw-r--r--sound/soc/sh/rcar/dma.c128
1 files changed, 87 insertions, 41 deletions
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index d306e298c63d..bfbb8a5e93bd 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -27,6 +27,15 @@ struct rsnd_dma_ctrl {
int dmapp_num;
};
+struct rsnd_dma_ops {
+ char *name;
+ void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
+ void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
+ int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id,
+ struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
+ void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
+};
+
#define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma)
/*
@@ -168,7 +177,7 @@ static int rsnd_dmaen_init(struct rsnd_dai_stream *io,
dma_cap_set(DMA_SLAVE, mask);
dmaen->chan = dma_request_channel(mask, shdma_chan_filter,
- (void *)id);
+ (void *)(uintptr_t)id);
}
if (IS_ERR_OR_NULL(dmaen->chan)) {
dmaen->chan = NULL;
@@ -182,7 +191,8 @@ static int rsnd_dmaen_init(struct rsnd_dai_stream *io,
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- dev_dbg(dev, "dma : %pad -> %pad\n",
+ dev_dbg(dev, "%s %pad -> %pad\n",
+ dma->ops->name,
&cfg.src_addr, &cfg.dst_addr);
ret = dmaengine_slave_config(dmaen->chan, &cfg);
@@ -215,6 +225,7 @@ static void rsnd_dmaen_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
}
static struct rsnd_dma_ops rsnd_dmaen_ops = {
+ .name = "audmac",
.start = rsnd_dmaen_start,
.stop = rsnd_dmaen_stop,
.init = rsnd_dmaen_init,
@@ -360,6 +371,7 @@ static int rsnd_dmapp_init(struct rsnd_dai_stream *io,
}
static struct rsnd_dma_ops rsnd_dmapp_ops = {
+ .name = "audmac-pp",
.start = rsnd_dmapp_start,
.stop = rsnd_dmapp_stop,
.init = rsnd_dmapp_init,
@@ -414,7 +426,9 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU);
int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod);
int use_src = !!rsnd_io_to_mod_src(io);
- int use_dvc = !!rsnd_io_to_mod_dvc(io);
+ int use_cmd = !!rsnd_io_to_mod_dvc(io) ||
+ !!rsnd_io_to_mod_mix(io) ||
+ !!rsnd_io_to_mod_ctu(io);
int id = rsnd_mod_id(mod);
struct dma_addr {
dma_addr_t out_addr;
@@ -452,7 +466,7 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
};
/* it shouldn't happen */
- if (use_dvc && !use_src)
+ if (use_cmd && !use_src)
dev_err(dev, "DVC is selected without SRC\n");
/* use SSIU or SSI ? */
@@ -460,8 +474,8 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
is_ssi++;
return (is_from) ?
- dma_addrs[is_ssi][is_play][use_src + use_dvc].out_addr :
- dma_addrs[is_ssi][is_play][use_src + use_dvc].in_addr;
+ dma_addrs[is_ssi][is_play][use_src + use_cmd].out_addr :
+ dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr;
}
static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
@@ -482,7 +496,7 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
return rsnd_gen2_dma_addr(io, mod, is_play, is_from);
}
-#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */
+#define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */
static void rsnd_dma_of_path(struct rsnd_dma *dma,
struct rsnd_dai_stream *io,
int is_play,
@@ -492,55 +506,81 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
struct rsnd_mod *this = rsnd_dma_to_mod(dma);
struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+ struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io);
+ struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
struct rsnd_mod *mod[MOD_MAX];
- int i, index;
+ struct rsnd_mod *mod_start, *mod_end;
+ struct rsnd_priv *priv = rsnd_mod_to_priv(this);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ int nr, i;
+ if (!ssi)
+ return;
- for (i = 0; i < MOD_MAX; i++)
+ nr = 0;
+ for (i = 0; i < MOD_MAX; i++) {
mod[i] = NULL;
+ nr += !!rsnd_io_to_mod(io, i);
+ }
/*
- * in play case...
+ * [S] -*-> [E]
+ * [S] -*-> SRC -o-> [E]
+ * [S] -*-> SRC -> DVC -o-> [E]
+ * [S] -*-> SRC -> CTU -> MIX -> DVC -o-> [E]
*
- * src -> dst
+ * playback [S] = mem
+ * [E] = SSI
*
- * mem -> SSI
- * mem -> SRC -> SSI
- * mem -> SRC -> DVC -> SSI
+ * capture [S] = SSI
+ * [E] = mem
+ *
+ * -*-> Audio DMAC
+ * -o-> Audio DMAC peri peri
*/
- mod[0] = NULL; /* for "mem" */
- index = 1;
- for (i = 1; i < MOD_MAX; i++) {
- if (!src) {
- mod[i] = ssi;
- } else if (!dvc) {
- mod[i] = src;
- src = NULL;
- } else {
- if ((!is_play) && (this == src))
- this = dvc;
+ mod_start = (is_play) ? NULL : ssi;
+ mod_end = (is_play) ? ssi : NULL;
- mod[i] = (is_play) ? src : dvc;
- i++;
- mod[i] = (is_play) ? dvc : src;
+ mod[0] = mod_start;
+ for (i = 1; i < nr; i++) {
+ if (src) {
+ mod[i] = src;
src = NULL;
+ } else if (ctu) {
+ mod[i] = ctu;
+ ctu = NULL;
+ } else if (mix) {
+ mod[i] = mix;
+ mix = NULL;
+ } else if (dvc) {
+ mod[i] = dvc;
dvc = NULL;
}
-
- if (mod[i] == this)
- index = i;
-
- if (mod[i] == ssi)
- break;
}
+ mod[i] = mod_end;
- if (is_play) {
- *mod_from = mod[index - 1];
- *mod_to = mod[index];
+ /*
+ * | SSI | SRC |
+ * -------------+-----+-----+
+ * is_play | o | * |
+ * !is_play | * | o |
+ */
+ if ((this == ssi) == (is_play)) {
+ *mod_from = mod[nr - 1];
+ *mod_to = mod[nr];
} else {
- *mod_from = mod[index];
- *mod_to = mod[index - 1];
+ *mod_from = mod[0];
+ *mod_to = mod[1];
+ }
+
+ dev_dbg(dev, "module connection (this is %s[%d])\n",
+ rsnd_mod_name(this), rsnd_mod_id(this));
+ for (i = 0; i <= nr; i++) {
+ dev_dbg(dev, " %s[%d]%s\n",
+ rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]),
+ (mod[i] == *mod_from) ? " from" :
+ (mod[i] == *mod_to) ? " to" : "");
}
}
@@ -568,10 +608,11 @@ void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id)
{
- struct rsnd_mod *mod_from;
- struct rsnd_mod *mod_to;
+ struct rsnd_mod *mod_from = NULL;
+ struct rsnd_mod *mod_to = NULL;
struct rsnd_priv *priv = rsnd_io_to_priv(io);
struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+ struct device *dev = rsnd_priv_to_dev(priv);
int is_play = rsnd_io_is_play(io);
/*
@@ -598,6 +639,11 @@ int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id)
if (rsnd_is_gen1(priv))
dma->ops = &rsnd_dmaen_ops;
+ dev_dbg(dev, "%s %s[%d] -> %s[%d]\n",
+ dma->ops->name,
+ rsnd_mod_name(mod_from), rsnd_mod_id(mod_from),
+ rsnd_mod_name(mod_to), rsnd_mod_id(mod_to));
+
return dma->ops->init(io, dma, id, mod_from, mod_to);
}