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

ASoC: rsnd: add R-Car Gen4 Sound support

This patch is tested on V4H White Hawk + ARD-AUDIO-DA7212
Signed-off-by: default avatarLinh Phung <linh.phung.jy@renesas.com>
Signed-off-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87o7qe5ej5.wl-kuninori.morimoto.gx@renesas.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent f76fec60
...@@ -57,6 +57,10 @@ struct rsnd_adg { ...@@ -57,6 +57,10 @@ struct rsnd_adg {
i++) i++)
#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg) #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
static const char * const clkin_name_gen4[] = {
[CLKA] = "clkin",
};
static const char * const clkin_name_gen2[] = { static const char * const clkin_name_gen2[] = {
[CLKA] = "clk_a", [CLKA] = "clk_a",
[CLKB] = "clk_b", [CLKB] = "clk_b",
...@@ -435,6 +439,10 @@ static int rsnd_adg_get_clkin(struct rsnd_priv *priv) ...@@ -435,6 +439,10 @@ static int rsnd_adg_get_clkin(struct rsnd_priv *priv)
clkin_name = clkin_name_gen2; clkin_name = clkin_name_gen2;
clkin_size = ARRAY_SIZE(clkin_name_gen2); clkin_size = ARRAY_SIZE(clkin_name_gen2);
if (rsnd_is_gen4(priv)) {
clkin_name = clkin_name_gen4;
clkin_size = ARRAY_SIZE(clkin_name_gen4);
}
for (i = 0; i < clkin_size; i++) { for (i = 0; i < clkin_size; i++) {
clk = devm_clk_get(dev, clkin_name[i]); clk = devm_clk_get(dev, clkin_name[i]);
...@@ -568,6 +576,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) ...@@ -568,6 +576,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
clkout_name = clkout_name_gen2; clkout_name = clkout_name_gen2;
clkout_size = ARRAY_SIZE(clkout_name_gen2); clkout_size = ARRAY_SIZE(clkout_name_gen2);
if (rsnd_is_gen4(priv))
clkout_size = 1; /* reuse clkout_name_gen2[] */
/* /*
* ADG supports BRRA/BRRB output only. * ADG supports BRRA/BRRB output only.
......
...@@ -102,6 +102,7 @@ static const struct of_device_id rsnd_of_match[] = { ...@@ -102,6 +102,7 @@ static const struct of_device_id rsnd_of_match[] = {
{ .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 }, { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 },
{ .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 }, { .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 },
{ .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN3 }, { .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN3 },
{ .compatible = "renesas,rcar_sound-gen4", .data = (void *)RSND_GEN4 },
/* Special Handling */ /* Special Handling */
{ .compatible = "renesas,rcar_sound-r8a77990", .data = (void *)(RSND_GEN3 | RSND_SOC_E) }, { .compatible = "renesas,rcar_sound-r8a77990", .data = (void *)(RSND_GEN3 | RSND_SOC_E) },
{}, {},
...@@ -1467,7 +1468,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) ...@@ -1467,7 +1468,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
if (is_graph) { if (is_graph) {
for_each_endpoint_of_node(dai_node, dai_np) { for_each_endpoint_of_node(dai_node, dai_np) {
__rsnd_dai_probe(priv, dai_np, dai_i); __rsnd_dai_probe(priv, dai_np, dai_i);
if (rsnd_is_gen3(priv)) { if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
rdai = rsnd_rdai_get(priv, dai_i); rdai = rsnd_rdai_get(priv, dai_i);
rsnd_parse_connect_graph(priv, &rdai->playback, dai_np); rsnd_parse_connect_graph(priv, &rdai->playback, dai_np);
...@@ -1478,7 +1479,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) ...@@ -1478,7 +1479,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
} else { } else {
for_each_child_of_node(dai_node, dai_np) { for_each_child_of_node(dai_node, dai_np) {
__rsnd_dai_probe(priv, dai_np, dai_i); __rsnd_dai_probe(priv, dai_np, dai_i);
if (rsnd_is_gen3(priv)) { if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
rdai = rsnd_rdai_get(priv, dai_i); rdai = rsnd_rdai_get(priv, dai_i);
rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); rsnd_parse_connect_simple(priv, &rdai->playback, dai_np);
......
...@@ -653,6 +653,36 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, ...@@ -653,6 +653,36 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr; dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr;
} }
/*
* Gen4 DMA read/write register offset
*
* ex) R-Car V4H case
* mod / SYS-DMAC in / SYS-DMAC out
* SSI_SDMC: 0xec400000 / 0xec400000 / 0xec400000
*/
#define RDMA_SSI_SDMC(addr, i) (addr + (0x8000 * i))
static dma_addr_t
rsnd_gen4_dma_addr(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
int is_play, int is_from)
{
struct rsnd_priv *priv = rsnd_io_to_priv(io);
phys_addr_t addr = rsnd_gen_get_phy_addr(priv, RSND_GEN4_SDMC);
int id = rsnd_mod_id(mod);
int busif = rsnd_mod_id_sub(mod);
/*
* SSI0 only is supported
*/
if (id != 0) {
struct device *dev = rsnd_priv_to_dev(priv);
dev_err(dev, "This driver doesn't support non SSI0");
return -EINVAL;
}
return RDMA_SSI_SDMC(addr, busif);
}
static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io, static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
struct rsnd_mod *mod, struct rsnd_mod *mod,
int is_play, int is_from) int is_play, int is_from)
...@@ -667,6 +697,8 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io, ...@@ -667,6 +697,8 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
*/ */
if (rsnd_is_gen1(priv)) if (rsnd_is_gen1(priv))
return 0; return 0;
else if (rsnd_is_gen4(priv))
return rsnd_gen4_dma_addr(io, mod, is_play, is_from);
else else
return rsnd_gen2_dma_addr(io, mod, is_play, is_from); return rsnd_gen2_dma_addr(io, mod, is_play, is_from);
} }
...@@ -891,6 +923,10 @@ int rsnd_dma_probe(struct rsnd_priv *priv) ...@@ -891,6 +923,10 @@ int rsnd_dma_probe(struct rsnd_priv *priv)
return 0; /* it will be PIO mode */ return 0; /* it will be PIO mode */
} }
/* for Gen4 doesn't have DMA-pp */
if (rsnd_is_gen4(priv))
goto audmapp_end;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audmapp"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audmapp");
if (!res) { if (!res) {
dev_err(dev, "lack of audmapp in DT\n"); dev_err(dev, "lack of audmapp in DT\n");
...@@ -902,7 +938,7 @@ int rsnd_dma_probe(struct rsnd_priv *priv) ...@@ -902,7 +938,7 @@ int rsnd_dma_probe(struct rsnd_priv *priv)
dmac->ppbase = devm_ioremap_resource(dev, res); dmac->ppbase = devm_ioremap_resource(dev, res);
if (IS_ERR(dmac->ppbase)) if (IS_ERR(dmac->ppbase))
return PTR_ERR(dmac->ppbase); return PTR_ERR(dmac->ppbase);
audmapp_end:
priv->dma = dmac; priv->dma = dmac;
/* dummy mem mod for debug */ /* dummy mem mod for debug */
......
...@@ -215,6 +215,74 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, ...@@ -215,6 +215,74 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
return 0; return 0;
} }
/*
* Gen4
*/
static int rsnd_gen4_probe(struct rsnd_priv *priv)
{
static const struct rsnd_regmap_field_conf conf_ssiu[] = {
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0, 0x850),
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858),
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4, 0x890),
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6, 0x898),
RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840),
RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848),
RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880),
RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888),
RSND_GEN_S_REG(SSI_BUSIF0_MODE, 0x0),
RSND_GEN_S_REG(SSI_BUSIF0_ADINR, 0x4),
RSND_GEN_S_REG(SSI_BUSIF0_DALIGN, 0x8),
RSND_GEN_S_REG(SSI_BUSIF1_MODE, 0x20),
RSND_GEN_S_REG(SSI_BUSIF1_ADINR, 0x24),
RSND_GEN_S_REG(SSI_BUSIF1_DALIGN, 0x28),
RSND_GEN_S_REG(SSI_BUSIF2_MODE, 0x40),
RSND_GEN_S_REG(SSI_BUSIF2_ADINR, 0x44),
RSND_GEN_S_REG(SSI_BUSIF2_DALIGN, 0x48),
RSND_GEN_S_REG(SSI_BUSIF3_MODE, 0x60),
RSND_GEN_S_REG(SSI_BUSIF3_ADINR, 0x64),
RSND_GEN_S_REG(SSI_BUSIF3_DALIGN, 0x68),
RSND_GEN_S_REG(SSI_BUSIF4_MODE, 0x500),
RSND_GEN_S_REG(SSI_BUSIF4_ADINR, 0x504),
RSND_GEN_S_REG(SSI_BUSIF4_DALIGN, 0x508),
RSND_GEN_S_REG(SSI_BUSIF5_MODE, 0x520),
RSND_GEN_S_REG(SSI_BUSIF5_ADINR, 0x524),
RSND_GEN_S_REG(SSI_BUSIF5_DALIGN, 0x528),
RSND_GEN_S_REG(SSI_BUSIF6_MODE, 0x540),
RSND_GEN_S_REG(SSI_BUSIF6_ADINR, 0x544),
RSND_GEN_S_REG(SSI_BUSIF6_DALIGN, 0x548),
RSND_GEN_S_REG(SSI_BUSIF7_MODE, 0x560),
RSND_GEN_S_REG(SSI_BUSIF7_ADINR, 0x564),
RSND_GEN_S_REG(SSI_BUSIF7_DALIGN, 0x568),
RSND_GEN_S_REG(SSI_CTRL, 0x010),
RSND_GEN_S_REG(SSI_INT_ENABLE, 0x018),
RSND_GEN_S_REG(SSI_MODE, 0x00c),
RSND_GEN_S_REG(SSI_MODE2, 0xa0c),
};
static const struct rsnd_regmap_field_conf conf_adg[] = {
RSND_GEN_S_REG(BRRA, 0x00),
RSND_GEN_S_REG(BRRB, 0x04),
RSND_GEN_S_REG(BRGCKR, 0x08),
RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
};
static const struct rsnd_regmap_field_conf conf_ssi[] = {
RSND_GEN_S_REG(SSICR, 0x00),
RSND_GEN_S_REG(SSISR, 0x04),
RSND_GEN_S_REG(SSITDR, 0x08),
RSND_GEN_S_REG(SSIRDR, 0x0c),
RSND_GEN_S_REG(SSIWSR, 0x20),
};
static const struct rsnd_regmap_field_conf conf_sdmc[] = {
RSND_GEN_M_REG(SSI_BUSIF, 0x0, 0x8000),
};
int ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_ADG, "adg", conf_adg);
int ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SSIU, "ssiu", conf_ssiu);
int ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SSI, "ssi", conf_ssi);
int ret_sdmc = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SDMC, "sdmc", conf_sdmc);
return ret_adg | ret_ssiu | ret_ssi | ret_sdmc;
}
/* /*
* Gen2 * Gen2
*/ */
...@@ -484,6 +552,8 @@ int rsnd_gen_probe(struct rsnd_priv *priv) ...@@ -484,6 +552,8 @@ int rsnd_gen_probe(struct rsnd_priv *priv)
else if (rsnd_is_gen2(priv) || else if (rsnd_is_gen2(priv) ||
rsnd_is_gen3(priv)) rsnd_is_gen3(priv))
ret = rsnd_gen2_probe(priv); ret = rsnd_gen2_probe(priv);
else if (rsnd_is_gen4(priv))
ret = rsnd_gen4_probe(priv);
if (ret < 0) if (ret < 0)
dev_err(dev, "unknown generation R-Car sound device\n"); dev_err(dev, "unknown generation R-Car sound device\n");
......
...@@ -31,6 +31,11 @@ ...@@ -31,6 +31,11 @@
#define RSND_GEN2_SSIU 2 #define RSND_GEN2_SSIU 2
#define RSND_GEN2_SSI 3 #define RSND_GEN2_SSI 3
#define RSND_GEN4_ADG 0
#define RSND_GEN4_SSIU 1
#define RSND_GEN4_SSI 2
#define RSND_GEN4_SDMC 3
#define RSND_BASE_MAX 4 #define RSND_BASE_MAX 4
/* /*
...@@ -197,6 +202,7 @@ enum rsnd_reg { ...@@ -197,6 +202,7 @@ enum rsnd_reg {
SSI_SYS_INT_ENABLE5, SSI_SYS_INT_ENABLE5,
SSI_SYS_INT_ENABLE6, SSI_SYS_INT_ENABLE6,
SSI_SYS_INT_ENABLE7, SSI_SYS_INT_ENABLE7,
SSI_BUSIF,
HDMI0_SEL, HDMI0_SEL,
HDMI1_SEL, HDMI1_SEL,
SSI9_BUSIF0_MODE, SSI9_BUSIF0_MODE,
...@@ -629,6 +635,7 @@ struct rsnd_priv { ...@@ -629,6 +635,7 @@ struct rsnd_priv {
#define RSND_GEN1 (1 << 0) #define RSND_GEN1 (1 << 0)
#define RSND_GEN2 (2 << 0) #define RSND_GEN2 (2 << 0)
#define RSND_GEN3 (3 << 0) #define RSND_GEN3 (3 << 0)
#define RSND_GEN4 (4 << 0)
#define RSND_SOC_MASK (0xFF << 4) #define RSND_SOC_MASK (0xFF << 4)
#define RSND_SOC_E (1 << 4) /* E1/E2/E3 */ #define RSND_SOC_E (1 << 4) /* E1/E2/E3 */
...@@ -703,6 +710,7 @@ struct rsnd_priv { ...@@ -703,6 +710,7 @@ struct rsnd_priv {
#define rsnd_is_gen1(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1) #define rsnd_is_gen1(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1)
#define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2) #define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2)
#define rsnd_is_gen3(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN3) #define rsnd_is_gen3(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN3)
#define rsnd_is_gen4(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN4)
#define rsnd_is_e3(priv) (((priv)->flags & \ #define rsnd_is_e3(priv) (((priv)->flags & \
(RSND_GEN_MASK | RSND_SOC_MASK)) == \ (RSND_GEN_MASK | RSND_SOC_MASK)) == \
(RSND_GEN3 | RSND_SOC_E)) (RSND_GEN3 | RSND_SOC_E))
......
...@@ -29,8 +29,8 @@ struct rsnd_ssiu { ...@@ -29,8 +29,8 @@ struct rsnd_ssiu {
i++) i++)
/* /*
* SSI Gen2 Gen3 * SSI Gen2 Gen3 Gen4
* 0 BUSIF0-3 BUSIF0-7 * 0 BUSIF0-3 BUSIF0-7 BUSIF0-7
* 1 BUSIF0-3 BUSIF0-7 * 1 BUSIF0-3 BUSIF0-7
* 2 BUSIF0-3 BUSIF0-7 * 2 BUSIF0-3 BUSIF0-7
* 3 BUSIF0 BUSIF0-7 * 3 BUSIF0 BUSIF0-7
...@@ -40,10 +40,11 @@ struct rsnd_ssiu { ...@@ -40,10 +40,11 @@ struct rsnd_ssiu {
* 7 BUSIF0 BUSIF0 * 7 BUSIF0 BUSIF0
* 8 BUSIF0 BUSIF0 * 8 BUSIF0 BUSIF0
* 9 BUSIF0-3 BUSIF0-7 * 9 BUSIF0-3 BUSIF0-7
* total 22 52 * total 22 52 8
*/ */
static const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 }; static const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 };
static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 }; static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 };
static const int gen4_id[] = { 0 };
/* enable busif buffer over/under run interrupt. */ /* enable busif buffer over/under run interrupt. */
#define rsnd_ssiu_busif_err_irq_enable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 1) #define rsnd_ssiu_busif_err_irq_enable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 1)
...@@ -152,6 +153,10 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, ...@@ -152,6 +153,10 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
/* clear status */ /* clear status */
rsnd_ssiu_busif_err_status_clear(mod); rsnd_ssiu_busif_err_status_clear(mod);
/* Gen4 doesn't have SSI_MODE */
if (rsnd_is_gen4(priv))
goto ssi_mode_setting_end;
/* /*
* SSI_MODE0 * SSI_MODE0
*/ */
...@@ -206,6 +211,7 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, ...@@ -206,6 +211,7 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1); rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1);
rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2); rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2);
ssi_mode_setting_end:
/* /*
* Enable busif buffer over/under run interrupt. * Enable busif buffer over/under run interrupt.
* It will be handled from ssi.c * It will be handled from ssi.c
...@@ -553,6 +559,9 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv) ...@@ -553,6 +559,9 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
} else if (rsnd_is_gen3(priv)) { } else if (rsnd_is_gen3(priv)) {
list = gen3_id; list = gen3_id;
nr = ARRAY_SIZE(gen3_id); nr = ARRAY_SIZE(gen3_id);
} else if (rsnd_is_gen4(priv)) {
list = gen4_id;
nr = ARRAY_SIZE(gen4_id);
} else { } else {
dev_err(dev, "unknown SSIU\n"); dev_err(dev, "unknown SSIU\n");
return -ENODEV; return -ENODEV;
......
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