1
0
Fork 0

SoC: rsnd: add interrupt support for SSI BUSIF buffer

[ Upstream commit 66c705d07d ]

SSI BUSIF buffer is possible to overflow or underflow, especially in a
hypervisor environment. If there is no interrupt support, it will eventually
lead to errors in pcm data.
This patch adds overflow and underflow interrupt support for SSI BUSIF buffer.

Reported-by: Chen Li <licheng0822@thundersoft.com>
Signed-off-by: Yongbo Zhang <giraffesnn123@gmail.com>
Tested-by: Chen Li <licheng0822@thundersoft.com>
Acked-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/20200512093003.28332-1-giraffesnn123@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5.4-rM2-2.2.x-imx-squashed
Yongbo Zhang 2020-05-12 17:30:03 +08:00 committed by Greg Kroah-Hartman
parent f34a3697a8
commit b0ccdd2fdd
3 changed files with 162 additions and 0 deletions

View File

@ -224,6 +224,14 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884),
RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888),
RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c),
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0, 0x850),
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE1, 0x854),
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858),
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE3, 0x85c),
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4, 0x890),
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE5, 0x894),
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6, 0x898),
RSND_GEN_S_REG(SSI_SYS_INT_ENABLE7, 0x89c),
RSND_GEN_S_REG(HDMI0_SEL, 0x9e0),
RSND_GEN_S_REG(HDMI1_SEL, 0x9e4),

View File

@ -189,6 +189,14 @@ enum rsnd_reg {
SSI_SYS_STATUS5,
SSI_SYS_STATUS6,
SSI_SYS_STATUS7,
SSI_SYS_INT_ENABLE0,
SSI_SYS_INT_ENABLE1,
SSI_SYS_INT_ENABLE2,
SSI_SYS_INT_ENABLE3,
SSI_SYS_INT_ENABLE4,
SSI_SYS_INT_ENABLE5,
SSI_SYS_INT_ENABLE6,
SSI_SYS_INT_ENABLE7,
HDMI0_SEL,
HDMI1_SEL,
SSI9_BUSIF0_MODE,
@ -237,6 +245,7 @@ enum rsnd_reg {
#define SSI9_BUSIF_ADINR(i) (SSI9_BUSIF0_ADINR + (i))
#define SSI9_BUSIF_DALIGN(i) (SSI9_BUSIF0_DALIGN + (i))
#define SSI_SYS_STATUS(i) (SSI_SYS_STATUS0 + (i))
#define SSI_SYS_INT_ENABLE(i) (SSI_SYS_INT_ENABLE0 + (i))
struct rsnd_priv;

View File

@ -372,6 +372,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
u32 wsr = ssi->wsr;
int width;
int is_tdm, is_tdm_split;
int id = rsnd_mod_id(mod);
int i;
u32 sys_int_enable = 0;
is_tdm = rsnd_runtime_is_tdm(io);
is_tdm_split = rsnd_runtime_is_tdm_split(io);
@ -447,6 +450,38 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
cr_mode = DIEN; /* PIO : enable Data interrupt */
}
/* enable busif buffer over/under run interrupt. */
if (is_tdm || is_tdm_split) {
switch (id) {
case 0:
case 1:
case 2:
case 3:
case 4:
for (i = 0; i < 4; i++) {
sys_int_enable = rsnd_mod_read(mod,
SSI_SYS_INT_ENABLE(i * 2));
sys_int_enable |= 0xf << (id * 4);
rsnd_mod_write(mod,
SSI_SYS_INT_ENABLE(i * 2),
sys_int_enable);
}
break;
case 9:
for (i = 0; i < 4; i++) {
sys_int_enable = rsnd_mod_read(mod,
SSI_SYS_INT_ENABLE((i * 2) + 1));
sys_int_enable |= 0xf << 4;
rsnd_mod_write(mod,
SSI_SYS_INT_ENABLE((i * 2) + 1),
sys_int_enable);
}
break;
}
}
init_end:
ssi->cr_own = cr_own;
ssi->cr_mode = cr_mode;
@ -496,6 +531,13 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
{
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct device *dev = rsnd_priv_to_dev(priv);
int is_tdm, is_tdm_split;
int id = rsnd_mod_id(mod);
int i;
u32 sys_int_enable = 0;
is_tdm = rsnd_runtime_is_tdm(io);
is_tdm_split = rsnd_runtime_is_tdm_split(io);
if (!rsnd_ssi_is_run_mods(mod, io))
return 0;
@ -517,6 +559,38 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
ssi->wsr = 0;
}
/* disable busif buffer over/under run interrupt. */
if (is_tdm || is_tdm_split) {
switch (id) {
case 0:
case 1:
case 2:
case 3:
case 4:
for (i = 0; i < 4; i++) {
sys_int_enable = rsnd_mod_read(mod,
SSI_SYS_INT_ENABLE(i * 2));
sys_int_enable &= ~(0xf << (id * 4));
rsnd_mod_write(mod,
SSI_SYS_INT_ENABLE(i * 2),
sys_int_enable);
}
break;
case 9:
for (i = 0; i < 4; i++) {
sys_int_enable = rsnd_mod_read(mod,
SSI_SYS_INT_ENABLE((i * 2) + 1));
sys_int_enable &= ~(0xf << 4);
rsnd_mod_write(mod,
SSI_SYS_INT_ENABLE((i * 2) + 1),
sys_int_enable);
}
break;
}
}
return 0;
}
@ -622,6 +696,11 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod,
int enable)
{
u32 val = 0;
int is_tdm, is_tdm_split;
int id = rsnd_mod_id(mod);
is_tdm = rsnd_runtime_is_tdm(io);
is_tdm_split = rsnd_runtime_is_tdm_split(io);
if (rsnd_is_gen1(priv))
return 0;
@ -635,6 +714,19 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod,
if (enable)
val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000;
if (is_tdm || is_tdm_split) {
switch (id) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 9:
val |= 0x0000ff00;
break;
}
}
rsnd_mod_write(mod, SSI_INT_ENABLE, val);
return 0;
@ -651,6 +743,12 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
u32 status;
bool elapsed = false;
bool stop = false;
int id = rsnd_mod_id(mod);
int i;
int is_tdm, is_tdm_split;
is_tdm = rsnd_runtime_is_tdm(io);
is_tdm_split = rsnd_runtime_is_tdm_split(io);
spin_lock(&priv->lock);
@ -672,6 +770,53 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
stop = true;
}
status = 0;
if (is_tdm || is_tdm_split) {
switch (id) {
case 0:
case 1:
case 2:
case 3:
case 4:
for (i = 0; i < 4; i++) {
status = rsnd_mod_read(mod,
SSI_SYS_STATUS(i * 2));
status &= 0xf << (id * 4);
if (status) {
rsnd_dbg_irq_status(dev,
"%s err status : 0x%08x\n",
rsnd_mod_name(mod), status);
rsnd_mod_write(mod,
SSI_SYS_STATUS(i * 2),
0xf << (id * 4));
stop = true;
break;
}
}
break;
case 9:
for (i = 0; i < 4; i++) {
status = rsnd_mod_read(mod,
SSI_SYS_STATUS((i * 2) + 1));
status &= 0xf << 4;
if (status) {
rsnd_dbg_irq_status(dev,
"%s err status : 0x%08x\n",
rsnd_mod_name(mod), status);
rsnd_mod_write(mod,
SSI_SYS_STATUS((i * 2) + 1),
0xf << 4);
stop = true;
break;
}
}
break;
}
}
rsnd_ssi_status_clear(mod);
rsnd_ssi_interrupt_out:
spin_unlock(&priv->lock);