forked from Minki/linux
SoC: rsnd: add interrupt support for SSI BUSIF buffer
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>
This commit is contained in:
parent
7d8785bc7a
commit
66c705d07d
@ -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),
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user