]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/commitdiff
SoC: rsnd: add interrupt support for SSI BUSIF buffer
authorYongbo Zhang <giraffesnn123@gmail.com>
Tue, 12 May 2020 09:30:03 +0000 (17:30 +0800)
committerKhalid Elmously <khalid.elmously@canonical.com>
Sat, 8 Aug 2020 05:53:12 +0000 (01:53 -0400)
BugLink: https://bugs.launchpad.net/bugs/1885322
[ Upstream commit 66c705d07d784fb6b4622c6e47b6acae357472db ]

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>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Kelsey Skunberg <kelsey.skunberg@canonical.com>
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/ssi.c

index af19010b9d88f9f59565ccf47f787b12eaf71e8f..8bd49c8a9517e5dd13c9fdf86e0cebbd903e2cca 100644 (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),
 
index ea6cbaa9743ee81c3f6a508d896674ab9dc8ec4d..d47608ff5facc37981bdf8f3cce960c85c5aafe0 100644 (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;
index 4a7d3413917fc253e873e9f8f46bba6fa4ba63cf..47d5ddb526f2116e0755f4a6238c62abb02e7811 100644 (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);