Commit 7fa72cca authored by Kuninori Morimoto's avatar Kuninori Morimoto Committed by Mark Brown

ASoC: rsnd: add HDMI output support

Renesas R-Car Gen3 can output HDMI sound if SSIU/SSI are connected to
R-Car built-in HDMI device (R-Car Gen3 built-in HDMI device will be
controlled by DRM/KMS driver).
If SSIx was connected to HDMI0/1 on DT, SSI driver will detect it
automatically by this patch.
Note is that now Renesas R-Car sound driver is assuming that it is
using OF-graph base simple card for HDMI sound.
Signed-off-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 4d4b334b
...@@ -38,7 +38,7 @@ config SND_SOC_RCAR ...@@ -38,7 +38,7 @@ config SND_SOC_RCAR
tristate "R-Car series SRU/SCU/SSIU/SSI support" tristate "R-Car series SRU/SCU/SSIU/SSI support"
depends on COMMON_CLK depends on COMMON_CLK
depends on OF || COMPILE_TEST depends on OF || COMPILE_TEST
select SND_SIMPLE_CARD select SND_SIMPLE_CARD_UTILS
select REGMAP_MMIO select REGMAP_MMIO
help help
This option enables R-Car SRU/SCU/SSIU/SSI sound support This option enables R-Car SRU/SCU/SSIU/SSI sound support
......
...@@ -909,8 +909,11 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) ...@@ -909,8 +909,11 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
*/ */
dai_i = 0; dai_i = 0;
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++, is_graph); __rsnd_dai_probe(priv, dai_np, dai_i, is_graph);
rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i);
dai_i++;
}
} 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++, is_graph); __rsnd_dai_probe(priv, dai_np, dai_i++, is_graph);
......
...@@ -219,6 +219,8 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) ...@@ -219,6 +219,8 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884), RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884),
RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888), RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888),
RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c), RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c),
RSND_GEN_S_REG(HDMI0_SEL, 0x9e0),
RSND_GEN_S_REG(HDMI1_SEL, 0x9e4),
/* FIXME: it needs SSI_MODE2/3 in the future */ /* FIXME: it needs SSI_MODE2/3 in the future */
RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80),
......
...@@ -170,6 +170,8 @@ enum rsnd_reg { ...@@ -170,6 +170,8 @@ enum rsnd_reg {
RSND_REG_SSI_SYS_STATUS5, RSND_REG_SSI_SYS_STATUS5,
RSND_REG_SSI_SYS_STATUS6, RSND_REG_SSI_SYS_STATUS6,
RSND_REG_SSI_SYS_STATUS7, RSND_REG_SSI_SYS_STATUS7,
RSND_REG_HDMI0_SEL,
RSND_REG_HDMI1_SEL,
/* SSI */ /* SSI */
RSND_REG_SSICR, RSND_REG_SSICR,
...@@ -646,6 +648,13 @@ int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); ...@@ -646,6 +648,13 @@ int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io); u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io);
#define RSND_SSI_HDMI_PORT0 0xf0
#define RSND_SSI_HDMI_PORT1 0xf1
int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io);
void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
struct device_node *endpoint,
int dai_i);
#define rsnd_ssi_is_pin_sharing(io) \ #define rsnd_ssi_is_pin_sharing(io) \
__rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <sound/simple_card_utils.h>
#include <linux/delay.h> #include <linux/delay.h>
#include "rsnd.h" #include "rsnd.h"
#define RSND_SSI_NAME_SIZE 16 #define RSND_SSI_NAME_SIZE 16
...@@ -81,6 +82,8 @@ struct rsnd_ssi { ...@@ -81,6 +82,8 @@ struct rsnd_ssi {
/* flags */ /* flags */
#define RSND_SSI_CLK_PIN_SHARE (1 << 0) #define RSND_SSI_CLK_PIN_SHARE (1 << 0)
#define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ #define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */
#define RSND_SSI_HDMI0 (1 << 2) /* for HDMI0 */
#define RSND_SSI_HDMI1 (1 << 3) /* for HDMI1 */
#define for_each_rsnd_ssi(pos, priv, i) \ #define for_each_rsnd_ssi(pos, priv, i) \
for (i = 0; \ for (i = 0; \
...@@ -99,6 +102,20 @@ struct rsnd_ssi { ...@@ -99,6 +102,20 @@ struct rsnd_ssi {
#define rsnd_ssi_is_run_mods(mod, io) \ #define rsnd_ssi_is_run_mods(mod, io) \
(rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod))) (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod)))
int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io)
{
struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI0)
return RSND_SSI_HDMI_PORT0;
if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI1)
return RSND_SSI_HDMI_PORT1;
return 0;
}
int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
{ {
struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
...@@ -835,6 +852,47 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, ...@@ -835,6 +852,47 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
of_node_put(node); of_node_put(node);
} }
static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
struct rsnd_dai_stream *io,
struct device_node *remote_ep)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
struct rsnd_ssi *ssi;
if (!mod)
return;
ssi = rsnd_mod_to_ssi(mod);
if (strstr(remote_ep->full_name, "hdmi0")) {
ssi->flags |= RSND_SSI_HDMI0;
dev_dbg(dev, "%s[%d] connected to HDMI0\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
}
if (strstr(remote_ep->full_name, "hdmi1")) {
ssi->flags |= RSND_SSI_HDMI1;
dev_dbg(dev, "%s[%d] connected to HDMI1\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
}
}
void rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv,
struct device_node *endpoint,
int dai_i)
{
struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i);
struct device_node *remote_ep;
remote_ep = of_graph_get_remote_endpoint(endpoint);
if (!remote_ep)
return;
__rsnd_ssi_parse_hdmi_connection(priv, &rdai->playback, remote_ep);
__rsnd_ssi_parse_hdmi_connection(priv, &rdai->capture, remote_ep);
}
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
{ {
if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
......
...@@ -123,6 +123,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, ...@@ -123,6 +123,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
struct rsnd_priv *priv) struct rsnd_priv *priv)
{ {
int hdmi = rsnd_ssi_hdmi_port(io);
int ret; int ret;
ret = rsnd_ssiu_init(mod, io, priv); ret = rsnd_ssiu_init(mod, io, priv);
...@@ -149,6 +150,42 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, ...@@ -149,6 +150,42 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
rsnd_get_dalign(mod, io)); rsnd_get_dalign(mod, io));
} }
if (hdmi) {
enum rsnd_mod_type rsnd_ssi_array[] = {
RSND_MOD_SSIM1,
RSND_MOD_SSIM2,
RSND_MOD_SSIM3,
};
struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
struct rsnd_mod *pos;
u32 val;
int i, shift;
i = rsnd_mod_id(ssi_mod);
/* output all same SSI as default */
val = i << 16 |
i << 20 |
i << 24 |
i << 28 |
i;
for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) {
shift = (i * 4) + 16;
val = (val & ~(0xF << shift)) |
rsnd_mod_id(pos) << shift;
}
switch (hdmi) {
case RSND_SSI_HDMI_PORT0:
rsnd_mod_write(mod, HDMI0_SEL, val);
break;
case RSND_SSI_HDMI_PORT1:
rsnd_mod_write(mod, HDMI1_SEL, val);
break;
}
}
return 0; return 0;
} }
......
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