Commit d9288d0b authored by Kuninori Morimoto's avatar Kuninori Morimoto Committed by Mark Brown

ASoC: rsnd: SSI + DMA can select BUSIF

Sound data needs to be sent to R-Car sound SSI when playback.
But, there are 2 interfaces for it.
1st is SSITDR/SSIRDR which are mapped on SSI.
2nd is SSIn_BUSIF which are mapped on SSIU.

2nd SSIn_BUSIF is used when DMA transfer,
and it is always used if sound data came from via SRC.
But, we can use it when SSI+DMA case too.
(Current driver is assuming 1st SSITDR/SSIRDR for it)

2nd SSIn_BUSIF can be used as FIFO.
This is very helpful/useful for SSI+DMA.

But DMA address / DMA ID are not same between 1st/2nd cases.
This patch care about these settings.
Signed-off-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: default avatarMark Brown <broonie@linaro.org>
parent 8457e0e9
...@@ -21,6 +21,7 @@ SSI subnode properties: ...@@ -21,6 +21,7 @@ SSI subnode properties:
- interrupts : Should contain SSI interrupt for PIO transfer - interrupts : Should contain SSI interrupt for PIO transfer
- shared-pin : if shared clock pin - shared-pin : if shared clock pin
- pio-transfer : use PIO transfer mode - pio-transfer : use PIO transfer mode
- no-busif : BUSIF is not ussed when [mem -> SSI] via DMA case
SRC subnode properties: SRC subnode properties:
no properties at this point no properties at this point
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
* B : SSI direction * B : SSI direction
*/ */
#define RSND_SSI_CLK_PIN_SHARE (1 << 31) #define RSND_SSI_CLK_PIN_SHARE (1 << 31)
#define RSND_SSI_NO_BUSIF (1 << 30) /* SSI+DMA without BUSIF */
#define RSND_SSI(_dma_id, _pio_irq, _flags) \ #define RSND_SSI(_dma_id, _pio_irq, _flags) \
{ .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags } { .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
......
...@@ -138,6 +138,17 @@ char *rsnd_mod_name(struct rsnd_mod *mod) ...@@ -138,6 +138,17 @@ char *rsnd_mod_name(struct rsnd_mod *mod)
return mod->ops->name; return mod->ops->name;
} }
char *rsnd_mod_dma_name(struct rsnd_mod *mod)
{
if (!mod || !mod->ops)
return "unknown";
if (!mod->ops->dma_name)
return mod->ops->name;
return mod->ops->dma_name(mod);
}
void rsnd_mod_init(struct rsnd_priv *priv, void rsnd_mod_init(struct rsnd_priv *priv,
struct rsnd_mod *mod, struct rsnd_mod *mod,
struct rsnd_mod_ops *ops, struct rsnd_mod_ops *ops,
...@@ -261,7 +272,7 @@ static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod) ...@@ -261,7 +272,7 @@ static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod)
{ {
if (mod) if (mod)
return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d", return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d",
rsnd_mod_name(mod), rsnd_mod_id(mod)); rsnd_mod_dma_name(mod), rsnd_mod_id(mod));
else else
return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem"); return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem");
...@@ -343,11 +354,8 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, ...@@ -343,11 +354,8 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
dma_cap_zero(mask); dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask);
if (dev->of_node) rsnd_dma_of_name(dma, is_play, dma_name);
rsnd_dma_of_name(dma, is_play, dma_name); rsnd_gen_dma_addr(priv, dma, &cfg, is_play, id);
else
snprintf(dma_name, DMA_NAME_SIZE,
is_play ? "tx" : "rx");
dev_dbg(dev, "dma name : %s\n", dma_name); dev_dbg(dev, "dma name : %s\n", dma_name);
...@@ -359,8 +367,6 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, ...@@ -359,8 +367,6 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
return -EIO; return -EIO;
} }
rsnd_gen_dma_addr(priv, dma, &cfg, is_play, id);
ret = dmaengine_slave_config(dma->chan, &cfg); ret = dmaengine_slave_config(dma->chan, &cfg);
if (ret < 0) if (ret < 0)
goto rsnd_dma_init_err; goto rsnd_dma_init_err;
......
...@@ -165,15 +165,19 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv, ...@@ -165,15 +165,19 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv,
* *
* ex) R-Car H2 case * ex) R-Car H2 case
* mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out * mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out
* SSI : 0xec541000 / 0xec241008 / 0xec24100c / 0xec400000 / 0xec400000 * SSI : 0xec541000 / 0xec241008 / 0xec24100c
* SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000
* SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000 * SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000
* CMD : 0xec500000 / 0xec008000 0xec308000 * CMD : 0xec500000 / 0xec008000 0xec308000
*/ */
#define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8) #define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8)
#define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc) #define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc)
#define RDMA_SSI_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) #define RDMA_SSIU_I_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i))
#define RDMA_SSI_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) #define RDMA_SSIU_O_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i))
#define RDMA_SSIU_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i))
#define RDMA_SSIU_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i))
#define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i)) #define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i))
#define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) #define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i))
...@@ -204,26 +208,36 @@ static void rsnd_gen2_dma_addr(struct rsnd_priv *priv, ...@@ -204,26 +208,36 @@ static void rsnd_gen2_dma_addr(struct rsnd_priv *priv,
struct dma_addr { struct dma_addr {
dma_addr_t src_addr; dma_addr_t src_addr;
dma_addr_t dst_addr; dma_addr_t dst_addr;
} dma_addrs[2][2][3] = { } dma_addrs[3][2][3] = {
{ /* SRC */ /* SRC */
/* Capture */ {{{ 0, 0 },
{{ 0, 0 }, /* Capture */
{ RDMA_SRC_O_N(src, id), 0 }, { RDMA_SRC_O_N(src, id), 0 },
{ RDMA_CMD_O_N(src, id), 0 }}, { RDMA_CMD_O_N(src, id), 0 } },
/* Playback */ /* Playback */
{{ 0, 0, }, {{ 0, 0, },
{ 0, RDMA_SRC_I_N(src, id) }, { 0, RDMA_SRC_I_N(src, id) },
{ 0, RDMA_SRC_I_N(src, id) }} { 0, RDMA_SRC_I_N(src, id) } }
}, { /* SSI */ },
/* Capture */ /* SSI */
{{ RDMA_SSI_O_N(ssi, id), 0 }, /* Capture */
{ RDMA_SSI_O_P(ssi, id), RDMA_SRC_I_P(src, id) }, {{{ RDMA_SSI_O_N(ssi, id), 0 },
{ RDMA_SSI_O_P(ssi, id), RDMA_SRC_I_P(src, id) }}, { 0, 0 },
/* Playback */ { 0, 0 } },
{{ 0, RDMA_SSI_I_N(ssi, id) }, /* Playback */
{ RDMA_SRC_O_P(src, id), RDMA_SSI_I_P(ssi, id) }, {{ 0, RDMA_SSI_I_N(ssi, id) },
{ RDMA_CMD_O_P(src, id), RDMA_SSI_I_P(ssi, id) }} { 0, 0 },
} { 0, 0 } }
},
/* SSIU */
/* Capture */
{{{ RDMA_SSIU_O_N(ssi, id), 0 },
{ RDMA_SSIU_O_P(ssi, id), RDMA_SRC_I_P(src, id) },
{ RDMA_SSIU_O_P(ssi, id), RDMA_SRC_I_P(src, id) } },
/* Playback */
{{ 0, RDMA_SSIU_I_N(ssi, id) },
{ RDMA_SRC_O_P(src, id), RDMA_SSIU_I_P(ssi, id) },
{ RDMA_CMD_O_P(src, id), RDMA_SSIU_I_P(ssi, id) } } },
}; };
/* it shouldn't happen */ /* it shouldn't happen */
...@@ -232,6 +246,10 @@ static void rsnd_gen2_dma_addr(struct rsnd_priv *priv, ...@@ -232,6 +246,10 @@ static void rsnd_gen2_dma_addr(struct rsnd_priv *priv,
return; return;
} }
/* use SSIU or SSI ? */
if (is_ssi && (0 == strcmp(rsnd_mod_dma_name(mod), "ssiu")))
is_ssi++;
cfg->src_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].src_addr; cfg->src_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].src_addr;
cfg->dst_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].dst_addr; cfg->dst_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].dst_addr;
......
...@@ -185,6 +185,7 @@ enum rsnd_mod_type { ...@@ -185,6 +185,7 @@ enum rsnd_mod_type {
struct rsnd_mod_ops { struct rsnd_mod_ops {
char *name; char *name;
char* (*dma_name)(struct rsnd_mod *mod);
int (*probe)(struct rsnd_mod *mod, int (*probe)(struct rsnd_mod *mod,
struct rsnd_dai *rdai); struct rsnd_dai *rdai);
int (*remove)(struct rsnd_mod *mod, int (*remove)(struct rsnd_mod *mod,
...@@ -224,6 +225,7 @@ void rsnd_mod_init(struct rsnd_priv *priv, ...@@ -224,6 +225,7 @@ void rsnd_mod_init(struct rsnd_priv *priv,
enum rsnd_mod_type type, enum rsnd_mod_type type,
int id); int id);
char *rsnd_mod_name(struct rsnd_mod *mod); char *rsnd_mod_name(struct rsnd_mod *mod);
char *rsnd_mod_dma_name(struct rsnd_mod *mod);
/* /*
* R-Car sound DAI * R-Car sound DAI
...@@ -391,8 +393,12 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); ...@@ -391,8 +393,12 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
struct snd_pcm_runtime *runtime); struct snd_pcm_runtime *runtime);
int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai); struct rsnd_dai *rdai,
int use_busif);
int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai,
int use_busif);
int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod, int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai); struct rsnd_dai *rdai);
......
...@@ -106,18 +106,17 @@ struct rsnd_src { ...@@ -106,18 +106,17 @@ struct rsnd_src {
/* /*
* Gen1/Gen2 common functions * Gen1/Gen2 common functions
*/ */
int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai) struct rsnd_dai *rdai,
int use_busif)
{ {
struct rsnd_dai_stream *io = rsnd_mod_to_io(ssi_mod);
struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
int ssi_id = rsnd_mod_id(ssi_mod); int ssi_id = rsnd_mod_id(ssi_mod);
/* /*
* SSI_MODE0 * SSI_MODE0
*/ */
rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id), rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id),
src_mod ? 0 : (1 << ssi_id)); !use_busif << ssi_id);
/* /*
* SSI_MODE1 * SSI_MODE1
...@@ -143,6 +142,29 @@ int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, ...@@ -143,6 +142,29 @@ int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod,
0x2 << shift : 0x1 << shift); 0x2 << shift : 0x1 << shift);
} }
/*
* DMA settings for SSIU
*/
if (use_busif) {
rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR,
rsnd_get_adinr(ssi_mod));
rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1);
rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1);
}
return 0;
}
int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai,
int use_busif)
{
/*
* DMA settings for SSIU
*/
if (use_busif)
rsnd_mod_write(ssi_mod, SSI_CTRL, 0);
return 0; return 0;
} }
...@@ -467,9 +489,6 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, ...@@ -467,9 +489,6 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
if (ret < 0) if (ret < 0)
return ret; return ret;
rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_get_adinr(mod));
rsnd_mod_write(mod, SSI_BUSIF_MODE, 1);
rsnd_mod_write(mod, SRC_SRCCR, 0x00011110); rsnd_mod_write(mod, SRC_SRCCR, 0x00011110);
rsnd_mod_write(mod, SRC_BSDSR, 0x01800000); rsnd_mod_write(mod, SRC_BSDSR, 0x01800000);
...@@ -554,7 +573,6 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod, ...@@ -554,7 +573,6 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod,
rsnd_dma_start(rsnd_mod_to_dma(&src->mod)); rsnd_dma_start(rsnd_mod_to_dma(&src->mod));
rsnd_mod_write(mod, SSI_CTRL, 0x1);
rsnd_mod_write(mod, SRC_CTRL, val); rsnd_mod_write(mod, SRC_CTRL, val);
return rsnd_src_start(mod, rdai); return rsnd_src_start(mod, rdai);
...@@ -565,7 +583,6 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod, ...@@ -565,7 +583,6 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
{ {
struct rsnd_src *src = rsnd_mod_to_src(mod); struct rsnd_src *src = rsnd_mod_to_src(mod);
rsnd_mod_write(mod, SSI_CTRL, 0);
rsnd_mod_write(mod, SRC_CTRL, 0); rsnd_mod_write(mod, SRC_CTRL, 0);
rsnd_dma_stop(rsnd_mod_to_dma(&src->mod)); rsnd_dma_stop(rsnd_mod_to_dma(&src->mod));
......
...@@ -90,6 +90,20 @@ struct rsnd_ssi { ...@@ -90,6 +90,20 @@ struct rsnd_ssi {
#define rsnd_ssi_mode_flags(p) ((p)->info->flags) #define rsnd_ssi_mode_flags(p) ((p)->info->flags)
#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
static int rsnd_ssi_use_busif(struct rsnd_mod *mod)
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
int use_busif = 0;
if (!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_NO_BUSIF))
use_busif = 1;
if (rsnd_io_to_mod_src(io))
use_busif = 1;
return use_busif;
}
static void rsnd_ssi_status_check(struct rsnd_mod *mod, static void rsnd_ssi_status_check(struct rsnd_mod *mod,
u32 bit) u32 bit)
{ {
...@@ -289,8 +303,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, ...@@ -289,8 +303,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
ssi->cr_own = cr; ssi->cr_own = cr;
ssi->err = -1; /* ignore 1st error */ ssi->err = -1; /* ignore 1st error */
rsnd_src_ssi_mode_init(mod, rdai);
return 0; return 0;
} }
...@@ -389,6 +401,8 @@ static int rsnd_ssi_pio_start(struct rsnd_mod *mod, ...@@ -389,6 +401,8 @@ static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
/* enable PIO IRQ */ /* enable PIO IRQ */
ssi->cr_etc = UIEN | OIEN | DIEN; ssi->cr_etc = UIEN | OIEN | DIEN;
rsnd_src_ssiu_start(mod, rdai, 0);
rsnd_src_enable_ssi_irq(mod, rdai); rsnd_src_enable_ssi_irq(mod, rdai);
rsnd_ssi_hw_start(ssi, rdai, io); rsnd_ssi_hw_start(ssi, rdai, io);
...@@ -405,6 +419,8 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, ...@@ -405,6 +419,8 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
rsnd_ssi_hw_stop(ssi, rdai); rsnd_ssi_hw_stop(ssi, rdai);
rsnd_src_ssiu_stop(mod, rdai, 0);
return 0; return 0;
} }
...@@ -457,6 +473,8 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod, ...@@ -457,6 +473,8 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
/* enable DMA transfer */ /* enable DMA transfer */
ssi->cr_etc = DMEN; ssi->cr_etc = DMEN;
rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod));
rsnd_dma_start(dma); rsnd_dma_start(dma);
rsnd_ssi_hw_start(ssi, ssi->rdai, io); rsnd_ssi_hw_start(ssi, ssi->rdai, io);
...@@ -482,11 +500,19 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, ...@@ -482,11 +500,19 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
rsnd_dma_stop(dma); rsnd_dma_stop(dma);
rsnd_src_ssiu_stop(mod, rdai, 1);
return 0; return 0;
} }
static char *rsnd_ssi_dma_name(struct rsnd_mod *mod)
{
return rsnd_ssi_use_busif(mod) ? "ssiu" : SSI_NAME;
}
static struct rsnd_mod_ops rsnd_ssi_dma_ops = { static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
.name = SSI_NAME, .name = SSI_NAME,
.dma_name = rsnd_ssi_dma_name,
.probe = rsnd_ssi_dma_probe, .probe = rsnd_ssi_dma_probe,
.remove = rsnd_ssi_dma_remove, .remove = rsnd_ssi_dma_remove,
.init = rsnd_ssi_init, .init = rsnd_ssi_init,
...@@ -595,6 +621,9 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev, ...@@ -595,6 +621,9 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev,
*/ */
ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ? ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ?
0 : 1; 0 : 1;
if (of_get_property(np, "no-busif", NULL))
ssi_info->flags |= RSND_SSI_NO_BUSIF;
} }
rsnd_of_parse_ssi_end: rsnd_of_parse_ssi_end:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment