audio: auge: fix PAO for frhdmirx [1/2]
authorXing Wang <xing.wang@amlogic.com>
Wed, 27 Feb 2019 06:12:11 +0000 (14:12 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Mon, 18 Mar 2019 12:09:23 +0000 (04:09 -0800)
PD#SWPL-4010

Problem:
Not detect audio type by PAO for frhdmirx

Solution:
Add hw detect for frdhmirx PAO
audio type is checked by hw for PCM too

Verify:
x301

Change-Id: Ib60d738c69f336866250a8181609503912bf0485
Signed-off-by: Xing Wang <xing.wang@amlogic.com>
sound/soc/amlogic/auge/extn.c
sound/soc/amlogic/auge/frhdmirx_hw.c
sound/soc/amlogic/auge/frhdmirx_hw.h
sound/soc/amlogic/auge/spdif.c
sound/soc/amlogic/auge/tdm.c

index 65c4e8d..722957b 100644 (file)
 
 #define DRV_NAME "EXTN"
 
+#define MAX_INT    0x7ffffff
+
+struct extn_chipinfo {
+       /* try to check papb before fetch pcpd
+        * no nonpcm2pcm irq for tl1
+        */
+       bool no_nonpcm2pcm_clr;
+};
+
 struct extn {
        struct aml_audio_controller *actrl;
        struct device *dev;
@@ -69,9 +78,19 @@ struct extn {
        int arc_src;
        int arc_en;
 
+       /* check whether irq generating
+        * if not, reset
+        * 'cuase no irq from nonpcm2pcm, do it by sw.
+        */
+       unsigned int frhdmirx_cnt;      /* irq counter */
+       unsigned int frhdmirx_last_cnt;
+       unsigned int frhdmirx_same_cnt;
+       bool nonpcm_flag;
+
+       struct extn_chipinfo *chipinfo;
 };
 
-#define PREALLOC_BUFFER                (128 * 1024)
+#define PREALLOC_BUFFER                (256 * 1024)
 #define PREALLOC_BUFFER_MAX    (256 * 1024)
 
 #define EXTN_RATES      (SNDRV_PCM_RATE_8000_192000)
@@ -100,21 +119,58 @@ static const struct snd_pcm_hardware extn_hardware = {
        .channels_max = 32,
 };
 
+static void frhdmirx_nonpcm2pcm_clr_reset(struct extn *p_extn)
+{
+       p_extn->frhdmirx_cnt = 0;
+       p_extn->frhdmirx_last_cnt = 0;
+       p_extn->frhdmirx_same_cnt = 0;
+}
+
 static irqreturn_t extn_ddr_isr(int irq, void *devid)
 {
        struct snd_pcm_substream *substream =
                (struct snd_pcm_substream *)devid;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct device *dev = rtd->platform->dev;
+       struct extn *p_extn = (struct extn *)dev_get_drvdata(dev);
 
        if (!snd_pcm_running(substream))
                return IRQ_HANDLED;
 
        snd_pcm_period_elapsed(substream);
 
+       /* check pcm or nonpcm */
+       if (p_extn &&
+               p_extn->chipinfo &&
+               p_extn->chipinfo->no_nonpcm2pcm_clr) {
+               if (p_extn->frhdmirx_last_cnt == p_extn->frhdmirx_cnt) {
+
+                       p_extn->frhdmirx_same_cnt++;
+
+                       if (p_extn->frhdmirx_same_cnt > 5)
+                               frhdmirx_nonpcm2pcm_clr_reset(p_extn);
+
+                       if (p_extn->frhdmirx_cnt == 0)
+                               p_extn->nonpcm_flag = false;
+               } else {
+                       p_extn->frhdmirx_last_cnt = p_extn->frhdmirx_cnt;
+                       p_extn->frhdmirx_same_cnt = 0;
+                       p_extn->nonpcm_flag = true;
+                       frhdmirx_clr_PAO_irq_bits();
+               }
+       }
+
        return IRQ_HANDLED;
 }
 
 static irqreturn_t frhdmirx_isr(int irq, void *devid)
 {
+       struct extn *p_extn = (struct extn *)devid;
+
+       p_extn->frhdmirx_cnt++;
+       if (p_extn->frhdmirx_cnt > MAX_INT - 2)
+               frhdmirx_nonpcm2pcm_clr_reset(p_extn);
+
        return IRQ_HANDLED;
 }
 
@@ -177,8 +233,12 @@ static int extn_close(struct snd_pcm_substream *substream)
        else {
                aml_audio_unregister_toddr(p_extn->dev, substream);
 
-               if (toddr_src_get() == FRHDMIRX)
+               if (toddr_src_get() == FRHDMIRX) {
+                       frhdmirx_nonpcm2pcm_clr_reset(p_extn);
+                       if (p_extn->hdmirx_mode == 1)
+                               frhdmirx_clr_PAO_irq_bits();
                        free_irq(p_extn->irq_frhdmirx, p_extn);
+               }
        }
        runtime->private_data = NULL;
 
@@ -639,7 +699,7 @@ static const struct sppdif_audio_info type_texts[] = {
        {3, 0xb, "DTS-I"},
        {3, 0x0c, "DTS-II"},
        {3, 0x0d, "DTS-III"},
-       {3, 0x11, "DTS-IV"},
+       {4, 0x11, "DTS-IV"},
        {4, 0, "DTS-HD"},
        {5, 0x16, "TRUEHD"},
        {6, 0x103, "PAUSE"},
@@ -651,13 +711,16 @@ static const struct soc_enum hdmirx_audio_type_enum =
        SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(spdif_audio_type_texts),
                        spdif_audio_type_texts);
 
-static int hdmiin_check_audio_type(void)
+static int hdmiin_check_audio_type(struct extn *p_extn)
 {
        int total_num = sizeof(type_texts)/sizeof(struct sppdif_audio_info);
        int pc = frhdmirx_get_chan_status_pc();
        int audio_type = 0;
        int i;
 
+       if (!p_extn->nonpcm_flag)
+               return audio_type;
+
        for (i = 0; i < total_num; i++) {
                if (pc == type_texts[i].pc) {
                        audio_type = type_texts[i].aud_type;
@@ -674,8 +737,12 @@ static int hdmirx_audio_type_get_enum(
        struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct extn *p_extn = dev_get_drvdata(component->dev);
+
        ucontrol->value.enumerated.item[0] =
-               hdmiin_check_audio_type();
+               hdmiin_check_audio_type(p_extn);
+
        return 0;
 }
 #endif
@@ -735,6 +802,7 @@ static const struct snd_kcontrol_new extn_controls[] = {
                0,
                aml_get_atmos_audio_edid,
                aml_set_atmos_audio_edid),
+
        SOC_ENUM_EXT("HDMIIN Audio Type",
                         hdmirx_audio_type_enum,
                         hdmirx_audio_type_get_enum,
@@ -749,9 +817,18 @@ static const struct snd_soc_component_driver extn_component = {
        .name           = DRV_NAME,
 };
 
+struct extn_chipinfo tl1_extn_chipinfo = {
+       .no_nonpcm2pcm_clr = true,
+};
+
 static const struct of_device_id extn_device_id[] = {
        {
                .compatible = "amlogic, snd-extn",
+               .data       = &tl1_extn_chipinfo,
+       },
+       {
+               .compatible = "amlogic, tl1-snd-extn",
+               .data       = &tl1_extn_chipinfo,
        },
        {},
 };
@@ -766,9 +843,9 @@ static int extn_platform_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct aml_audio_controller *actrl = NULL;
        struct extn *p_extn = NULL;
+       struct extn_chipinfo *p_chipinfo;
        int ret = 0;
 
-
        p_extn = devm_kzalloc(dev, sizeof(struct extn), GFP_KERNEL);
        if (!p_extn)
                return -ENOMEM;
@@ -776,6 +853,14 @@ static int extn_platform_probe(struct platform_device *pdev)
        p_extn->dev = dev;
        dev_set_drvdata(dev, p_extn);
 
+       /* match data */
+       p_chipinfo = (struct extn_chipinfo *)
+               of_device_get_match_data(dev);
+       if (!p_chipinfo)
+               dev_warn_once(dev, "check whether to update chipinfo\n");
+       else
+               p_extn->chipinfo = p_chipinfo;
+
        /* get audio controller */
        node_prt = of_get_parent(node);
        if (node_prt == NULL)
@@ -798,8 +883,8 @@ static int extn_platform_probe(struct platform_device *pdev)
        /* Default ARC SRC */
        p_extn->arc_src = 1;
 
-       /* Default: SPDIF in mode */
-       p_extn->hdmirx_mode = 0;
+       /* Default: PAO mode */
+       p_extn->hdmirx_mode = 1;
 
        ret = snd_soc_register_component(&pdev->dev,
                                &extn_component,
index 19c55f4..1dd0593 100644 (file)
@@ -15,6 +15,7 @@
  *
  */
 #include <linux/types.h>
+#include <linux/kernel.h>
 
 #include "frhdmirx_hw.h"
 #include "regs.h"
@@ -48,7 +49,7 @@ void frhdmirx_src_select(int src)
                (bool)src << 23);
 }
 
-void frhdmirx_enable_irq_bits(int channels, int src)
+static void frhdmirx_enable_irq_bits(int channels, int src)
 {
        int lane, int_bits = 0, i;
 
@@ -59,10 +60,11 @@ void frhdmirx_enable_irq_bits(int channels, int src)
 
        /* interrupt bits */
        if (src) { /* PAO mode */
-               int_bits = (0x1 << 24 | /*  PAO data: find papb */
-                       0x1 << 16 /* PAO data: find pcpd changed */
+               int_bits = (
+                       0x1 << INT_PAO_PAPB_MASK | /* find papb */
+                       0x1 << INT_PAO_PCPD_MASK   /* find pcpd changed */
                        );
-       } else { /* SPDIF Lane*/
+       } else { /* SPDIF Lane */
                int lane_irq_bits = (0x1 << 7 | /* lane: find papb */
                        0x1 << 6 | /* lane: find papb */
                        0x1 << 5 | /* lane: find nonpcm to pcm */
@@ -77,6 +79,39 @@ void frhdmirx_enable_irq_bits(int channels, int src)
        audiobus_write(EE_AUDIO_FRHDMIRX_CTRL2, int_bits);
 }
 
+void frhdmirx_clr_irq_bits(int channels, int src)
+{
+       int lane, int_clr_mask = 0, i;
+
+       if (channels % 2)
+               lane = channels / 2 + 1;
+       else
+               lane = channels / 2;
+
+       /* interrupt bits */
+       if (src) { /* PAO mode */
+               int_clr_mask = (
+                       0x1 << INT_PAO_PAPB_MASK | /* find papb */
+                       0x1 << INT_PAO_PCPD_MASK   /* find pcpd changed */
+                       );
+       } else { /* SPDIF Lane */
+               int lane_irq_bits = (0x1 << 7 | /* lane: find papb */
+                       0x1 << 6 | /* lane: find valid changed; */
+                       0x1 << 5 | /* lane: find nonpcm to pcm */
+                       0x1 << 4 | /* lane: find pcpd changed */
+                       0x1 << 3 | /* lane: find ch status changed */
+                       0x1 << 1 /* lane: find parity error */
+                       );
+
+               for (i = 0; i < lane; i++)
+                       int_clr_mask |= (lane_irq_bits << i);
+       }
+       audiobus_write(EE_AUDIO_FRHDMIRX_CTRL3, ~int_clr_mask);
+       audiobus_write(EE_AUDIO_FRHDMIRX_CTRL3, int_clr_mask);
+       audiobus_write(EE_AUDIO_FRHDMIRX_CTRL4, ~int_clr_mask);
+       audiobus_write(EE_AUDIO_FRHDMIRX_CTRL4, int_clr_mask);
+}
+
 void frhdmirx_ctrl(int channels, int src)
 {
        int lane, lane_mask = 0, i;
@@ -84,30 +119,27 @@ void frhdmirx_ctrl(int channels, int src)
        /* PAO mode */
        if (src) {
                audiobus_write(EE_AUDIO_FRHDMIRX_CTRL0,
-                       0x1 << 23 | /* slect pao mode */
                        0x1 << 22 | /* capture input by fall edge*/
-                       0x1 << 7  | /* start sending ch num info out */
                        0x1 << 8  | /* start detect PAPB */
-                       0x1 << 6    /* chan status sel: pao pc/pd value */);
-               return;
-       }
-
-       if (channels % 2)
-               lane = channels / 2 + 1;
-       else
-               lane = channels / 2;
-
-       for (i = 0; i < lane; i++)
-               lane_mask |= (1 << i);
+                       0x4 << 4    /* chan status sel: pao pc/pd value */
+                       );
+       } else {
+               if (channels % 2)
+                       lane = channels / 2 + 1;
+               else
+                       lane = channels / 2;
 
-       audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL0,
-               0x1 << 30 | 0xf << 24 | 0x1 << 22 | 0x3 << 11,
-               0x1 << 30 | /* chnum_sel */
-               lane_mask << 24 | /* chnum_sel */
-               0x1 << 22 | /* clk_inv */
-               0x0 << 11  /* req_sel, Sync 4 spdifin by which */
-               );
+               for (i = 0; i < lane; i++)
+                       lane_mask |= (1 << i);
 
+               audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL0,
+                       0x1 << 30 | 0xf << 24 | 0x1 << 22 | 0x3 << 11,
+                       0x1 << 30 | /* chnum_sel */
+                       lane_mask << 24 | /* chnum_sel */
+                       0x1 << 22 | /* clk_inv */
+                       0x0 << 11  /* req_sel, Sync 4 spdifin by which */
+                       );
+       }
        /* nonpcm2pcm_th */
        audiobus_write(EE_AUDIO_FRHDMIRX_CTRL1, 0xff << 20);
 
@@ -115,6 +147,22 @@ void frhdmirx_ctrl(int channels, int src)
        frhdmirx_enable_irq_bits(channels, src);
 }
 
+void frhdmirx_clr_PAO_irq_bits(void)
+{
+       audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL4,
+               0x1 << INT_PAO_PAPB_MASK | 0x1 << INT_PAO_PCPD_MASK,
+               0x1 << INT_PAO_PAPB_MASK | 0x1 << INT_PAO_PCPD_MASK);
+
+       audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL4,
+               0x1 << INT_PAO_PAPB_MASK | 0x1 << INT_PAO_PCPD_MASK,
+               0x0 << INT_PAO_PAPB_MASK | 0x0 << INT_PAO_PCPD_MASK);
+}
+
+unsigned int frhdmirx_get_ch_status0to31(void)
+{
+       return (unsigned int)audiobus_read(EE_AUDIO_FRHDMIRX_STAT0);
+}
+
 unsigned int frhdmirx_get_chan_status_pc(void)
 {
        unsigned int val;
@@ -122,6 +170,3 @@ unsigned int frhdmirx_get_chan_status_pc(void)
        val = audiobus_read(EE_AUDIO_FRHDMIRX_STAT1);
        return (val >> 16) & 0xff;
 }
-
-
-
index e0ebfe4..7c83dd0 100644 (file)
 #ifndef __FRHDMIRX_HW_H__
 #define __FRHDMIRX_HW_H__
 
+#define INT_PAO_PAPB_MASK    24
+#define INT_PAO_PCPD_MASK    16
+
 extern void frhdmirx_enable(bool enable);
 extern void frhdmirx_src_select(int src);
 extern void frhdmirx_ctrl(int channels, int src);
+extern void frhdmirx_clr_PAO_irq_bits(void);
+extern unsigned int frhdmirx_get_ch_status0to31(void);
 extern unsigned int frhdmirx_get_chan_status_pc(void);
 #endif
index 8567d7e..0205867 100644 (file)
@@ -907,7 +907,7 @@ static struct snd_pcm_ops aml_spdif_ops = {
        .mmap      = aml_spdif_mmap,
 };
 
-#define PREALLOC_BUFFER                (128 * 1024)
+#define PREALLOC_BUFFER                (256 * 1024)
 #define PREALLOC_BUFFER_MAX    (256 * 1024)
 static int aml_spdif_new(struct snd_soc_pcm_runtime *rtd)
 {
index 79742b3..0d0c150 100644 (file)
@@ -409,7 +409,7 @@ static struct snd_pcm_ops aml_tdm_ops = {
        .mmap = aml_tdm_mmap,
 };
 
-#define PREALLOC_BUFFER                (128 * 1024)
+#define PREALLOC_BUFFER                (256 * 1024)
 #define PREALLOC_BUFFER_MAX    (256 * 1024)
 static int aml_tdm_new(struct snd_soc_pcm_runtime *rtd)
 {